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