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