multiVis.c revision 6728f30e
1/** ------------------------------------------------------------------------
2	This file contains functions to create a list of regions which
3	tile a specified window.  Each region contains all visible
4	portions of the window which are drawn with the same visual.
5	If the window consists of subwindows of two different visual types,
6	there will be two regions in the list.  The list can be traversed
7	to correctly pull an image of the window using XGetImage or the
8	Image Library.
9
10Copyright 1994 Hewlett-Packard Co.
11Copyright 1996, 1998  The Open Group
12
13Permission to use, copy, modify, distribute, and sell this software and its
14documentation for any purpose is hereby granted without fee, provided that
15the above copyright notice appear in all copies and that both that
16copyright notice and this permission notice appear in supporting
17documentation.
18
19The above copyright notice and this permission notice shall be included
20in all copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
26OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28OTHER DEALINGS IN THE SOFTWARE.
29
30Except as contained in this notice, the name of The Open Group shall
31not be used in advertising or otherwise to promote the sale, use or
32other dealings in this Software without prior written authorization
33from The Open Group.
34
35    ------------------------------------------------------------------------ **/
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <X11/Xlib.h>
41#include <X11/Xutil.h>
42#include <X11/X.h>
43#include "list.h"
44#include "wsutils.h"
45#include "multiVis.h"
46/* These structures are copied from X11/region.h.  For some reason
47 * they're invisible from the outside.
48 */
49typedef struct {
50    short x1, x2, y1, y2;
51} myBox, myBOX, myBoxRec, *myBoxPtr;
52
53typedef struct my_XRegion {
54    long size;
55    long numRects;
56    myBOX *rects;
57    myBOX extents;
58} myREGION;
59
60/* Items in long list of windows that have some part in the grabbed area */
61typedef struct {
62    Window win;
63    Visual *vis;
64    Colormap cmap;
65    int x_rootrel, y_rootrel;   /* root relative location of window */
66    int x_vis, y_vis;           /* rt rel x,y of vis part, not parent clipped */
67    int width, height;          /* width and height of visible part */
68    int border_width;           /* border width of the window */
69    Window parent;              /* id of parent (for debugging) */
70} image_win_type;
71
72/*  Items in short list of regions that tile the grabbed area.  May have
73    multiple windows in the region.
74*/
75typedef struct {
76    Window win;                 /* lowest window of this visual */
77    Visual *vis;
78    Colormap cmap;
79    int x_rootrel, y_rootrel;   /* root relative location of bottom window */
80    int x_vis, y_vis;           /* rt rel x,y of vis part, not parent clipped */
81    int width, height;          /* w & h of visible rect of bottom window */
82    int border;                 /* border width of the window */
83    Region visible_region;
84} image_region_type;
85
86/** ------------------------------------------------------------------------
87	Returns TRUE if the two structs pointed to have the same "vis" &
88	"cmap" fields and s2 lies completely within s1.  s1 and s2 can
89	point to structs of image_win_type or image_region_type.
90    ------------------------------------------------------------------------ **/
91#define SAME_REGIONS( s1, s2)	\
92	((s1)->vis == (s2)->vis && (s1)->cmap == (s2)->cmap &&   	\
93	 (s1)->x_vis <= (s2)->x_vis &&				    \
94	 (s1)->y_vis <= (s2)->y_vis &&				    \
95	 (s1)->x_vis + (s1)->width  >= (s2)->x_vis + (s2)->width && \
96	 (s1)->y_vis + (s1)->height >= (s2)->y_vis + (s2)->height)
97
98#ifndef MIN
99#define MIN( a, b)	((a) < (b) ? a : b)
100#define MAX( a, b)	((a) > (b) ? a : b)
101#endif
102
103#define	RED_SHIFT        16
104#define GREEN_SHIFT       8
105#define BLUE_SHIFT        0
106
107/* Prototype Declarations for Static Functions */
108static void QueryColorMap(Display *, Colormap, Visual *,
109                          XColor **, int *, int *, int *);
110static void TransferImage(Display *, XImage *, int, int, image_region_type *,
111                          XImage *, int, int);
112static XImage *ReadRegionsInList(Display *, Visual *, int, int, unsigned int,
113                                 unsigned int, XRectangle, list_ptr);
114
115static list_ptr make_region_list(Display *, Window, XRectangle *,
116                                 int *, int, XVisualInfo **, int *);
117static void destroy_region_list(list_ptr);
118static void subtr_rect_from_image_region(image_region_type *,
119                                         int, int, int, int);
120static void add_rect_to_image_region(image_region_type *,
121                                     int, int, int, int);
122static int src_in_region_list(image_win_type *, list_ptr);
123static void add_window_to_list(list_ptr, Window, int, int,
124                               int, int, int, int, int,
125                               Visual *, Colormap, Window);
126static int src_in_image(image_win_type *, int, XVisualInfo **);
127static int src_in_overlay(image_region_type *, int, OverlayInfo *, int *,
128                          int *);
129static void make_src_list(Display *, list_ptr, XRectangle *, Window, int, int,
130                          XWindowAttributes *, XRectangle *);
131static void destroy_image_region(image_region_type *);
132
133/* End of Prototype Declarations */
134
135void
136initFakeVisual(Visual *Vis)
137{
138    Vis->ext_data = NULL;
139    Vis->class = DirectColor;
140    Vis->red_mask = 0x00FF0000;
141    Vis->green_mask = 0x0000FF00;
142    Vis->blue_mask = 0x000000FF;
143    Vis->map_entries = 256;
144    Vis->bits_per_rgb = 8;
145}
146
147static void
148QueryColorMap(Display *disp, Colormap src_cmap, Visual *src_vis,
149              XColor **src_colors, int *rShift, int *gShift, int *bShift)
150{
151    unsigned int ncolors;
152    XColor *colors;
153
154    ncolors = (unsigned) src_vis->map_entries;
155    *src_colors = colors = calloc(ncolors, sizeof(XColor));
156
157    if (src_vis->class != TrueColor && src_vis->class != DirectColor) {
158        for (unsigned int i = 0; i < ncolors; i++) {
159            colors[i].pixel = i;
160            colors[i].pad = 0;
161            colors[i].flags = DoRed | DoGreen | DoBlue;
162        }
163    }
164    else { /** src is decomposed rgb ***/
165        unsigned long redMask, greenMask, blueMask;
166        int redShift, greenShift, blueShift;
167
168        /* Get the X colormap */
169        redMask = src_vis->red_mask;
170        greenMask = src_vis->green_mask;
171        blueMask = src_vis->blue_mask;
172        redShift = 0;
173        while (!(redMask & 0x1)) {
174            redShift++;
175            redMask = redMask >> 1;
176        }
177        greenShift = 0;
178        while (!(greenMask & 0x1)) {
179            greenShift++;
180            greenMask = greenMask >> 1;
181        }
182        blueShift = 0;
183        while (!(blueMask & 0x1)) {
184            blueShift++;
185            blueMask = blueMask >> 1;
186        }
187        *rShift = redShift;
188        *gShift = greenShift;
189        *bShift = blueShift;
190        for (unsigned int i = 0; i < ncolors; i++) {
191            if (i <= redMask)
192                colors[i].pixel = (i << redShift);
193            if (i <= greenMask)
194                colors[i].pixel |= (i << greenShift);
195            if (i <= blueMask)
196                colors[i].pixel |= (i << blueShift);
197            /***** example: for gecko's 3-3-2 map, blue index should be <= 3.
198                colors[i].pixel = (i<<redShift)|(i<<greenShift)|(i<<blueShift);
199             *****/
200            colors[i].pad = 0;
201            colors[i].flags = DoRed | DoGreen | DoBlue;
202        }
203    }
204
205    XQueryColors(disp, src_cmap, colors, (int) ncolors);
206}
207
208int
209GetMultiVisualRegions(Display *disp,
210                      /* root win on which grab was done */
211                      Window srcRootWinid,
212                      /* root rel UL corner of bounding box of grab */
213                      int x, int y,
214                      /* size of bounding box of grab */
215                      unsigned int width, unsigned int height,
216                      int *transparentOverlays, int *numVisuals,
217                      XVisualInfo **pVisuals, int *numOverlayVisuals,
218                      OverlayInfo **pOverlayVisuals,
219                      int *numImageVisuals, XVisualInfo ***pImageVisuals,
220                      /* list of regions to read from */
221                      list_ptr *vis_regions,
222                      list_ptr *vis_image_regions, int *allImage)
223{
224    int hasNonDefault;
225    XRectangle bbox;            /* bounding box of grabbed area */
226
227    bbox.x = x;                 /* init X rect for bounding box */
228    bbox.y = y;
229    bbox.width = width;
230    bbox.height = height;
231
232    GetXVisualInfo(disp, DefaultScreen(disp),
233                   transparentOverlays,
234                   numVisuals, pVisuals,
235                   numOverlayVisuals, pOverlayVisuals,
236                   numImageVisuals, pImageVisuals);
237
238    *vis_regions = *vis_image_regions = NULL;
239    if ((*vis_regions = make_region_list(disp, srcRootWinid, &bbox,
240                                         &hasNonDefault, *numImageVisuals,
241                                         *pImageVisuals, allImage)) == NULL)
242        return 0;
243
244    if (*transparentOverlays) {
245        *allImage = 1;        /* until proven otherwise,
246                                 this flags that it to be an image only list */
247        *vis_image_regions =
248            make_region_list(disp, srcRootWinid, &bbox, &hasNonDefault,
249                             *numImageVisuals, *pImageVisuals, allImage);
250    }
251
252    /* if there is a second region in any of the two lists return 1 */
253    if ((*vis_regions && (*vis_regions)->next && (*vis_regions)->next->next) ||
254        (*vis_image_regions && (*vis_image_regions)->next &&
255         (*vis_image_regions)->next->next))
256        return 1;
257    else
258        return 0;
259
260}
261
262static void
263TransferImage(Display *disp, XImage *reg_image,
264              int srcw, int srch,
265              image_region_type *reg, XImage *target_image,
266              int dst_x, int dst_y)
267{
268    XColor *colors;
269    int rShift = 0, gShift = 0, bShift = 0;
270
271    QueryColorMap(disp, reg->cmap, reg->vis, &colors,
272                  &rShift, &gShift, &bShift);
273
274    switch (reg->vis->class) {
275    case TrueColor:
276        for (int i = 0; i < srch; i++) {
277            for (int j = 0; j < srcw; j++) {
278                int old_pixel = XGetPixel(reg_image, j, i);
279                int new_pixel;
280
281                if (reg->vis->map_entries == 16) {
282                    int red_ind = (old_pixel & reg->vis->red_mask) >> rShift;
283                    int green_ind = (old_pixel & reg->vis->green_mask) >> gShift;
284                    int blue_ind = (old_pixel & reg->vis->blue_mask) >> bShift;
285
286                    new_pixel = (
287                        ((colors[red_ind].red >> 8) << RED_SHIFT) |
288                        ((colors[green_ind].green >> 8) << GREEN_SHIFT) |
289                        ((colors[blue_ind].blue >> 8) << BLUE_SHIFT)
290                        );
291                }
292                else
293                    new_pixel = old_pixel;
294
295                XPutPixel(target_image, dst_x + j, dst_y + i, new_pixel);
296
297            }
298        }
299        break;
300    case DirectColor:
301        for (int i = 0; i < srch; i++) {
302
303            for (int j = 0; j < srcw; j++) {
304                int old_pixel = XGetPixel(reg_image, j, i);
305                int red_ind = (old_pixel & reg->vis->red_mask) >> rShift;
306                int green_ind = (old_pixel & reg->vis->green_mask) >> gShift;
307                int blue_ind = (old_pixel & reg->vis->blue_mask) >> bShift;
308
309                int new_pixel = (
310                    ((colors[red_ind].red >> 8) << RED_SHIFT) |
311                    ((colors[green_ind].green >> 8) << GREEN_SHIFT) |
312                    ((colors[blue_ind].blue >> 8) << BLUE_SHIFT)
313                    );
314                XPutPixel(target_image, dst_x + j, dst_y + i, new_pixel);
315
316            }
317        }
318        break;
319    default:
320        for (int i = 0; i < srch; i++) {
321            for (int j = 0; j < srcw; j++) {
322                int old_pixel = XGetPixel(reg_image, j, i);
323
324                int new_pixel = (
325                    ((colors[old_pixel].red >> 8) << RED_SHIFT) |
326                    ((colors[old_pixel].green >> 8) << GREEN_SHIFT) |
327                    ((colors[old_pixel].blue >> 8) << BLUE_SHIFT)
328                    );
329                XPutPixel(target_image, dst_x + j, dst_y + i, new_pixel);
330
331            }
332        }
333        break;
334    }
335}
336
337static XImage *
338ReadRegionsInList(Display *disp, Visual *fakeVis, int depth, int format,
339                  unsigned int width, unsigned int height,
340                  XRectangle bbox,    /* bounding box of grabbed area */
341                  list_ptr regions)   /* list of regions to read from */
342{
343    int datalen;
344
345    XImage *reg_image, *ximage;
346    int bytes_per_line;
347
348    ximage = XCreateImage(disp, fakeVis, depth, format, 0, NULL, width, height,
349                          8, 0);
350    bytes_per_line = ximage->bytes_per_line;
351
352    datalen = height * bytes_per_line;
353    if (format != ZPixmap)
354        datalen *= depth;
355    ximage->data = malloc(datalen);
356    memset(ximage->data, 0, datalen);
357
358    ximage->bits_per_pixel = depth; /** Valid only if format is ZPixmap ***/
359
360    for (image_region_type *reg = (image_region_type *) first_in_list(regions);
361         reg; reg = (image_region_type *) next_in_list(regions)) {
362
363        struct my_XRegion *vis_reg = (struct my_XRegion *) (reg->visible_region);
364
365        for (int rect = 0; rect < vis_reg->numRects; rect++) {
366/** ------------------------------------------------------------------------
367	Intersect bbox with visible part of region giving src rect & output
368	location.  Width is the min right side minus the max left side.
369	Similar for height.  Offset src rect so x,y are relative to
370	origin of win, not the root-relative visible rect of win.
371 ------------------------------------------------------------------------ **/
372            int srcRect_width =
373                MIN(vis_reg->rects[rect].x2, bbox.width + bbox.x) -
374                MAX(vis_reg->rects[rect].x1, bbox.x);
375            int srcRect_height =
376                MIN(vis_reg->rects[rect].y2, bbox.height + bbox.y) -
377                MAX(vis_reg->rects[rect].y1, bbox.y);
378            int srcRect_x, srcRect_y;
379            int dst_x, dst_y;           /* where in pixmap to write (UL) */
380
381            int diff = bbox.x - vis_reg->rects[rect].x1;
382            srcRect_x = MAX(0,diff) +
383                (vis_reg->rects[rect].x1 - reg->x_rootrel - reg->border);
384            dst_x = MAX(0, -diff);
385
386            diff = bbox.y - vis_reg->rects[rect].y1;
387            srcRect_y = MAX(0, diff) +
388                (vis_reg->rects[rect].y1 - reg->y_rootrel - reg->border);
389            dst_y = MAX(0, -diff);
390
391            reg_image = XGetImage(disp, reg->win, srcRect_x, srcRect_y,
392                                  srcRect_width, srcRect_height, AllPlanes,
393                                  format);
394            TransferImage(disp, reg_image, srcRect_width, srcRect_height, reg,
395                          ximage, dst_x, dst_y);
396        }
397    }
398    return ximage;
399}
400
401
402/** ------------------------------------------------------------------------
403    ------------------------------------------------------------------------ **/
404
405XImage *
406ReadAreaToImage(Display *disp,
407                /* root win on which grab was done */
408                Window srcRootWinid,
409                /* root rel UL corner of bounding box of grab */
410                int x, int y,
411                /* size of bounding box of grab */
412                unsigned int width, unsigned int height,
413                int numVisuals, XVisualInfo *pVisuals,
414                int numOverlayVisuals, OverlayInfo *pOverlayVisuals,
415                int numImageVisuals, XVisualInfo **pImageVisuals,
416                /* list of regions to read from */
417                list_ptr vis_regions,
418                /* list of regions to read from */
419                list_ptr vis_image_regions,
420                int format, int allImage)
421{
422    image_region_type *reg;
423    XRectangle bbox;            /* bounding box of grabbed area */
424    int depth;
425    XImage *ximage, *ximage_ipm = NULL;
426    Visual fakeVis;
427    XImage *image;
428
429#if 0
430    unsigned char *pmData, *ipmData;
431#endif
432    int transparentColor, transparentType;
433
434    bbox.x = x;                 /* init X rect for bounding box */
435    bbox.y = y;
436    bbox.width = width;
437    bbox.height = height;
438
439    initFakeVisual(&fakeVis);
440
441    depth = 24;
442    ximage = ReadRegionsInList(disp, &fakeVis, depth, format, width, height,
443                               bbox, vis_regions);
444#if 0
445    pmData = (unsigned char *) ximage->data;
446#endif
447
448/* if transparency possible do it again, but this time for image planes only */
449    if (vis_image_regions && (vis_image_regions->next) && !allImage) {
450        ximage_ipm =
451            ReadRegionsInList(disp, &fakeVis, depth, format, width, height,
452                              bbox, vis_image_regions);
453#if 0
454        ipmData = (unsigned char *) ximage_ipm->data;
455#endif
456    }
457/* Now tranverse the overlay visual windows and test for transparency index.  */
458/* If you find one, substitute the value from the matching image plane pixmap. */
459
460    for (reg = (image_region_type *) first_in_list(vis_regions); reg;
461         reg = (image_region_type *) next_in_list(vis_regions)) {
462
463        if (src_in_overlay(reg, numOverlayVisuals, pOverlayVisuals,
464                           &transparentColor, &transparentType)) {
465            int srcRect_x, srcRect_y, srcRect_width, srcRect_height;
466            int diff;
467            int dst_x, dst_y;           /* where in pixmap to write (UL) */
468            int test = 0;
469
470            srcRect_width =
471                MIN(reg->width + reg->x_vis, bbox.width + bbox.x)
472                - MAX(reg->x_vis, bbox.x);
473            srcRect_height =
474                MIN(reg->height + reg->y_vis, bbox.height + bbox.y)
475                - MAX(reg->y_vis, bbox.y);
476            diff = bbox.x - reg->x_vis;
477            srcRect_x =
478                MAX(0, diff) + (reg->x_vis - reg->x_rootrel - reg->border);
479            dst_x = MAX(0, -diff);
480            diff = bbox.y - reg->y_vis;
481            srcRect_y =
482                MAX(0, diff) + (reg->y_vis - reg->y_rootrel - reg->border);
483            dst_y = MAX(0, -diff);
484            /* let's test some pixels for transparency */
485            image = XGetImage(disp, reg->win, srcRect_x, srcRect_y,
486                              srcRect_width, srcRect_height, 0xffffffff,
487                              ZPixmap);
488
489            /* let's assume byte per pixel for overlay image for now */
490            if ((image->depth == 8) && (transparentType == TransparentPixel)) {
491                unsigned char *pixel_ptr;
492                unsigned char *start_of_line = (unsigned char *) image->data;
493
494                for (int y1 = 0; y1 < srcRect_height; y1++) {
495                    pixel_ptr = start_of_line;
496                    for (int x1 = 0; x1 < srcRect_width; x1++) {
497                        if (*pixel_ptr++ == transparentColor) {
498                            int pixel;
499#if 0
500                            *pmData++ = *ipmData++;
501                            *pmData++ = *ipmData++;
502                            *pmData++ = *ipmData++;
503#endif
504                            pixel =
505                                XGetPixel(ximage_ipm, dst_x + x1, dst_y + y1);
506                            XPutPixel(ximage, dst_x + x1, dst_y + y1, pixel);
507
508                            if (!test) {
509                                test = 1;
510                            }
511                        }
512#if 0
513                        else {
514                            pmData += 3;
515                            ipmData += 3;
516                        }
517#endif
518                    }
519                    start_of_line += image->bytes_per_line;
520                }
521            }
522            else {
523                if (transparentType == TransparentPixel) {
524                    for (int y1 = 0; y1 < srcRect_height; y1++) {
525                        for (int x1 = 0; x1 < srcRect_width; x1++) {
526                            int pixel_value = XGetPixel(image, x1, y1);
527
528                            if (pixel_value == transparentColor) {
529                                int pixel;
530#if 0
531                                *pmData++ = *ipmData++;
532                                *pmData++ = *ipmData++;
533                                *pmData++ = *ipmData++;
534#endif
535                                pixel =
536                                    XGetPixel(ximage_ipm, dst_x + x1,
537                                              dst_y + y1);
538                                XPutPixel(ximage, dst_x + x1, dst_y + y1,
539                                          pixel);
540                                if (!test) {
541                                    test = 1;
542                                }
543                            }
544#if 0
545                            else {
546                                pmData += 3;
547                                ipmData += 3;
548                            }
549#endif
550                        }
551                    }
552                }
553                else {
554                    for (int y1 = 0; y1 < srcRect_height; y1++) {
555                        for (int x1 = 0; x1 < srcRect_width; x1++) {
556                            int pixel_value = XGetPixel(image, x1, y1);
557
558                            if (pixel_value & transparentColor) {
559                                int pixel;
560#if 0
561                                *pmData++ = *ipmData++;
562                                *pmData++ = *ipmData++;
563                                *pmData++ = *ipmData++;
564#endif
565                                pixel =
566                                    XGetPixel(ximage_ipm, dst_x + x1,
567                                              dst_y + y1);
568                                XPutPixel(ximage, dst_x + x1, dst_y + y1,
569                                          pixel);
570                                if (!test) {
571                                    test = 1;
572                                }
573                            }
574#if 0
575                            else {
576                                pmData += 3;
577                                ipmData += 3;
578                            }
579#endif
580                        }
581                    }
582                }
583            }
584            XDestroyImage(image);
585        }                       /* end of src_in_overlay */
586    } /** end transparency **/
587    destroy_region_list(vis_regions);
588    if (vis_image_regions)
589        destroy_region_list(vis_image_regions);
590    FreeXVisualInfo(pVisuals, pOverlayVisuals, pImageVisuals);
591    XSync(disp, 0);
592
593    return ximage;
594}
595
596/** ------------------------------------------------------------------------
597	Creates a list of the subwindows of a given window which have a
598	different visual than their parents.  The function is recursive.
599	This list is used in make_region_list(), which coalesces the
600	windows with the same visual into a region.
601	image_wins must point to an existing list struct that's already
602	been zeroed (zero_list()).
603    ------------------------------------------------------------------------ **/
604static void
605make_src_list(Display *disp, list_ptr image_wins,
606              /* bnding box of area we want */
607              XRectangle *bbox,
608              Window curr,
609              /* pos of curr WRT root */
610              int x_rootrel, int y_rootrel,
611              XWindowAttributes *curr_attrs,
612              /* visible part of curr, not obscurred by ancestors */
613              XRectangle *pclip)
614{
615    XWindowAttributes child_attrs;
616    Window root, parent, *child;        /* variables for XQueryTree() */
617    unsigned int nchild;                /* variables for XQueryTree() */
618    XRectangle child_clip;              /* vis part of child */
619
620    /* check that win is mapped & not outside bounding box */
621    if (curr_attrs->map_state == IsViewable &&
622        curr_attrs->class == InputOutput &&
623        !(pclip->x >= (int) (bbox->x + bbox->width) ||
624          pclip->y >= (int) (bbox->y + bbox->height) ||
625          (int) (pclip->x + pclip->width) <= bbox->x ||
626          (int) (pclip->y + pclip->height) <= bbox->y)) {
627
628        Window *save_child_list;
629        int curr_clipX, curr_clipY, curr_clipRt, curr_clipBt;
630
631        XQueryTree(disp, curr, &root, &parent, &child, &nchild);
632        save_child_list = child;   /* so we can free list when we're done */
633        add_window_to_list(image_wins, curr, x_rootrel, y_rootrel,
634                           pclip->x, pclip->y,
635                           pclip->width, pclip->height,
636                           curr_attrs->border_width, curr_attrs->visual,
637                           curr_attrs->colormap, parent);
638
639/** ------------------------------------------------------------------------
640	set RR coords of right (Rt), left (X), bottom (Bt) and top (Y)
641	of rect we clip all children by.  This is our own clip rect (pclip)
642	inflicted on us by our parent plus our own borders.  Within the
643	child loop, we figure the clip rect for each child by adding in
644	it's rectangle (not taking into account the child's borders).
645    ------------------------------------------------------------------------ **/
646        curr_clipX = MAX(pclip->x, x_rootrel + (int) curr_attrs->border_width);
647        curr_clipY = MAX(pclip->y, y_rootrel + (int) curr_attrs->border_width);
648        curr_clipRt = MIN(pclip->x + (int) pclip->width,
649                          x_rootrel + (int) curr_attrs->width +
650                          2 * (int) curr_attrs->border_width);
651        curr_clipBt = MIN(pclip->y + (int) pclip->height,
652                          y_rootrel + (int) curr_attrs->height +
653                          2 * (int) curr_attrs->border_width);
654
655        while (nchild--) {
656            int new_width, new_height;
657            int child_xrr, child_yrr;   /* root relative x & y of child */
658
659            XGetWindowAttributes(disp, *child, &child_attrs);
660
661            /* intersect parent & child clip rects */
662            child_xrr = x_rootrel + child_attrs.x + curr_attrs->border_width;
663            child_clip.x = MAX(curr_clipX, child_xrr);
664            new_width = MIN(curr_clipRt, child_xrr + (int) child_attrs.width
665                            + 2 * child_attrs.border_width)
666                - child_clip.x;
667            if (new_width >= 0) {
668                child_clip.width = new_width;
669
670                child_yrr = y_rootrel + child_attrs.y +
671                    curr_attrs->border_width;
672                child_clip.y = MAX(curr_clipY, child_yrr);
673                new_height = MIN(curr_clipBt,
674                                 child_yrr + (int) child_attrs.height +
675                                 2 * child_attrs.border_width)
676                    - child_clip.y;
677                if (new_height >= 0) {
678                    child_clip.height = new_height;
679                    make_src_list(disp, image_wins, bbox, *child,
680                                  child_xrr, child_yrr,
681                                  &child_attrs, &child_clip);
682                }
683            }
684            child++;
685        }
686        XFree(save_child_list);
687    }
688}
689
690
691/** ------------------------------------------------------------------------
692	This function creates a list of regions which tile a specified
693	window.  Each region contains all visible portions of the window
694	which are drawn with the same visual.  For example, if the
695	window consists of subwindows of two different visual types,
696	there will be two regions in the list.
697	Returns a pointer to the list.
698    ------------------------------------------------------------------------ **/
699static list_ptr
700make_region_list(Display *disp, Window win, XRectangle *bbox,
701                 int *hasNonDefault, int numImageVisuals,
702                 XVisualInfo **pImageVisuals, int *allImage)
703{
704    XWindowAttributes win_attrs;
705    list image_wins;
706    list_ptr image_regions;
707    list_ptr srcs_left;
708    image_region_type *new_reg;
709    image_win_type *base_src, *src;
710    Region bbox_region = XCreateRegion();
711    XRectangle clip;
712    int image_only;
713    int count = 0;
714
715    *hasNonDefault = False;
716    XUnionRectWithRegion(bbox, bbox_region, bbox_region);
717    XGetWindowAttributes(disp, win, &win_attrs);
718
719    zero_list(&image_wins);
720    clip.x = 0;
721    clip.y = 0;
722    clip.width = win_attrs.width;
723    clip.height = win_attrs.height;
724    make_src_list(disp, &image_wins, bbox, win,
725                  0 /* x_rootrel */, 0 /* y_rootrel */, &win_attrs, &clip);
726
727    image_regions = new_list();
728    image_only = (*allImage) ? True : False;
729
730    for (base_src = (image_win_type *) first_in_list(&image_wins); base_src;
731         base_src = (image_win_type *) next_in_list(&image_wins)) {
732        /* test for image visual */
733        if (!image_only ||
734            src_in_image(base_src, numImageVisuals, pImageVisuals)) {
735            /* find a window whose visual hasn't been put in list yet */
736            if (!src_in_region_list(base_src, image_regions)) {
737                if (!(new_reg = malloc(sizeof(image_region_type)))) {
738                    return (list_ptr) NULL;
739                }
740                count++;
741
742                new_reg->visible_region = XCreateRegion();
743                new_reg->win            = base_src->win;
744                new_reg->vis            = base_src->vis;
745                new_reg->cmap           = base_src->cmap;
746                new_reg->x_rootrel      = base_src->x_rootrel;
747                new_reg->y_rootrel      = base_src->y_rootrel;
748                new_reg->x_vis          = base_src->x_vis;
749                new_reg->y_vis          = base_src->y_vis;
750                new_reg->width          = base_src->width;
751                new_reg->height         = base_src->height;
752                new_reg->border         = base_src->border_width;
753
754                srcs_left =
755                    (list_ptr) dup_list_head(&image_wins, START_AT_CURR);
756                for (src = (image_win_type *) first_in_list(srcs_left); src;
757                     src = (image_win_type *) next_in_list(srcs_left)) {
758                    if (SAME_REGIONS(base_src, src)) {
759                        add_rect_to_image_region(new_reg,
760                                                 src->x_vis, src->y_vis,
761                                                 src->width, src->height);
762                    }
763                    else {
764                        if (!image_only ||
765                            src_in_image(src, numImageVisuals, pImageVisuals))
766                        {
767                            subtr_rect_from_image_region(new_reg, src->x_vis,
768                                                         src->y_vis, src->width,
769                                                         src->height);
770                        }
771                    }
772                }
773                XIntersectRegion(bbox_region, new_reg->visible_region,
774                                 new_reg->visible_region);
775                if (!XEmptyRegion(new_reg->visible_region)) {
776                    add_to_list(image_regions, new_reg);
777                    if (new_reg->vis != DefaultVisualOfScreen(win_attrs.screen)
778                        || new_reg->cmap !=
779                        DefaultColormapOfScreen(win_attrs.screen)) {
780                        *hasNonDefault = True;
781                    }
782                }
783                else {
784                    XDestroyRegion(new_reg->visible_region);
785                    free(new_reg);
786                }
787            }
788        }
789        else
790            *allImage = 0;
791    }
792    delete_list(&image_wins, True);
793    XDestroyRegion(bbox_region);
794    return image_regions;
795}
796
797/** ------------------------------------------------------------------------
798	Destructor called from destroy_region_list().
799    ------------------------------------------------------------------------ **/
800static void
801destroy_image_region(image_region_type *image_region)
802{
803    XDestroyRegion(image_region->visible_region);
804    free(image_region);
805}
806
807/** ------------------------------------------------------------------------
808	Destroys the region list, destroying all the regions contained in it.
809    ------------------------------------------------------------------------ **/
810static void
811destroy_region_list(list_ptr rlist)
812{
813    delete_list_destroying(rlist, (DESTRUCT_FUNC_PTR) destroy_image_region);
814}
815
816/** ------------------------------------------------------------------------
817	Subtracts the specified rectangle from the region in image_region.
818	First converts the rectangle to a region of its own, since X
819	only provides a way to subtract one region from another, not a
820	rectangle from a region.
821    ------------------------------------------------------------------------ **/
822static void
823subtr_rect_from_image_region(image_region_type *image_region,
824                             int x, int y, int width, int height)
825{
826    XRectangle rect;
827    Region rect_region;
828
829    rect_region = XCreateRegion();
830    rect.x = x;
831    rect.y = y;
832    rect.width = width;
833    rect.height = height;
834    XUnionRectWithRegion(&rect, rect_region, rect_region);
835    XSubtractRegion(image_region->visible_region, rect_region,
836                    image_region->visible_region);
837    XDestroyRegion(rect_region);
838}
839
840/** ------------------------------------------------------------------------
841	Adds the specified rectangle to the region in image_region.
842    ------------------------------------------------------------------------ **/
843static void
844add_rect_to_image_region(image_region_type *image_region,
845                         int x, int y, int width, int height)
846{
847    XRectangle rect;
848
849    rect.x = x;
850    rect.y = y;
851    rect.width = width;
852    rect.height = height;
853    XUnionRectWithRegion(&rect, image_region->visible_region,
854                         image_region->visible_region);
855}
856
857/** ------------------------------------------------------------------------
858	Returns TRUE if the given src's visual is already represented in
859	the image_regions list, FALSE otherwise.
860    ------------------------------------------------------------------------ **/
861static int
862src_in_region_list(image_win_type *src, list_ptr image_regions)
863{
864    image_region_type *ir;
865
866    for (ir = (image_region_type *) first_in_list(image_regions); ir;
867         ir = (image_region_type *) next_in_list(image_regions)) {
868        if (SAME_REGIONS(ir, src)) {
869
870            return 1;
871        }
872    }
873
874    return 0;
875}
876
877/** ------------------------------------------------------------------------
878	Makes a new entry in image_wins with the given fields filled in.
879    ------------------------------------------------------------------------ **/
880static void
881add_window_to_list(list_ptr image_wins, Window w,
882                   int xrr, int yrr, int x_vis, int y_vis,
883                   int width, int height, int border_width,
884                   Visual *vis, Colormap cmap, Window parent)
885{
886    image_win_type *new_src;
887
888    if ((new_src = malloc(sizeof(image_win_type))) == NULL)
889        return;
890
891    new_src->win = w;
892    new_src->x_rootrel = xrr;
893    new_src->y_rootrel = yrr;
894    new_src->x_vis = x_vis;
895    new_src->y_vis = y_vis;
896    new_src->width = width;
897    new_src->height = height;
898    new_src->border_width = border_width;
899    new_src->vis = vis;
900    new_src->cmap = cmap;
901    new_src->parent = parent;
902    add_to_list(image_wins, new_src);
903}
904
905/** ------------------------------------------------------------------------
906	Returns TRUE if the given src's visual is in the image planes,
907	FALSE otherwise.
908    ------------------------------------------------------------------------ **/
909static int
910src_in_image(image_win_type *src, int numImageVisuals,
911             XVisualInfo **pImageVisuals)
912{
913    int i;
914
915    for (i = 0; i < numImageVisuals; i++) {
916        if (pImageVisuals[i]->visual == src->vis)
917            return 1;
918    }
919    return 0;
920}
921
922
923/** ------------------------------------------------------------------------
924	Returns TRUE if the given src's visual is in the overlay planes
925	and transparency is possible, FALSE otherwise.
926    ------------------------------------------------------------------------ **/
927static int
928src_in_overlay(image_region_type *src, int numOverlayVisuals,
929               OverlayInfo *pOverlayVisuals,
930               int *transparentColor, int *transparentType)
931{
932    int i;
933
934    for (i = 0; i < numOverlayVisuals; i++) {
935        if (((pOverlayVisuals[i].pOverlayVisualInfo)->visual == src->vis)
936            && (pOverlayVisuals[i].transparentType != None)) {
937            *transparentColor = pOverlayVisuals[i].value;
938            *transparentType = pOverlayVisuals[i].transparentType;
939            return 1;
940        }
941    }
942    return 0;
943}
944
945
946/********************** from wsutils.c ******************************/
947
948/******************************************************************************
949 *
950 * This file contains a set of example utility procedures; procedures that can
951 * help a "window-smart" Starbase or PHIGS program determine information about
952 * a device, and create image and overlay plane windows.  To use these
953 * utilities, #include "wsutils.h" and compile this file and link the results
954 * with your program.
955 *
956 ******************************************************************************/
957
958
959static int weCreateServerOverlayVisualsProperty = False;
960
961
962/******************************************************************************
963 *
964 * GetXVisualInfo()
965 *
966 * This routine takes an X11 Display, screen number, and returns whether the
967 * screen supports transparent overlays and three arrays:
968 *
969 *	1) All of the XVisualInfo struct's for the screen.
970 *	2) All of the OverlayInfo struct's for the screen.
971 *	3) An array of pointers to the screen's image plane XVisualInfo
972 *	   structs.
973 *
974 * The code below obtains the array of all the screen's visuals, and obtains
975 * the array of all the screen's overlay visual information.  It then processes
976 * the array of the screen's visuals, determining whether the visual is an
977 * overlay or image visual.
978 *
979 * If the routine successfully obtained the visual information, it returns zero.
980 * If the routine didn't obtain the visual information, it returns non-zero.
981 *
982 ******************************************************************************/
983
984int
985GetXVisualInfo(   /* Which X server (aka "display"). */
986                  Display *display,
987                  /* Which screen of the "display". */
988                  int screen,
989                  /* Non-zero if there's at least one overlay visual and
990                   * if at least one of those supports a transparent pixel. */
991                  int *transparentOverlays,
992                  /* Number of XVisualInfo struct's pointed to by pVisuals. */
993                  int *numVisuals,
994                  /* All of the device's visuals. */
995                  XVisualInfo **pVisuals,
996                  /* Number of OverlayInfo's pointed to by pOverlayVisuals.
997                   * If this number is zero, the device does not have
998                   * overlay planes. */
999                  int *numOverlayVisuals,
1000                  /* The device's overlay plane visual information. */
1001                  OverlayInfo **pOverlayVisuals,
1002                  /* Number of XVisualInfo's pointed to by pImageVisuals. */
1003                  int *numImageVisuals,
1004                  /* The device's image visuals. */
1005                  XVisualInfo ***pImageVisuals)
1006{
1007    XVisualInfo getVisInfo;     /* Parameters of XGetVisualInfo */
1008    int mask;
1009    XVisualInfo *pVis, **pIVis; /* Faster, local copies */
1010    OverlayVisualPropertyRec *pOOldVis;
1011    int nVisuals;
1012    Atom overlayVisualsAtom;    /* Parameters for XGetWindowProperty */
1013    Atom actualType;
1014    unsigned long numLongs, bytesAfter;
1015    int actualFormat;
1016    int nImageVisualsAlloced;   /* Values to process the XVisualInfo */
1017
1018    /* First, get the list of visuals for this screen. */
1019    getVisInfo.screen = screen;
1020    mask = VisualScreenMask;
1021
1022    *pVisuals = XGetVisualInfo(display, mask, &getVisInfo, numVisuals);
1023    if ((nVisuals = *numVisuals) <= 0) {
1024        /* Return that the information wasn't successfully obtained: */
1025        return (1);
1026    }
1027    pVis = *pVisuals;
1028
1029    /* Now, get the overlay visual information for this screen.  To obtain
1030     * this information, get the SERVER_OVERLAY_VISUALS property.
1031     */
1032    overlayVisualsAtom = XInternAtom(display, "SERVER_OVERLAY_VISUALS", True);
1033    if (overlayVisualsAtom != None) {
1034        /* Since the Atom exists, we can request the property's contents.  The
1035         * do-while loop makes sure we get the entire list from the X server.
1036         */
1037        bytesAfter = 0;
1038        numLongs = sizeof(OverlayVisualPropertyRec) / sizeof(long);
1039        do {
1040            numLongs += bytesAfter * sizeof(long);
1041            XGetWindowProperty(display, RootWindow(display, screen),
1042                               overlayVisualsAtom, 0, numLongs, False,
1043                               overlayVisualsAtom, &actualType, &actualFormat,
1044                               &numLongs, &bytesAfter,
1045                               (unsigned char **) pOverlayVisuals);
1046        } while (bytesAfter > 0);
1047
1048        /* Calculate the number of overlay visuals in the list. */
1049        *numOverlayVisuals =
1050            numLongs / (sizeof(OverlayVisualPropertyRec) / sizeof(long));
1051    }
1052    else {
1053        /* This screen doesn't have overlay planes. */
1054        *numOverlayVisuals = 0;
1055        *pOverlayVisuals = NULL;
1056        *transparentOverlays = 0;
1057    }
1058
1059    /* Process the pVisuals array. */
1060    *numImageVisuals = 0;
1061    nImageVisualsAlloced = 1;
1062    pIVis = *pImageVisuals = malloc(sizeof(XVisualInfo *));
1063    while (--nVisuals >= 0) {
1064        int nOVisuals = *numOverlayVisuals;
1065        OverlayInfo *pOVis = *pOverlayVisuals;
1066        int imageVisual = True;
1067
1068        while (--nOVisuals >= 0) {
1069            pOOldVis = (OverlayVisualPropertyRec *) pOVis;
1070            if (pVis->visualid == pOOldVis->visualID) {
1071                imageVisual = False;
1072                pOVis->pOverlayVisualInfo = pVis;
1073                if (pOVis->transparentType == TransparentPixel)
1074                    *transparentOverlays = 1;
1075            }
1076            pOVis++;
1077        }
1078        if (imageVisual) {
1079            if ((*numImageVisuals += 1) > nImageVisualsAlloced) {
1080                nImageVisualsAlloced++;
1081                *pImageVisuals = (XVisualInfo **)
1082                    realloc(*pImageVisuals,
1083                            (nImageVisualsAlloced * sizeof(XVisualInfo *)));
1084                pIVis = *pImageVisuals + (*numImageVisuals - 1);
1085            }
1086            *pIVis++ = pVis;
1087        }
1088        pVis++;
1089    }
1090
1091    /* Return that the information was successfully obtained: */
1092    return (0);
1093
1094}                               /* GetXVisualInfo() */
1095
1096/******************************************************************************
1097 *
1098 * FreeXVisualInfo()
1099 *
1100 * This routine frees the data that was allocated by GetXVisualInfo().
1101 *
1102 ******************************************************************************/
1103
1104void
1105FreeXVisualInfo(XVisualInfo *pVisuals, OverlayInfo *pOverlayVisuals,
1106                XVisualInfo **pImageVisuals)
1107{
1108    XFree(pVisuals);
1109    if (weCreateServerOverlayVisualsProperty)
1110        free(pOverlayVisuals);
1111    else
1112        XFree(pOverlayVisuals);
1113    free(pImageVisuals);
1114
1115}                               /* FreeXVisualInfo() */
1116