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