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