1/*
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28/*
29 * Authors:
30 *   Kevin E. Martin <kem@redhat.com>
31 *
32 */
33
34/** \file
35 * This file provides support for GC operations. */
36
37#ifdef HAVE_DMX_CONFIG_H
38#include <dmx-config.h>
39#endif
40
41#include "dmx.h"
42#include "dmxsync.h"
43#include "dmxgc.h"
44#include "dmxgcops.h"
45#include "dmxwindow.h"
46#include "dmxpixmap.h"
47
48#include "mi.h"
49#include "gcstruct.h"
50#include "pixmapstr.h"
51#include "dixfontstr.h"
52
53#ifdef PANORAMIX
54#include "panoramiXsrv.h"
55#endif
56
57#define DMX_GCOPS_SET_DRAWABLE(_pDraw, _draw)				\
58do {									\
59    if ((_pDraw)->type == DRAWABLE_WINDOW) {				\
60	dmxWinPrivPtr  pWinPriv =					\
61	    DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw));			\
62	(_draw) = (Drawable)pWinPriv->window;				\
63    } else {								\
64	dmxPixPrivPtr  pPixPriv =					\
65	    DMX_GET_PIXMAP_PRIV((PixmapPtr)(_pDraw));			\
66	(_draw) = (Drawable)pPixPriv->pixmap;				\
67    }									\
68} while (0)
69
70#define DMX_GCOPS_OFFSCREEN(_pDraw)					\
71    (!dmxScreens[(_pDraw)->pScreen->myNum].beDisplay ||			\
72     (dmxOffScreenOpt &&						\
73      (_pDraw)->type == DRAWABLE_WINDOW &&				\
74      (DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->offscreen ||		\
75       !DMX_GET_WINDOW_PRIV((WindowPtr)(_pDraw))->window)))
76
77/** Fill spans -- this function should never be called. */
78void dmxFillSpans(DrawablePtr pDrawable, GCPtr pGC,
79		  int nInit, DDXPointPtr pptInit, int *pwidthInit,
80		  int fSorted)
81{
82    /* Error -- this should never happen! */
83}
84
85/** Set spans -- this function should never be called. */
86void dmxSetSpans(DrawablePtr pDrawable, GCPtr pGC,
87		 char *psrc, DDXPointPtr ppt, int *pwidth, int nspans,
88		 int fSorted)
89{
90    /* Error -- this should never happen! */
91}
92
93/** Transfer \a pBits image to back-end server associated with \a
94 *  pDrawable's screen.  If primitive subdivision optimization is
95 *  enabled, then only transfer the sections of \a pBits that are
96 *  visible (i.e., not-clipped) to the back-end server. */
97void dmxPutImage(DrawablePtr pDrawable, GCPtr pGC,
98		 int depth, int x, int y, int w, int h,
99		 int leftPad, int format, char *pBits)
100{
101    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
102    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
103    XImage        *img;
104
105    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
106
107    img = XCreateImage(dmxScreen->beDisplay,
108		       dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual,
109		       depth, format, leftPad, pBits, w, h,
110		       BitmapPad(dmxScreen->beDisplay),
111		       (format == ZPixmap) ?
112		       PixmapBytePad(w, depth) : BitmapBytePad(w+leftPad));
113
114    if (img) {
115	Drawable draw;
116
117	DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
118
119	if (dmxSubdividePrimitives && pGC->pCompositeClip) {
120	    RegionPtr  pSubImages;
121	    RegionPtr  pClip;
122	    BoxRec     box;
123	    BoxPtr     pBox;
124	    int        nBox;
125
126	    box.x1 = x;
127	    box.y1 = y;
128	    box.x2 = x + w;
129	    box.y2 = y + h;
130	    pSubImages = RegionCreate(&box, 1);
131
132	    pClip = RegionCreate(NullBox, 1);
133	    RegionCopy(pClip, pGC->pCompositeClip);
134	    RegionTranslate(pClip,
135			     -pDrawable->x, -pDrawable->y);
136	    RegionIntersect(pSubImages, pSubImages, pClip);
137
138	    nBox = RegionNumRects(pSubImages);
139	    pBox = RegionRects(pSubImages);
140
141	    while (nBox--) {
142		XPutImage(dmxScreen->beDisplay, draw, pGCPriv->gc, img,
143			  pBox->x1 - box.x1,
144			  pBox->y1 - box.y1,
145			  pBox->x1,
146			  pBox->y1,
147			  pBox->x2 - pBox->x1,
148			  pBox->y2 - pBox->y1);
149		pBox++;
150	    }
151            RegionDestroy(pClip);
152            RegionDestroy(pSubImages);
153	} else {
154	    XPutImage(dmxScreen->beDisplay, draw, pGCPriv->gc,
155		      img, 0, 0, x, y, w, h);
156	}
157	XFree(img);             /* Use XFree instead of XDestroyImage
158                                 * because pBits is passed in from the
159                                 * caller. */
160
161	dmxSync(dmxScreen, FALSE);
162    } else {
163	/* Error -- this should not happen! */
164    }
165}
166
167/** Copy area from \a pSrc drawable to \a pDst drawable on the back-end
168 *  server associated with \a pSrc drawable's screen.  If the offscreen
169 *  optimization is enabled, only copy when both \a pSrc and \a pDst are
170 *  at least partially visible. */
171RegionPtr dmxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
172		      int srcx, int srcy, int w, int h, int dstx, int dsty)
173{
174    DMXScreenInfo *dmxScreen = &dmxScreens[pSrc->pScreen->myNum];
175    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
176    Drawable       srcDraw, dstDraw;
177
178    if (DMX_GCOPS_OFFSCREEN(pSrc) || DMX_GCOPS_OFFSCREEN(pDst))
179	return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h,
180				 dstx, dsty, 0L);
181
182    DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw);
183    DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw);
184
185    XCopyArea(dmxScreen->beDisplay, srcDraw, dstDraw, pGCPriv->gc,
186	      srcx, srcy, w, h, dstx, dsty);
187    dmxSync(dmxScreen, FALSE);
188
189    return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h,
190			     dstx, dsty, 0L);
191}
192
193/** Copy plane number \a bitPlane from \a pSrc drawable to \a pDst
194 *  drawable on the back-end server associated with \a pSrc drawable's
195 *  screen.  If the offscreen optimization is enabled, only copy when
196 *  both \a pSrc and \a pDst are at least partially visible. */
197RegionPtr dmxCopyPlane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC,
198		       int srcx, int srcy, int width, int height,
199		       int dstx, int dsty, unsigned long bitPlane)
200{
201    DMXScreenInfo *dmxScreen = &dmxScreens[pSrc->pScreen->myNum];
202    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
203    Drawable       srcDraw, dstDraw;
204
205    if (DMX_GCOPS_OFFSCREEN(pSrc) || DMX_GCOPS_OFFSCREEN(pDst))
206	return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, width, height,
207				 dstx, dsty, bitPlane);
208
209    DMX_GCOPS_SET_DRAWABLE(pSrc, srcDraw);
210    DMX_GCOPS_SET_DRAWABLE(pDst, dstDraw);
211
212    XCopyPlane(dmxScreen->beDisplay, srcDraw, dstDraw, pGCPriv->gc,
213	       srcx, srcy, width, height, dstx, dsty, bitPlane);
214    dmxSync(dmxScreen, FALSE);
215
216    return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, width, height,
217			     dstx, dsty, bitPlane);
218}
219
220/** Render list of points, \a pptInit in \a pDrawable on the back-end
221 *  server associated with \a pDrawable's screen.  If the offscreen
222 *  optimization is enabled, only draw when \a pDrawable is at least
223 *  partially visible. */
224void dmxPolyPoint(DrawablePtr pDrawable, GCPtr pGC,
225		  int mode, int npt, DDXPointPtr pptInit)
226{
227    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
228    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
229    Drawable       draw;
230
231    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
232
233    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
234
235    XDrawPoints(dmxScreen->beDisplay, draw, pGCPriv->gc,
236		(XPoint *)pptInit, npt, mode);
237    dmxSync(dmxScreen, FALSE);
238}
239
240/** Render list of connected lines, \a pptInit in \a pDrawable on the
241 *  back-end server associated with \a pDrawable's screen.  If the
242 *  offscreen optimization is enabled, only draw when \a pDrawable is at
243 *  least partially visible. */
244void dmxPolylines(DrawablePtr pDrawable, GCPtr pGC,
245		  int mode, int npt, DDXPointPtr pptInit)
246{
247    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
248    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
249    Drawable       draw;
250
251    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
252
253    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
254
255    XDrawLines(dmxScreen->beDisplay, draw, pGCPriv->gc,
256	       (XPoint *)pptInit, npt, mode);
257    dmxSync(dmxScreen, FALSE);
258}
259
260/** Render list of disjoint segments, \a pSegs in \a pDrawable on the
261 *  back-end server associated with \a pDrawable's screen.  If the
262 *  offscreen optimization is enabled, only draw when \a pDrawable is at
263 *  least partially visible. */
264void dmxPolySegment(DrawablePtr pDrawable, GCPtr pGC,
265		    int nseg, xSegment *pSegs)
266{
267    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
268    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
269    Drawable       draw;
270
271    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
272
273    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
274
275    XDrawSegments(dmxScreen->beDisplay, draw, pGCPriv->gc,
276		  (XSegment *)pSegs, nseg);
277    dmxSync(dmxScreen, FALSE);
278}
279
280/** Render list of rectangle outlines, \a pRects in \a pDrawable on the
281 *  back-end server associated with \a pDrawable's screen.  If the
282 *  offscreen optimization is enabled, only draw when \a pDrawable is at
283 *  least partially visible. */
284void dmxPolyRectangle(DrawablePtr pDrawable, GCPtr pGC,
285		      int nrects, xRectangle *pRects)
286{
287    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
288    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
289    Drawable       draw;
290
291    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
292
293    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
294
295    XDrawRectangles(dmxScreen->beDisplay, draw, pGCPriv->gc,
296		    (XRectangle *)pRects, nrects);
297
298    dmxSync(dmxScreen, FALSE);
299}
300
301/** Render list of arc outlines, \a parcs in \a pDrawable on the
302 *  back-end server associated with \a pDrawable's screen.  If the
303 *  offscreen optimization is enabled, only draw when \a pDrawable is at
304 *  least partially visible. */
305void dmxPolyArc(DrawablePtr pDrawable, GCPtr pGC,
306		int narcs, xArc *parcs)
307{
308    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
309    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
310    Drawable       draw;
311
312    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
313
314    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
315
316    XDrawArcs(dmxScreen->beDisplay, draw, pGCPriv->gc,
317	      (XArc *)parcs, narcs);
318    dmxSync(dmxScreen, FALSE);
319}
320
321/** Render a filled polygons in \a pDrawable on the back-end server
322 *  associated with \a pDrawable's screen.  If the offscreen
323 *  optimization is enabled, only draw when \a pDrawable is at least
324 *  partially visible. */
325void dmxFillPolygon(DrawablePtr pDrawable, GCPtr pGC,
326		    int shape, int mode, int count, DDXPointPtr pPts)
327{
328    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
329    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
330    Drawable       draw;
331
332    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
333
334    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
335
336    XFillPolygon(dmxScreen->beDisplay, draw, pGCPriv->gc,
337		 (XPoint *)pPts, count, shape, mode);
338    dmxSync(dmxScreen, FALSE);
339}
340
341/** Render list of filled rectangles, \a prectInit in \a pDrawable on
342 *  the back-end server associated with \a pDrawable's screen.  If the
343 *  offscreen optimization is enabled, only draw when \a pDrawable is at
344 *  least partially visible. */
345void dmxPolyFillRect(DrawablePtr pDrawable, GCPtr pGC,
346		     int nrectFill, xRectangle *prectInit)
347{
348    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
349    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
350    Drawable       draw;
351
352    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
353
354    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
355
356    XFillRectangles(dmxScreen->beDisplay, draw, pGCPriv->gc,
357		    (XRectangle *)prectInit, nrectFill);
358    dmxSync(dmxScreen, FALSE);
359}
360
361/** Render list of filled arcs, \a parcs in \a pDrawable on the back-end
362 *  server associated with \a pDrawable's screen.  If the offscreen
363 *  optimization is enabled, only draw when \a pDrawable is at least
364 *  partially visible. */
365void dmxPolyFillArc(DrawablePtr pDrawable, GCPtr pGC,
366		    int narcs, xArc *parcs)
367{
368    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
369    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
370    Drawable       draw;
371
372    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
373
374    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
375
376    XFillArcs(dmxScreen->beDisplay, draw, pGCPriv->gc,
377	      (XArc *)parcs, narcs);
378    dmxSync(dmxScreen, FALSE);
379}
380
381/** Render string of 8-bit \a chars (foreground only) in \a pDrawable on
382 *  the back-end server associated with \a pDrawable's screen.  If the
383 *  offscreen optimization is enabled, only draw when \a pDrawable is at
384 *  least partially visible. */
385int dmxPolyText8(DrawablePtr pDrawable, GCPtr pGC,
386		 int x, int y, int count, char *chars)
387{
388    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
389    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
390    unsigned long  n, i;
391    int            w;
392    CharInfoPtr    charinfo[255];
393    Drawable       draw;
394
395    GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
396	      Linear8Bit, &n, charinfo);
397
398    /* Calculate text width */
399    w = 0;
400    for (i = 0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
401
402    if (n != 0 && !DMX_GCOPS_OFFSCREEN(pDrawable)) {
403	DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
404
405	XDrawString(dmxScreen->beDisplay, draw, pGCPriv->gc,
406		    x, y, chars, count);
407	dmxSync(dmxScreen, FALSE);
408    }
409
410    return x+w;
411}
412
413/** Render string of 16-bit \a chars (foreground only) in \a pDrawable
414 *  on the back-end server associated with \a pDrawable's screen.  If
415 *  the offscreen optimization is enabled, only draw when \a pDrawable
416 *  is at least partially visible. */
417int dmxPolyText16(DrawablePtr pDrawable, GCPtr pGC,
418		  int x, int y, int count, unsigned short *chars)
419{
420    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
421    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
422    unsigned long  n, i;
423    int            w;
424    CharInfoPtr    charinfo[255];
425    Drawable       draw;
426
427    GetGlyphs(pGC->font, (unsigned long)count, (unsigned char *)chars,
428	      (FONTLASTROW(pGC->font) == 0) ? Linear16Bit : TwoD16Bit,
429	      &n, charinfo);
430
431    /* Calculate text width */
432    w = 0;
433    for (i = 0; i < n; i++) w += charinfo[i]->metrics.characterWidth;
434
435    if (n != 0 && !DMX_GCOPS_OFFSCREEN(pDrawable)) {
436	DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
437
438	XDrawString16(dmxScreen->beDisplay, draw, pGCPriv->gc,
439		      x, y, (XChar2b *)chars, count);
440	dmxSync(dmxScreen, FALSE);
441    }
442
443    return x+w;
444}
445
446/** Render string of 8-bit \a chars (both foreground and background) in
447 *  \a pDrawable on the back-end server associated with \a pDrawable's
448 *  screen.  If the offscreen optimization is enabled, only draw when \a
449 *  pDrawable is at least partially visible. */
450void dmxImageText8(DrawablePtr pDrawable, GCPtr pGC,
451		   int x, int y, int count, char *chars)
452{
453    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
454    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
455    Drawable       draw;
456
457    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
458
459    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
460
461    XDrawImageString(dmxScreen->beDisplay, draw, pGCPriv->gc,
462		     x, y, chars, count);
463    dmxSync(dmxScreen, FALSE);
464}
465
466/** Render string of 16-bit \a chars (both foreground and background) in
467 *  \a pDrawable on the back-end server associated with \a pDrawable's
468 *  screen.  If the offscreen optimization is enabled, only draw when \a
469 *  pDrawable is at least partially visible. */
470void dmxImageText16(DrawablePtr pDrawable, GCPtr pGC,
471		    int x, int y, int count, unsigned short *chars)
472{
473    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
474    dmxGCPrivPtr   pGCPriv = DMX_GET_GC_PRIV(pGC);
475    Drawable       draw;
476
477    if (DMX_GCOPS_OFFSCREEN(pDrawable)) return;
478
479    DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
480
481    XDrawImageString16(dmxScreen->beDisplay, draw, pGCPriv->gc,
482		       x, y, (XChar2b *)chars, count);
483    dmxSync(dmxScreen, FALSE);
484}
485
486/** Image Glyph Blt -- this function should never be called. */
487void dmxImageGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
488		      int x, int y, unsigned int nglyph,
489		      CharInfoPtr *ppci, pointer pglyphBase)
490{
491    /* Error -- this should never happen! */
492}
493
494/** Poly Glyph Blt -- this function should never be called. */
495void dmxPolyGlyphBlt(DrawablePtr pDrawable, GCPtr pGC,
496		     int x, int y, unsigned int nglyph,
497		     CharInfoPtr *ppci, pointer pglyphBase)
498{
499    /* Error -- this should never happen! */
500}
501
502/** Push Pixels -- this function should never be called. */
503void dmxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDst,
504		   int w, int h, int x, int y)
505{
506    /* Error -- this should never happen! */
507}
508
509/**********************************************************************
510 * Miscellaneous drawing commands
511 */
512
513/** When Xinerama is active, the client pixmaps are always obtained from
514 * screen 0.  When screen 0 is detached, the pixmaps must be obtained
515 * from any other screen that is not detached.  Usually, this is screen
516 * 1. */
517static DMXScreenInfo *dmxFindAlternatePixmap(DrawablePtr pDrawable, XID *draw)
518{
519#ifdef PANORAMIX
520    PanoramiXRes  *pXinPix;
521    int           i;
522    DMXScreenInfo *dmxScreen;
523
524    if (noPanoramiXExtension)               return NULL;
525    if (pDrawable->type != DRAWABLE_PIXMAP) return NULL;
526
527    if (Success != dixLookupResourceByType((pointer*) &pXinPix,
528					   pDrawable->id, XRT_PIXMAP,
529					   NullClient, DixUnknownAccess))
530        return NULL;
531
532    for (i = 1; i < PanoramiXNumScreens; i++) {
533        dmxScreen = &dmxScreens[i];
534        if (dmxScreen->beDisplay) {
535            PixmapPtr     pSrc;
536            dmxPixPrivPtr pSrcPriv;
537
538            dixLookupResourceByType((pointer*) &pSrc, pXinPix->info[i].id,
539				    RT_PIXMAP, NullClient, DixUnknownAccess);
540            pSrcPriv = DMX_GET_PIXMAP_PRIV(pSrc);
541            if (pSrcPriv->pixmap) {
542                *draw = pSrcPriv->pixmap;
543                return dmxScreen;
544            }
545        }
546    }
547#endif
548    return NULL;
549}
550
551/** Get an image from the back-end server associated with \a pDrawable's
552 *  screen.  If \a pDrawable is a window, it must be viewable to get an
553 *  image from it.  If it is not viewable, then get the image from the
554 *  first ancestor of \a pDrawable that is viewable.  If no viewable
555 *  ancestor is found, then simply return without getting an image.  */
556void dmxGetImage(DrawablePtr pDrawable, int sx, int sy, int w, int h,
557		 unsigned int format, unsigned long planeMask, char *pdstLine)
558{
559    DMXScreenInfo *dmxScreen = &dmxScreens[pDrawable->pScreen->myNum];
560    XImage        *img;
561    Drawable       draw;
562
563    /* Cannot get image from unviewable window */
564    if (pDrawable->type == DRAWABLE_WINDOW) {
565	WindowPtr pWindow = (WindowPtr)pDrawable;
566	if (!pWindow->viewable) {
567	    while (!pWindow->viewable && pWindow->parent) {
568		sx += pWindow->origin.x - wBorderWidth(pWindow);
569		sx += pWindow->origin.y - wBorderWidth(pWindow);
570		pWindow = pWindow->parent;
571	    }
572	    if (!pWindow->viewable) {
573		return;
574	    }
575	}
576	DMX_GCOPS_SET_DRAWABLE(&pWindow->drawable, draw);
577	if (DMX_GCOPS_OFFSCREEN(&pWindow->drawable))
578	    return;
579    } else {
580	DMX_GCOPS_SET_DRAWABLE(pDrawable, draw);
581	if (DMX_GCOPS_OFFSCREEN(pDrawable)) {
582            /* Try to find the pixmap on a non-detached Xinerama screen */
583            dmxScreen = dmxFindAlternatePixmap(pDrawable, &draw);
584            if (!dmxScreen) return;
585        }
586    }
587
588    img = XGetImage(dmxScreen->beDisplay, draw,
589		    sx, sy, w, h, planeMask, format);
590    if (img) {
591	int len = img->bytes_per_line * img->height;
592	memmove(pdstLine, img->data, len);
593	XDestroyImage(img);
594    }
595
596    dmxSync(dmxScreen, FALSE);
597}
598
599/** Get Spans -- this function should never be called. */
600void dmxGetSpans(DrawablePtr pDrawable, int wMax,
601		 DDXPointPtr ppt, int *pwidth, int nspans,
602		 char *pdstStart)
603{
604    /* Error -- this should never happen! */
605}
606