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