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