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