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