dtcm: Resolve CID 87713
[oweals/cde.git] / cde / programs / dsdm / dsdm.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these 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 /* $TOG: dsdm.c /main/6 1997/06/18 17:27:35 samborn $ */
24 /*      Copyright (c) 1990, 1991, 1992, 1993 UNIX System Laboratories, Inc.     */
25 /*      Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 AT&T     */
26 /*        All Rights Reserved   */
27
28 /*      THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF          */
29 /*      UNIX System Laboratories, Inc.                          */
30 /*      The copyright notice above does not evidence any        */
31 /*      actual or intended publication of such source code.     */
32
33 /*
34  *      Copyright (C) 1986,1992  Sun Microsystems, Inc
35  *                      All rights reserved.
36  *              Notice of copyright on this source code
37  *              product does not indicate publication.
38  *
39  * RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by
40  * the U.S. Government is subject to restrictions as set forth
41  * in subparagraph (c)(1)(ii) of the Rights in Technical Data
42  * and Computer Software Clause at DFARS 252.227-7013 (Oct. 1988)
43  * and FAR 52.227-19 (c) (June 1987).
44  *
45  *      Sun Microsystems, Inc., 2550 Garcia Avenue,
46  *      Mountain View, California 94043.
47  *
48  */
49
50 /*
51  * @(#)dsdm.c   1.5 91/02/13
52  * Drop Site Database Manager for drag'n'drop.
53  *
54  * Master algorithm:
55  *
56  * Start with visible region as whole screen.
57  * For each top-level window, do
58  * (0) flatten its interest rectangles
59  * (1) intersect interest rects with the top-level window
60  * (2) intersect them with the visible region
61  * (3) append them to the master list
62  * (4) subtract this top-level frame from the visible region
63  *
64  * USL changes are #ifdef'd with "oldcode" or commented with *USL* - Sam Chang
65  */
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #if defined(SVR4) || defined(SYSV)
70 #include <string.h>                     /*USL*/
71 #else   /* SVR4 or SYSV */
72 #include <strings.h>
73 #endif  /* SVR4 or SYSV */
74
75 #if !defined(__STDC__) && !defined(__cplusplus) && !defined(c_plusplus) /*USL*/
76 #define void    char
77 #endif
78
79 #define XFreeDefn       char *
80
81 #include <X11/Xproto.h>
82 #include <X11/Xlib.h>
83 #include <X11/Xutil.h>
84 #include <X11/Xatom.h>
85
86 /*
87  * Use DPRINTF to write debugging messages.  Place all arguments in an
88  * extra pair of parentheses, like so:
89  *      DPRINTF(("%s: some error occurred (code=%d)\n", ProgramName, err));
90  */
91
92 #ifdef    DEBUG
93 #define DPRINTF(args) (void) printf args
94 #else  /* DEBUG */
95 #define DPRINTF(a)
96 #endif /* DEBUG */
97
98 #define INTEREST_MAX 100000000L /*(1024L*1024L)*/
99
100 #define FIND_CONTINUE ((Window) 0L)
101 #define FIND_STOP     ((Window) 1L)
102
103 #define PROXY 1
104 #ifdef PROXY
105 extern Window GetAtomWindow();
106 extern Atom ATOM_MOTIF_RECEIVER_INFO;
107 Window proxy_win;
108 #endif
109
110 char *ProgramName;
111 Atom ATOM_DRAGDROP_DSDM;
112 Atom ATOM_DRAGDROP_INTEREST;
113 Atom ATOM_WM_STATE;
114 Atom ATOM_SITE_RECTS;
115
116
117 int (*DefaultErrorHandler)();
118
119 typedef struct _site {
120     int screen;
121     unsigned long site_id;
122     Window window_id;
123     unsigned long flags;
124     Region region;
125     struct _site *next;
126 } drop_site_t;
127
128 drop_site_t *MasterSiteList = NULL;
129 drop_site_t **NextSite;
130 int SitesFound = 0;
131
132
133 Bool SearchChildren();
134
135 /*
136  * Region stuff.  Stolen from region.h.
137  */
138
139 typedef struct _box {
140     short x1, x2, y1, y2;
141 } BOX;
142
143 typedef struct {
144     long size;
145     long numRects;
146     BOX *rects;
147     BOX extents;
148 } REGION;
149
150
151 #define REGION_NUMRECTS(r) (((REGION *)(r))->numRects)
152
153
154
155 #ifdef DEBUG    /*USL*/
156 /*
157  * Flash the visible region.  Useful for debugging.
158  */
159 void
160 FlashRegion(Display *dpy, int s, GC gc)
161 {
162     XEvent e;
163     Bool done = False;
164     Window root = RootWindow(dpy, s);
165
166     if (GrabSuccess != XGrabPointer(dpy, root, False,
167         ButtonPressMask, GrabModeAsync, GrabModeAsync,
168         None, None, CurrentTime)) {
169             fputs("can't grab the pointer\n", stderr);
170             return;
171     }
172
173     do {
174         XFillRectangle(dpy, root, gc, 0, 0,
175                        DisplayWidth(dpy, s),
176                        DisplayHeight(dpy, s));
177         XFlush(dpy);
178
179         XMaskEvent(dpy, ButtonPressMask, &e);
180         if (e.xbutton.button == Button3)
181             done = True;
182
183         XFillRectangle(dpy, root, gc, 0, 0,
184                        DisplayWidth(dpy, s),
185                        DisplayHeight(dpy, s));
186         XFlush(dpy);
187     } while (!done);
188     XUngrabPointer(dpy, CurrentTime);
189 } /* end of FlashRegion */
190
191
192 void
193 FlashDropSites(Display *dpy)
194 {
195     drop_site_t *site = MasterSiteList;
196     XGCValues gcv;
197     GC *gcs;
198     int s;
199     GC gc;
200
201     gcv.function = GXinvert;
202     gcv.subwindow_mode = IncludeInferiors;
203
204     gcs = (GC *) malloc(sizeof(GC)*ScreenCount(dpy));
205     for (s=0; s<ScreenCount(dpy); ++s)
206         gcs[s] = XCreateGC(dpy, RootWindow(dpy, s),
207                            GCFunction|GCSubwindowMode, &gcv);
208
209     while (site != NULL) {
210         printf("sid %ld   wid 0x%lx   flags 0x%lx\n",
211                site->site_id, site->window_id, site->flags);
212         gc = gcs[site->screen];
213         XSetRegion(dpy, gc, site->region);
214         FlashRegion(dpy, site->screen, gc);
215         site = site->next;
216     }
217
218     for (s=0; s<ScreenCount(dpy); ++s)
219         XFreeGC(dpy, gcs[s]);
220     free(gcs);
221 } /* end of FlashDropSites */
222
223 #endif /* DEBUG */
224
225
226 /*
227  * Get the interest property from this window.  If a valid interest property
228  * was found, a pointer to the data is returned.  This data must be freed with
229  * XFree().  If no valid property is found, NULL is returned.
230  */
231 #ifdef oldcode
232 void *
233 GetInterestProperty(Display *dpy, Window win, int *nitems)
234 #else
235 unsigned char *
236 GetInterestProperty(Display *dpy, Window win, unsigned long *nitems)
237 #endif
238 {
239     Status s;
240     Atom acttype;
241 #ifdef oldcode
242     int actfmt, remain;
243     void *data;
244 #else
245         int             actfmt;
246         unsigned long   remain;
247         unsigned char * data;
248 #endif
249
250     s = XGetWindowProperty(dpy, win, ATOM_DRAGDROP_INTEREST, 0L, INTEREST_MAX,
251                            False, ATOM_DRAGDROP_INTEREST, &acttype, &actfmt,
252                            nitems, &remain, &data);
253
254     if (s != Success)
255         return NULL;
256
257     if (acttype == None)
258         /* property does not exist */
259         return NULL;
260
261     if (acttype != ATOM_DRAGDROP_INTEREST) {
262         fputs("dsdm: interest property has wrong type\n", stderr);
263         return NULL;
264     }
265
266     if (actfmt != 32) {
267         fputs("dsdm: interest property has wrong format\n", stderr);
268 #ifdef oldcode
269         XFree(data);
270 #else
271         XFree((XFreeDefn) data);
272 #endif
273         return NULL;
274     }
275
276     if (remain > 0) {
277         /* XXX didn't read it all, punt */
278         fputs("dsdm: interest property too long\n", stderr);
279 #ifdef oldcode
280         XFree(data);
281 #else
282         XFree((XFreeDefn) data);
283 #endif
284         return NULL;
285     }
286     return data;
287 } /* end of GetInterestProperty */
288
289
290 /*
291  * Check to see if window win is a top-level window, that is, if it is a
292  * viewable, InputOutput window that has a drop interest or WM_STATE property
293  * on it.  If either property is found, return True.  Additionally, if True is
294  * returned, psite will be set to point to the drop interest property data if 
295  * that property is found, or NULL if not.  If neither property is found, all 
296  * children of this window are searched.
297  */
298 Bool
299 FindRecursively(Display *dpy, Window root, Window win, Window *pwin, void **psite, unsigned long *plen, int *px, int *py)
300 {
301     XWindowAttributes attr;
302     Window junk;
303     Atom acttype;
304     int actfmt;
305     unsigned long nitems;
306     unsigned long remain;
307 #ifdef oldcode
308     void *data;
309 #else
310         unsigned char * data;
311 #endif
312     Status s;
313     
314     if (XGetWindowAttributes(dpy, win, &attr) == 0) {
315         fprintf(stderr, "%s: XGetWindowAttributes failed for window 0x%lx\n",
316                 ProgramName, win);
317         return False;
318     }
319
320     if (attr.depth == 0 || attr.class == InputOnly ||
321             attr.map_state != IsViewable) {
322         return False;
323     }
324
325     data = GetInterestProperty(dpy, win, &nitems);
326     if (data != NULL) {
327         if (!XTranslateCoordinates(dpy, win, root, 0, 0, px, py, &junk)) {
328             fprintf(stderr, "%s: window 0x%lx isn't on the same root!\n",
329                     ProgramName, win);
330 #ifdef oldcode
331             XFree(data);
332 #else
333             XFree((XFreeDefn) data);
334 #endif
335             return False;
336         }
337         *psite = (void *) data;
338         *plen = nitems;
339         *pwin = win;
340         DPRINTF(("%s: found top-level window 0x%lx with an interest\n",
341                  ProgramName, win));
342         return True;
343     }
344         
345     s = XGetWindowProperty(dpy, win, ATOM_WM_STATE, 0L, 1,
346                            False, ATOM_WM_STATE, &acttype, &actfmt,
347                            &nitems, &remain, &data);
348
349     if (s != Success)   /* couldn't find the window */
350         return False;
351
352     if (acttype == ATOM_WM_STATE) {
353         /* found it! */
354         DPRINTF(("%s: found top-level window 0x%lx with no interest\n",
355                  ProgramName, win));
356 #ifdef oldcode
357         XFree(data);
358 #else
359         XFree((XFreeDefn) data);
360 #endif
361         *psite = NULL;
362         *plen = 0;
363
364 #ifdef PROXY
365 #define DRAGDROP_VERSION        0
366 #define INTEREST_RECT           0
367 #define DATA_LEN                11
368 #define MOTIF_RECEIVER_FLAG     0x80000000
369         /* only do the following if the window doesnot 
370            have SUN_DND_INTEREST advertised */
371         if (GetAtomWindow(dpy, win, ATOM_MOTIF_RECEIVER_INFO)) {
372             /* got a motif receiver, create a drop site */
373             CARD32 *data = (CARD32 *) malloc(sizeof(CARD32) * DATA_LEN);
374
375             data[0] = DRAGDROP_VERSION;
376             data[1] = 1;        /* site count */
377             data[2] = proxy_win;        /* event_window, xview needs this */
378             data[3] = win;      /* site_id */
379             data[4] = MOTIF_RECEIVER_FLAG; /*flag to indicate motif receiver */
380             data[5] = INTEREST_RECT; /* drop site type */
381             data[6] = 1;        /* drop site count */
382             data[7] = 0;        /* drop window x */
383             data[8] = 0;        /* drop window y */
384             data[9] = attr.width;       /* drop window width */
385             data[10] = attr.height;     /* drop window height */
386
387             *pwin = win;
388             *psite = (void *) data;
389             *plen = DATA_LEN;
390             XTranslateCoordinates(dpy, win, root, 0, 0, px, py, &junk);
391
392             /* XView needs this */
393             XChangeProperty(dpy,
394                     win,
395                     ATOM_DRAGDROP_INTEREST, /* property */
396                     ATOM_DRAGDROP_INTEREST, /* type */
397                     32,               /* format */
398                     PropModeReplace, /* mode */
399                     (unsigned char *) data, /* data */
400                     DATA_LEN  /* number of elements */
401                     );
402
403             /* dsdm needs this */
404             data[2] = win;
405         }
406 #undef DATA_LEN
407 #endif
408         return True;
409     }
410
411 #ifdef oldcode
412     return(SearchChildren(dpy, root, win, pwin, psite, plen, px, py));
413 #else
414     return(SearchChildren(dpy, root, win, pwin, psite, plen, px, py, True));
415 #endif
416 } /* end of FindRecursively */
417
418
419
420 /*
421  * Look through all the children of window win for a top-level window.
422  */
423 Bool
424 #ifdef oldcode
425 SearchChildren(Display *dpy, Window root, Window win, Window *pwin, void **psite, unsigned long *plen, int *px, int *py)
426 #else
427 SearchChildren(Display *dpy, Window root, Window win, Window *pwin, void **psite, unsigned long *plen, int *px, int *py, Bool from_FindRec)
428 #endif
429 {
430     Window junk;
431     Window *children;
432 #ifdef oldcode
433     int nchildren;
434 #else
435     unsigned int nchildren;
436 #endif
437     int i;
438
439     if (XQueryTree(dpy, win, &junk, &junk, &children, &nchildren) == 0)
440         return False;
441
442     for (i=0; i<nchildren; ++i) {
443         if (FindRecursively(dpy, root, children[i], pwin, psite, plen, px, py))
444 #ifdef oldcode
445             return True;
446 #else
447         {
448                 XFree((XFreeDefn)children);
449             return True;
450         }
451 #endif
452     }
453 #ifndef oldcode
454         if (from_FindRec == False && nchildren)
455                 XFree((XFreeDefn)children);
456 #endif
457     return False;
458 } /* end of SearchChildren */
459
460
461 /*
462  * Create and return a region that contains a given rectangle.
463  */
464 Region
465 MakeRegionFromRect(int x, int y, unsigned int w, unsigned int h)
466 {
467     XRectangle r;
468     Region reg;
469
470     r.x = x;
471     r.y = y;
472     r.width = w;
473     r.height = h;
474     reg = XCreateRegion();
475     XUnionRectWithRegion(&r, reg, reg);
476     return reg;
477 } /* end of MakeRegionFromRect */
478
479
480 /*
481  * Create and return a region that contains the geometry of the window.
482  * The region returned must be destroyed with XDestroyRegion().  The offset 
483  * parameter indicates whether the window's geometry should be offset by its
484  * (x,y) location w.r.t. its parent.  If it is false, the region's upper left 
485  * corner is at (0,0).
486  */
487 Region
488 GetWindowRegion(Display *dpy, Window win, Bool offset)
489 {
490     Window wjunk;
491     int x, y;
492     unsigned int width, height, junk;
493     Region winrgn;
494
495 #ifdef oldcode
496     winrgn = XCreateRegion();
497 #endif
498     if (0 == XGetGeometry(dpy, win, &wjunk, &x, &y, &width, &height,
499                           &junk, &junk)) {
500         fprintf(stderr, "%s: XGetGeometry failed on window 0x%lx\n",
501                 ProgramName, win);
502 #ifndef oldcode
503             winrgn = XCreateRegion();
504 #endif
505         return winrgn;
506     }
507     return MakeRegionFromRect(offset ? x : 0, offset ? y: 0, width, height);
508 } /* end of GetWindowRegion */
509
510
511 /*
512  * Subtract the area of a window from the current visible region.
513  */
514 void
515 SubtractWindowFromVisibleRegion(Display *dpy, Window win, Region visrgn)
516 {
517     Region winrgn = GetWindowRegion(dpy, win, True);
518     XSubtractRegion(visrgn, winrgn, visrgn);
519     XDestroyRegion(winrgn);
520 } /* end of SubtractWindowFromVisibleRegion */
521
522
523 #define DRAGDROP_VERSION        0
524 #define INTEREST_RECT           0
525 #define INTEREST_WINDOW         1
526
527 #define NEXTWORD(dest) do {                                             \
528             if (++cur >= datalen) {                                     \
529                 fprintf(stderr,                                         \
530                         "%s: drop interest data too short on 0x%lx\n",  \
531                         ProgramName, win);                              \
532                 if (region != NULL)                                     \
533                     XDestroyRegion(region);                             \
534                 if (toprgn != NULL)                                     \
535                     XDestroyRegion(toprgn);                             \
536                 return;                                                 \
537             }                                                           \
538             (dest) = array[cur];                                        \
539         } while (0)
540
541
542 void
543 ProcessInterestProperty(dpy, win, screen, data, datalen, visrgn, xoff, yoff)
544 #ifndef oldcode
545         Display *       dpy;
546 #endif
547     Window win;
548     int screen;
549     void *data;
550     unsigned long datalen;
551     Region visrgn;
552     int xoff, yoff;
553 {
554     unsigned long *array = (unsigned long *)data;
555     int cur = 0;
556     int i, j, nsites;
557     Window wid;
558     Window wjunk;
559     Window areawin;
560     unsigned long sid;
561     int areatype;
562     int nrects;
563     unsigned long flags;
564     Region region = NULL;
565     Region toprgn = NULL;
566     XRectangle rect;
567     drop_site_t *site;
568     int x, y;
569     unsigned int width, height, junk, border;
570 #ifndef oldcode
571         int     ignore;
572 #endif
573
574     if (array[cur] != DRAGDROP_VERSION) {
575         fprintf(stderr,
576                 "%s: unknown drop interest property version (%ld) on 0x%lx\n",
577                 ProgramName, array[cur], win);
578         return;
579     }
580
581     toprgn = GetWindowRegion(dpy, win, False);
582
583     NEXTWORD(nsites);
584     for (i=0; i<nsites; ++i) {
585         NEXTWORD(wid);
586         NEXTWORD(sid);
587         NEXTWORD(flags);
588 #ifdef PROXY
589         if (flags & MOTIF_RECEIVER_FLAG)
590             wid = sid;    /* replace proxy window id with receiver window id */
591 #endif
592         NEXTWORD(areatype);
593         switch (areatype) {
594         case INTEREST_RECT:
595             region = XCreateRegion();
596             NEXTWORD(nrects);
597             for (j=0; j<nrects; ++j) {
598                 NEXTWORD(rect.x);
599                 NEXTWORD(rect.y);
600                 NEXTWORD(rect.width);
601                 NEXTWORD(rect.height);
602                 XUnionRectWithRegion(&rect, region, region);
603             }
604             break;
605         case INTEREST_WINDOW:
606             region = XCreateRegion();
607             NEXTWORD(nrects);
608             for (j=0; j<nrects; ++j) {
609                 NEXTWORD(areawin);
610                 /* REMIND need to make sure areawin isn't bogus */
611 #ifdef oldcode
612                 if (0 == XGetGeometry(dpy, areawin, &wjunk, &junk, &junk,
613 #else
614                 if (0 == XGetGeometry(dpy, areawin, &wjunk, &ignore, &ignore,
615 #endif
616                                       &width, &height, &border, &junk)) {
617                     fprintf(stderr,
618                             "%s: XGetGeometry failed on window 0x%lx\n",
619                             ProgramName, win);
620                     return;
621                 }
622                 (void) XTranslateCoordinates(dpy, areawin, win, 0, 0,
623                                              &x, &y, &wjunk);
624                 rect.x = x - border;
625                 rect.y = y - border;
626                 rect.width = width + border;
627                 rect.height = height + border;
628                 XUnionRectWithRegion(&rect, region, region);
629             }
630             break;
631         default:
632             fprintf(stderr,
633                     "%s: unknown site area type on window 0x%lx\n",
634                     ProgramName, win);
635             return;
636         }
637         XIntersectRegion(region, toprgn, region);
638         XOffsetRegion(region, xoff, yoff);
639         XIntersectRegion(region, visrgn, region);
640         site = (drop_site_t *) malloc(sizeof(drop_site_t));
641         /* XXX check for site == NULL */
642         site->screen = screen;
643         site->site_id = sid;
644         site->window_id = wid;
645         site->flags = flags;
646         site->region = region;
647         site->next = NULL;
648         (*NextSite) = site;
649         NextSite = &site->next;
650         ++SitesFound;
651         region = NULL;
652     }
653 #ifndef oldcode
654     XDestroyRegion(toprgn);
655 #endif
656 } /* end of ProcessInterestProperty */
657
658
659 /*
660  * For the root window of each screen, get the list of children.  For each 
661  * child, get its drop forwarding information and find the top-level window 
662  * underneath that child, and get the top-level window's drop site 
663  * information.  Add the top-level window's site information and the site 
664  * forwarding information to the site database.
665  */
666 void
667 FindDropSites(Display *dpy)
668 {
669 #ifdef oldcode
670     int s, i, nchildren;
671 #else
672         int             s, i;
673         unsigned int    nchildren;
674 #endif
675     Window root, junk, *children, topwin;
676     void *sitedata;
677     Region visrgn, framergn, toprgn;
678     XWindowAttributes attr;
679     unsigned long datalen;
680     int xoff, yoff;
681     void *fwdsitedata;
682     unsigned long fwdlen;
683     Bool foundtoplevel;
684
685     for (s=0; s<ScreenCount(dpy); ++s) {
686
687         /* Find the virtual root here, if necessary. */
688         root = RootWindow(dpy, s);
689         visrgn = GetWindowRegion(dpy, root, False);
690
691         if (XQueryTree(dpy, root, &junk, &junk, &children, &nchildren) == 0) {
692             fprintf(stderr, "%s: XQueryTree failed on root window 0x%lx\n",
693                     ProgramName, root);
694             continue;
695         }
696
697         /*
698          * For each mapped, InputOutput, child-of-root window, look for a drop
699          * interest property.  This will be a forwarding interest property
700          * placed by the window manager.  Then, find the top-level window
701          * underneath this window and process its interest property.
702          */
703
704         for (i=nchildren-1; i>=0; --i) {
705             if (XGetWindowAttributes(dpy, children[i], &attr) == 0) {
706                 fprintf(stderr,
707                         "%s: XGetWindowAttributes failed for window 0x%lx\n",
708                         ProgramName, children[i]);
709                 continue;
710             }
711
712             if (attr.depth == 0 || attr.class == InputOnly ||
713                 attr.map_state != IsViewable) {
714                     continue;
715             }
716
717             fwdsitedata = GetInterestProperty(dpy, children[i], &fwdlen);
718
719 #ifdef oldcode
720             foundtoplevel = SearchChildren(dpy, root, children[i], &topwin,
721                                            &sitedata, &datalen, &xoff, &yoff);
722 #else
723             foundtoplevel = SearchChildren(dpy, root, children[i], &topwin,
724                                    &sitedata, &datalen, &xoff, &yoff, False);
725 #endif
726             if (foundtoplevel && sitedata != NULL) {
727                 /* we found a valid drop interest */
728                 ProcessInterestProperty(dpy, topwin, s, sitedata,
729                                         datalen, visrgn, xoff, yoff);
730 #ifdef oldcode
731                 XFree(sitedata);
732 #else
733                 XFree((XFreeDefn)sitedata);
734 #endif
735                 if (fwdsitedata != NULL) {
736                     framergn = MakeRegionFromRect(attr.x, attr.y,
737                                                   attr.width, attr.height);
738                     XIntersectRegion(framergn, visrgn, framergn);
739                     toprgn = GetWindowRegion(dpy, topwin, False);
740                     XOffsetRegion(toprgn, xoff, yoff);
741                     XSubtractRegion(framergn, toprgn, framergn);
742                     ProcessInterestProperty(dpy, children[i], s, fwdsitedata,
743                                             fwdlen, framergn, attr.x, attr.y);
744                     XDestroyRegion(framergn);
745                     XDestroyRegion(toprgn);
746 #ifdef oldcode
747                     XFree(fwdsitedata);
748 #else
749                     XFree((XFreeDefn)fwdsitedata);
750 #endif
751                 }
752             } else {
753                 if (fwdsitedata != NULL) {
754                     ProcessInterestProperty(dpy, children[i], s, fwdsitedata,
755                                             fwdlen, visrgn, attr.x, attr.y);
756 #ifdef oldcode
757                     XFree(fwdsitedata);
758 #else
759                     XFree((XFreeDefn)fwdsitedata);
760 #endif
761                 }
762             }
763
764             SubtractWindowFromVisibleRegion(dpy, children[i], visrgn);
765         }
766         XDestroyRegion(visrgn);
767 #ifndef oldcode
768                 if (nchildren)
769                         XFree((XFreeDefn)children);
770 #endif
771     }
772 } /* end of FindDropSites */
773
774
775 void
776 FreeDropSites(void)
777 {
778     drop_site_t *next, *temp;
779
780     next = MasterSiteList;
781     while (next != NULL) {
782         temp = next->next;
783 #ifdef oldcode
784         free(next);
785 #else
786         if (next->region)
787                 XDestroyRegion(next->region);
788         XFree((XFreeDefn)next);
789 #endif
790         next = temp;
791     }
792     MasterSiteList = NULL;
793     SitesFound = 0;
794     NextSite = &MasterSiteList;
795 } /* end of FreeDropSites */
796
797
798 /*
799  * Write a property containing site rectangle information.  The format 
800  * consists of zero or more blocks of 8 words, as follows:
801  *      8k+0    screen number
802  *      8k+1    site id
803  *      8k+2    window id
804  *      8k+3    x
805  *      8k+4    y
806  *      8k+5    width
807  *      8k+6    height
808  *      8k+7    flags
809  */
810 void
811 WriteSiteRectList(Display *dpy, Window win, Atom prop)
812 {
813     unsigned long *cur;
814     unsigned long *array;
815     drop_site_t *site;
816     int numrects = 0;
817     REGION *region;
818     BOX *box, *last;
819
820     site = MasterSiteList;
821     while (site != NULL) {
822         numrects += REGION_NUMRECTS(site->region);
823         site = site->next;
824     }
825
826     /* XXX beware of malloc(0) */
827 #ifdef oldcode
828     array = (unsigned long *) malloc(8*numrects*sizeof(int));
829 #else
830     array = (unsigned long *) malloc(8*numrects*sizeof(unsigned long));
831 #endif
832     cur = array;
833     site = MasterSiteList;
834     while (site != NULL) {
835         region = (REGION *) site->region;
836         box = region->rects;
837         last = box + region->numRects;
838         for ( ; box < last ; ++box) {
839             *cur++ = site->screen;
840             *cur++ = site->site_id;
841 #ifdef PROXY
842             /* if the receiver is motif then let event window be proxy win */
843             if (site->flags & MOTIF_RECEIVER_FLAG)
844                 *cur++ = proxy_win;
845             else
846                 *cur++ = site->window_id;
847 #else
848             *cur++ = site->window_id;
849 #endif
850             *cur++ = box->x1;
851             *cur++ = box->y1;
852             *cur++ = box->x2 - box->x1;
853             *cur++ = box->y2 - box->y1;
854             *cur++ = site->flags;
855         }
856         site = site->next;
857     }
858
859     XChangeProperty(dpy, win, prop, XA_INTEGER, 32, PropModeReplace,
860 #ifdef oldcode
861                     (char *)array, cur - array);
862     free(array);
863 #else
864                     (unsigned char *)array, cur - array);
865     XFree((XFreeDefn)array);
866 #endif
867 } /* end of WriteSiteRectList */
868
869
870 /*
871  * Ignore BadWindow and BadDrawable errors on a variety of requests.  These
872  * errors often occur if the requester window goes away after requesting the
873  * site database.  REMIND: more robust error handling is called for.
874  */
875 int
876 ErrorHandler(Display *dpy, XErrorEvent *error)
877 {
878     if (    (error->error_code == BadWindow ||
879              error->error_code == BadDrawable) &&
880             (error->request_code == X_GetWindowAttributes ||
881              error->request_code == X_ChangeWindowAttributes ||
882              error->request_code == X_GetGeometry ||
883              error->request_code == X_QueryTree ||
884              error->request_code == X_ChangeProperty ||
885              error->request_code == X_GetProperty ||
886              error->request_code == X_SendEvent)) {
887         DPRINTF(("ignored BadWindow error on request %d\n",
888                  error->request_code));
889         return 0;
890     }
891
892     fputs("dsdm: ", stderr);
893     (*DefaultErrorHandler)(dpy, error);
894     exit(1);
895     /*NOTREACHED*/
896 } /* end of ErrorHandler */
897
898
899 int
900 main(int argc, char **argv)
901 {
902     enum { XA_SUN_DRAGDROP_DSDM, XA_SUN_DRAGDROP_INTEREST,
903            XA_SUN_DRAGDROP_SITE_RECTS, XAWM_STATE, NUM_ATOMS };
904     static char *atom_names[] = {
905       "_SUN_DRAGDROP_DSDM", "_SUN_DRAGDROP_INTEREST",
906       "_SUN_DRAGDROP_SITE_RECTS", "WM_STATE" };
907
908     Display *dpy;
909     Window selwin, win;
910     XSetWindowAttributes attr;
911     XEvent e;
912     XEvent reply;
913     int xflag = 0;
914     char *slash = NULL;
915     char *cp;
916     char call_proxy_main;
917     Atom atoms[NUM_ATOMS];
918
919     cp = argv[0];
920     while (*cp != '\0') {
921         if (*cp == '/')
922             slash = cp;
923         ++cp;
924     }
925     if (slash != NULL)
926         ProgramName = slash + 1;
927     else
928         ProgramName = argv[0];  
929
930     dpy = XOpenDisplay(NULL);
931     if (dpy == NULL) {
932         fprintf(stderr, "%s: can't open display %s\n",
933                 ProgramName, XDisplayName(NULL));
934         exit(1);
935     }
936
937     DefaultErrorHandler = XSetErrorHandler(ErrorHandler);
938
939     XInternAtoms(dpy, atom_names, NUM_ATOMS, False, atoms);
940     ATOM_DRAGDROP_DSDM = atoms[XA_SUN_DRAGDROP_DSDM];
941     ATOM_DRAGDROP_INTEREST = atoms[XA_SUN_DRAGDROP_INTEREST];
942     ATOM_SITE_RECTS = atoms[XA_SUN_DRAGDROP_SITE_RECTS];
943     ATOM_WM_STATE = atoms[XAWM_STATE];
944
945     attr.event_mask = PropertyChangeMask;
946     selwin = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0,
947                            InputOnly, CopyFromParent,
948                            CWEventMask, &attr);
949
950     if (argc > 1 && 0 == strcmp(argv[1], "-x"))
951         xflag = 1;
952
953     XGrabServer(dpy);
954     win = XGetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM);
955
956     if (xflag) {
957         if (win == None) {
958             fprintf(stderr, "%s: no DSDM is running\n", ProgramName);
959             exit(1);
960         }
961         /* Clear any DSDM selection to force the running DSDM to exit */
962         XSetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM, None, CurrentTime);
963         XFlush(dpy);
964         exit(0);
965     }
966
967     if (win != None) {
968         fprintf(stderr,
969                 "%s: another DSDM is already running\n",
970                 ProgramName);
971         exit(1);
972     }
973
974 #ifdef PROXY
975     ProxyInit(dpy, selwin);
976 #endif
977
978     XSetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM, selwin, CurrentTime);
979     /* no need to get owner per ICCCM, because we have the server grabbed */
980     XUngrabServer(dpy);
981     XFlush(dpy);
982
983 /* An attempt to minimize contention at startup:  in the olinitrc file, DO
984  * NOT start the window manager or the file manager in the background.  This
985  * way, the initialization code for the two applications is run sequentially.
986  */
987     if (argc == 1)
988         if (fork() != 0)
989             exit(0); /* on parent success or failure */
990
991     for (;;) {
992         call_proxy_main = True;
993         XNextEvent(dpy, &e);
994         switch (e.type) {
995         case SelectionRequest:
996             if (e.xselectionrequest.selection != ATOM_DRAGDROP_DSDM) {
997 #ifndef PROXY
998                 DPRINTF(("%s: got SelectionRequest on wrong selection?\n",
999                          ProgramName));
1000 #endif
1001                 break;
1002             }
1003             if (e.xselectionrequest.owner != selwin) {
1004                 fprintf(stderr, "%s: got SelectionRequest on wrong window?\n",
1005                         ProgramName);
1006                 break;
1007             }
1008                 
1009             reply.xselection.display = e.xselectionrequest.display;
1010             reply.xselection.type = SelectionNotify;
1011             reply.xselection.requestor = e.xselectionrequest.requestor;
1012             reply.xselection.selection = ATOM_DRAGDROP_DSDM;
1013             reply.xselection.target = e.xselectionrequest.target;
1014             reply.xselection.time = e.xselectionrequest.time;
1015
1016             if (e.xselectionrequest.target != ATOM_SITE_RECTS) {
1017                 fprintf(stderr,
1018                         "%s: got SelectionRequest for unknown target\n",
1019                         ProgramName);
1020                 reply.xselection.property = None;
1021             } else {
1022                 DPRINTF(("%s: got SelectionRequest event OK\n", ProgramName));
1023                 FreeDropSites();
1024                 FindDropSites(dpy);
1025                 WriteSiteRectList(dpy, e.xselectionrequest.requestor,
1026                                   e.xselectionrequest.property);
1027                 reply.xselection.property =
1028                     e.xselectionrequest.property;
1029             }
1030
1031             (void) XSendEvent(dpy, reply.xselection.requestor, False, 0,
1032                               &reply);
1033             call_proxy_main = False;
1034             break;
1035         case SelectionClear:
1036             exit(0);
1037         }
1038 #ifdef PROXY
1039         if (call_proxy_main)
1040                 ProxyMain(dpy, &e);
1041 #endif
1042     }
1043 } /* end of main */
1044