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