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