Don't use fstat for readable pipe chars in dtexec.
[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(dpy, s, gc)
161     Display *dpy;
162     int s;
163     GC gc;
164 {
165     XEvent e;
166     Bool done = False;
167     Window root = RootWindow(dpy, s);
168
169     if (GrabSuccess != XGrabPointer(dpy, root, False,
170         ButtonPressMask, GrabModeAsync, GrabModeAsync,
171         None, None, CurrentTime)) {
172             fputs("can't grab the pointer\n", stderr);
173             return;
174     }
175
176     do {
177         XFillRectangle(dpy, root, gc, 0, 0,
178                        DisplayWidth(dpy, s),
179                        DisplayHeight(dpy, s));
180         XFlush(dpy);
181
182         XMaskEvent(dpy, ButtonPressMask, &e);
183         if (e.xbutton.button == Button3)
184             done = True;
185
186         XFillRectangle(dpy, root, gc, 0, 0,
187                        DisplayWidth(dpy, s),
188                        DisplayHeight(dpy, s));
189         XFlush(dpy);
190     } while (!done);
191     XUngrabPointer(dpy, CurrentTime);
192 } /* end of FlashRegion */
193
194
195 void
196 FlashDropSites(dpy)
197     Display *dpy;
198 {
199     drop_site_t *site = MasterSiteList;
200     XGCValues gcv;
201     GC *gcs;
202     int s;
203     GC gc;
204
205     gcv.function = GXinvert;
206     gcv.subwindow_mode = IncludeInferiors;
207
208     gcs = (GC *) malloc(sizeof(GC)*ScreenCount(dpy));
209     for (s=0; s<ScreenCount(dpy); ++s)
210         gcs[s] = XCreateGC(dpy, RootWindow(dpy, s),
211                            GCFunction|GCSubwindowMode, &gcv);
212
213     while (site != NULL) {
214         printf("sid %ld   wid 0x%lx   flags 0x%lx\n",
215                site->site_id, site->window_id, site->flags);
216         gc = gcs[site->screen];
217         XSetRegion(dpy, gc, site->region);
218         FlashRegion(dpy, site->screen, gc);
219         site = site->next;
220     }
221
222     for (s=0; s<ScreenCount(dpy); ++s)
223         XFreeGC(dpy, gcs[s]);
224     free(gcs);
225 } /* end of FlashDropSites */
226
227 #endif /* DEBUG */
228
229
230 /*
231  * Get the interest property from this window.  If a valid interest property
232  * was found, a pointer to the data is returned.  This data must be freed with
233  * XFree().  If no valid property is found, NULL is returned.
234  */
235 #ifdef oldcode
236 void *
237 #else
238 unsigned char *
239 #endif
240 GetInterestProperty(dpy, win, nitems)
241     Display *dpy;
242     Window win;
243 #ifdef oldcode
244     int *nitems;
245 #else
246     unsigned long *nitems;
247 #endif
248 {
249     Status s;
250     Atom acttype;
251 #ifdef oldcode
252     int actfmt, remain;
253     void *data;
254 #else
255         int             actfmt;
256         unsigned long   remain;
257         unsigned char * data;
258 #endif
259
260     s = XGetWindowProperty(dpy, win, ATOM_DRAGDROP_INTEREST, 0L, INTEREST_MAX,
261                            False, ATOM_DRAGDROP_INTEREST, &acttype, &actfmt,
262                            nitems, &remain, &data);
263
264     if (s != Success)
265         return NULL;
266
267     if (acttype == None)
268         /* property does not exist */
269         return NULL;
270
271     if (acttype != ATOM_DRAGDROP_INTEREST) {
272         fputs("dsdm: interest property has wrong type\n", stderr);
273         return NULL;
274     }
275
276     if (actfmt != 32) {
277         fputs("dsdm: interest property has wrong format\n", stderr);
278 #ifdef oldcode
279         XFree(data);
280 #else
281         XFree((XFreeDefn) data);
282 #endif
283         return NULL;
284     }
285
286     if (remain > 0) {
287         /* XXX didn't read it all, punt */
288         fputs("dsdm: interest property too long\n", stderr);
289 #ifdef oldcode
290         XFree(data);
291 #else
292         XFree((XFreeDefn) data);
293 #endif
294         return NULL;
295     }
296     return data;
297 } /* end of GetInterestProperty */
298
299
300 /*
301  * Check to see if window win is a top-level window, that is, if it is a
302  * viewable, InputOutput window that has a drop interest or WM_STATE property
303  * on it.  If either property is found, return True.  Additionally, if True is
304  * returned, psite will be set to point to the drop interest property data if 
305  * that property is found, or NULL if not.  If neither property is found, all 
306  * children of this window are searched.
307  */
308 Bool
309 FindRecursively(dpy, root, win, pwin, psite, plen, px, py)
310     Display *dpy;
311     Window root, win, *pwin;
312     void **psite;
313     unsigned long *plen;
314     int *px, *py;
315 {
316     XWindowAttributes attr;
317     Window junk;
318     Atom acttype;
319     int actfmt;
320     unsigned long nitems;
321     unsigned long remain;
322 #ifdef oldcode
323     void *data;
324 #else
325         unsigned char * data;
326 #endif
327     Status s;
328     
329     if (XGetWindowAttributes(dpy, win, &attr) == 0) {
330         fprintf(stderr, "%s: XGetWindowAttributes failed for window 0x%lx\n",
331                 ProgramName, win);
332         return False;
333     }
334
335     if (attr.depth == 0 || attr.class == InputOnly ||
336             attr.map_state != IsViewable) {
337         return False;
338     }
339
340     data = GetInterestProperty(dpy, win, &nitems);
341     if (data != NULL) {
342         if (!XTranslateCoordinates(dpy, win, root, 0, 0, px, py, &junk)) {
343             fprintf(stderr, "%s: window 0x%lx isn't on the same root!\n",
344                     ProgramName, win);
345 #ifdef oldcode
346             XFree(data);
347 #else
348             XFree((XFreeDefn) data);
349 #endif
350             return False;
351         }
352         *psite = (void *) data;
353         *plen = nitems;
354         *pwin = win;
355         DPRINTF(("%s: found top-level window 0x%lx with an interest\n",
356                  ProgramName, win));
357         return True;
358     }
359         
360     s = XGetWindowProperty(dpy, win, ATOM_WM_STATE, 0L, 1,
361                            False, ATOM_WM_STATE, &acttype, &actfmt,
362                            &nitems, &remain, &data);
363
364     if (s != Success)   /* couldn't find the window */
365         return False;
366
367     if (acttype == ATOM_WM_STATE) {
368         /* found it! */
369         DPRINTF(("%s: found top-level window 0x%lx with no interest\n",
370                  ProgramName, win));
371 #ifdef oldcode
372         XFree(data);
373 #else
374         XFree((XFreeDefn) data);
375 #endif
376         *psite = NULL;
377         *plen = 0;
378
379 #ifdef PROXY
380 #define DRAGDROP_VERSION        0
381 #define INTEREST_RECT           0
382 #define DATA_LEN                11
383 #define MOTIF_RECEIVER_FLAG     0x80000000
384         /* only do the following if the window doesnot 
385            have SUN_DND_INTEREST advertised */
386         if (GetAtomWindow(dpy, win, ATOM_MOTIF_RECEIVER_INFO)) {
387             /* got a motif receiver, create a drop site */
388             CARD32 *data = (CARD32 *) malloc(sizeof(CARD32) * DATA_LEN);
389
390             data[0] = DRAGDROP_VERSION;
391             data[1] = 1;        /* site count */
392             data[2] = proxy_win;        /* event_window, xview needs this */
393             data[3] = win;      /* site_id */
394             data[4] = MOTIF_RECEIVER_FLAG; /*flag to indicate motif receiver */
395             data[5] = INTEREST_RECT; /* drop site type */
396             data[6] = 1;        /* drop site count */
397             data[7] = 0;        /* drop window x */
398             data[8] = 0;        /* drop window y */
399             data[9] = attr.width;       /* drop window width */
400             data[10] = attr.height;     /* drop window height */
401
402             *pwin = win;
403             *psite = (void *) data;
404             *plen = DATA_LEN;
405             XTranslateCoordinates(dpy, win, root, 0, 0, px, py, &junk);
406
407             /* XView needs this */
408             XChangeProperty(dpy,
409                     win,
410                     ATOM_DRAGDROP_INTEREST, /* property */
411                     ATOM_DRAGDROP_INTEREST, /* type */
412                     32,               /* format */
413                     PropModeReplace, /* mode */
414                     (unsigned char *) data, /* data */
415                     DATA_LEN  /* number of elements */
416                     );
417
418             /* dsdm needs this */
419             data[2] = win;
420         }
421 #undef DATA_LEN
422 #endif
423         return True;
424     }
425
426 #ifdef oldcode
427     return(SearchChildren(dpy, root, win, pwin, psite, plen, px, py));
428 #else
429     return(SearchChildren(dpy, root, win, pwin, psite, plen, px, py, True));
430 #endif
431 } /* end of FindRecursively */
432
433
434
435 /*
436  * Look through all the children of window win for a top-level window.
437  */
438 Bool
439 #ifdef oldcode
440 SearchChildren(dpy, root, win, pwin, psite, plen, px, py)
441     Display *dpy;
442     Window root, win, *pwin;
443     void **psite;
444     unsigned long *plen;
445     int *px, *py;
446 #else
447 SearchChildren(dpy, root, win, pwin, psite, plen, px, py, from_FindRec)
448     Display *dpy;
449     Window root, win, *pwin;
450     void **psite;
451     unsigned long *plen;
452     int *px, *py;
453     Bool from_FindRec;
454 #endif
455 {
456     Window junk;
457     Window *children;
458 #ifdef oldcode
459     int nchildren;
460 #else
461     unsigned int nchildren;
462 #endif
463     int i;
464
465     if (XQueryTree(dpy, win, &junk, &junk, &children, &nchildren) == 0)
466         return False;
467
468     for (i=0; i<nchildren; ++i) {
469         if (FindRecursively(dpy, root, children[i], pwin, psite, plen, px, py))
470 #ifdef oldcode
471             return True;
472 #else
473         {
474                 XFree((XFreeDefn)children);
475             return True;
476         }
477 #endif
478     }
479 #ifndef oldcode
480         if (from_FindRec == False && nchildren)
481                 XFree((XFreeDefn)children);
482 #endif
483     return False;
484 } /* end of SearchChildren */
485
486
487 /*
488  * Create and return a region that contains a given rectangle.
489  */
490 Region
491 MakeRegionFromRect(x, y, w, h)
492     int x, y;
493     unsigned int w, h;
494 {
495     XRectangle r;
496     Region reg;
497
498     r.x = x;
499     r.y = y;
500     r.width = w;
501     r.height = h;
502     reg = XCreateRegion();
503     XUnionRectWithRegion(&r, reg, reg);
504     return reg;
505 } /* end of MakeRegionFromRect */
506
507
508 /*
509  * Create and return a region that contains the geometry of the window.
510  * The region returned must be destroyed with XDestroyRegion().  The offset 
511  * parameter indicates whether the window's geometry should be offset by its
512  * (x,y) location w.r.t. its parent.  If it is false, the region's upper left 
513  * corner is at (0,0).
514  */
515 Region
516 GetWindowRegion(dpy, win, offset)
517     Display *dpy;
518     Window win;
519     Bool offset;
520 {
521     Window wjunk;
522     int x, y;
523     unsigned int width, height, junk;
524     Region winrgn;
525
526 #ifdef oldcode
527     winrgn = XCreateRegion();
528 #endif
529     if (0 == XGetGeometry(dpy, win, &wjunk, &x, &y, &width, &height,
530                           &junk, &junk)) {
531         fprintf(stderr, "%s: XGetGeometry failed on window 0x%lx\n",
532                 ProgramName, win);
533 #ifndef oldcode
534             winrgn = XCreateRegion();
535 #endif
536         return winrgn;
537     }
538     return MakeRegionFromRect(offset ? x : 0, offset ? y: 0, width, height);
539 } /* end of GetWindowRegion */
540
541
542 /*
543  * Subtract the area of a window from the current visible region.
544  */
545 void
546 SubtractWindowFromVisibleRegion(dpy, win, visrgn)
547     Display *dpy;
548     Window win;
549     Region visrgn;
550 {
551     Region winrgn = GetWindowRegion(dpy, win, True);
552     XSubtractRegion(visrgn, winrgn, visrgn);
553     XDestroyRegion(winrgn);
554 } /* end of SubtractWindowFromVisibleRegion */
555
556
557 #define DRAGDROP_VERSION        0
558 #define INTEREST_RECT           0
559 #define INTEREST_WINDOW         1
560
561 #define NEXTWORD(dest) do {                                             \
562             if (++cur >= datalen) {                                     \
563                 fprintf(stderr,                                         \
564                         "%s: drop interest data too short on 0x%lx\n",  \
565                         ProgramName, win);                              \
566                 if (region != NULL)                                     \
567                     XDestroyRegion(region);                             \
568                 if (toprgn != NULL)                                     \
569                     XDestroyRegion(toprgn);                             \
570                 return;                                                 \
571             }                                                           \
572             (dest) = array[cur];                                        \
573         } while (0)
574
575
576 void
577 ProcessInterestProperty(dpy, win, screen, data, datalen, visrgn, xoff, yoff)
578 #ifndef oldcode
579         Display *       dpy;
580 #endif
581     Window win;
582     int screen;
583     void *data;
584     unsigned long datalen;
585     Region visrgn;
586     int xoff, yoff;
587 {
588     unsigned long *array = (unsigned long *)data;
589     int cur = 0;
590     int i, j, nsites;
591     Window wid;
592     Window wjunk;
593     Window areawin;
594     unsigned long sid;
595     int areatype;
596     int nrects;
597     unsigned long flags;
598     Region region = NULL;
599     Region toprgn = NULL;
600     XRectangle rect;
601     drop_site_t *site;
602     int x, y;
603     unsigned int width, height, junk, border;
604 #ifndef oldcode
605         int     ignore;
606 #endif
607
608     if (array[cur] != DRAGDROP_VERSION) {
609         fprintf(stderr,
610                 "%s: unknown drop interest property version (%ld) on 0x%lx\n",
611                 ProgramName, array[cur], win);
612         return;
613     }
614
615     toprgn = GetWindowRegion(dpy, win, False);
616
617     NEXTWORD(nsites);
618     for (i=0; i<nsites; ++i) {
619         NEXTWORD(wid);
620         NEXTWORD(sid);
621         NEXTWORD(flags);
622 #ifdef PROXY
623         if (flags & MOTIF_RECEIVER_FLAG)
624             wid = sid;    /* replace proxy window id with receiver window id */
625 #endif
626         NEXTWORD(areatype);
627         switch (areatype) {
628         case INTEREST_RECT:
629             region = XCreateRegion();
630             NEXTWORD(nrects);
631             for (j=0; j<nrects; ++j) {
632                 NEXTWORD(rect.x);
633                 NEXTWORD(rect.y);
634                 NEXTWORD(rect.width);
635                 NEXTWORD(rect.height);
636                 XUnionRectWithRegion(&rect, region, region);
637             }
638             break;
639         case INTEREST_WINDOW:
640             region = XCreateRegion();
641             NEXTWORD(nrects);
642             for (j=0; j<nrects; ++j) {
643                 NEXTWORD(areawin);
644                 /* REMIND need to make sure areawin isn't bogus */
645 #ifdef oldcode
646                 if (0 == XGetGeometry(dpy, areawin, &wjunk, &junk, &junk,
647 #else
648                 if (0 == XGetGeometry(dpy, areawin, &wjunk, &ignore, &ignore,
649 #endif
650                                       &width, &height, &border, &junk)) {
651                     fprintf(stderr,
652                             "%s: XGetGeometry failed on window 0x%lx\n",
653                             ProgramName, win);
654                     return;
655                 }
656                 (void) XTranslateCoordinates(dpy, areawin, win, 0, 0,
657                                              &x, &y, &wjunk);
658                 rect.x = x - border;
659                 rect.y = y - border;
660                 rect.width = width + border;
661                 rect.height = height + border;
662                 XUnionRectWithRegion(&rect, region, region);
663             }
664             break;
665         default:
666             fprintf(stderr,
667                     "%s: unknown site area type on window 0x%lx\n",
668                     ProgramName, win);
669             return;
670         }
671         XIntersectRegion(region, toprgn, region);
672         XOffsetRegion(region, xoff, yoff);
673         XIntersectRegion(region, visrgn, region);
674         site = (drop_site_t *) malloc(sizeof(drop_site_t));
675         /* XXX check for site == NULL */
676         site->screen = screen;
677         site->site_id = sid;
678         site->window_id = wid;
679         site->flags = flags;
680         site->region = region;
681         site->next = NULL;
682         (*NextSite) = site;
683         NextSite = &site->next;
684         ++SitesFound;
685         region = NULL;
686     }
687 #ifndef oldcode
688     XDestroyRegion(toprgn);
689 #endif
690 } /* end of ProcessInterestProperty */
691
692
693 /*
694  * For the root window of each screen, get the list of children.  For each 
695  * child, get its drop forwarding information and find the top-level window 
696  * underneath that child, and get the top-level window's drop site 
697  * information.  Add the top-level window's site information and the site 
698  * forwarding information to the site database.
699  */
700 void
701 FindDropSites(dpy)
702     Display *dpy;
703 {
704 #ifdef oldcode
705     int s, i, nchildren;
706 #else
707         int             s, i;
708         unsigned int    nchildren;
709 #endif
710     Window root, junk, *children, topwin;
711     void *sitedata;
712     Region visrgn, framergn, toprgn;
713     XWindowAttributes attr;
714     unsigned long datalen;
715     int xoff, yoff;
716     void *fwdsitedata;
717     unsigned long fwdlen;
718     Bool foundtoplevel;
719
720     for (s=0; s<ScreenCount(dpy); ++s) {
721
722         /* Find the virtual root here, if necessary. */
723         root = RootWindow(dpy, s);
724         visrgn = GetWindowRegion(dpy, root, False);
725
726         if (XQueryTree(dpy, root, &junk, &junk, &children, &nchildren) == 0) {
727             fprintf(stderr, "%s: XQueryTree failed on root window 0x%lx\n",
728                     ProgramName, root);
729             continue;
730         }
731
732         /*
733          * For each mapped, InputOutput, child-of-root window, look for a drop
734          * interest property.  This will be a forwarding interest property
735          * placed by the window manager.  Then, find the top-level window
736          * underneath this window and process its interest property.
737          */
738
739         for (i=nchildren-1; i>=0; --i) {
740             if (XGetWindowAttributes(dpy, children[i], &attr) == 0) {
741                 fprintf(stderr,
742                         "%s: XGetWindowAttributes failed for window 0x%lx\n",
743                         ProgramName, children[i]);
744                 continue;
745             }
746
747             if (attr.depth == 0 || attr.class == InputOnly ||
748                 attr.map_state != IsViewable) {
749                     continue;
750             }
751
752             fwdsitedata = GetInterestProperty(dpy, children[i], &fwdlen);
753
754 #ifdef oldcode
755             foundtoplevel = SearchChildren(dpy, root, children[i], &topwin,
756                                            &sitedata, &datalen, &xoff, &yoff);
757 #else
758             foundtoplevel = SearchChildren(dpy, root, children[i], &topwin,
759                                    &sitedata, &datalen, &xoff, &yoff, False);
760 #endif
761             if (foundtoplevel && sitedata != NULL) {
762                 /* we found a valid drop interest */
763                 ProcessInterestProperty(dpy, topwin, s, sitedata,
764                                         datalen, visrgn, xoff, yoff);
765 #ifdef oldcode
766                 XFree(sitedata);
767 #else
768                 XFree((XFreeDefn)sitedata);
769 #endif
770                 if (fwdsitedata != NULL) {
771                     framergn = MakeRegionFromRect(attr.x, attr.y,
772                                                   attr.width, attr.height);
773                     XIntersectRegion(framergn, visrgn, framergn);
774                     toprgn = GetWindowRegion(dpy, topwin, False);
775                     XOffsetRegion(toprgn, xoff, yoff);
776                     XSubtractRegion(framergn, toprgn, framergn);
777                     ProcessInterestProperty(dpy, children[i], s, fwdsitedata,
778                                             fwdlen, framergn, attr.x, attr.y);
779                     XDestroyRegion(framergn);
780                     XDestroyRegion(toprgn);
781 #ifdef oldcode
782                     XFree(fwdsitedata);
783 #else
784                     XFree((XFreeDefn)fwdsitedata);
785 #endif
786                 }
787             } else {
788                 if (fwdsitedata != NULL) {
789                     ProcessInterestProperty(dpy, children[i], s, fwdsitedata,
790                                             fwdlen, visrgn, attr.x, attr.y);
791 #ifdef oldcode
792                     XFree(fwdsitedata);
793 #else
794                     XFree((XFreeDefn)fwdsitedata);
795 #endif
796                 }
797             }
798
799             SubtractWindowFromVisibleRegion(dpy, children[i], visrgn);
800         }
801         XDestroyRegion(visrgn);
802 #ifndef oldcode
803                 if (nchildren)
804                         XFree((XFreeDefn)children);
805 #endif
806     }
807 } /* end of FindDropSites */
808
809
810 void
811 FreeDropSites()
812 {
813     drop_site_t *next, *temp;
814
815     next = MasterSiteList;
816     while (next != NULL) {
817         temp = next->next;
818 #ifdef oldcode
819         free(next);
820 #else
821         if (next->region)
822                 XDestroyRegion(next->region);
823         XFree((XFreeDefn)next);
824 #endif
825         next = temp;
826     }
827     MasterSiteList = NULL;
828     SitesFound = 0;
829     NextSite = &MasterSiteList;
830 } /* end of FreeDropSites */
831
832
833 /*
834  * Write a property containing site rectangle information.  The format 
835  * consists of zero or more blocks of 8 words, as follows:
836  *      8k+0    screen number
837  *      8k+1    site id
838  *      8k+2    window id
839  *      8k+3    x
840  *      8k+4    y
841  *      8k+5    width
842  *      8k+6    height
843  *      8k+7    flags
844  */
845 void
846 WriteSiteRectList(dpy, win, prop)
847     Display *dpy;
848     Window win;
849     Atom prop;
850 {
851     unsigned long *cur;
852     unsigned long *array;
853     drop_site_t *site;
854     int numrects = 0;
855     REGION *region;
856     BOX *box, *last;
857
858     site = MasterSiteList;
859     while (site != NULL) {
860         numrects += REGION_NUMRECTS(site->region);
861         site = site->next;
862     }
863
864     /* XXX beware of malloc(0) */
865 #ifdef oldcode
866     array = (unsigned long *) malloc(8*numrects*sizeof(int));
867 #else
868     array = (unsigned long *) malloc(8*numrects*sizeof(unsigned long));
869 #endif
870     cur = array;
871     site = MasterSiteList;
872     while (site != NULL) {
873         region = (REGION *) site->region;
874         box = region->rects;
875         last = box + region->numRects;
876         for ( ; box < last ; ++box) {
877             *cur++ = site->screen;
878             *cur++ = site->site_id;
879 #ifdef PROXY
880             /* if the receiver is motif then let event window be proxy win */
881             if (site->flags & MOTIF_RECEIVER_FLAG)
882                 *cur++ = proxy_win;
883             else
884                 *cur++ = site->window_id;
885 #else
886             *cur++ = site->window_id;
887 #endif
888             *cur++ = box->x1;
889             *cur++ = box->y1;
890             *cur++ = box->x2 - box->x1;
891             *cur++ = box->y2 - box->y1;
892             *cur++ = site->flags;
893         }
894         site = site->next;
895     }
896
897     XChangeProperty(dpy, win, prop, XA_INTEGER, 32, PropModeReplace,
898 #ifdef oldcode
899                     (char *)array, cur - array);
900     free(array);
901 #else
902                     (unsigned char *)array, cur - array);
903     XFree((XFreeDefn)array);
904 #endif
905 } /* end of WriteSiteRectList */
906
907
908 /*
909  * Ignore BadWindow and BadDrawable errors on a variety of requests.  These
910  * errors often occur if the requester window goes away after requesting the
911  * site database.  REMIND: more robust error handling is called for.
912  */
913 int
914 ErrorHandler(dpy, error)
915     Display *dpy;
916     XErrorEvent *error;
917 {
918     if (    (error->error_code == BadWindow ||
919              error->error_code == BadDrawable) &&
920             (error->request_code == X_GetWindowAttributes ||
921              error->request_code == X_ChangeWindowAttributes ||
922              error->request_code == X_GetGeometry ||
923              error->request_code == X_QueryTree ||
924              error->request_code == X_ChangeProperty ||
925              error->request_code == X_GetProperty ||
926              error->request_code == X_SendEvent)) {
927         DPRINTF(("ignored BadWindow error on request %d\n",
928                  error->request_code));
929         return 0;
930     }
931
932     fputs("dsdm: ", stderr);
933     (*DefaultErrorHandler)(dpy, error);
934     exit(1);
935     /*NOTREACHED*/
936 } /* end of ErrorHandler */
937
938
939 main(argc, argv)
940     int argc;
941     char **argv;
942 {
943     enum { XA_SUN_DRAGDROP_DSDM, XA_SUN_DRAGDROP_INTEREST,
944            XA_SUN_DRAGDROP_SITE_RECTS, XAWM_STATE, NUM_ATOMS };
945     static char *atom_names[] = {
946       "_SUN_DRAGDROP_DSDM", "_SUN_DRAGDROP_INTEREST",
947       "_SUN_DRAGDROP_SITE_RECTS", "WM_STATE" };
948
949     Display *dpy;
950     Window selwin, win;
951     XSetWindowAttributes attr;
952     XEvent e;
953     XEvent reply;
954     int xflag = 0;
955     char *slash = NULL;
956     char *cp;
957     char call_proxy_main;
958     Atom atoms[NUM_ATOMS];
959
960     cp = argv[0];
961     while (*cp != '\0') {
962         if (*cp == '/')
963             slash = cp;
964         ++cp;
965     }
966     if (slash != NULL)
967         ProgramName = slash + 1;
968     else
969         ProgramName = argv[0];  
970
971     dpy = XOpenDisplay(NULL);
972     if (dpy == NULL) {
973         fprintf(stderr, "%s: can't open display %s\n",
974                 ProgramName, XDisplayName(NULL));
975         exit(1);
976     }
977
978     DefaultErrorHandler = XSetErrorHandler(ErrorHandler);
979
980     XInternAtoms(dpy, atom_names, NUM_ATOMS, False, atoms);
981     ATOM_DRAGDROP_DSDM = atoms[XA_SUN_DRAGDROP_DSDM];
982     ATOM_DRAGDROP_INTEREST = atoms[XA_SUN_DRAGDROP_INTEREST];
983     ATOM_SITE_RECTS = atoms[XA_SUN_DRAGDROP_SITE_RECTS];
984     ATOM_WM_STATE = atoms[XAWM_STATE];
985
986     attr.event_mask = PropertyChangeMask;
987     selwin = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0,
988                            InputOnly, CopyFromParent,
989                            CWEventMask, &attr);
990
991     if (argc > 1 && 0 == strcmp(argv[1], "-x"))
992         xflag = 1;
993
994     XGrabServer(dpy);
995     win = XGetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM);
996
997     if (xflag) {
998         if (win == None) {
999             fprintf(stderr, "%s: no DSDM is running\n", ProgramName);
1000             exit(1);
1001         }
1002         /* Clear any DSDM selection to force the running DSDM to exit */
1003         XSetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM, None, CurrentTime);
1004         XFlush(dpy);
1005         exit(0);
1006     }
1007
1008     if (win != None) {
1009         fprintf(stderr,
1010                 "%s: another DSDM is already running\n",
1011                 ProgramName);
1012         exit(1);
1013     }
1014
1015 #ifdef PROXY
1016     ProxyInit(dpy, selwin);
1017 #endif
1018
1019     XSetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM, selwin, CurrentTime);
1020     /* no need to get owner per ICCCM, because we have the server grabbed */
1021     XUngrabServer(dpy);
1022     XFlush(dpy);
1023
1024 /* An attempt to minimize contention at startup:  in the olinitrc file, DO
1025  * NOT start the window manager or the file manager in the background.  This
1026  * way, the initialization code for the two applications is run sequentially.
1027  */
1028     if (argc == 1)
1029         if (fork() != 0)
1030             exit(0); /* on parent success or failure */
1031
1032     for (;;) {
1033         call_proxy_main = True;
1034         XNextEvent(dpy, &e);
1035         switch (e.type) {
1036         case SelectionRequest:
1037             if (e.xselectionrequest.selection != ATOM_DRAGDROP_DSDM) {
1038 #ifndef PROXY
1039                 DPRINTF(("%s: got SelectionRequest on wrong selection?\n",
1040                          ProgramName));
1041 #endif
1042                 break;
1043             }
1044             if (e.xselectionrequest.owner != selwin) {
1045                 fprintf(stderr, "%s: got SelectionRequest on wrong window?\n",
1046                         ProgramName);
1047                 break;
1048             }
1049                 
1050             reply.xselection.display = e.xselectionrequest.display;
1051             reply.xselection.type = SelectionNotify;
1052             reply.xselection.requestor = e.xselectionrequest.requestor;
1053             reply.xselection.selection = ATOM_DRAGDROP_DSDM;
1054             reply.xselection.target = e.xselectionrequest.target;
1055             reply.xselection.time = e.xselectionrequest.time;
1056
1057             if (e.xselectionrequest.target != ATOM_SITE_RECTS) {
1058                 fprintf(stderr,
1059                         "%s: got SelectionRequest for unknown target\n",
1060                         ProgramName);
1061                 reply.xselection.property = None;
1062             } else {
1063                 DPRINTF(("%s: got SelectionRequest event OK\n", ProgramName));
1064                 FreeDropSites();
1065                 FindDropSites(dpy);
1066                 WriteSiteRectList(dpy, e.xselectionrequest.requestor,
1067                                   e.xselectionrequest.property);
1068                 reply.xselection.property =
1069                     e.xselectionrequest.property;
1070             }
1071
1072             (void) XSendEvent(dpy, reply.xselection.requestor, False, 0,
1073                               &reply);
1074             call_proxy_main = False;
1075             break;
1076         case SelectionClear:
1077             exit(0);
1078         }
1079 #ifdef PROXY
1080         if (call_proxy_main)
1081                 ProxyMain(dpy, &e);
1082 #endif
1083     }
1084 } /* end of main */