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