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
39Copyright 1994 Hewlett-Packard Co.
40Copyright 1996, 1998 The Open Group
41
42Permission to use, copy, modify, distribute, and sell this software and its
43documentation for any purpose is hereby granted without fee, provided that
44the above copyright notice appear in all copies and that both that
45copyright notice and this permission notice appear in supporting
46documentation.
47
48The above copyright notice and this permission notice shall be included
49in all copies or substantial portions of the Software.
50
51THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
52OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
53MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
54IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
55OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
56ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
57OTHER DEALINGS IN THE SOFTWARE.
58
59Except as contained in this notice, the name of The Open Group shall
60not be used in advertising or otherwise to promote the sale, use or
61other dealings in this Software without prior written authorization
62from 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 */
77typedef struct {
78 short x1, x2, y1, y2;
79} myBox, myBOX, myBoxRec, *myBoxPtr;
80
81typedef 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 */
89typedef 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*/
103typedef 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/*
136extern list_ptr new_list();
137extern list_ptr dup_list_head();
138extern void * first_in_list();
139extern void * next_in_list();
140extern int add_to_list();
141extern void zero_list();
142extern void delete_list();
143extern void delete_list_destroying();
144extern unsigned int list_length();
145*/
146
147/* Prototype Declarations for Static Functions */
148static void QueryColorMap(
149 Display *, Colormap , Visual *,
150 XColor **, int *, int *, int *
151 );
152static void TransferImage(
153 Display *, XImage *,int, int , image_region_type*,
154 XImage *,int ,int
155 );
156static XImage * ReadRegionsInList(
157 Display *, Visual *, int, int, unsigned int,
158 unsigned int, XRectangle, list_ptr
159 );
160
161static list_ptr make_region_list(
162 Display*, Window, XRectangle*,
163 int*, int, XVisualInfo**, int *
164 );
165
166static void destroy_region_list(
167 list_ptr
168 ) ;
169static void subtr_rect_from_image_region(
170 image_region_type *, int , int , int , int
171 );
172static void add_rect_to_image_region(
173 image_region_type *,
174 int , int , int , int
175 );
176static int src_in_region_list(
177 image_win_type *, list_ptr
178 );
179static void add_window_to_list(
180 list_ptr, Window, int, int ,
181 int , int , int , int, int,
182 Visual*, Colormap, Window
183 );
184static int src_in_image(
185 image_win_type *, int , XVisualInfo**
186 );
187static int src_in_overlay(
188 image_region_type *, int, OverlayInfo *, int*, int*
189 );
190static void make_src_list(
191 Display *, list_ptr, XRectangle *, Window,
192 int, int, XWindowAttributes *, XRectangle *
193);
194static void destroy_image_region(
195 image_region_type *
196);
197
198/* End of Prototype Declarations */
199
200void 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
211static void
212QueryColorMap(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
268int
269GetMultiVisualRegions(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
322static 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
417static XImage *
418ReadRegionsInList(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
488XImage *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 ------------------------------------------------------------------------ **/
680static 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 ------------------------------------------------------------------------ **/
774static 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 ------------------------------------------------------------------------ **/
871static 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 ------------------------------------------------------------------------ **/
880static 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 ------------------------------------------------------------------------ **/
892static 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 ------------------------------------------------------------------------ **/
913static 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 ------------------------------------------------------------------------ **/
931static 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 ------------------------------------------------------------------------ **/
950static 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 ------------------------------------------------------------------------ **/
979static 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 ------------------------------------------------------------------------ **/
997static 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
1042static 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
1067int 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
1199void 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() */
1210