1b3307321Smrg/** ------------------------------------------------------------------------
2b3307321Smrg	This file contains functions to create a list of regions which
374a3f230Smrg	tile a specified window.  Each region contains all visible
4b3307321Smrg	portions of the window which are drawn with the same visual.
5b3307321Smrg	If the window consists of subwindows of two different visual types,
6b3307321Smrg	there will be two regions in the list.  The list can be traversed
7b3307321Smrg	to correctly pull an image of the window using XGetImage or the
8b3307321Smrg	Image Library.
9b3307321Smrg
10b3307321SmrgCopyright 1994 Hewlett-Packard Co.
11b3307321SmrgCopyright 1996, 1998  The Open Group
12b3307321Smrg
13b3307321SmrgPermission to use, copy, modify, distribute, and sell this software and its
14b3307321Smrgdocumentation for any purpose is hereby granted without fee, provided that
15b3307321Smrgthe above copyright notice appear in all copies and that both that
16b3307321Smrgcopyright notice and this permission notice appear in supporting
17b3307321Smrgdocumentation.
18b3307321Smrg
19b3307321SmrgThe above copyright notice and this permission notice shall be included
20b3307321Smrgin all copies or substantial portions of the Software.
21b3307321Smrg
22b3307321SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23b3307321SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24b3307321SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25b3307321SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
26b3307321SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27b3307321SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28b3307321SmrgOTHER DEALINGS IN THE SOFTWARE.
29b3307321Smrg
30b3307321SmrgExcept as contained in this notice, the name of The Open Group shall
31b3307321Smrgnot be used in advertising or otherwise to promote the sale, use or
32b3307321Smrgother dealings in this Software without prior written authorization
33b3307321Smrgfrom The Open Group.
34b3307321Smrg
35b3307321Smrg    ------------------------------------------------------------------------ **/
36b3307321Smrg
3774b97a6cSmrg#include <stdio.h>
38b3307321Smrg#include <stdlib.h>
3974b97a6cSmrg#include <string.h>
40b3307321Smrg#include <X11/Xlib.h>
41b3307321Smrg#include <X11/Xutil.h>
42b3307321Smrg#include <X11/X.h>
43b3307321Smrg#include "list.h"
44b3307321Smrg#include "wsutils.h"
45b3307321Smrg#include "multiVis.h"
46b3307321Smrg/* These structures are copied from X11/region.h.  For some reason
47b3307321Smrg * they're invisible from the outside.
48b3307321Smrg */
49b3307321Smrgtypedef struct {
50b3307321Smrg    short x1, x2, y1, y2;
51b3307321Smrg} myBox, myBOX, myBoxRec, *myBoxPtr;
52b3307321Smrg
53b3307321Smrgtypedef struct my_XRegion {
54b3307321Smrg    long size;
55b3307321Smrg    long numRects;
56b3307321Smrg    myBOX *rects;
57b3307321Smrg    myBOX extents;
58b3307321Smrg} myREGION;
59b3307321Smrg
60b3307321Smrg/* Items in long list of windows that have some part in the grabbed area */
61b3307321Smrgtypedef struct {
62b3307321Smrg    Window win;
63b3307321Smrg    Visual *vis;
64b3307321Smrg    Colormap cmap;
6574b97a6cSmrg    int x_rootrel, y_rootrel;   /* root relative location of window */
6674b97a6cSmrg    int x_vis, y_vis;           /* rt rel x,y of vis part, not parent clipped */
6774b97a6cSmrg    int width, height;          /* width and height of visible part */
6874b97a6cSmrg    int border_width;           /* border width of the window */
6974b97a6cSmrg    Window parent;              /* id of parent (for debugging) */
70b3307321Smrg} image_win_type;
71b3307321Smrg
7274a3f230Smrg/*  Items in short list of regions that tile the grabbed area.  May have
73b3307321Smrg    multiple windows in the region.
74b3307321Smrg*/
75b3307321Smrgtypedef struct {
7674b97a6cSmrg    Window win;                 /* lowest window of this visual */
77b3307321Smrg    Visual *vis;
78b3307321Smrg    Colormap cmap;
7974b97a6cSmrg    int x_rootrel, y_rootrel;   /* root relative location of bottom window */
8074b97a6cSmrg    int x_vis, y_vis;           /* rt rel x,y of vis part, not parent clipped */
8174b97a6cSmrg    int width, height;          /* w & h of visible rect of bottom window */
8274b97a6cSmrg    int border;                 /* border width of the window */
83b3307321Smrg    Region visible_region;
84b3307321Smrg} image_region_type;
85b3307321Smrg
86b3307321Smrg/** ------------------------------------------------------------------------
8774a3f230Smrg	Returns TRUE if the two structs pointed to have the same "vis" &
88b3307321Smrg	"cmap" fields and s2 lies completely within s1.  s1 and s2 can
89b3307321Smrg	point to structs of image_win_type or image_region_type.
90b3307321Smrg    ------------------------------------------------------------------------ **/
91b3307321Smrg#define SAME_REGIONS( s1, s2)	\
92b3307321Smrg	((s1)->vis == (s2)->vis && (s1)->cmap == (s2)->cmap &&   	\
93b3307321Smrg	 (s1)->x_vis <= (s2)->x_vis &&				    \
94b3307321Smrg	 (s1)->y_vis <= (s2)->y_vis &&				    \
95b3307321Smrg	 (s1)->x_vis + (s1)->width  >= (s2)->x_vis + (s2)->width && \
96b3307321Smrg	 (s1)->y_vis + (s1)->height >= (s2)->y_vis + (s2)->height)
97b3307321Smrg
98b3307321Smrg#ifndef MIN
99b3307321Smrg#define MIN( a, b)	((a) < (b) ? a : b)
100b3307321Smrg#define MAX( a, b)	((a) > (b) ? a : b)
101b3307321Smrg#endif
102b3307321Smrg
103b3307321Smrg#define	RED_SHIFT        16
104b3307321Smrg#define GREEN_SHIFT       8
105b3307321Smrg#define BLUE_SHIFT        0
106b3307321Smrg
107b3307321Smrg/* Prototype Declarations for Static Functions */
10874b97a6cSmrgstatic void QueryColorMap(Display *, Colormap, Visual *,
10974b97a6cSmrg                          XColor **, int *, int *, int *);
11074b97a6cSmrgstatic void TransferImage(Display *, XImage *, int, int, image_region_type *,
11174b97a6cSmrg                          XImage *, int, int);
11274b97a6cSmrgstatic XImage *ReadRegionsInList(Display *, Visual *, int, int, unsigned int,
11374b97a6cSmrg                                 unsigned int, XRectangle, list_ptr);
11474b97a6cSmrg
11574b97a6cSmrgstatic list_ptr make_region_list(Display *, Window, XRectangle *,
11674b97a6cSmrg                                 int *, int, XVisualInfo **, int *);
11774b97a6cSmrgstatic void destroy_region_list(list_ptr);
11874b97a6cSmrgstatic void subtr_rect_from_image_region(image_region_type *,
11974b97a6cSmrg                                         int, int, int, int);
12074b97a6cSmrgstatic void add_rect_to_image_region(image_region_type *,
12174b97a6cSmrg                                     int, int, int, int);
12274b97a6cSmrgstatic int src_in_region_list(image_win_type *, list_ptr);
12374b97a6cSmrgstatic void add_window_to_list(list_ptr, Window, int, int,
12474b97a6cSmrg                               int, int, int, int, int,
12574b97a6cSmrg                               Visual *, Colormap, Window);
12674b97a6cSmrgstatic int src_in_image(image_win_type *, int, XVisualInfo **);
12774b97a6cSmrgstatic int src_in_overlay(image_region_type *, int, OverlayInfo *, int *,
12874b97a6cSmrg                          int *);
12974b97a6cSmrgstatic void make_src_list(Display *, list_ptr, XRectangle *, Window, int, int,
13074b97a6cSmrg                          XWindowAttributes *, XRectangle *);
13174b97a6cSmrgstatic void destroy_image_region(image_region_type *);
132b3307321Smrg
133b3307321Smrg/* End of Prototype Declarations */
134b3307321Smrg
13574b97a6cSmrgvoid
13674b97a6cSmrginitFakeVisual(Visual *Vis)
137b3307321Smrg{
13874b97a6cSmrg    Vis->ext_data = NULL;
13974b97a6cSmrg    Vis->class = DirectColor;
14074b97a6cSmrg    Vis->red_mask = 0x00FF0000;
14174b97a6cSmrg    Vis->green_mask = 0x0000FF00;
14274b97a6cSmrg    Vis->blue_mask = 0x000000FF;
14374b97a6cSmrg    Vis->map_entries = 256;
14474b97a6cSmrg    Vis->bits_per_rgb = 8;
145b3307321Smrg}
146b3307321Smrg
14774a3f230Smrgstatic void
1485e358ecaSmrgQueryColorMap(Display *disp, Colormap src_cmap, Visual *src_vis,
14974b97a6cSmrg              XColor **src_colors, int *rShift, int *gShift, int *bShift)
150b3307321Smrg{
1516728f30eSmrg    unsigned int ncolors;
15274b97a6cSmrg    XColor *colors;
15374b97a6cSmrg
15474b97a6cSmrg    ncolors = (unsigned) src_vis->map_entries;
15574b97a6cSmrg    *src_colors = colors = calloc(ncolors, sizeof(XColor));
15674b97a6cSmrg
15774b97a6cSmrg    if (src_vis->class != TrueColor && src_vis->class != DirectColor) {
1586728f30eSmrg        for (unsigned int i = 0; i < ncolors; i++) {
15974b97a6cSmrg            colors[i].pixel = i;
16074b97a6cSmrg            colors[i].pad = 0;
16174b97a6cSmrg            colors[i].flags = DoRed | DoGreen | DoBlue;
16274b97a6cSmrg        }
16374b97a6cSmrg    }
16474b97a6cSmrg    else { /** src is decomposed rgb ***/
1656728f30eSmrg        unsigned long redMask, greenMask, blueMask;
1666728f30eSmrg        int redShift, greenShift, blueShift;
16774b97a6cSmrg
168b3307321Smrg        /* Get the X colormap */
169b3307321Smrg        redMask = src_vis->red_mask;
170b3307321Smrg        greenMask = src_vis->green_mask;
171b3307321Smrg        blueMask = src_vis->blue_mask;
17274b97a6cSmrg        redShift = 0;
17374b97a6cSmrg        while (!(redMask & 0x1)) {
17474b97a6cSmrg            redShift++;
17574b97a6cSmrg            redMask = redMask >> 1;
176b3307321Smrg        }
17774b97a6cSmrg        greenShift = 0;
17874b97a6cSmrg        while (!(greenMask & 0x1)) {
17974b97a6cSmrg            greenShift++;
18074b97a6cSmrg            greenMask = greenMask >> 1;
181b3307321Smrg        }
18274b97a6cSmrg        blueShift = 0;
18374b97a6cSmrg        while (!(blueMask & 0x1)) {
18474b97a6cSmrg            blueShift++;
18574b97a6cSmrg            blueMask = blueMask >> 1;
186b3307321Smrg        }
18774b97a6cSmrg        *rShift = redShift;
18874b97a6cSmrg        *gShift = greenShift;
18974b97a6cSmrg        *bShift = blueShift;
1906728f30eSmrg        for (unsigned int i = 0; i < ncolors; i++) {
19174b97a6cSmrg            if (i <= redMask)
19274b97a6cSmrg                colors[i].pixel = (i << redShift);
19374b97a6cSmrg            if (i <= greenMask)
19474b97a6cSmrg                colors[i].pixel |= (i << greenShift);
19574b97a6cSmrg            if (i <= blueMask)
19674b97a6cSmrg                colors[i].pixel |= (i << blueShift);
19774b97a6cSmrg            /***** example: for gecko's 3-3-2 map, blue index should be <= 3.
198b3307321Smrg                colors[i].pixel = (i<<redShift)|(i<<greenShift)|(i<<blueShift);
19974b97a6cSmrg             *****/
20074b97a6cSmrg            colors[i].pad = 0;
20174b97a6cSmrg            colors[i].flags = DoRed | DoGreen | DoBlue;
202b3307321Smrg        }
20374b97a6cSmrg    }
204b3307321Smrg
20574b97a6cSmrg    XQueryColors(disp, src_cmap, colors, (int) ncolors);
206b3307321Smrg}
207b3307321Smrg
208b3307321Smrgint
2095e358ecaSmrgGetMultiVisualRegions(Display *disp,
21074b97a6cSmrg                      /* root win on which grab was done */
21174b97a6cSmrg                      Window srcRootWinid,
21274b97a6cSmrg                      /* root rel UL corner of bounding box of grab */
21374b97a6cSmrg                      int x, int y,
21474b97a6cSmrg                      /* size of bounding box of grab */
21574b97a6cSmrg                      unsigned int width, unsigned int height,
21674b97a6cSmrg                      int *transparentOverlays, int *numVisuals,
21774b97a6cSmrg                      XVisualInfo **pVisuals, int *numOverlayVisuals,
21874b97a6cSmrg                      OverlayInfo **pOverlayVisuals,
21974b97a6cSmrg                      int *numImageVisuals, XVisualInfo ***pImageVisuals,
22074b97a6cSmrg                      /* list of regions to read from */
22174b97a6cSmrg                      list_ptr *vis_regions,
22274b97a6cSmrg                      list_ptr *vis_image_regions, int *allImage)
223b3307321Smrg{
22474b97a6cSmrg    int hasNonDefault;
22574b97a6cSmrg    XRectangle bbox;            /* bounding box of grabbed area */
226b3307321Smrg
227b3307321Smrg    bbox.x = x;                 /* init X rect for bounding box */
228b3307321Smrg    bbox.y = y;
229b3307321Smrg    bbox.width = width;
230b3307321Smrg    bbox.height = height;
231b3307321Smrg
23274b97a6cSmrg    GetXVisualInfo(disp, DefaultScreen(disp),
23374b97a6cSmrg                   transparentOverlays,
23474b97a6cSmrg                   numVisuals, pVisuals,
23574b97a6cSmrg                   numOverlayVisuals, pOverlayVisuals,
23674b97a6cSmrg                   numImageVisuals, pImageVisuals);
237b3307321Smrg
23874b97a6cSmrg    *vis_regions = *vis_image_regions = NULL;
23974b97a6cSmrg    if ((*vis_regions = make_region_list(disp, srcRootWinid, &bbox,
240b3307321Smrg                                         &hasNonDefault, *numImageVisuals,
24174a3f230Smrg                                         *pImageVisuals, allImage)) == NULL)
24274b97a6cSmrg        return 0;
24374a3f230Smrg
24474b97a6cSmrg    if (*transparentOverlays) {
24574b97a6cSmrg        *allImage = 1;        /* until proven otherwise,
24674b97a6cSmrg                                 this flags that it to be an image only list */
247b3307321Smrg        *vis_image_regions =
24874b97a6cSmrg            make_region_list(disp, srcRootWinid, &bbox, &hasNonDefault,
24974b97a6cSmrg                             *numImageVisuals, *pImageVisuals, allImage);
250b3307321Smrg    }
251b3307321Smrg
25274b97a6cSmrg    /* if there is a second region in any of the two lists return 1 */
25374b97a6cSmrg    if ((*vis_regions && (*vis_regions)->next && (*vis_regions)->next->next) ||
25474b97a6cSmrg        (*vis_image_regions && (*vis_image_regions)->next &&
25574b97a6cSmrg         (*vis_image_regions)->next->next))
25674b97a6cSmrg        return 1;
25774b97a6cSmrg    else
25874b97a6cSmrg        return 0;
259b3307321Smrg
260b3307321Smrg}
261b3307321Smrg
26274b97a6cSmrgstatic void
26374b97a6cSmrgTransferImage(Display *disp, XImage *reg_image,
26474b97a6cSmrg              int srcw, int srch,
26574b97a6cSmrg              image_region_type *reg, XImage *target_image,
26674b97a6cSmrg              int dst_x, int dst_y)
267b3307321Smrg{
268b3307321Smrg    XColor *colors;
26974a3f230Smrg    int rShift = 0, gShift = 0, bShift = 0;
270b3307321Smrg
27174b97a6cSmrg    QueryColorMap(disp, reg->cmap, reg->vis, &colors,
27274b97a6cSmrg                  &rShift, &gShift, &bShift);
273b3307321Smrg
274b3307321Smrg    switch (reg->vis->class) {
27574b97a6cSmrg    case TrueColor:
2766728f30eSmrg        for (int i = 0; i < srch; i++) {
2776728f30eSmrg            for (int j = 0; j < srcw; j++) {
2786728f30eSmrg                int old_pixel = XGetPixel(reg_image, j, i);
2796728f30eSmrg                int new_pixel;
28074b97a6cSmrg
28174b97a6cSmrg                if (reg->vis->map_entries == 16) {
2826728f30eSmrg                    int red_ind = (old_pixel & reg->vis->red_mask) >> rShift;
2836728f30eSmrg                    int green_ind = (old_pixel & reg->vis->green_mask) >> gShift;
2846728f30eSmrg                    int blue_ind = (old_pixel & reg->vis->blue_mask) >> bShift;
28574b97a6cSmrg
28674b97a6cSmrg                    new_pixel = (
28774b97a6cSmrg                        ((colors[red_ind].red >> 8) << RED_SHIFT) |
28874b97a6cSmrg                        ((colors[green_ind].green >> 8) << GREEN_SHIFT) |
28974b97a6cSmrg                        ((colors[blue_ind].blue >> 8) << BLUE_SHIFT)
29074b97a6cSmrg                        );
29174b97a6cSmrg                }
29274b97a6cSmrg                else
29374b97a6cSmrg                    new_pixel = old_pixel;
29474b97a6cSmrg
29574b97a6cSmrg                XPutPixel(target_image, dst_x + j, dst_y + i, new_pixel);
29674b97a6cSmrg
29774b97a6cSmrg            }
29874b97a6cSmrg        }
29974b97a6cSmrg        break;
30074b97a6cSmrg    case DirectColor:
3016728f30eSmrg        for (int i = 0; i < srch; i++) {
30274b97a6cSmrg
3036728f30eSmrg            for (int j = 0; j < srcw; j++) {
3046728f30eSmrg                int old_pixel = XGetPixel(reg_image, j, i);
3056728f30eSmrg                int red_ind = (old_pixel & reg->vis->red_mask) >> rShift;
3066728f30eSmrg                int green_ind = (old_pixel & reg->vis->green_mask) >> gShift;
3076728f30eSmrg                int blue_ind = (old_pixel & reg->vis->blue_mask) >> bShift;
30874b97a6cSmrg
3096728f30eSmrg                int new_pixel = (
31074b97a6cSmrg                    ((colors[red_ind].red >> 8) << RED_SHIFT) |
31174b97a6cSmrg                    ((colors[green_ind].green >> 8) << GREEN_SHIFT) |
31274b97a6cSmrg                    ((colors[blue_ind].blue >> 8) << BLUE_SHIFT)
31374b97a6cSmrg                    );
31474b97a6cSmrg                XPutPixel(target_image, dst_x + j, dst_y + i, new_pixel);
31574b97a6cSmrg
31674b97a6cSmrg            }
31774b97a6cSmrg        }
31874b97a6cSmrg        break;
31974b97a6cSmrg    default:
3206728f30eSmrg        for (int i = 0; i < srch; i++) {
3216728f30eSmrg            for (int j = 0; j < srcw; j++) {
3226728f30eSmrg                int old_pixel = XGetPixel(reg_image, j, i);
32374b97a6cSmrg
3246728f30eSmrg                int new_pixel = (
32574b97a6cSmrg                    ((colors[old_pixel].red >> 8) << RED_SHIFT) |
32674b97a6cSmrg                    ((colors[old_pixel].green >> 8) << GREEN_SHIFT) |
32774b97a6cSmrg                    ((colors[old_pixel].blue >> 8) << BLUE_SHIFT)
32874b97a6cSmrg                    );
32974b97a6cSmrg                XPutPixel(target_image, dst_x + j, dst_y + i, new_pixel);
33074b97a6cSmrg
33174b97a6cSmrg            }
33274b97a6cSmrg        }
33374b97a6cSmrg        break;
334b3307321Smrg    }
335b3307321Smrg}
336b3307321Smrg
337b3307321Smrgstatic XImage *
3385e358ecaSmrgReadRegionsInList(Display *disp, Visual *fakeVis, int depth, int format,
33974b97a6cSmrg                  unsigned int width, unsigned int height,
34074b97a6cSmrg                  XRectangle bbox,    /* bounding box of grabbed area */
34174b97a6cSmrg                  list_ptr regions)   /* list of regions to read from */
342b3307321Smrg{
3436728f30eSmrg    int datalen;
344b3307321Smrg
34574b97a6cSmrg    XImage *reg_image, *ximage;
34674b97a6cSmrg    int bytes_per_line;
34774a3f230Smrg
34874b97a6cSmrg    ximage = XCreateImage(disp, fakeVis, depth, format, 0, NULL, width, height,
34974b97a6cSmrg                          8, 0);
350b3307321Smrg    bytes_per_line = ximage->bytes_per_line;
351b3307321Smrg
35274b97a6cSmrg    datalen = height * bytes_per_line;
35374b97a6cSmrg    if (format != ZPixmap)
35474b97a6cSmrg        datalen *= depth;
35574b97a6cSmrg    ximage->data = malloc(datalen);
35674b97a6cSmrg    memset(ximage->data, 0, datalen);
357b3307321Smrg
358b3307321Smrg    ximage->bits_per_pixel = depth; /** Valid only if format is ZPixmap ***/
35974a3f230Smrg
3606728f30eSmrg    for (image_region_type *reg = (image_region_type *) first_in_list(regions);
3616728f30eSmrg         reg; reg = (image_region_type *) next_in_list(regions)) {
3626728f30eSmrg
3636728f30eSmrg        struct my_XRegion *vis_reg = (struct my_XRegion *) (reg->visible_region);
36474b97a6cSmrg
3656728f30eSmrg        for (int rect = 0; rect < vis_reg->numRects; rect++) {
36674b97a6cSmrg/** ------------------------------------------------------------------------
36774b97a6cSmrg	Intersect bbox with visible part of region giving src rect & output
36874b97a6cSmrg	location.  Width is the min right side minus the max left side.
36974b97a6cSmrg	Similar for height.  Offset src rect so x,y are relative to
37074b97a6cSmrg	origin of win, not the root-relative visible rect of win.
37174b97a6cSmrg ------------------------------------------------------------------------ **/
3726728f30eSmrg            int srcRect_width =
37374b97a6cSmrg                MIN(vis_reg->rects[rect].x2, bbox.width + bbox.x) -
37474b97a6cSmrg                MAX(vis_reg->rects[rect].x1, bbox.x);
3756728f30eSmrg            int srcRect_height =
37674b97a6cSmrg                MIN(vis_reg->rects[rect].y2, bbox.height + bbox.y) -
37774b97a6cSmrg                MAX(vis_reg->rects[rect].y1, bbox.y);
3786728f30eSmrg            int srcRect_x, srcRect_y;
3796728f30eSmrg            int dst_x, dst_y;           /* where in pixmap to write (UL) */
38074b97a6cSmrg
3816728f30eSmrg            int diff = bbox.x - vis_reg->rects[rect].x1;
38274b97a6cSmrg            srcRect_x = MAX(0,diff) +
38374b97a6cSmrg                (vis_reg->rects[rect].x1 - reg->x_rootrel - reg->border);
38474b97a6cSmrg            dst_x = MAX(0, -diff);
38574b97a6cSmrg
38674b97a6cSmrg            diff = bbox.y - vis_reg->rects[rect].y1;
38774b97a6cSmrg            srcRect_y = MAX(0, diff) +
38874b97a6cSmrg                (vis_reg->rects[rect].y1 - reg->y_rootrel - reg->border);
38974b97a6cSmrg            dst_y = MAX(0, -diff);
39074b97a6cSmrg
39174b97a6cSmrg            reg_image = XGetImage(disp, reg->win, srcRect_x, srcRect_y,
39274b97a6cSmrg                                  srcRect_width, srcRect_height, AllPlanes,
39374b97a6cSmrg                                  format);
39474b97a6cSmrg            TransferImage(disp, reg_image, srcRect_width, srcRect_height, reg,
39574b97a6cSmrg                          ximage, dst_x, dst_y);
39674b97a6cSmrg        }
397b3307321Smrg    }
39874b97a6cSmrg    return ximage;
399b3307321Smrg}
400b3307321Smrg
401b3307321Smrg
402b3307321Smrg/** ------------------------------------------------------------------------
403b3307321Smrg    ------------------------------------------------------------------------ **/
404b3307321Smrg
40574b97a6cSmrgXImage *
40674b97a6cSmrgReadAreaToImage(Display *disp,
40774b97a6cSmrg                /* root win on which grab was done */
40874b97a6cSmrg                Window srcRootWinid,
40974b97a6cSmrg                /* root rel UL corner of bounding box of grab */
41074b97a6cSmrg                int x, int y,
41174b97a6cSmrg                /* size of bounding box of grab */
41274b97a6cSmrg                unsigned int width, unsigned int height,
41374b97a6cSmrg                int numVisuals, XVisualInfo *pVisuals,
41474b97a6cSmrg                int numOverlayVisuals, OverlayInfo *pOverlayVisuals,
41574b97a6cSmrg                int numImageVisuals, XVisualInfo **pImageVisuals,
41674b97a6cSmrg                /* list of regions to read from */
41774b97a6cSmrg                list_ptr vis_regions,
41874b97a6cSmrg                /* list of regions to read from */
41974b97a6cSmrg                list_ptr vis_image_regions,
42074b97a6cSmrg                int format, int allImage)
421b3307321Smrg{
42274b97a6cSmrg    image_region_type *reg;
42374b97a6cSmrg    XRectangle bbox;            /* bounding box of grabbed area */
42474b97a6cSmrg    int depth;
42574b97a6cSmrg    XImage *ximage, *ximage_ipm = NULL;
42674b97a6cSmrg    Visual fakeVis;
42774b97a6cSmrg    XImage *image;
42874b97a6cSmrg
429b3307321Smrg#if 0
43074b97a6cSmrg    unsigned char *pmData, *ipmData;
431b3307321Smrg#endif
43274b97a6cSmrg    int transparentColor, transparentType;
433b3307321Smrg
43474b97a6cSmrg    bbox.x = x;                 /* init X rect for bounding box */
435b3307321Smrg    bbox.y = y;
436b3307321Smrg    bbox.width = width;
437b3307321Smrg    bbox.height = height;
438b3307321Smrg
43974b97a6cSmrg    initFakeVisual(&fakeVis);
440b3307321Smrg
44174b97a6cSmrg    depth = 24;
44274b97a6cSmrg    ximage = ReadRegionsInList(disp, &fakeVis, depth, format, width, height,
44374b97a6cSmrg                               bbox, vis_regions);
444b3307321Smrg#if 0
44574b97a6cSmrg    pmData = (unsigned char *) ximage->data;
446b3307321Smrg#endif
447b3307321Smrg
448b3307321Smrg/* if transparency possible do it again, but this time for image planes only */
44974b97a6cSmrg    if (vis_image_regions && (vis_image_regions->next) && !allImage) {
45074b97a6cSmrg        ximage_ipm =
45174b97a6cSmrg            ReadRegionsInList(disp, &fakeVis, depth, format, width, height,
45274b97a6cSmrg                              bbox, vis_image_regions);
453b3307321Smrg#if 0
45474b97a6cSmrg        ipmData = (unsigned char *) ximage_ipm->data;
455b3307321Smrg#endif
456b3307321Smrg    }
457b3307321Smrg/* Now tranverse the overlay visual windows and test for transparency index.  */
4586728f30eSmrg/* If you find one, substitute the value from the matching image plane pixmap. */
459b3307321Smrg
46074b97a6cSmrg    for (reg = (image_region_type *) first_in_list(vis_regions); reg;
46174b97a6cSmrg         reg = (image_region_type *) next_in_list(vis_regions)) {
46274b97a6cSmrg
46374b97a6cSmrg        if (src_in_overlay(reg, numOverlayVisuals, pOverlayVisuals,
46474b97a6cSmrg                           &transparentColor, &transparentType)) {
4656728f30eSmrg            int srcRect_x, srcRect_y, srcRect_width, srcRect_height;
4666728f30eSmrg            int diff;
4676728f30eSmrg            int dst_x, dst_y;           /* where in pixmap to write (UL) */
46874b97a6cSmrg            int test = 0;
46974b97a6cSmrg
47074b97a6cSmrg            srcRect_width =
47174b97a6cSmrg                MIN(reg->width + reg->x_vis, bbox.width + bbox.x)
47274b97a6cSmrg                - MAX(reg->x_vis, bbox.x);
47374b97a6cSmrg            srcRect_height =
47474b97a6cSmrg                MIN(reg->height + reg->y_vis, bbox.height + bbox.y)
47574b97a6cSmrg                - MAX(reg->y_vis, bbox.y);
47674b97a6cSmrg            diff = bbox.x - reg->x_vis;
47774b97a6cSmrg            srcRect_x =
47874b97a6cSmrg                MAX(0, diff) + (reg->x_vis - reg->x_rootrel - reg->border);
47974b97a6cSmrg            dst_x = MAX(0, -diff);
48074b97a6cSmrg            diff = bbox.y - reg->y_vis;
48174b97a6cSmrg            srcRect_y =
48274b97a6cSmrg                MAX(0, diff) + (reg->y_vis - reg->y_rootrel - reg->border);
48374b97a6cSmrg            dst_y = MAX(0, -diff);
48474b97a6cSmrg            /* let's test some pixels for transparency */
48574b97a6cSmrg            image = XGetImage(disp, reg->win, srcRect_x, srcRect_y,
48674b97a6cSmrg                              srcRect_width, srcRect_height, 0xffffffff,
48774b97a6cSmrg                              ZPixmap);
48874b97a6cSmrg
48974b97a6cSmrg            /* let's assume byte per pixel for overlay image for now */
49074b97a6cSmrg            if ((image->depth == 8) && (transparentType == TransparentPixel)) {
49174b97a6cSmrg                unsigned char *pixel_ptr;
49274b97a6cSmrg                unsigned char *start_of_line = (unsigned char *) image->data;
49374b97a6cSmrg
4946728f30eSmrg                for (int y1 = 0; y1 < srcRect_height; y1++) {
49574b97a6cSmrg                    pixel_ptr = start_of_line;
4966728f30eSmrg                    for (int x1 = 0; x1 < srcRect_width; x1++) {
49774b97a6cSmrg                        if (*pixel_ptr++ == transparentColor) {
4986728f30eSmrg                            int pixel;
499b3307321Smrg#if 0
50074b97a6cSmrg                            *pmData++ = *ipmData++;
50174b97a6cSmrg                            *pmData++ = *ipmData++;
50274b97a6cSmrg                            *pmData++ = *ipmData++;
503b3307321Smrg#endif
50474b97a6cSmrg                            pixel =
50574b97a6cSmrg                                XGetPixel(ximage_ipm, dst_x + x1, dst_y + y1);
50674b97a6cSmrg                            XPutPixel(ximage, dst_x + x1, dst_y + y1, pixel);
50774b97a6cSmrg
50874b97a6cSmrg                            if (!test) {
50974b97a6cSmrg                                test = 1;
51074b97a6cSmrg                            }
51174b97a6cSmrg                        }
512b3307321Smrg#if 0
51374b97a6cSmrg                        else {
51474b97a6cSmrg                            pmData += 3;
51574b97a6cSmrg                            ipmData += 3;
51674b97a6cSmrg                        }
517b3307321Smrg#endif
51874b97a6cSmrg                    }
51974b97a6cSmrg                    start_of_line += image->bytes_per_line;
52074b97a6cSmrg                }
52174b97a6cSmrg            }
52274b97a6cSmrg            else {
52374b97a6cSmrg                if (transparentType == TransparentPixel) {
5246728f30eSmrg                    for (int y1 = 0; y1 < srcRect_height; y1++) {
5256728f30eSmrg                        for (int x1 = 0; x1 < srcRect_width; x1++) {
52674b97a6cSmrg                            int pixel_value = XGetPixel(image, x1, y1);
52774b97a6cSmrg
52874b97a6cSmrg                            if (pixel_value == transparentColor) {
5296728f30eSmrg                                int pixel;
530b3307321Smrg#if 0
53174b97a6cSmrg                                *pmData++ = *ipmData++;
53274b97a6cSmrg                                *pmData++ = *ipmData++;
53374b97a6cSmrg                                *pmData++ = *ipmData++;
534b3307321Smrg#endif
53574b97a6cSmrg                                pixel =
53674b97a6cSmrg                                    XGetPixel(ximage_ipm, dst_x + x1,
53774b97a6cSmrg                                              dst_y + y1);
53874b97a6cSmrg                                XPutPixel(ximage, dst_x + x1, dst_y + y1,
53974b97a6cSmrg                                          pixel);
54074b97a6cSmrg                                if (!test) {
54174b97a6cSmrg                                    test = 1;
54274b97a6cSmrg                                }
54374b97a6cSmrg                            }
544b3307321Smrg#if 0
54574b97a6cSmrg                            else {
54674b97a6cSmrg                                pmData += 3;
54774b97a6cSmrg                                ipmData += 3;
54874b97a6cSmrg                            }
549b3307321Smrg#endif
55074b97a6cSmrg                        }
55174b97a6cSmrg                    }
55274b97a6cSmrg                }
55374b97a6cSmrg                else {
5546728f30eSmrg                    for (int y1 = 0; y1 < srcRect_height; y1++) {
5556728f30eSmrg                        for (int x1 = 0; x1 < srcRect_width; x1++) {
55674b97a6cSmrg                            int pixel_value = XGetPixel(image, x1, y1);
55774b97a6cSmrg
55874b97a6cSmrg                            if (pixel_value & transparentColor) {
5596728f30eSmrg                                int pixel;
560b3307321Smrg#if 0
56174b97a6cSmrg                                *pmData++ = *ipmData++;
56274b97a6cSmrg                                *pmData++ = *ipmData++;
56374b97a6cSmrg                                *pmData++ = *ipmData++;
564b3307321Smrg#endif
56574b97a6cSmrg                                pixel =
56674b97a6cSmrg                                    XGetPixel(ximage_ipm, dst_x + x1,
56774b97a6cSmrg                                              dst_y + y1);
56874b97a6cSmrg                                XPutPixel(ximage, dst_x + x1, dst_y + y1,
56974b97a6cSmrg                                          pixel);
57074b97a6cSmrg                                if (!test) {
57174b97a6cSmrg                                    test = 1;
57274b97a6cSmrg                                }
57374b97a6cSmrg                            }
574b3307321Smrg#if 0
57574b97a6cSmrg                            else {
57674b97a6cSmrg                                pmData += 3;
57774b97a6cSmrg                                ipmData += 3;
57874b97a6cSmrg                            }
579b3307321Smrg#endif
58074b97a6cSmrg                        }
58174b97a6cSmrg                    }
58274b97a6cSmrg                }
58374b97a6cSmrg            }
58474b97a6cSmrg            XDestroyImage(image);
58574b97a6cSmrg        }                       /* end of src_in_overlay */
586b3307321Smrg    } /** end transparency **/
58774b97a6cSmrg    destroy_region_list(vis_regions);
58874b97a6cSmrg    if (vis_image_regions)
58974b97a6cSmrg        destroy_region_list(vis_image_regions);
590b3307321Smrg    FreeXVisualInfo(pVisuals, pOverlayVisuals, pImageVisuals);
591b3307321Smrg    XSync(disp, 0);
592b3307321Smrg
593b3307321Smrg    return ximage;
594b3307321Smrg}
595b3307321Smrg
596b3307321Smrg/** ------------------------------------------------------------------------
597b3307321Smrg	Creates a list of the subwindows of a given window which have a
598b3307321Smrg	different visual than their parents.  The function is recursive.
599b3307321Smrg	This list is used in make_region_list(), which coalesces the
600b3307321Smrg	windows with the same visual into a region.
601b3307321Smrg	image_wins must point to an existing list struct that's already
602b3307321Smrg	been zeroed (zero_list()).
603b3307321Smrg    ------------------------------------------------------------------------ **/
60474b97a6cSmrgstatic void
60574b97a6cSmrgmake_src_list(Display *disp, list_ptr image_wins,
60674b97a6cSmrg              /* bnding box of area we want */
60774b97a6cSmrg              XRectangle *bbox,
60874b97a6cSmrg              Window curr,
60974b97a6cSmrg              /* pos of curr WRT root */
61074b97a6cSmrg              int x_rootrel, int y_rootrel,
61174b97a6cSmrg              XWindowAttributes *curr_attrs,
61274b97a6cSmrg              /* visible part of curr, not obscurred by ancestors */
61374b97a6cSmrg              XRectangle *pclip)
614b3307321Smrg{
615b3307321Smrg    XWindowAttributes child_attrs;
61674b97a6cSmrg    Window root, parent, *child;        /* variables for XQueryTree() */
61774b97a6cSmrg    unsigned int nchild;                /* variables for XQueryTree() */
61874b97a6cSmrg    XRectangle child_clip;              /* vis part of child */
619b3307321Smrg
620b3307321Smrg    /* check that win is mapped & not outside bounding box */
621b3307321Smrg    if (curr_attrs->map_state == IsViewable &&
62274b97a6cSmrg        curr_attrs->class == InputOutput &&
62374b97a6cSmrg        !(pclip->x >= (int) (bbox->x + bbox->width) ||
62474b97a6cSmrg          pclip->y >= (int) (bbox->y + bbox->height) ||
62574b97a6cSmrg          (int) (pclip->x + pclip->width) <= bbox->x ||
62674b97a6cSmrg          (int) (pclip->y + pclip->height) <= bbox->y)) {
62774b97a6cSmrg
6286728f30eSmrg        Window *save_child_list;
6296728f30eSmrg        int curr_clipX, curr_clipY, curr_clipRt, curr_clipBt;
6306728f30eSmrg
63174b97a6cSmrg        XQueryTree(disp, curr, &root, &parent, &child, &nchild);
63274b97a6cSmrg        save_child_list = child;   /* so we can free list when we're done */
63374b97a6cSmrg        add_window_to_list(image_wins, curr, x_rootrel, y_rootrel,
63474b97a6cSmrg                           pclip->x, pclip->y,
63574b97a6cSmrg                           pclip->width, pclip->height,
63674b97a6cSmrg                           curr_attrs->border_width, curr_attrs->visual,
63774b97a6cSmrg                           curr_attrs->colormap, parent);
63874a3f230Smrg
639b3307321Smrg/** ------------------------------------------------------------------------
640b3307321Smrg	set RR coords of right (Rt), left (X), bottom (Bt) and top (Y)
641b3307321Smrg	of rect we clip all children by.  This is our own clip rect (pclip)
642b3307321Smrg	inflicted on us by our parent plus our own borders.  Within the
643b3307321Smrg	child loop, we figure the clip rect for each child by adding in
644b3307321Smrg	it's rectangle (not taking into account the child's borders).
645b3307321Smrg    ------------------------------------------------------------------------ **/
64674b97a6cSmrg        curr_clipX = MAX(pclip->x, x_rootrel + (int) curr_attrs->border_width);
64774b97a6cSmrg        curr_clipY = MAX(pclip->y, y_rootrel + (int) curr_attrs->border_width);
64874b97a6cSmrg        curr_clipRt = MIN(pclip->x + (int) pclip->width,
64974b97a6cSmrg                          x_rootrel + (int) curr_attrs->width +
65074b97a6cSmrg                          2 * (int) curr_attrs->border_width);
65174b97a6cSmrg        curr_clipBt = MIN(pclip->y + (int) pclip->height,
65274b97a6cSmrg                          y_rootrel + (int) curr_attrs->height +
65374b97a6cSmrg                          2 * (int) curr_attrs->border_width);
65474b97a6cSmrg
65574b97a6cSmrg        while (nchild--) {
65674b97a6cSmrg            int new_width, new_height;
65774b97a6cSmrg            int child_xrr, child_yrr;   /* root relative x & y of child */
65874b97a6cSmrg
65974b97a6cSmrg            XGetWindowAttributes(disp, *child, &child_attrs);
66074b97a6cSmrg
66174b97a6cSmrg            /* intersect parent & child clip rects */
66274b97a6cSmrg            child_xrr = x_rootrel + child_attrs.x + curr_attrs->border_width;
66374b97a6cSmrg            child_clip.x = MAX(curr_clipX, child_xrr);
66474b97a6cSmrg            new_width = MIN(curr_clipRt, child_xrr + (int) child_attrs.width
66574b97a6cSmrg                            + 2 * child_attrs.border_width)
66674b97a6cSmrg                - child_clip.x;
66774b97a6cSmrg            if (new_width >= 0) {
66874b97a6cSmrg                child_clip.width = new_width;
66974b97a6cSmrg
67074b97a6cSmrg                child_yrr = y_rootrel + child_attrs.y +
67174b97a6cSmrg                    curr_attrs->border_width;
67274b97a6cSmrg                child_clip.y = MAX(curr_clipY, child_yrr);
67374b97a6cSmrg                new_height = MIN(curr_clipBt,
67474b97a6cSmrg                                 child_yrr + (int) child_attrs.height +
67574b97a6cSmrg                                 2 * child_attrs.border_width)
67674b97a6cSmrg                    - child_clip.y;
67774b97a6cSmrg                if (new_height >= 0) {
67874b97a6cSmrg                    child_clip.height = new_height;
67974b97a6cSmrg                    make_src_list(disp, image_wins, bbox, *child,
68074b97a6cSmrg                                  child_xrr, child_yrr,
68174b97a6cSmrg                                  &child_attrs, &child_clip);
68274b97a6cSmrg                }
68374b97a6cSmrg            }
68474b97a6cSmrg            child++;
68574b97a6cSmrg        }
68674b97a6cSmrg        XFree(save_child_list);
687b3307321Smrg    }
688b3307321Smrg}
689b3307321Smrg
690b3307321Smrg
691b3307321Smrg/** ------------------------------------------------------------------------
692b3307321Smrg	This function creates a list of regions which tile a specified
693b3307321Smrg	window.  Each region contains all visible portions of the window
694b3307321Smrg	which are drawn with the same visual.  For example, if the
695b3307321Smrg	window consists of subwindows of two different visual types,
69674a3f230Smrg	there will be two regions in the list.
697b3307321Smrg	Returns a pointer to the list.
698b3307321Smrg    ------------------------------------------------------------------------ **/
69974b97a6cSmrgstatic list_ptr
70074b97a6cSmrgmake_region_list(Display *disp, Window win, XRectangle *bbox,
70174b97a6cSmrg                 int *hasNonDefault, int numImageVisuals,
70274b97a6cSmrg                 XVisualInfo **pImageVisuals, int *allImage)
703b3307321Smrg{
70474b97a6cSmrg    XWindowAttributes win_attrs;
70574b97a6cSmrg    list image_wins;
70674b97a6cSmrg    list_ptr image_regions;
70774b97a6cSmrg    list_ptr srcs_left;
70874b97a6cSmrg    image_region_type *new_reg;
70974b97a6cSmrg    image_win_type *base_src, *src;
71074b97a6cSmrg    Region bbox_region = XCreateRegion();
71174b97a6cSmrg    XRectangle clip;
71274b97a6cSmrg    int image_only;
71374b97a6cSmrg    int count = 0;
71474a3f230Smrg
715b3307321Smrg    *hasNonDefault = False;
71674b97a6cSmrg    XUnionRectWithRegion(bbox, bbox_region, bbox_region);
71774b97a6cSmrg    XGetWindowAttributes(disp, win, &win_attrs);
718b3307321Smrg
71974b97a6cSmrg    zero_list(&image_wins);
720b3307321Smrg    clip.x = 0;
721b3307321Smrg    clip.y = 0;
72274b97a6cSmrg    clip.width = win_attrs.width;
723b3307321Smrg    clip.height = win_attrs.height;
72474b97a6cSmrg    make_src_list(disp, &image_wins, bbox, win,
72574b97a6cSmrg                  0 /* x_rootrel */, 0 /* y_rootrel */, &win_attrs, &clip);
726b3307321Smrg
727b3307321Smrg    image_regions = new_list();
72874b97a6cSmrg    image_only = (*allImage) ? True : False;
72974b97a6cSmrg
73074b97a6cSmrg    for (base_src = (image_win_type *) first_in_list(&image_wins); base_src;
73174b97a6cSmrg         base_src = (image_win_type *) next_in_list(&image_wins)) {
73274b97a6cSmrg        /* test for image visual */
73374b97a6cSmrg        if (!image_only ||
73474b97a6cSmrg            src_in_image(base_src, numImageVisuals, pImageVisuals)) {
73574b97a6cSmrg            /* find a window whose visual hasn't been put in list yet */
73674b97a6cSmrg            if (!src_in_region_list(base_src, image_regions)) {
7376728f30eSmrg                if (!(new_reg = malloc(sizeof(image_region_type)))) {
73874b97a6cSmrg                    return (list_ptr) NULL;
73974b97a6cSmrg                }
74074b97a6cSmrg                count++;
74174b97a6cSmrg
74274b97a6cSmrg                new_reg->visible_region = XCreateRegion();
74374b97a6cSmrg                new_reg->win            = base_src->win;
74474b97a6cSmrg                new_reg->vis            = base_src->vis;
74574b97a6cSmrg                new_reg->cmap           = base_src->cmap;
74674b97a6cSmrg                new_reg->x_rootrel      = base_src->x_rootrel;
74774b97a6cSmrg                new_reg->y_rootrel      = base_src->y_rootrel;
74874b97a6cSmrg                new_reg->x_vis          = base_src->x_vis;
74974b97a6cSmrg                new_reg->y_vis          = base_src->y_vis;
75074b97a6cSmrg                new_reg->width          = base_src->width;
75174b97a6cSmrg                new_reg->height         = base_src->height;
75274b97a6cSmrg                new_reg->border         = base_src->border_width;
75374b97a6cSmrg
75474b97a6cSmrg                srcs_left =
75574b97a6cSmrg                    (list_ptr) dup_list_head(&image_wins, START_AT_CURR);
75674b97a6cSmrg                for (src = (image_win_type *) first_in_list(srcs_left); src;
75774b97a6cSmrg                     src = (image_win_type *) next_in_list(srcs_left)) {
75874b97a6cSmrg                    if (SAME_REGIONS(base_src, src)) {
75974b97a6cSmrg                        add_rect_to_image_region(new_reg,
76074b97a6cSmrg                                                 src->x_vis, src->y_vis,
76174b97a6cSmrg                                                 src->width, src->height);
76274b97a6cSmrg                    }
76374b97a6cSmrg                    else {
76474b97a6cSmrg                        if (!image_only ||
76574b97a6cSmrg                            src_in_image(src, numImageVisuals, pImageVisuals))
76674b97a6cSmrg                        {
76774b97a6cSmrg                            subtr_rect_from_image_region(new_reg, src->x_vis,
76874b97a6cSmrg                                                         src->y_vis, src->width,
76974b97a6cSmrg                                                         src->height);
77074b97a6cSmrg                        }
77174b97a6cSmrg                    }
77274b97a6cSmrg                }
77374b97a6cSmrg                XIntersectRegion(bbox_region, new_reg->visible_region,
77474b97a6cSmrg                                 new_reg->visible_region);
77574b97a6cSmrg                if (!XEmptyRegion(new_reg->visible_region)) {
77674b97a6cSmrg                    add_to_list(image_regions, new_reg);
77774b97a6cSmrg                    if (new_reg->vis != DefaultVisualOfScreen(win_attrs.screen)
77874b97a6cSmrg                        || new_reg->cmap !=
77974b97a6cSmrg                        DefaultColormapOfScreen(win_attrs.screen)) {
78074b97a6cSmrg                        *hasNonDefault = True;
78174b97a6cSmrg                    }
78274b97a6cSmrg                }
78374b97a6cSmrg                else {
78474b97a6cSmrg                    XDestroyRegion(new_reg->visible_region);
7856728f30eSmrg                    free(new_reg);
78674b97a6cSmrg                }
78774b97a6cSmrg            }
78874b97a6cSmrg        }
78974b97a6cSmrg        else
79074b97a6cSmrg            *allImage = 0;
791b3307321Smrg    }
79274b97a6cSmrg    delete_list(&image_wins, True);
79374b97a6cSmrg    XDestroyRegion(bbox_region);
794b3307321Smrg    return image_regions;
795b3307321Smrg}
79674b97a6cSmrg
797b3307321Smrg/** ------------------------------------------------------------------------
798b3307321Smrg	Destructor called from destroy_region_list().
799b3307321Smrg    ------------------------------------------------------------------------ **/
80074b97a6cSmrgstatic void
80174b97a6cSmrgdestroy_image_region(image_region_type *image_region)
802b3307321Smrg{
80374b97a6cSmrg    XDestroyRegion(image_region->visible_region);
8046728f30eSmrg    free(image_region);
805b3307321Smrg}
806b3307321Smrg
807b3307321Smrg/** ------------------------------------------------------------------------
808b3307321Smrg	Destroys the region list, destroying all the regions contained in it.
809b3307321Smrg    ------------------------------------------------------------------------ **/
81074b97a6cSmrgstatic void
81174b97a6cSmrgdestroy_region_list(list_ptr rlist)
812b3307321Smrg{
81374b97a6cSmrg    delete_list_destroying(rlist, (DESTRUCT_FUNC_PTR) destroy_image_region);
814b3307321Smrg}
815b3307321Smrg
816b3307321Smrg/** ------------------------------------------------------------------------
817b3307321Smrg	Subtracts the specified rectangle from the region in image_region.
818b3307321Smrg	First converts the rectangle to a region of its own, since X
819b3307321Smrg	only provides a way to subtract one region from another, not a
820b3307321Smrg	rectangle from a region.
821b3307321Smrg    ------------------------------------------------------------------------ **/
82274b97a6cSmrgstatic void
82374b97a6cSmrgsubtr_rect_from_image_region(image_region_type *image_region,
82474b97a6cSmrg                             int x, int y, int width, int height)
825b3307321Smrg{
826b3307321Smrg    XRectangle rect;
827b3307321Smrg    Region rect_region;
828b3307321Smrg
829b3307321Smrg    rect_region = XCreateRegion();
830b3307321Smrg    rect.x = x;
831b3307321Smrg    rect.y = y;
832b3307321Smrg    rect.width = width;
833b3307321Smrg    rect.height = height;
83474b97a6cSmrg    XUnionRectWithRegion(&rect, rect_region, rect_region);
83574b97a6cSmrg    XSubtractRegion(image_region->visible_region, rect_region,
83674b97a6cSmrg                    image_region->visible_region);
83774b97a6cSmrg    XDestroyRegion(rect_region);
838b3307321Smrg}
839b3307321Smrg
840b3307321Smrg/** ------------------------------------------------------------------------
841b3307321Smrg	Adds the specified rectangle to the region in image_region.
842b3307321Smrg    ------------------------------------------------------------------------ **/
84374b97a6cSmrgstatic void
84474b97a6cSmrgadd_rect_to_image_region(image_region_type *image_region,
84574b97a6cSmrg                         int x, int y, int width, int height)
846b3307321Smrg{
847b3307321Smrg    XRectangle rect;
848b3307321Smrg
849b3307321Smrg    rect.x = x;
850b3307321Smrg    rect.y = y;
851b3307321Smrg    rect.width = width;
852b3307321Smrg    rect.height = height;
85374b97a6cSmrg    XUnionRectWithRegion(&rect, image_region->visible_region,
85474b97a6cSmrg                         image_region->visible_region);
855b3307321Smrg}
856b3307321Smrg
857b3307321Smrg/** ------------------------------------------------------------------------
858b3307321Smrg	Returns TRUE if the given src's visual is already represented in
859b3307321Smrg	the image_regions list, FALSE otherwise.
860b3307321Smrg    ------------------------------------------------------------------------ **/
86174b97a6cSmrgstatic int
86274b97a6cSmrgsrc_in_region_list(image_win_type *src, list_ptr image_regions)
863b3307321Smrg{
86474b97a6cSmrg    image_region_type *ir;
865b3307321Smrg
86674b97a6cSmrg    for (ir = (image_region_type *) first_in_list(image_regions); ir;
86774b97a6cSmrg         ir = (image_region_type *) next_in_list(image_regions)) {
86874b97a6cSmrg        if (SAME_REGIONS(ir, src)) {
869b3307321Smrg
87074b97a6cSmrg            return 1;
87174b97a6cSmrg        }
872b3307321Smrg    }
873b3307321Smrg
874b3307321Smrg    return 0;
875b3307321Smrg}
876b3307321Smrg
877b3307321Smrg/** ------------------------------------------------------------------------
878b3307321Smrg	Makes a new entry in image_wins with the given fields filled in.
879b3307321Smrg    ------------------------------------------------------------------------ **/
88074b97a6cSmrgstatic void
88174b97a6cSmrgadd_window_to_list(list_ptr image_wins, Window w,
88274b97a6cSmrg                   int xrr, int yrr, int x_vis, int y_vis,
88374b97a6cSmrg                   int width, int height, int border_width,
88474b97a6cSmrg                   Visual *vis, Colormap cmap, Window parent)
885b3307321Smrg{
88674b97a6cSmrg    image_win_type *new_src;
887b3307321Smrg
8886728f30eSmrg    if ((new_src = malloc(sizeof(image_win_type))) == NULL)
88974b97a6cSmrg        return;
890b3307321Smrg
891b3307321Smrg    new_src->win = w;
892b3307321Smrg    new_src->x_rootrel = xrr;
893b3307321Smrg    new_src->y_rootrel = yrr;
894b3307321Smrg    new_src->x_vis = x_vis;
895b3307321Smrg    new_src->y_vis = y_vis;
896b3307321Smrg    new_src->width = width;
897b3307321Smrg    new_src->height = height;
898b3307321Smrg    new_src->border_width = border_width;
899b3307321Smrg    new_src->vis = vis;
900b3307321Smrg    new_src->cmap = cmap;
901b3307321Smrg    new_src->parent = parent;
90274b97a6cSmrg    add_to_list(image_wins, new_src);
903b3307321Smrg}
904b3307321Smrg
905b3307321Smrg/** ------------------------------------------------------------------------
906b3307321Smrg	Returns TRUE if the given src's visual is in the image planes,
907b3307321Smrg	FALSE otherwise.
908b3307321Smrg    ------------------------------------------------------------------------ **/
90974b97a6cSmrgstatic int
91074b97a6cSmrgsrc_in_image(image_win_type *src, int numImageVisuals,
91174b97a6cSmrg             XVisualInfo **pImageVisuals)
912b3307321Smrg{
91374b97a6cSmrg    int i;
914b3307321Smrg
91574b97a6cSmrg    for (i = 0; i < numImageVisuals; i++) {
91674b97a6cSmrg        if (pImageVisuals[i]->visual == src->vis)
91774b97a6cSmrg            return 1;
918b3307321Smrg    }
919b3307321Smrg    return 0;
920b3307321Smrg}
921b3307321Smrg
922b3307321Smrg
923b3307321Smrg/** ------------------------------------------------------------------------
924b3307321Smrg	Returns TRUE if the given src's visual is in the overlay planes
925b3307321Smrg	and transparency is possible, FALSE otherwise.
926b3307321Smrg    ------------------------------------------------------------------------ **/
92774b97a6cSmrgstatic int
92874b97a6cSmrgsrc_in_overlay(image_region_type *src, int numOverlayVisuals,
92974b97a6cSmrg               OverlayInfo *pOverlayVisuals,
93074b97a6cSmrg               int *transparentColor, int *transparentType)
931b3307321Smrg{
93274b97a6cSmrg    int i;
93374b97a6cSmrg
93474b97a6cSmrg    for (i = 0; i < numOverlayVisuals; i++) {
93574b97a6cSmrg        if (((pOverlayVisuals[i].pOverlayVisualInfo)->visual == src->vis)
93674b97a6cSmrg            && (pOverlayVisuals[i].transparentType != None)) {
93774b97a6cSmrg            *transparentColor = pOverlayVisuals[i].value;
93874b97a6cSmrg            *transparentType = pOverlayVisuals[i].transparentType;
93974b97a6cSmrg            return 1;
94074b97a6cSmrg        }
941b3307321Smrg    }
942b3307321Smrg    return 0;
943b3307321Smrg}
944b3307321Smrg
945b3307321Smrg
946b3307321Smrg/********************** from wsutils.c ******************************/
947b3307321Smrg
948b3307321Smrg/******************************************************************************
949b3307321Smrg *
950b3307321Smrg * This file contains a set of example utility procedures; procedures that can
951b3307321Smrg * help a "window-smart" Starbase or PHIGS program determine information about
952b3307321Smrg * a device, and create image and overlay plane windows.  To use these
953b3307321Smrg * utilities, #include "wsutils.h" and compile this file and link the results
954b3307321Smrg * with your program.
955b3307321Smrg *
956b3307321Smrg ******************************************************************************/
957b3307321Smrg
958b3307321Smrg
95974b97a6cSmrgstatic int weCreateServerOverlayVisualsProperty = False;
960b3307321Smrg
961b3307321Smrg
962b3307321Smrg/******************************************************************************
963b3307321Smrg *
964b3307321Smrg * GetXVisualInfo()
965b3307321Smrg *
966b3307321Smrg * This routine takes an X11 Display, screen number, and returns whether the
967b3307321Smrg * screen supports transparent overlays and three arrays:
968b3307321Smrg *
969b3307321Smrg *	1) All of the XVisualInfo struct's for the screen.
970b3307321Smrg *	2) All of the OverlayInfo struct's for the screen.
971b3307321Smrg *	3) An array of pointers to the screen's image plane XVisualInfo
972b3307321Smrg *	   structs.
973b3307321Smrg *
974b3307321Smrg * The code below obtains the array of all the screen's visuals, and obtains
975b3307321Smrg * the array of all the screen's overlay visual information.  It then processes
976b3307321Smrg * the array of the screen's visuals, determining whether the visual is an
977b3307321Smrg * overlay or image visual.
978b3307321Smrg *
9796728f30eSmrg * If the routine successfully obtained the visual information, it returns zero.
980b3307321Smrg * If the routine didn't obtain the visual information, it returns non-zero.
981b3307321Smrg *
982b3307321Smrg ******************************************************************************/
983b3307321Smrg
98474b97a6cSmrgint
98574b97a6cSmrgGetXVisualInfo(   /* Which X server (aka "display"). */
98674b97a6cSmrg                  Display *display,
98774b97a6cSmrg                  /* Which screen of the "display". */
98874b97a6cSmrg                  int screen,
98974b97a6cSmrg                  /* Non-zero if there's at least one overlay visual and
99074b97a6cSmrg                   * if at least one of those supports a transparent pixel. */
99174b97a6cSmrg                  int *transparentOverlays,
99274b97a6cSmrg                  /* Number of XVisualInfo struct's pointed to by pVisuals. */
99374b97a6cSmrg                  int *numVisuals,
99474b97a6cSmrg                  /* All of the device's visuals. */
99574b97a6cSmrg                  XVisualInfo **pVisuals,
99674b97a6cSmrg                  /* Number of OverlayInfo's pointed to by pOverlayVisuals.
99774b97a6cSmrg                   * If this number is zero, the device does not have
99874b97a6cSmrg                   * overlay planes. */
99974b97a6cSmrg                  int *numOverlayVisuals,
100074b97a6cSmrg                  /* The device's overlay plane visual information. */
100174b97a6cSmrg                  OverlayInfo **pOverlayVisuals,
100274b97a6cSmrg                  /* Number of XVisualInfo's pointed to by pImageVisuals. */
100374b97a6cSmrg                  int *numImageVisuals,
100474b97a6cSmrg                  /* The device's image visuals. */
100574b97a6cSmrg                  XVisualInfo ***pImageVisuals)
1006b3307321Smrg{
100774b97a6cSmrg    XVisualInfo getVisInfo;     /* Parameters of XGetVisualInfo */
100874b97a6cSmrg    int mask;
100974b97a6cSmrg    XVisualInfo *pVis, **pIVis; /* Faster, local copies */
101074b97a6cSmrg    OverlayVisualPropertyRec *pOOldVis;
10116728f30eSmrg    int nVisuals;
101274b97a6cSmrg    Atom overlayVisualsAtom;    /* Parameters for XGetWindowProperty */
101374b97a6cSmrg    Atom actualType;
1014b3307321Smrg    unsigned long numLongs, bytesAfter;
101574b97a6cSmrg    int actualFormat;
101674b97a6cSmrg    int nImageVisualsAlloced;   /* Values to process the XVisualInfo */
1017b3307321Smrg
1018b3307321Smrg    /* First, get the list of visuals for this screen. */
1019b3307321Smrg    getVisInfo.screen = screen;
102074a3f230Smrg    mask = VisualScreenMask;
1021b3307321Smrg
1022b3307321Smrg    *pVisuals = XGetVisualInfo(display, mask, &getVisInfo, numVisuals);
102374b97a6cSmrg    if ((nVisuals = *numVisuals) <= 0) {
10246728f30eSmrg        /* Return that the information wasn't successfully obtained: */
102574b97a6cSmrg        return (1);
1026b3307321Smrg    }
1027b3307321Smrg    pVis = *pVisuals;
1028b3307321Smrg
1029b3307321Smrg    /* Now, get the overlay visual information for this screen.  To obtain
1030b3307321Smrg     * this information, get the SERVER_OVERLAY_VISUALS property.
1031b3307321Smrg     */
1032b3307321Smrg    overlayVisualsAtom = XInternAtom(display, "SERVER_OVERLAY_VISUALS", True);
103374b97a6cSmrg    if (overlayVisualsAtom != None) {
103474b97a6cSmrg        /* Since the Atom exists, we can request the property's contents.  The
103574b97a6cSmrg         * do-while loop makes sure we get the entire list from the X server.
103674b97a6cSmrg         */
103774b97a6cSmrg        bytesAfter = 0;
103874b97a6cSmrg        numLongs = sizeof(OverlayVisualPropertyRec) / sizeof(long);
103974b97a6cSmrg        do {
104074b97a6cSmrg            numLongs += bytesAfter * sizeof(long);
104174b97a6cSmrg            XGetWindowProperty(display, RootWindow(display, screen),
104274b97a6cSmrg                               overlayVisualsAtom, 0, numLongs, False,
104374b97a6cSmrg                               overlayVisualsAtom, &actualType, &actualFormat,
104474b97a6cSmrg                               &numLongs, &bytesAfter,
104574b97a6cSmrg                               (unsigned char **) pOverlayVisuals);
104674b97a6cSmrg        } while (bytesAfter > 0);
104774b97a6cSmrg
104874b97a6cSmrg        /* Calculate the number of overlay visuals in the list. */
104974b97a6cSmrg        *numOverlayVisuals =
105074b97a6cSmrg            numLongs / (sizeof(OverlayVisualPropertyRec) / sizeof(long));
1051b3307321Smrg    }
105274b97a6cSmrg    else {
105374b97a6cSmrg        /* This screen doesn't have overlay planes. */
105474b97a6cSmrg        *numOverlayVisuals = 0;
105574b97a6cSmrg        *pOverlayVisuals = NULL;
105674b97a6cSmrg        *transparentOverlays = 0;
1057b3307321Smrg    }
1058b3307321Smrg
1059b3307321Smrg    /* Process the pVisuals array. */
1060b3307321Smrg    *numImageVisuals = 0;
1061b3307321Smrg    nImageVisualsAlloced = 1;
10626728f30eSmrg    pIVis = *pImageVisuals = malloc(sizeof(XVisualInfo *));
106374b97a6cSmrg    while (--nVisuals >= 0) {
10646728f30eSmrg        int nOVisuals = *numOverlayVisuals;
10656728f30eSmrg        OverlayInfo *pOVis = *pOverlayVisuals;
10666728f30eSmrg        int imageVisual = True;
10676728f30eSmrg
106874b97a6cSmrg        while (--nOVisuals >= 0) {
106974b97a6cSmrg            pOOldVis = (OverlayVisualPropertyRec *) pOVis;
107074b97a6cSmrg            if (pVis->visualid == pOOldVis->visualID) {
107174b97a6cSmrg                imageVisual = False;
107274b97a6cSmrg                pOVis->pOverlayVisualInfo = pVis;
107374b97a6cSmrg                if (pOVis->transparentType == TransparentPixel)
107474b97a6cSmrg                    *transparentOverlays = 1;
107574b97a6cSmrg            }
107674b97a6cSmrg            pOVis++;
107774b97a6cSmrg        }
107874b97a6cSmrg        if (imageVisual) {
107974b97a6cSmrg            if ((*numImageVisuals += 1) > nImageVisualsAlloced) {
108074b97a6cSmrg                nImageVisualsAlloced++;
108174b97a6cSmrg                *pImageVisuals = (XVisualInfo **)
108274b97a6cSmrg                    realloc(*pImageVisuals,
108374b97a6cSmrg                            (nImageVisualsAlloced * sizeof(XVisualInfo *)));
108474b97a6cSmrg                pIVis = *pImageVisuals + (*numImageVisuals - 1);
108574b97a6cSmrg            }
108674b97a6cSmrg            *pIVis++ = pVis;
108774b97a6cSmrg        }
108874b97a6cSmrg        pVis++;
1089b3307321Smrg    }
1090b3307321Smrg
10916728f30eSmrg    /* Return that the information was successfully obtained: */
109274b97a6cSmrg    return (0);
1093b3307321Smrg
109474b97a6cSmrg}                               /* GetXVisualInfo() */
1095b3307321Smrg
1096b3307321Smrg/******************************************************************************
1097b3307321Smrg *
1098b3307321Smrg * FreeXVisualInfo()
1099b3307321Smrg *
1100b3307321Smrg * This routine frees the data that was allocated by GetXVisualInfo().
1101b3307321Smrg *
1102b3307321Smrg ******************************************************************************/
1103b3307321Smrg
110474b97a6cSmrgvoid
110574b97a6cSmrgFreeXVisualInfo(XVisualInfo *pVisuals, OverlayInfo *pOverlayVisuals,
110674b97a6cSmrg                XVisualInfo **pImageVisuals)
1107b3307321Smrg{
1108b3307321Smrg    XFree(pVisuals);
1109b3307321Smrg    if (weCreateServerOverlayVisualsProperty)
111074b97a6cSmrg        free(pOverlayVisuals);
1111b3307321Smrg    else
111274b97a6cSmrg        XFree(pOverlayVisuals);
1113b3307321Smrg    free(pImageVisuals);
1114b3307321Smrg
111574b97a6cSmrg}                               /* FreeXVisualInfo() */
1116