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