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