2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
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 */
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. */
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.
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).
45 * Sun Microsystems, Inc., 2550 Garcia Avenue,
46 * Mountain View, California 94043.
51 * @(#)dsdm.c 1.5 91/02/13
52 * Drop Site Database Manager for drag'n'drop.
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
64 * USL changes are #ifdef'd with "oldcode" or commented with *USL* - Sam Chang
69 #if defined(SVR4) || defined(SYSV)
70 #include <string.h> /*USL*/
71 #else /* SVR4 or SYSV */
73 #endif /* SVR4 or SYSV */
75 #if !defined(__STDC__) && !defined(__cplusplus) && !defined(c_plusplus) /*USL*/
79 #define XFreeDefn char *
81 #include <X11/Xproto.h>
83 #include <X11/Xutil.h>
84 #include <X11/Xatom.h>
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));
93 #define DPRINTF(args) (void) printf args
98 #define INTEREST_MAX 100000000L /*(1024L*1024L)*/
100 #define FIND_CONTINUE ((Window) 0L)
101 #define FIND_STOP ((Window) 1L)
105 extern Window GetAtomWindow();
106 extern Atom ATOM_MOTIF_RECEIVER_INFO;
111 Atom ATOM_DRAGDROP_DSDM;
112 Atom ATOM_DRAGDROP_INTEREST;
114 Atom ATOM_SITE_RECTS;
117 int (*DefaultErrorHandler)();
119 typedef struct _site {
121 unsigned long site_id;
128 drop_site_t *MasterSiteList = NULL;
129 drop_site_t **NextSite;
133 Bool SearchChildren();
136 * Region stuff. Stolen from region.h.
139 typedef struct _box {
140 short x1, x2, y1, y2;
151 #define REGION_NUMRECTS(r) (((REGION *)(r))->numRects)
157 * Flash the visible region. Useful for debugging.
160 FlashRegion(dpy, s, gc)
167 Window root = RootWindow(dpy, s);
169 if (GrabSuccess != XGrabPointer(dpy, root, False,
170 ButtonPressMask, GrabModeAsync, GrabModeAsync,
171 None, None, CurrentTime)) {
172 fputs("can't grab the pointer\n", stderr);
177 XFillRectangle(dpy, root, gc, 0, 0,
178 DisplayWidth(dpy, s),
179 DisplayHeight(dpy, s));
182 XMaskEvent(dpy, ButtonPressMask, &e);
183 if (e.xbutton.button == Button3)
186 XFillRectangle(dpy, root, gc, 0, 0,
187 DisplayWidth(dpy, s),
188 DisplayHeight(dpy, s));
191 XUngrabPointer(dpy, CurrentTime);
192 } /* end of FlashRegion */
199 drop_site_t *site = MasterSiteList;
205 gcv.function = GXinvert;
206 gcv.subwindow_mode = IncludeInferiors;
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);
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);
222 for (s=0; s<ScreenCount(dpy); ++s)
223 XFreeGC(dpy, gcs[s]);
225 } /* end of FlashDropSites */
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.
240 GetInterestProperty(dpy, win, nitems)
246 unsigned long *nitems;
256 unsigned long remain;
257 unsigned char * data;
260 s = XGetWindowProperty(dpy, win, ATOM_DRAGDROP_INTEREST, 0L, INTEREST_MAX,
261 False, ATOM_DRAGDROP_INTEREST, &acttype, &actfmt,
262 nitems, &remain, &data);
268 /* property does not exist */
271 if (acttype != ATOM_DRAGDROP_INTEREST) {
272 fputs("dsdm: interest property has wrong type\n", stderr);
277 fputs("dsdm: interest property has wrong format\n", stderr);
281 XFree((XFreeDefn) data);
287 /* XXX didn't read it all, punt */
288 fputs("dsdm: interest property too long\n", stderr);
292 XFree((XFreeDefn) data);
297 } /* end of GetInterestProperty */
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.
309 FindRecursively(dpy, root, win, pwin, psite, plen, px, py)
311 Window root, win, *pwin;
316 XWindowAttributes attr;
320 unsigned long nitems;
321 unsigned long remain;
325 unsigned char * data;
329 if (XGetWindowAttributes(dpy, win, &attr) == 0) {
330 fprintf(stderr, "%s: XGetWindowAttributes failed for window 0x%lx\n",
335 if (attr.depth == 0 || attr.class == InputOnly ||
336 attr.map_state != IsViewable) {
340 data = GetInterestProperty(dpy, win, &nitems);
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",
348 XFree((XFreeDefn) data);
352 *psite = (void *) data;
355 DPRINTF(("%s: found top-level window 0x%lx with an interest\n",
360 s = XGetWindowProperty(dpy, win, ATOM_WM_STATE, 0L, 1,
361 False, ATOM_WM_STATE, &acttype, &actfmt,
362 &nitems, &remain, &data);
364 if (s != Success) /* couldn't find the window */
367 if (acttype == ATOM_WM_STATE) {
369 DPRINTF(("%s: found top-level window 0x%lx with no interest\n",
374 XFree((XFreeDefn) data);
380 #define DRAGDROP_VERSION 0
381 #define INTEREST_RECT 0
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);
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 */
403 *psite = (void *) data;
405 XTranslateCoordinates(dpy, win, root, 0, 0, px, py, &junk);
407 /* XView needs this */
410 ATOM_DRAGDROP_INTEREST, /* property */
411 ATOM_DRAGDROP_INTEREST, /* type */
413 PropModeReplace, /* mode */
414 (unsigned char *) data, /* data */
415 DATA_LEN /* number of elements */
418 /* dsdm needs this */
427 return(SearchChildren(dpy, root, win, pwin, psite, plen, px, py));
429 return(SearchChildren(dpy, root, win, pwin, psite, plen, px, py, True));
431 } /* end of FindRecursively */
436 * Look through all the children of window win for a top-level window.
440 SearchChildren(dpy, root, win, pwin, psite, plen, px, py)
442 Window root, win, *pwin;
447 SearchChildren(dpy, root, win, pwin, psite, plen, px, py, from_FindRec)
449 Window root, win, *pwin;
461 unsigned int nchildren;
465 if (XQueryTree(dpy, win, &junk, &junk, &children, &nchildren) == 0)
468 for (i=0; i<nchildren; ++i) {
469 if (FindRecursively(dpy, root, children[i], pwin, psite, plen, px, py))
474 XFree((XFreeDefn)children);
480 if (from_FindRec == False && nchildren)
481 XFree((XFreeDefn)children);
484 } /* end of SearchChildren */
488 * Create and return a region that contains a given rectangle.
491 MakeRegionFromRect(x, y, w, h)
502 reg = XCreateRegion();
503 XUnionRectWithRegion(&r, reg, reg);
505 } /* end of MakeRegionFromRect */
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).
516 GetWindowRegion(dpy, win, offset)
523 unsigned int width, height, junk;
527 winrgn = XCreateRegion();
529 if (0 == XGetGeometry(dpy, win, &wjunk, &x, &y, &width, &height,
531 fprintf(stderr, "%s: XGetGeometry failed on window 0x%lx\n",
534 winrgn = XCreateRegion();
538 return MakeRegionFromRect(offset ? x : 0, offset ? y: 0, width, height);
539 } /* end of GetWindowRegion */
543 * Subtract the area of a window from the current visible region.
546 SubtractWindowFromVisibleRegion(dpy, win, visrgn)
551 Region winrgn = GetWindowRegion(dpy, win, True);
552 XSubtractRegion(visrgn, winrgn, visrgn);
553 XDestroyRegion(winrgn);
554 } /* end of SubtractWindowFromVisibleRegion */
557 #define DRAGDROP_VERSION 0
558 #define INTEREST_RECT 0
559 #define INTEREST_WINDOW 1
561 #define NEXTWORD(dest) do { \
562 if (++cur >= datalen) { \
564 "%s: drop interest data too short on 0x%lx\n", \
566 if (region != NULL) \
567 XDestroyRegion(region); \
568 if (toprgn != NULL) \
569 XDestroyRegion(toprgn); \
572 (dest) = array[cur]; \
577 ProcessInterestProperty(dpy, win, screen, data, datalen, visrgn, xoff, yoff)
584 unsigned long datalen;
588 unsigned long *array = (unsigned long *)data;
598 Region region = NULL;
599 Region toprgn = NULL;
603 unsigned int width, height, junk, border;
608 if (array[cur] != DRAGDROP_VERSION) {
610 "%s: unknown drop interest property version (%ld) on 0x%lx\n",
611 ProgramName, array[cur], win);
615 toprgn = GetWindowRegion(dpy, win, False);
618 for (i=0; i<nsites; ++i) {
623 if (flags & MOTIF_RECEIVER_FLAG)
624 wid = sid; /* replace proxy window id with receiver window id */
629 region = XCreateRegion();
631 for (j=0; j<nrects; ++j) {
634 NEXTWORD(rect.width);
635 NEXTWORD(rect.height);
636 XUnionRectWithRegion(&rect, region, region);
639 case INTEREST_WINDOW:
640 region = XCreateRegion();
642 for (j=0; j<nrects; ++j) {
644 /* REMIND need to make sure areawin isn't bogus */
646 if (0 == XGetGeometry(dpy, areawin, &wjunk, &junk, &junk,
648 if (0 == XGetGeometry(dpy, areawin, &wjunk, &ignore, &ignore,
650 &width, &height, &border, &junk)) {
652 "%s: XGetGeometry failed on window 0x%lx\n",
656 (void) XTranslateCoordinates(dpy, areawin, win, 0, 0,
660 rect.width = width + border;
661 rect.height = height + border;
662 XUnionRectWithRegion(&rect, region, region);
667 "%s: unknown site area type on window 0x%lx\n",
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;
678 site->window_id = wid;
680 site->region = region;
683 NextSite = &site->next;
688 XDestroyRegion(toprgn);
690 } /* end of ProcessInterestProperty */
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.
708 unsigned int nchildren;
710 Window root, junk, *children, topwin;
712 Region visrgn, framergn, toprgn;
713 XWindowAttributes attr;
714 unsigned long datalen;
717 unsigned long fwdlen;
720 for (s=0; s<ScreenCount(dpy); ++s) {
722 /* Find the virtual root here, if necessary. */
723 root = RootWindow(dpy, s);
724 visrgn = GetWindowRegion(dpy, root, False);
726 if (XQueryTree(dpy, root, &junk, &junk, &children, &nchildren) == 0) {
727 fprintf(stderr, "%s: XQueryTree failed on root window 0x%lx\n",
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.
739 for (i=nchildren-1; i>=0; --i) {
740 if (XGetWindowAttributes(dpy, children[i], &attr) == 0) {
742 "%s: XGetWindowAttributes failed for window 0x%lx\n",
743 ProgramName, children[i]);
747 if (attr.depth == 0 || attr.class == InputOnly ||
748 attr.map_state != IsViewable) {
752 fwdsitedata = GetInterestProperty(dpy, children[i], &fwdlen);
755 foundtoplevel = SearchChildren(dpy, root, children[i], &topwin,
756 &sitedata, &datalen, &xoff, &yoff);
758 foundtoplevel = SearchChildren(dpy, root, children[i], &topwin,
759 &sitedata, &datalen, &xoff, &yoff, False);
761 if (foundtoplevel && sitedata != NULL) {
762 /* we found a valid drop interest */
763 ProcessInterestProperty(dpy, topwin, s, sitedata,
764 datalen, visrgn, xoff, yoff);
768 XFree((XFreeDefn)sitedata);
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);
784 XFree((XFreeDefn)fwdsitedata);
788 if (fwdsitedata != NULL) {
789 ProcessInterestProperty(dpy, children[i], s, fwdsitedata,
790 fwdlen, visrgn, attr.x, attr.y);
794 XFree((XFreeDefn)fwdsitedata);
799 SubtractWindowFromVisibleRegion(dpy, children[i], visrgn);
801 XDestroyRegion(visrgn);
804 XFree((XFreeDefn)children);
807 } /* end of FindDropSites */
813 drop_site_t *next, *temp;
815 next = MasterSiteList;
816 while (next != NULL) {
822 XDestroyRegion(next->region);
823 XFree((XFreeDefn)next);
827 MasterSiteList = NULL;
829 NextSite = &MasterSiteList;
830 } /* end of FreeDropSites */
834 * Write a property containing site rectangle information. The format
835 * consists of zero or more blocks of 8 words, as follows:
846 WriteSiteRectList(dpy, win, prop)
852 unsigned long *array;
858 site = MasterSiteList;
859 while (site != NULL) {
860 numrects += REGION_NUMRECTS(site->region);
864 /* XXX beware of malloc(0) */
866 array = (unsigned long *) malloc(8*numrects*sizeof(int));
868 array = (unsigned long *) malloc(8*numrects*sizeof(unsigned long));
871 site = MasterSiteList;
872 while (site != NULL) {
873 region = (REGION *) site->region;
875 last = box + region->numRects;
876 for ( ; box < last ; ++box) {
877 *cur++ = site->screen;
878 *cur++ = site->site_id;
880 /* if the receiver is motif then let event window be proxy win */
881 if (site->flags & MOTIF_RECEIVER_FLAG)
884 *cur++ = site->window_id;
886 *cur++ = site->window_id;
890 *cur++ = box->x2 - box->x1;
891 *cur++ = box->y2 - box->y1;
892 *cur++ = site->flags;
897 XChangeProperty(dpy, win, prop, XA_INTEGER, 32, PropModeReplace,
899 (char *)array, cur - array);
902 (unsigned char *)array, cur - array);
903 XFree((XFreeDefn)array);
905 } /* end of WriteSiteRectList */
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.
914 ErrorHandler(dpy, error)
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));
932 fputs("dsdm: ", stderr);
933 (*DefaultErrorHandler)(dpy, error);
936 } /* end of ErrorHandler */
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" };
951 XSetWindowAttributes attr;
957 char call_proxy_main;
958 Atom atoms[NUM_ATOMS];
961 while (*cp != '\0') {
967 ProgramName = slash + 1;
969 ProgramName = argv[0];
971 dpy = XOpenDisplay(NULL);
973 fprintf(stderr, "%s: can't open display %s\n",
974 ProgramName, XDisplayName(NULL));
978 DefaultErrorHandler = XSetErrorHandler(ErrorHandler);
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];
986 attr.event_mask = PropertyChangeMask;
987 selwin = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0, 0,
988 InputOnly, CopyFromParent,
991 if (argc > 1 && 0 == strcmp(argv[1], "-x"))
995 win = XGetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM);
999 fprintf(stderr, "%s: no DSDM is running\n", ProgramName);
1002 /* Clear any DSDM selection to force the running DSDM to exit */
1003 XSetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM, None, CurrentTime);
1010 "%s: another DSDM is already running\n",
1016 ProxyInit(dpy, selwin);
1019 XSetSelectionOwner(dpy, ATOM_DRAGDROP_DSDM, selwin, CurrentTime);
1020 /* no need to get owner per ICCCM, because we have the server grabbed */
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.
1030 exit(0); /* on parent success or failure */
1033 call_proxy_main = True;
1034 XNextEvent(dpy, &e);
1036 case SelectionRequest:
1037 if (e.xselectionrequest.selection != ATOM_DRAGDROP_DSDM) {
1039 DPRINTF(("%s: got SelectionRequest on wrong selection?\n",
1044 if (e.xselectionrequest.owner != selwin) {
1045 fprintf(stderr, "%s: got SelectionRequest on wrong window?\n",
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;
1057 if (e.xselectionrequest.target != ATOM_SITE_RECTS) {
1059 "%s: got SelectionRequest for unknown target\n",
1061 reply.xselection.property = None;
1063 DPRINTF(("%s: got SelectionRequest event OK\n", ProgramName));
1066 WriteSiteRectList(dpy, e.xselectionrequest.requestor,
1067 e.xselectionrequest.property);
1068 reply.xselection.property =
1069 e.xselectionrequest.property;
1072 (void) XSendEvent(dpy, reply.xselection.requestor, False, 0,
1074 call_proxy_main = False;
1076 case SelectionClear:
1080 if (call_proxy_main)