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