#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include <X11/X.h>
#include <X11/Xproto.h>
#include "scrnintstr.h"
#include "colormapst.h"
#include "glyphstr.h"
#include "resource.h"
#include <X11/fonts/font.h>
#include "dixfontstr.h"
#include <X11/fonts/fontstruct.h>
#include "micmap.h"
#include "fb.h"
#include "fbpseudocolor.h"

static Bool xxCreateGC(GCPtr pGC);
static void xxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDraw);
static void xxDestroyGC(GCPtr pGC);
static void xxChangeGC (GCPtr pGC, unsigned long   mask);
static void xxCopyGC (GCPtr pGCSrc, unsigned long   mask, GCPtr pGCDst);
static void xxChangeClip (GCPtr pGC, int type, pointer pvalue, int nrects);

static void xxCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
static void xxDestroyClip(GCPtr pGC);
static void xxFillSpans(DrawablePtr pDraw, GC *pGC, int nInit,
			DDXPointPtr pptInit, int *pwidthInit, int fSorted);
static void xxSetSpans(DrawablePtr pDraw, GCPtr	pGC, char *pcharsrc,
		       DDXPointPtr pptInit, int	*pwidthInit, int nspans,
		       int fSorted);
static void xxPutImage(DrawablePtr pDraw, GCPtr	pGC, int depth, int x, int y,
		       int w, int h,int	leftPad, int format, char *pImage);
static RegionPtr xxCopyPlane(DrawablePtr pSrc,
			     DrawablePtr pDst, GCPtr pGC,int srcx, int srcy,
			     int width, int height, int	dstx, int dsty,
			     unsigned long bitPlane);
static void xxPolyPoint(DrawablePtr pDraw, GCPtr pGC, int mode, int npt,
			xPoint *pptInit);
static void xxPolylines(DrawablePtr pDraw, GCPtr pGC, int mode,
			int npt, DDXPointPtr pptInit);
static void xxPolySegment(DrawablePtr pDraw, GCPtr pGC, int nseg,
			  xSegment *pSeg);
static void xxPolyRectangle(DrawablePtr  pDraw, GCPtr pGC, int nRects,
			    xRectangle  *pRects);
static void xxPolyArc( DrawablePtr pDraw, GCPtr	pGC, int narcs, xArc *parcs);
static void xxFillPolygon(DrawablePtr pDraw, GCPtr pGC, int shape,
			  int mode, int count, DDXPointPtr pptInit);
static void xxPolyFillRect(DrawablePtr pDraw, GCPtr pGC, int nRectsInit, 
			   xRectangle *pRectsInit);
static RegionPtr xxCopyArea(DrawablePtr pSrc, DrawablePtr pDst, GC *pGC,
			    int srcx, int srcy, int width, int height,
			    int dstx, int dsty);
static void xxPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs,
			  xArc *parcs);
static int xxPolyText8(DrawablePtr pDraw, GCPtr	pGC, int x, int	y, int count,
		       char *chars);
static int xxPolyText16(DrawablePtr pDraw, GCPtr pGC, int x, int y,
			int count, unsigned short *chars);
static void xxImageText8(DrawablePtr pDraw, GCPtr pGC, int x, 
			 int y, int count, char	*chars);
static void xxImageText16(DrawablePtr pDraw, GCPtr pGC, int x, int y,
			  int count, unsigned short *chars);
static void xxImageGlyphBlt(DrawablePtr pDraw, GCPtr pGC, int x, int y,
			    unsigned int nglyph, CharInfoPtr *ppci,
			    pointer pglyphBase);
static void xxPolyGlyphBlt(DrawablePtr pDraw, GCPtr pGC, int x, int y,
			   unsigned int nglyph, CharInfoPtr *ppci,
			   pointer pglyphBase);
static void xxPushPixels(GCPtr pGC, PixmapPtr pBitMap, DrawablePtr pDraw,
			 int	dx, int dy, int xOrg, int yOrg);
static void
xxComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
	     INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask,
	     INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
static void
xxGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
	  PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist,
	  GlyphListPtr list, GlyphPtr *glyphs);


typedef struct _xxCmapPrivRec {
    CARD32* cmap;
    ColormapPtr pmap;
    Bool dirty;
    struct _xxCmapPrivRec *next;
} xxCmapPrivRec, *xxCmapPrivPtr;


typedef struct {
    CloseScreenProcPtr		CloseScreen;
    CreateScreenResourcesProcPtr CreateScreenResources;
    CreateWindowProcPtr		CreateWindow;
    CopyWindowProcPtr		CopyWindow;
    PaintWindowProcPtr		PaintWindowBackground;
    PaintWindowProcPtr		PaintWindowBorder;
    WindowExposuresProcPtr	WindowExposures;
    CreateGCProcPtr		CreateGC;
    CreateColormapProcPtr	CreateColormap;
    DestroyColormapProcPtr	DestroyColormap;
    InstallColormapProcPtr	InstallColormap;
    UninstallColormapProcPtr	UninstallColormap;
    ListInstalledColormapsProcPtr ListInstalledColormaps;
    StoreColorsProcPtr		StoreColors;
#ifdef RENDER
    CompositeProcPtr		Composite;
    GlyphsProcPtr		Glyphs;
#endif    
    PixmapPtr			pPixmap;
    char *			addr;
    pointer			pBits;
    RegionRec			region;
    VisualPtr			bVisual;
    RegionRec			bRegion;
    int				myDepth;
    int				depth;
    ColormapPtr			baseCmap;
    ColormapPtr*		InstalledCmaps;
    xxCmapPrivPtr		Cmaps;
    int				numInstalledColormaps;
    int				colormapDirty;
    xxSyncFunc			sync;
} xxScrPrivRec, *xxScrPrivPtr;

#define xxGetScrPriv(s)	((xxScrPrivPtr) \
				 (xxScrPrivateIndex != -1) \
                          ? (s)->devPrivates[xxScrPrivateIndex].ptr\
				: NULL)
#define xxScrPriv(s)     xxScrPrivPtr pScrPriv = xxGetScrPriv(s)

#define xxGetCmapPriv(s) ((xxCmapPrivPtr) \
                          (s)->devPrivates[xxColormapPrivateIndex].ptr)
#define xxCmapPriv(s)    xxCmapPrivPtr pCmapPriv = xxGetCmapPriv(s);

typedef struct _xxGCPriv {
    GCOps   *ops;
    GCFuncs *funcs;
} xxGCPrivRec, *xxGCPrivPtr;

#define xxGetGCPriv(pGC) ((xxGCPrivPtr) \
				      (pGC)->devPrivates[xxGCPrivateIndex].ptr)
#define xxGCPriv(pGC)   xxGCPrivPtr  pGCPriv = xxGetGCPriv(pGC)

int xxScrPrivateIndex = -1;
int xxGCPrivateIndex;
int xxColormapPrivateIndex = -1;
int xxGeneration;


#define wrap(priv,real,mem,func) {\
    priv->mem = real->mem; \
    real->mem = func; \
}

#define unwrap(priv,real,mem) {\
    real->mem = priv->mem; \
}

#define MARK_DIRTY (1 << 31)

#define MAX_NUM_XX_INSTALLED_CMAPS 255
/* #define DEBUG  */
#ifdef DEBUG
# define DBG ErrorF
# define DBG_ARGS(x) ErrorF x
# define PRINT_RECTS(rec) {\
       int i;\
       BoxPtr box;\
       ErrorF("RECTS: %i\n",REGION_NUM_RECTS(&rec));\
       if (REGION_NUM_RECTS(&rec) > 1)  { \
          for (i = 0; i < REGION_NUM_RECTS(&rec); i++ ) {\
             box = REGION_BOX(&rec,i);\
	     ErrorF("x1: %hi x2: %hi y1: %hi y2: %hi\n", \
             box->x1,box->x2,box->y1,box->y2);\
          }\
       } else { \
             box = &(rec.extents); \
	     ErrorF("x1: %hi x2: %hi y1: %hi y2: %hi\n", \
             box->x1,box->x2,box->y1,box->y2);\
       } \
}
#else
# define DBG(x)
# define DBG_ARGS(x)
# define PRINT_RECTS(rec)
#endif

#if 0
static void xxCopyPseudocolorRegion(ScreenPtr pScreen, RegionPtr pReg,
				    xxCmapPrivPtr pCmapPriv);
static void xxUpdateFb(ScreenPtr pScreen);


static void
xxUpdateWindowImmediately(WindowPtr pWin)
{
    xxScrPriv(pWin->drawable.pScreen);
    xxCmapPrivPtr pCmapPriv;
    ColormapPtr pmap;
	    
    pmap = (ColormapPtr)LookupIDByType(wColormap(pWin),RT_COLORMAP);
    
    if (pmap && (pCmapPriv = xxGetCmapPriv(pmap)) != (pointer)-1) {
	xxCopyPseudocolorRegion(pWin->drawable.pScreen,
				&pScrPriv->region, pCmapPriv);
    }
}
#else
# define xxUpdateWindowImmediately(x)
#endif

static ColormapPtr
xxGetBaseColormap(ScreenPtr pScreen)
{
    xxScrPriv(pScreen);
    DepthPtr pDepth = pScreen->allowedDepths;
    int i,j,k;
    ColormapPtr pDefMap
	=  (ColormapPtr) LookupIDByType(pScreen->defColormap,RT_COLORMAP);
    ColormapPtr cmap = NULL;
    VisualPtr pVisual = NULL;
	
    for (i = 0; i < pScreen->numDepths; i++, pDepth++)
	if (pDepth->depth == pScrPriv->depth) {
	    for (j = 0; j < pDepth->numVids; j++) {
		if (pDefMap->pVisual->vid == pDepth->vids[j]
		    && pDefMap->pVisual->class == TrueColor) {
		    cmap = pDefMap;
		    break;
		}
		if (!pVisual) {
		    for (k = 0; k < pScreen->numVisuals; k++) {
			if (pScreen->visuals[k].class == TrueColor
			    && pScreen->visuals[k].vid
			    == pDepth->vids[j]) {
			    pVisual = &pScreen->visuals[k];
			    break;
			}
		    }
		}
	    }
	    if (cmap)
		break;
	}
	    
    if (!cmap) {
	CreateColormap(FakeClientID(0),pScreen,pVisual,&cmap,AllocNone,0);
    }
    
    return cmap;
}

static Bool
xxCreateScreenResources(ScreenPtr pScreen)
{
    PixmapPtr		pPix;
    xxScrPriv(pScreen);
    Bool		ret;
    PixmapPtr		pPixmap;
    BoxRec		box;
    int			depth = pScrPriv->myDepth;
    pointer		pBits;
    
    unwrap (pScrPriv,pScreen, CreateScreenResources);
    ret = pScreen->CreateScreenResources(pScreen);
    wrap(pScrPriv,pScreen,CreateScreenResources,xxCreateScreenResources);

    if (!ret) return FALSE;
    
    pScrPriv->pBits = NULL;
    if (pScrPriv->addr)
	pBits = pScrPriv->addr;
    else
	pBits = xalloc(pScreen->width * pScreen->height
		       * (BitsPerPixel(depth) >> 3));
    if (!pBits) return FALSE;
    
    pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth);
    if (!pPixmap) {
	xfree(pBits);
	return FALSE;
    }
    if (!(*pScreen->ModifyPixmapHeader)(pPixmap, pScreen->width,
					pScreen->height, depth,
					BitsPerPixel(depth),
					PixmapBytePad(pScreen->width, depth),
					pBits)) {
	xfree(pBits);
	return FALSE;
    }
    if (pScreen->rootDepth == pScrPriv->myDepth) {
	pPix = (PixmapPtr)pScreen->devPrivate;    
	if (!(*pScreen->ModifyPixmapHeader)(pPix, 0,0, pScrPriv->depth,
					    BitsPerPixel(pScrPriv->depth),
					    PixmapBytePad(pScreen->width,
							  pScrPriv->depth),
					    0)) {
	    xfree(pBits);
	    return FALSE;
	}
    }

    pScrPriv->baseCmap = xxGetBaseColormap(pScreen);
    
    pScrPriv->pBits = pBits;
    pScrPriv->pPixmap = pPixmap;
    box.x1 = 0;
    box.y1 = 0;
    box.x2 = pScreen->width;
    box.y2 = pScreen->height;
    REGION_NULL(pScreen, &pScrPriv->region);
    REGION_INIT(pScreen, &pScrPriv->bRegion, &box, 0);
    
    return TRUE;
}

static Bool
xxCloseScreen (int iScreen, ScreenPtr pScreen)
{
    xxScrPriv(pScreen);
    Bool		ret;

    (*pScreen->DestroyPixmap)(pScrPriv->pPixmap);
    /* We don't need to free the baseColormap as FreeClientResourcess
       will have taken care of it. */
    REGION_UNINIT (pScreen, &pScrPriv->region);
    
    unwrap (pScrPriv,pScreen, CloseScreen);
    ret = pScreen->CloseScreen(iScreen,pScreen);

    xfree(pScrPriv->pBits);
    xfree(pScrPriv->InstalledCmaps);
    xfree(pScrPriv);
    
    return TRUE;
}

static Bool
xxMyVisual(ScreenPtr pScreen, VisualID vid)
{
    xxScrPriv(pScreen);
    DepthPtr pDepth = pScreen->allowedDepths;
    int i,j;
    
    for (i = 0; i < pScreen->numDepths; i++, pDepth++)
	if (pDepth->depth == pScrPriv->myDepth) {
	    for (j = 0; j < pDepth->numVids; j++) {
		if (vid == pDepth->vids[j]) {
		    return TRUE;
		}
	    }
	}
    return FALSE;
}

static Bool
xxInitColormapDummy(ColormapPtr pmap, int index)
{
    return TRUE;
}

static Bool
xxInitColormapPrivate(ColormapPtr pmap)
{
    xxScrPriv(pmap->pScreen);
    xxCmapPrivPtr	pCmapPriv;
    pointer		cmap;

    pmap->devPrivates[xxColormapPrivateIndex].ptr = (pointer) -1;
    
    if (xxMyVisual(pmap->pScreen,pmap->pVisual->vid)) {
	DBG("CreateColormap\n");
	pCmapPriv = (xxCmapPrivPtr) xalloc (sizeof (xxCmapPrivRec));
	if (!pCmapPriv)
	    return FALSE;
	pmap->devPrivates[xxColormapPrivateIndex].ptr = (pointer) pCmapPriv;
	cmap = xalloc(sizeof (CARD32) * (1 << pScrPriv->myDepth));
	if (!cmap)
	return FALSE;

	memset(cmap,0,sizeof (CARD32) * (1 << pScrPriv->myDepth));
	
	pCmapPriv->cmap = cmap;
	pCmapPriv->dirty = FALSE;
	pCmapPriv->pmap = pmap;
	pCmapPriv->next = pScrPriv->Cmaps;
	pScrPriv->Cmaps = pCmapPriv;
    }
    return TRUE;
}


static Bool
xxCreateColormap(ColormapPtr pmap)
{
    xxScrPriv(pmap->pScreen);
    Bool		ret;
    
    if (!xxInitColormapPrivate(pmap)) return FALSE;
    
    unwrap(pScrPriv,pmap->pScreen, CreateColormap);
    ret = pmap->pScreen->CreateColormap(pmap);
    wrap(pScrPriv,pmap->pScreen,CreateColormap,xxCreateColormap);
    
    return ret;
}

static int
xxCmapInstalled(ColormapPtr pmap)
{
    xxScrPriv(pmap->pScreen);
    int i;
    
    for (i = 0; i < pScrPriv->numInstalledColormaps; i++)
	if (pScrPriv->InstalledCmaps[i] == pmap)
	    break;
	if (i == pScrPriv->numInstalledColormaps) /* not installed */
	    return -1;
	return i;
}

static void
xxInstalledCmapDelete(ScreenPtr pScreen, int num)
{
    xxScrPriv(pScreen);
    int i;

    pScrPriv->numInstalledColormaps--;
    
    for (i = num; i < pScrPriv->numInstalledColormaps; i++)
	pScrPriv->InstalledCmaps[i] = pScrPriv->InstalledCmaps[i+1];
}

static void
xxDestroyColormap(ColormapPtr pmap)
{
    xxScrPriv(pmap->pScreen);
    xxCmapPriv(pmap);

    if (pCmapPriv != (pointer) -1) {
	xxCmapPrivPtr tmpCmapPriv = pScrPriv->Cmaps;
	xxCmapPrivPtr *prevCmapPriv = &pScrPriv->Cmaps;
	int n;
	
	DBG("DestroyColormap\n");

	if ((n = xxCmapInstalled(pmap)) != -1)
	    xxInstalledCmapDelete(pmap->pScreen,n);

	while (tmpCmapPriv) {
	    if (tmpCmapPriv->pmap == pmap) {
		*prevCmapPriv = tmpCmapPriv->next;
		break;
	    }
	    prevCmapPriv = &tmpCmapPriv->next;
	    tmpCmapPriv = tmpCmapPriv->next;
	}
	
	xfree(pCmapPriv->cmap);
	xfree(pCmapPriv);
    }

    unwrap(pScrPriv,pmap->pScreen, DestroyColormap);
    pmap->pScreen->DestroyColormap(pmap);
    wrap(pScrPriv,pmap->pScreen,DestroyColormap,xxDestroyColormap);
}

#define Shift(v,d)  ((d) < 0 ? ((v) >> (-d)) : ((v) << (d)))

static int
xxComputeCmapShift (unsigned long mask)
{
    int	shift;
    unsigned long   bit;
    
    shift = 16;
    bit = 0x80000000;
    while (!(mask & bit))
    {
	shift--;
	bit >>= 1;
    }
    return shift;
}

static void
xxStoreColors(ColormapPtr pmap, int nColors, xColorItem *pColors)
{
    xxScrPriv(pmap->pScreen);
    xxCmapPriv(pmap);

    if (pCmapPriv != (pointer) -1) {

	xColorItem	*expanddefs;
	int		i;
	VisualPtr	bVisual;
	int		rs, gs, bs;

	if (nColors == 0) return;

	DBG("StoreColors\n");
	
	expanddefs = ALLOCATE_LOCAL(sizeof(xColorItem)
				    * (1 <<  pScrPriv->myDepth));
	if (!expanddefs) return;
	
	bVisual = pScrPriv->bVisual;

	DBG("StoreColors\n");

	rs = xxComputeCmapShift(bVisual->redMask);
	gs = xxComputeCmapShift(bVisual->greenMask);
	bs = xxComputeCmapShift(bVisual->blueMask);
	
	if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
	    nColors = miExpandDirectColors(pmap, nColors, pColors, expanddefs);
	    pColors = expanddefs;
	}

	for (i = 0; i < nColors; i++) {
	    DBG_ARGS(("index: %i r 0x%x g 0x%x b 0x%x\n", pColors->pixel,
		   pColors->red, pColors->green, pColors->blue));
	    pCmapPriv->cmap[pColors->pixel] = MARK_DIRTY
		| (Shift(pColors->red, rs) & bVisual->redMask)
		| (Shift(pColors->green, gs) & bVisual->greenMask)
		| (Shift(pColors->blue, bs)  & bVisual->blueMask);
	    pColors++;
	}

	DEALLOCATE_LOCAL(expanddefs);

	pCmapPriv->dirty = TRUE;
	pScrPriv->colormapDirty = TRUE;
	
	return;
    }
    
    unwrap(pScrPriv,pmap->pScreen, StoreColors);
    pmap->pScreen->StoreColors(pmap,nColors,pColors);
    wrap(pScrPriv,pmap->pScreen,StoreColors,xxStoreColors);
}

static void
xxInstallColormap(ColormapPtr pmap)
{
    int i;
    xxScrPriv(pmap->pScreen);
    xxCmapPriv(pmap);
    
    if (pCmapPriv != (pointer) -1) {
	Pixel		*pixels;
	xrgb		*colors;
	int		i;
	VisualPtr	pVisual;
	xColorItem	*defs;

	DBG("InstallColormap\n");

	if (xxCmapInstalled(pmap) != -1)
	    return;

	if (!pScrPriv->numInstalledColormaps) {
	    unwrap(pScrPriv,pmap->pScreen, InstallColormap);
	    pmap->pScreen->InstallColormap(pScrPriv->baseCmap);
	    wrap(pScrPriv,pmap->pScreen,InstallColormap,xxInstallColormap);
	}
	    
	pixels = ALLOCATE_LOCAL(sizeof(Pixel) * (1 <<  pScrPriv->myDepth));
	colors = ALLOCATE_LOCAL(sizeof(xrgb) * (1 <<  pScrPriv->myDepth));
	defs = ALLOCATE_LOCAL(sizeof(xColorItem) * (1 << pScrPriv->myDepth));
	
	if (!pixels || !colors)
	    return;

	/* if we have more than max installed delete the oldest */
	if (pScrPriv->numInstalledColormaps == MAX_NUM_XX_INSTALLED_CMAPS)
	    xxInstalledCmapDelete(pmap->pScreen,0);
	
	pScrPriv->InstalledCmaps[pScrPriv->numInstalledColormaps] = pmap;
	pScrPriv->numInstalledColormaps++;
	
	pVisual = pScrPriv->bVisual;
	
	for (i = 0; i < (1 <<  pScrPriv->myDepth); i++)
	    pixels[i] = i;
	
	QueryColors (pmap, (1 << pScrPriv->myDepth), pixels, colors);

	for (i = 0; i < (1 <<  pScrPriv->myDepth); i++) {
	    defs[i].pixel = pixels[i];
            defs[i].red = colors[i].red;
            defs[i].green = colors[i].green;
            defs[i].blue = colors[i].blue;
            defs[i].flags =  DoRed|DoGreen|DoBlue;
        }
	xxStoreColors(pmap,(1 <<  pScrPriv->myDepth),defs);

	DEALLOCATE_LOCAL(pixels);
	DEALLOCATE_LOCAL(colors);
	DEALLOCATE_LOCAL(defs);

	return;
    } 

    for (i = pScrPriv->numInstalledColormaps; i ; i--)
	WalkTree(pmap->pScreen, TellLostMap,
		 (char *)&pScrPriv->InstalledCmaps[i-1]->mid);
    
    pScrPriv->numInstalledColormaps = 0;
     
    unwrap(pScrPriv,pmap->pScreen, InstallColormap);
    pmap->pScreen->InstallColormap(pmap);
    wrap(pScrPriv,pmap->pScreen,InstallColormap,xxInstallColormap);
}

static void
xxUninstallColormap(ColormapPtr pmap)
{
    xxScrPriv(pmap->pScreen);
    xxCmapPriv(pmap);

    if (pCmapPriv != (pointer) -1) {
	int num;
	
	if ((num = xxCmapInstalled(pmap)) == -1)
	    return;
	
	DBG("UninstallColormap\n");
	xxInstalledCmapDelete(pmap->pScreen,num);

	return;
    } 
    
    unwrap(pScrPriv,pmap->pScreen, UninstallColormap);
    pmap->pScreen->UninstallColormap(pmap);
    wrap(pScrPriv,pmap->pScreen,UninstallColormap,xxUninstallColormap);
	
}

static int
xxListInstalledColormaps(ScreenPtr pScreen, Colormap *pCmapIds)
{
    int			n,i;
    xxScrPriv(pScreen);

    unwrap(pScrPriv,pScreen, ListInstalledColormaps);
    n = pScreen->ListInstalledColormaps(pScreen, pCmapIds);
    wrap (pScrPriv,pScreen,ListInstalledColormaps,xxListInstalledColormaps);

    pCmapIds += n;

    for (i = 0; i < pScrPriv->numInstalledColormaps; i++) {
	*pCmapIds++ = pScrPriv->InstalledCmaps[i]->mid;
	n++;
    }

    return n;
}

static Bool
xxCreateWindow(WindowPtr pWin)
{
    xxScrPriv(pWin->drawable.pScreen);
    
    if (pWin->drawable.class != InputOutput
	|| pScrPriv->myDepth != pWin->drawable.depth) {
	Bool ret;
	DBG("CreateWindow NoPseudo\n");
	unwrap (pScrPriv, pWin->drawable.pScreen, CreateWindow);
	ret = pWin->drawable.pScreen->CreateWindow(pWin);
	wrap(pScrPriv, pWin->drawable.pScreen, CreateWindow, xxCreateWindow);

	return ret;
    }
    
    DBG("CreateWindow\n");

    pWin->devPrivates[fbWinPrivateIndex].ptr = (pointer) pScrPriv->pPixmap;
    PRINT_RECTS(pScrPriv->region);
	if (!pWin->parent) {
	REGION_EMPTY (pWin->drawable.pScreen, &pScrPriv->region);
    }
    PRINT_RECTS(pScrPriv->region);
    
    return TRUE;
}

static void
xxWalkChildren(WindowPtr pWin, RegionPtr pReg, PixmapPtr pPixmap)
{
    
    WindowPtr		pCurWin = pWin;
    
    do {
	if (fbGetWindowPixmap(pCurWin) == pPixmap) {
	    DBG("WalkWindow Add\n");
	    REGION_UNION(pWin->drawable.pScreen,pReg,pReg,
			 &pCurWin->borderClip);
	} else {
	    DBG("WalkWindow Sub\n");
	    REGION_SUBTRACT(pWin->drawable.pScreen,pReg,pReg,
			    &pCurWin->borderClip);
	}
	if (pCurWin->lastChild)
	    xxWalkChildren(pCurWin->lastChild,pReg, pPixmap);
    } while ((pCurWin = pCurWin->prevSib));
}

static void
xxPickMyWindows(WindowPtr pWin, RegionPtr pRgn)
{
    ScreenPtr		pScreen = pWin->drawable.pScreen;
    xxScrPriv(pScreen);

    if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) {
	REGION_UNION(pWin->drawable.pScreen,pRgn,pRgn,&pWin->borderClip);
    }
    if (pWin->lastChild)
	xxWalkChildren(pWin->lastChild,pRgn,pScrPriv->pPixmap);
}

static void
xxCopyWindow(WindowPtr	pWin,
	     DDXPointRec	ptOldOrg,
	     RegionPtr	prgnSrc)
{
    ScreenPtr		pScreen = pWin->drawable.pScreen;
    xxScrPriv(pScreen);
    RegionRec		rgn;
    RegionRec		rgn_new;
    int			dx, dy;
    PixmapPtr pPixmap = fbGetWindowPixmap(pWin);

    DBG("xxCopyWindow\n");

    dx = ptOldOrg.x - pWin->drawable.x;
    dy = ptOldOrg.y - pWin->drawable.y;

    REGION_NULL(pScreen, &rgn_new);
    REGION_UNION(pScreen, &rgn_new,&rgn_new,prgnSrc);
    REGION_TRANSLATE(pScreen,&rgn_new,-dx,-dy);

    REGION_NULL(pScreen, &rgn);
    xxPickMyWindows(pWin,&rgn);

    unwrap (pScrPriv, pScreen, CopyWindow);
    pWin->devPrivates[fbWinPrivateIndex].ptr = fbGetScreenPixmap(pScreen);
    pScreen->CopyWindow(pWin, ptOldOrg, prgnSrc);
    pWin->devPrivates[fbWinPrivateIndex].ptr = pPixmap;
    wrap(pScrPriv, pScreen, CopyWindow, xxCopyWindow);

    REGION_INTERSECT(pScreen,&rgn,&rgn,&rgn_new);
    if (REGION_NOTEMPTY (pScreen,&rgn)) {
	fbCopyRegion(&pScrPriv->pPixmap->drawable,&pScrPriv->pPixmap->drawable,
		     0,&rgn,dx,dy,fbCopyWindowProc,0,(void*)0);
	REGION_TRANSLATE(pScreen,&rgn,dx,dy);
	REGION_INTERSECT(pScreen,&rgn_new,&pScrPriv->region,&rgn);
	REGION_SUBTRACT(pScreen,&pScrPriv->region,&pScrPriv->region,&rgn);
	REGION_TRANSLATE(pScreen,&rgn_new,-dx,-dy);
	REGION_UNION(pScreen,&pScrPriv->region,&pScrPriv->region,&rgn_new);
    }
#if 1
    REGION_UNINIT(pScreen,&rgn_new);
    REGION_UNINIT(pScreen,&rgn);
#endif
}

static void
xxWindowExposures (WindowPtr	pWin,
			  RegionPtr	prgn,
			  RegionPtr	other_exposed)
{
    xxScrPriv(pWin->drawable.pScreen);

    if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) {
	DBG("WindowExposures\n");
	PRINT_RECTS(pScrPriv->region);
	REGION_UNION(pWin->drawable.pScreen,&pScrPriv->region,
		     &pScrPriv->region,
		     prgn);
	PRINT_RECTS(pScrPriv->region);
    } else {
	DBG("WindowExposures NonPseudo\n");
	PRINT_RECTS(pScrPriv->region);
	REGION_SUBTRACT(pWin->drawable.pScreen,&pScrPriv->region,
		     &pScrPriv->region,
		     prgn);
	PRINT_RECTS(pScrPriv->region);
    }
    unwrap (pScrPriv, pWin->drawable.pScreen, WindowExposures);
    pWin->drawable.pScreen->WindowExposures(pWin, prgn, other_exposed);
    wrap(pScrPriv, pWin->drawable.pScreen, WindowExposures, xxWindowExposures);
}

static void
xxPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
{
    xxScrPriv(pWin->drawable.pScreen);
    RegionRec		rgni;

    DBG("xxPaintWindow\n");

    REGION_NULL (pWin->drawable.pScreen, &rgni);
#if 0
    REGION_UNION (pWin->drawable.pScreen, &rgni, &rgni, &pWin->borderClip);
    REGION_INTERSECT(pWin->drawable.pScreen, &rgni, &rgni, pRegion);
#else
    REGION_UNION (pWin->drawable.pScreen, &rgni, &rgni, pRegion);
#endif
    switch (what) {
    case PW_BORDER:
	REGION_SUBTRACT (pWin->drawable.pScreen, &rgni, &rgni, &pWin->winSize);
	if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) {
	    DBG("PaintWindowBorder\n");
	    REGION_UNION (pWin->drawable.pScreen, &pScrPriv->region,
			  &pScrPriv->region, &rgni);
	} else {
	    DBG("PaintWindowBorder NoOverlay\n");
	    REGION_SUBTRACT (pWin->drawable.pScreen, &pScrPriv->region,
			     &pScrPriv->region, &rgni);	
	}
	unwrap (pScrPriv, pWin->drawable.pScreen, PaintWindowBorder);
	pWin->drawable.pScreen->PaintWindowBorder (pWin, pRegion, what);
	wrap(pScrPriv, pWin->drawable.pScreen, PaintWindowBorder,
	     xxPaintWindow);	
	break;
    case PW_BACKGROUND:
	switch (pWin->backgroundState) {
	case None:
	    break;
	default:
	    REGION_INTERSECT (pWin->drawable.pScreen, &rgni,
			      &rgni,&pWin->winSize);
	    if (fbGetWindowPixmap(pWin) == pScrPriv->pPixmap) {
		DBG("PaintWindowBackground\n");
		REGION_UNION (pWin->drawable.pScreen, &pScrPriv->region,
			      &pScrPriv->region, &rgni);
	    } else {
		DBG("PaintWindowBackground NoOverlay\n");
		REGION_SUBTRACT (pWin->drawable.pScreen, &pScrPriv->region,
				 &pScrPriv->region, &rgni);	
	    }
	    break;
	}
	
	unwrap (pScrPriv, pWin->drawable.pScreen, PaintWindowBackground);
	pWin->drawable.pScreen->PaintWindowBackground (pWin, pRegion, what);
	wrap(pScrPriv, pWin->drawable.pScreen, PaintWindowBackground,
	     xxPaintWindow);
	break;
    }
    PRINT_RECTS(rgni);
    PRINT_RECTS(pScrPriv->region);
#if 1
    REGION_UNINIT(pWin->drawable.pScreen,&rgni);
#endif
}

static void
xxCopyPseudocolorRegion(ScreenPtr pScreen, RegionPtr pReg,
			xxCmapPrivPtr pCmapPriv)
{
    xxScrPriv(pScreen);
    CARD32		mask = (1 << pScrPriv->myDepth) - 1;
    int			num = REGION_NUM_RECTS(pReg);
    BoxPtr		pbox = REGION_RECTS(pReg);
    int			width, height;
    CARD8		*src;
    CARD16		*dst, *dst_base;
    int			dst_stride;
    register CARD32	*cmap = pCmapPriv->cmap;
    register CARD8      *s;
    register CARD16     *d;
    int w;

    dst_base = (CARD16*) ((PixmapPtr)pScreen->devPrivate)->devPrivate.ptr;
    dst_stride = (int)((PixmapPtr)pScreen->devPrivate)->devKind
	/ sizeof (CARD16);

    while (num--) {
	height = pbox->y2 - pbox->y1;
	width = pbox->x2 - pbox->x1;
	
	src = (unsigned char *) pScrPriv->pBits
	    + (pbox->y1 * pScreen->width) + pbox->x1;
	dst = dst_base + (pbox->y1 * dst_stride) + pbox->x1;
	while (height--) {
	    w = width;
	    s = src;
	    d = dst;

	    while(w--) {
		*(d++) = (CARD16)*(cmap + ((*(s++)) & mask));
	    }
	    src += pScreen->width;
	    dst += dst_stride;
	}
	pbox++;
    }
}

static void
xxUpdateCmapPseudocolorRegion(ScreenPtr pScreen, RegionPtr pReg,
			xxCmapPrivPtr pCmapPriv)
{
    xxScrPriv(pScreen);
    CARD32		mask = (1 << pScrPriv->myDepth) - 1;
    int			num = REGION_NUM_RECTS(pReg);
    BoxPtr		pbox = REGION_RECTS(pReg);
    int			width, height;
    CARD8		*src;
    CARD16		*dst, *dst_base;
    int			dst_stride;
    register CARD32	val;
    register CARD32	*cmap = pCmapPriv->cmap;
    register CARD8      *s;
    register CARD16     *d;
    int w;

    dst_base = (CARD16*) ((PixmapPtr)pScreen->devPrivate)->devPrivate.ptr;
    dst_stride = (int)((PixmapPtr)pScreen->devPrivate)->devKind
	/ sizeof (CARD16);

    while (num--) {

	height = pbox->y2 - pbox->y1;
	width = pbox->x2 - pbox->x1;
	
	src = (unsigned char *) pScrPriv->pBits
	    + (pbox->y1 * pScreen->width) + pbox->x1;
	dst = dst_base + (pbox->y1 * dst_stride) + pbox->x1;
	while (height--) {
	    w = width;
	    s = src;
	    d = dst;
	    while(w--) {
		val = *(cmap + ((*(s++)) & mask));
      		if (val & MARK_DIRTY) {
		    *d = (CARD16) val;
		}
		d++;
	    }
	    src += pScreen->width;
	    dst += dst_stride;
	}
	pbox++;
    }
}

static void
xxGetWindowRegion(WindowPtr pWin,RegionPtr winreg)
{
    REGION_NULL(pWin->drawable.pScreen,winreg);
    /* get visible part of the border ...Argh */
    REGION_SUBTRACT(pWin->drawable.pScreen,winreg,&pWin->borderSize,
		    &pWin->winSize);
    REGION_INTERSECT(pWin->drawable.pScreen,winreg,winreg,
		     &pWin->borderClip);
    /* add window interior excluding children */
    REGION_UNION(pWin->drawable.pScreen,winreg,winreg,
		 &pWin->clipList);
}

static int
xxUpdateRegion(WindowPtr pWin, pointer unused)
{
    ScreenPtr pScreen = pWin->drawable.pScreen;
    xxScrPriv(pScreen);
    ColormapPtr pmap = (pointer) -1;
    RegionRec		winreg, rgni;
    
    if (pScrPriv->myDepth == pWin->drawable.depth) {
	xxCmapPrivPtr pCmapPriv = (pointer)-1;
	xxGetWindowRegion(pWin,&winreg);

	if (pScrPriv->colormapDirty) {

	    pmap = (ColormapPtr)LookupIDByType(wColormap(pWin),RT_COLORMAP);
	    if (!pmap)
		goto CONTINUE; /* return ? */

	    pCmapPriv = xxGetCmapPriv(pmap);
	    if (pCmapPriv == (pointer) -1)
		return WT_WALKCHILDREN;
	    if (!pCmapPriv->dirty)
		goto CONTINUE;

	    REGION_NULL (pScreen, &rgni);
	    /* This will be taken care of when damaged regions are updated */
	    REGION_SUBTRACT(pScreen, &rgni, &winreg, &pScrPriv->region);
	    if (REGION_NOTEMPTY (pScreen,&rgni))
		xxUpdateCmapPseudocolorRegion(pScreen,&rgni, pCmapPriv);
	}
    CONTINUE:

	REGION_NULL (pScreen, &rgni);
	REGION_INTERSECT (pScreen, &rgni, &winreg, &pScrPriv->region);
	
	if (REGION_NOTEMPTY (pScreen,&rgni)) {
	    if (pmap == (pointer) -1) {
		pmap =
		    (ColormapPtr)LookupIDByType(wColormap(pWin),RT_COLORMAP);
		if (!pmap) /* return ? */
		    pmap = (ColormapPtr)LookupIDByType(pScreen->defColormap,
						       RT_COLORMAP);
		pCmapPriv = xxGetCmapPriv(pmap);
	    }
	    
	    if (pCmapPriv != (pointer)-1)
		xxCopyPseudocolorRegion(pScreen,&rgni, pCmapPriv);
	    REGION_SUBTRACT(pScreen, &pScrPriv->region, &pScrPriv->region,
			    &rgni);
	}
#if 1
	REGION_UNINIT(pScreen,&rgni);
	REGION_UNINIT(pScreen,&winreg);
#endif
    }
    return WT_WALKCHILDREN;
}


static void
xxUpdateFb(ScreenPtr pScreen)
{
    xxScrPriv(pScreen);

    DBG("Update FB\n");
    PRINT_RECTS(pScrPriv->region);

    if (pScrPriv->sync)
	pScrPriv->sync(pScreen); /*@!@*/
    
    WalkTree(pScreen,xxUpdateRegion,NULL);
#if 0
    if (REGION_NOTEMPTY (pScreen,&pScrPriv->region)) {
	ColormapPtr pmap = (pointer) -1;
	xxCmapPrivPtr pCmapPriv;
	
	pmap = (ColormapPtr)LookupIDByType(pScreen->defColormap,
					   RT_COLORMAP);
	pCmapPriv = xxGetCmapPriv(pmap);
	if (pCmapPriv != (pointer)-1)
	    xxCopyPseudocolorRegion(pScreen,&pScrPriv->region, pCmapPriv);
	REGION_SUBTRACT(pScreen, &pScrPriv->region, &pScrPriv->region,
			&pScrPriv->region);
    }
#endif
    if (pScrPriv->colormapDirty) {
	xxCmapPrivPtr pCmap = pScrPriv->Cmaps;

	while (pCmap) {
	    int j;

	    if (pCmap->dirty) {
		for (j = 0; j < (1 <<  pScrPriv->myDepth); j++) 
		    pCmap->cmap[j] &= ~MARK_DIRTY;
		pCmap->dirty = FALSE;
	    }
	    pCmap = pCmap->next;
	}
	pScrPriv->colormapDirty = FALSE;
    }
}

static void
xxBlockHandler (pointer	data,
		OSTimePtr pTimeout,
		pointer pRead)
{
    ScreenPtr	pScreen = (ScreenPtr) data;
    xxScrPriv(pScreen);

    if (REGION_NOTEMPTY (pScreen,&pScrPriv->region) || pScrPriv->colormapDirty)
	xxUpdateFb (pScreen);
}

static void
xxWakeupHandler (pointer data, int i, pointer LastSelectMask)
{
}

Bool
xxSetup(ScreenPtr pScreen, int myDepth, int baseDepth, char* addr, xxSyncFunc sync)
{
    xxScrPrivPtr	pScrPriv;
    DepthPtr		pDepths;
    ColormapPtr		pDefMap;
    int i,j,k;
    
#ifdef RENDER
    PictureScreenPtr	ps = GetPictureScreenIfSet(pScreen);
#endif

    if (xxGeneration != serverGeneration) {
	xxScrPrivateIndex = AllocateScreenPrivateIndex ();
	if (xxScrPrivateIndex == -1)
	    return FALSE;
	xxColormapPrivateIndex
	    = AllocateColormapPrivateIndex (xxInitColormapDummy);
	if (xxColormapPrivateIndex == -1)
	    return FALSE;
	xxGCPrivateIndex = AllocateGCPrivateIndex ();
	if (xxGCPrivateIndex == -1)
	    return FALSE;
	xxGeneration = serverGeneration;
    }

    if (!AllocateGCPrivate (pScreen, xxGCPrivateIndex, sizeof (xxGCPrivRec)))
	return FALSE;

    pScrPriv = (xxScrPrivPtr) xalloc (sizeof (xxScrPrivRec));
    if (!pScrPriv)
	return FALSE;
    
    if (baseDepth)
	pScrPriv->depth = baseDepth;
    else {
	pDepths = pScreen->allowedDepths;
        for (i = 0; i < pScreen->numDepths; i++, pDepths++)
	    if (pDepths->depth != myDepth)
		pScrPriv->depth = pDepths->depth;
    }
    if (!pScrPriv->depth)
	return FALSE;
    
    pDepths = pScreen->allowedDepths;
    for (i = 0; i < pScreen->numDepths; i++, pDepths++)
	if (pDepths->depth == pScrPriv->depth) {
	    for (j = 0; i < pDepths->numVids; j++) {
		for (k = 0; k < pScreen->numVisuals; k++) {
		    if (pScreen->visuals[k].vid
			== pDepths[i].vids[j]
			&& pScreen->visuals[k].class == TrueColor) {
			pScrPriv->bVisual =  &pScreen->visuals[k];
			goto DONE;
		    }
		}
	    }
	}
    
 DONE:
    if (!pScrPriv->bVisual)
	return FALSE;

    pScrPriv->myDepth = myDepth;
    pScrPriv->numInstalledColormaps = 0;
    pScrPriv->colormapDirty = FALSE;
    pScrPriv->Cmaps = NULL;
    pScrPriv->sync = sync;
    
    pScreen->maxInstalledCmaps += MAX_NUM_XX_INSTALLED_CMAPS;
    pScrPriv->InstalledCmaps = xcalloc(MAX_NUM_XX_INSTALLED_CMAPS,
				       sizeof(ColormapPtr));
    if (!pScrPriv->InstalledCmaps)
	return FALSE;

    
    if (!RegisterBlockAndWakeupHandlers (xxBlockHandler,
					 xxWakeupHandler,
					 (pointer) pScreen))
	return FALSE;

    wrap (pScrPriv, pScreen, CloseScreen, xxCloseScreen);
    wrap (pScrPriv, pScreen, CreateScreenResources, xxCreateScreenResources);
    wrap (pScrPriv, pScreen, CreateWindow, xxCreateWindow);
    wrap (pScrPriv, pScreen, CopyWindow, xxCopyWindow);
    wrap (pScrPriv, pScreen, PaintWindowBorder, xxPaintWindow);
    wrap (pScrPriv, pScreen, PaintWindowBackground, xxPaintWindow);
#if 0 /* can we leave this out even with backing store enabled ? */
    wrap (pScrPriv, pScreen, WindowExposures, xxWindowExposures);
#endif
    wrap (pScrPriv, pScreen, CreateGC, xxCreateGC);
    wrap (pScrPriv, pScreen, CreateColormap, xxCreateColormap);
    wrap (pScrPriv, pScreen, DestroyColormap, xxDestroyColormap);
    wrap (pScrPriv, pScreen, InstallColormap, xxInstallColormap);
    wrap (pScrPriv, pScreen, UninstallColormap, xxUninstallColormap);
    wrap (pScrPriv, pScreen, ListInstalledColormaps, xxListInstalledColormaps);
    wrap (pScrPriv, pScreen, StoreColors, xxStoreColors);
#ifdef RENDER
    if (ps) {
	wrap (pScrPriv, ps, Glyphs, xxGlyphs);
	wrap (pScrPriv, ps, Composite, xxComposite);
    }
#endif
    pScrPriv->addr = addr;
    pScreen->devPrivates[xxScrPrivateIndex].ptr = (pointer) pScrPriv;

    pDefMap = (ColormapPtr) LookupIDByType(pScreen->defColormap, RT_COLORMAP);
    if (!xxInitColormapPrivate(pDefMap))
	return FALSE;
    
    return TRUE;
}

GCFuncs xxGCFuncs = {
    xxValidateGC, xxChangeGC, xxCopyGC, xxDestroyGC,
    xxChangeClip, xxDestroyClip, xxCopyClip
};

GCOps xxGCOps = {
    xxFillSpans, xxSetSpans, 
    xxPutImage, xxCopyArea, 
    xxCopyPlane, xxPolyPoint, 
    xxPolylines, xxPolySegment, 
    xxPolyRectangle, xxPolyArc, 
    xxFillPolygon, xxPolyFillRect, 
    xxPolyFillArc, xxPolyText8, 
    xxPolyText16, xxImageText8, 
    xxImageText16, xxImageGlyphBlt, 
    xxPolyGlyphBlt, xxPushPixels,
#ifdef NEED_LINEHELPER
    NULL,
#endif
    {NULL}		/* devPrivate */
};

#define IS_VISIBLE(pDraw) (pDraw->type == DRAWABLE_WINDOW \
	   && (fbGetWindowPixmap((WindowPtr) pDraw) == pScrPriv->pPixmap))

#define TRANSLATE_BOX(box, pDraw) { \
    box.x1 += pDraw->x; \
    box.x2 += pDraw->x; \
    box.y1 += pDraw->y; \
    box.y2 += pDraw->y; \
    }

#define TRIM_BOX(box, pGC) { \
    BoxPtr extents = &pGC->pCompositeClip->extents;\
    if(box.x1 < extents->x1) box.x1 = extents->x1; \
    if(box.x2 > extents->x2) box.x2 = extents->x2; \
    if(box.y1 < extents->y1) box.y1 = extents->y1; \
    if(box.y2 > extents->y2) box.y2 = extents->y2; \
    }

#define BOX_NOT_EMPTY(box) \
    (((box.x2 - box.x1) > 0) && ((box.y2 - box.y1) > 0))


#define _ADD_BOX(box,pGC) {\
    if (BOX_NOT_EMPTY(box)) { \
       RegionRec region; \
       ScreenPtr pScreen = pGC->pScreen;\
       REGION_INIT (pScreen, &region, &box, 1); \
       REGION_INTERSECT(pScreen,&region,&region,\
                                 (pGC)->pCompositeClip);\
       if (REGION_NOTEMPTY(pScreen,&region)) { \
           xxScrPriv(pScreen);\
	   PRINT_RECTS(pScrPriv->region);\
           REGION_UNION(pScreen,&pScrPriv->region,&pScrPriv->region,&region);\
	   PRINT_RECTS(pScrPriv->region);\
           REGION_UNINIT(pScreen,&region);\
       }\
   }\
}

#define TRANSLATE_AND_ADD_BOX(box,pGC) {\
         TRANSLATE_BOX(box,pDraw); \
         TRIM_BOX(box,pGC); \
         _ADD_BOX(box,pGC); \
}

#define ADD_BOX(box,pGC) { \
        TRIM_BOX(box,pGC); \
        _ADD_BOX(box,pGC); \
}

#define XX_GC_FUNC_PROLOGUE(pGC) \
    xxGCPriv(pGC); \
    unwrap(pGCPriv, pGC, funcs); \
    if (pGCPriv->ops) unwrap(pGCPriv, pGC, ops)

#define XX_GC_FUNC_EPILOGUE(pGC) \
    wrap(pGCPriv, pGC, funcs, &xxGCFuncs);  \
    if (pGCPriv->ops) wrap(pGCPriv, pGC, ops, &xxGCOps)

static Bool
xxCreateGC(GCPtr pGC)
{
    ScreenPtr		pScreen = pGC->pScreen;
    xxScrPriv(pScreen);
    xxGCPriv(pGC);
    Bool ret;

    unwrap (pScrPriv, pScreen, CreateGC);
    if((ret = (*pScreen->CreateGC) (pGC))) {
	pGCPriv->ops = NULL;
	pGCPriv->funcs = pGC->funcs;
	pGC->funcs = &xxGCFuncs;
    }
    wrap (pScrPriv, pScreen, CreateGC, xxCreateGC);

    return ret;
}

static void
xxValidateGC(
   GCPtr         pGC,
   unsigned long changes,
   DrawablePtr   pDraw 
){
    XX_GC_FUNC_PROLOGUE (pGC);
    (*pGC->funcs->ValidateGC)(pGC, changes, pDraw);
    if(pDraw->type == DRAWABLE_WINDOW)
	pGCPriv->ops = pGC->ops;  /* just so it's not NULL */
    else 
	pGCPriv->ops = NULL;
    XX_GC_FUNC_EPILOGUE (pGC);
}

static void
xxDestroyGC(GCPtr pGC)
{
    XX_GC_FUNC_PROLOGUE (pGC);
    (*pGC->funcs->DestroyGC)(pGC);
    XX_GC_FUNC_EPILOGUE (pGC);
}

static void
xxChangeGC (
    GCPtr	    pGC,
    unsigned long   mask
){
    XX_GC_FUNC_PROLOGUE (pGC);
    (*pGC->funcs->ChangeGC) (pGC, mask);
    XX_GC_FUNC_EPILOGUE (pGC);
}

static void
xxCopyGC (
    GCPtr	    pGCSrc, 
    unsigned long   mask,
    GCPtr	    pGCDst
){
    XX_GC_FUNC_PROLOGUE (pGCDst);
    (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
    XX_GC_FUNC_EPILOGUE (pGCDst);
}

static void
xxChangeClip (
    GCPtr   pGC,
    int		type,
    pointer	pvalue,
    int		nrects 
){
    XX_GC_FUNC_PROLOGUE (pGC);
    (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
    XX_GC_FUNC_EPILOGUE (pGC);
}

static void
xxCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
{
    XX_GC_FUNC_PROLOGUE (pgcDst);
    (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
    XX_GC_FUNC_EPILOGUE (pgcDst);
}

static void
xxDestroyClip(GCPtr pGC)
{
    XX_GC_FUNC_PROLOGUE (pGC);
    (* pGC->funcs->DestroyClip)(pGC);
    XX_GC_FUNC_EPILOGUE (pGC);
}

#define XX_GC_OP_PROLOGUE(pGC,pDraw) \
    xxScrPriv(pDraw->pScreen); \
    xxGCPriv(pGC);  \
    GCFuncs *oldFuncs = pGC->funcs; \
    unwrap(pGCPriv, pGC, funcs);  \
    unwrap(pGCPriv, pGC, ops); \
	
#define XX_GC_OP_EPILOGUE(pGC,pDraw) \
    wrap(pGCPriv, pGC, funcs, oldFuncs); \
    wrap(pGCPriv, pGC, ops, &xxGCOps)

static void
xxFillSpans(
    DrawablePtr pDraw,
    GC		*pGC,
    int		nInit,	
    DDXPointPtr pptInit,	
    int 	*pwidthInit,		
    int 	fSorted 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);    

    if(IS_VISIBLE(pDraw) && nInit) {
	DDXPointPtr ppt = pptInit;
	int *pwidth = pwidthInit;
	int i = nInit;
	BoxRec box;

	DBG("FillSpans\n");
	box.x1 = ppt->x;
	box.x2 = box.x1 + *pwidth;
	box.y2 = box.y1 = ppt->y;

	while(--i) {
	   ppt++;
	   pwidthInit++;
	   if(box.x1 > ppt->x) box.x1 = ppt->x;
	   if(box.x2 < (ppt->x + *pwidth)) 
		box.x2 = ppt->x + *pwidth;
	   if(box.y1 > ppt->y) box.y1 = ppt->y;
	   else if(box.y2 < ppt->y) box.y2 = ppt->y;
	}

	box.y2++;

	(*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted);

	
	TRANSLATE_AND_ADD_BOX(box, pGC);
    } else
	(*pGC->ops->FillSpans)(pDraw, pGC, nInit, pptInit, pwidthInit, fSorted);

    XX_GC_OP_EPILOGUE(pGC, pDraw);
}

static void
xxSetSpans(
    DrawablePtr		pDraw,
    GCPtr		pGC,
    char		*pcharsrc,
    DDXPointPtr 	pptInit,
    int			*pwidthInit,
    int			nspans,
    int			fSorted 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && nspans) {
	DDXPointPtr ppt = pptInit;
	int *pwidth = pwidthInit;
	int i = nspans;
	BoxRec box;

	DBG("SetSpans\n");
	box.x1 = ppt->x;
	box.x2 = box.x1 + *pwidth;
	box.y2 = box.y1 = ppt->y;

	while(--i) {
	   ppt++;
	   pwidth++;
	   if(box.x1 > ppt->x) box.x1 = ppt->x;
	   if(box.x2 < (ppt->x + *pwidth)) 
		box.x2 = ppt->x + *pwidth;
	   if(box.y1 > ppt->y) box.y1 = ppt->y;
	   else if(box.y2 < ppt->y) box.y2 = ppt->y;
	}

	box.y2++;

	(*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, 
				pwidthInit, nspans, fSorted);

	TRANSLATE_AND_ADD_BOX(box, pGC);
    } else
	(*pGC->ops->SetSpans)(pDraw, pGC, pcharsrc, pptInit, 
				pwidthInit, nspans, fSorted);

    XX_GC_OP_EPILOGUE(pGC, pDraw);
}

static void
xxPutImage(
    DrawablePtr pDraw,
    GCPtr	pGC,
    int		depth, 
    int x, int y, int w, int h,
    int		leftPad,
    int		format,
    char 	*pImage 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PutImage)(pDraw, pGC, depth, x, y, w, h, 
		leftPad, format, pImage);
    XX_GC_OP_EPILOGUE(pGC, pDraw);
    if(IS_VISIBLE(pDraw)) {
	BoxRec box;

	DBG("PutImage\n");
	box.x1 = x + pDraw->x;
	box.x2 = box.x1 + w;
	box.y1 = y + pDraw->y;
	box.y2 = box.y1 + h;

	ADD_BOX(box, pGC);
    }
}

static RegionPtr
xxCopyArea(
    DrawablePtr pSrc,
    DrawablePtr pDst,
    GC *pGC,
    int srcx, int srcy,
    int width, int height,
    int dstx, int dsty 
){
    RegionPtr ret;
    XX_GC_OP_PROLOGUE(pGC, pDst);
    DBG("xxCopyArea\n");
    ret = (*pGC->ops->CopyArea)(pSrc, pDst,
            pGC, srcx, srcy, width, height, dstx, dsty);
    XX_GC_OP_EPILOGUE(pGC, pDst);

    if(IS_VISIBLE(pDst)) {
	BoxRec box;

	DBG("CopyArea\n");
	box.x1 = dstx + pDst->x;
	box.x2 = box.x1 + width;
	box.y1 = dsty + pDst->y;
	box.y2 = box.y1 + height;

	ADD_BOX(box, pGC);
    }

    return ret;
}

static RegionPtr
xxCopyPlane(
    DrawablePtr	pSrc,
    DrawablePtr	pDst,
    GCPtr pGC,
    int	srcx, int srcy,
    int	width, int height,
    int	dstx, int dsty,
    unsigned long bitPlane 
){
    RegionPtr ret;
    XX_GC_OP_PROLOGUE(pGC, pDst);
    ret = (*pGC->ops->CopyPlane)(pSrc, pDst,
	       pGC, srcx, srcy, width, height, dstx, dsty, bitPlane);
    XX_GC_OP_EPILOGUE(pGC, pDst);

    if(IS_VISIBLE(pDst)) {
	BoxRec box;

	DBG("CopyPlane\n");
	box.x1 = dstx + pDst->x;
	box.x2 = box.x1 + width;
	box.y1 = dsty + pDst->y;
	box.y2 = box.y1 + height;

	ADD_BOX(box, pGC);
    }

    return ret;
}

static void
xxPolyPoint(
    DrawablePtr pDraw,
    GCPtr pGC,
    int mode,
    int npt,
    xPoint *pptInit 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PolyPoint)(pDraw, pGC, mode, npt, pptInit);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && npt) {
	BoxRec box;

	DBG("PolyPoint\n");
	box.x2 = box.x1 = pptInit->x;
	box.y2 = box.y1 = pptInit->y;

	/* this could be slow if the points were spread out */

	while(--npt) {
	   pptInit++;
	   if(box.x1 > pptInit->x) box.x1 = pptInit->x;
	   else if(box.x2 < pptInit->x) box.x2 = pptInit->x;
	   if(box.y1 > pptInit->y) box.y1 = pptInit->y;
	   else if(box.y2 < pptInit->y) box.y2 = pptInit->y;
	}

	box.x2++;
	box.y2++;

	TRANSLATE_AND_ADD_BOX(box, pGC);
    }
}

static void
xxPolylines(
    DrawablePtr pDraw,
    GCPtr	pGC,
    int		mode,		
    int		npt,		
    DDXPointPtr pptInit 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->Polylines)(pDraw, pGC, mode, npt, pptInit);
    XX_GC_OP_EPILOGUE(pGC, pDraw);


    if(IS_VISIBLE(pDraw) && npt) {
	BoxRec box;
	int extra = pGC->lineWidth >> 1;

	DBG("PolyLine\n");
	box.x2 = box.x1 = pptInit->x;
	box.y2 = box.y1 = pptInit->y;

	if(npt > 1) {
	   if(pGC->joinStyle == JoinMiter)
		extra = 6 * pGC->lineWidth;
	   else if(pGC->capStyle == CapProjecting)
		extra = pGC->lineWidth;
        }

	if(mode == CoordModePrevious) {
	   int x = box.x1;
	   int y = box.y1;
	   while(--npt) {
		pptInit++;
		x += pptInit->x;
		y += pptInit->y;
		if(box.x1 > x) box.x1 = x;
		else if(box.x2 < x) box.x2 = x;
		if(box.y1 > y) box.y1 = y;
		else if(box.y2 < y) box.y2 = y;
	    }
	} else {
	   while(--npt) {
		pptInit++;
		if(box.x1 > pptInit->x) box.x1 = pptInit->x;
		else if(box.x2 < pptInit->x) box.x2 = pptInit->x;
		if(box.y1 > pptInit->y) box.y1 = pptInit->y;
		else if(box.y2 < pptInit->y) box.y2 = pptInit->y;
	    }
	}

	box.x2++;
	box.y2++;

	if(extra) {
	   box.x1 -= extra;
	   box.x2 += extra;
	   box.y1 -= extra;
	   box.y2 += extra;
        }

	TRANSLATE_AND_ADD_BOX(box, pGC);
    }
}

static void 
xxPolySegment(
    DrawablePtr	pDraw,
    GCPtr	pGC,
    int		nseg,
    xSegment	*pSeg
    ){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PolySegment)(pDraw, pGC, nseg, pSeg);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && nseg) {
	BoxRec box;
	int extra = pGC->lineWidth;

	DBG("PolySegment\n");
        if(pGC->capStyle != CapProjecting)	
	   extra >>= 1;

	if(pSeg->x2 > pSeg->x1) {
	    box.x1 = pSeg->x1;
	    box.x2 = pSeg->x2;
	} else {
	    box.x2 = pSeg->x1;
	    box.x1 = pSeg->x2;
	}

	if(pSeg->y2 > pSeg->y1) {
	    box.y1 = pSeg->y1;
	    box.y2 = pSeg->y2;
	} else {
	    box.y2 = pSeg->y1;
	    box.y1 = pSeg->y2;
	}

	while(--nseg) {
	    pSeg++;
	    if(pSeg->x2 > pSeg->x1) {
		if(pSeg->x1 < box.x1) box.x1 = pSeg->x1;
		if(pSeg->x2 > box.x2) box.x2 = pSeg->x2;
	    } else {
		if(pSeg->x2 < box.x1) box.x1 = pSeg->x2;
		if(pSeg->x1 > box.x2) box.x2 = pSeg->x1;
	    }
	    if(pSeg->y2 > pSeg->y1) {
		if(pSeg->y1 < box.y1) box.y1 = pSeg->y1;
		if(pSeg->y2 > box.y2) box.y2 = pSeg->y2;
	    } else {
		if(pSeg->y2 < box.y1) box.y1 = pSeg->y2;
		if(pSeg->y1 > box.y2) box.y2 = pSeg->y1;
	    }
	}

	box.x2++;
	box.y2++;

	if(extra) {
	   box.x1 -= extra;
	   box.x2 += extra;
	   box.y1 -= extra;
	   box.y2 += extra;
        }
	
	TRANSLATE_AND_ADD_BOX(box, pGC);
    }
}

static void
xxPolyRectangle(
    DrawablePtr  pDraw,
    GCPtr        pGC,
    int	         nRects,
    xRectangle  *pRects 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PolyRectangle)(pDraw, pGC, nRects, pRects);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && nRects) 
    {
	BoxRec box;
	int offset1, offset2, offset3;

	DBG("PolyRectangle\n");
	offset2 = pGC->lineWidth;
	if(!offset2) offset2 = 1;
	offset1 = offset2 >> 1;
	offset3 = offset2 - offset1;

	while(nRects--) 
	{
	    box.x1 = pRects->x - offset1;
	    box.y1 = pRects->y - offset1;
	    box.x2 = box.x1 + pRects->width + offset2;
	    box.y2 = box.y1 + offset2;		
	    TRANSLATE_AND_ADD_BOX(box, pGC);
	    box.x1 = pRects->x - offset1;
	    box.y1 = pRects->y + offset3;
	    box.x2 = box.x1 + offset2;
	    box.y2 = box.y1 + pRects->height - offset2;		
	    TRANSLATE_AND_ADD_BOX(box, pGC);
	    box.x1 = pRects->x + pRects->width - offset1;
	    box.y1 = pRects->y + offset3;
	    box.x2 = box.x1 + offset2;
	    box.y2 = box.y1 + pRects->height - offset2;		
	    TRANSLATE_AND_ADD_BOX(box, pGC);
	    box.x1 = pRects->x - offset1;
	    box.y1 = pRects->y + pRects->height - offset1;
	    box.x2 = box.x1 + pRects->width + offset2;
	    box.y2 = box.y1 + offset2;		
	    TRANSLATE_AND_ADD_BOX(box, pGC);

	    pRects++;
	}
    }
}

static void
xxPolyArc(
    DrawablePtr	pDraw,
    GCPtr	pGC,
    int		narcs,
    xArc	*parcs 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PolyArc)(pDraw, pGC, narcs, parcs);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && narcs) {
	int extra = pGC->lineWidth >> 1;
	BoxRec box;

	DBG("PolyArc\n");
	box.x1 = parcs->x;
	box.x2 = box.x1 + parcs->width;
	box.y1 = parcs->y;
	box.y2 = box.y1 + parcs->height;

	/* should I break these up instead ? */

	while(--narcs) {
	   parcs++;
	   if(box.x1 > parcs->x) box.x1 = parcs->x;
	   if(box.x2 < (parcs->x + parcs->width))
		box.x2 = parcs->x + parcs->width;
	   if(box.y1 > parcs->y) box.y1 = parcs->y;
	   if(box.y2 < (parcs->y + parcs->height))
		box.y2 = parcs->y + parcs->height;
        }

	if(extra) {
	   box.x1 -= extra;
	   box.x2 += extra;
	   box.y1 -= extra;
	   box.y2 += extra;
        }

	box.x2++;
	box.y2++;

	TRANSLATE_AND_ADD_BOX(box, pGC);
    }
}

static void
xxFillPolygon(
    DrawablePtr	pDraw,
    GCPtr	pGC,
    int		shape,
    int		mode,
    int		count,
    DDXPointPtr	pptInit 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && (count > 2)) {
	DDXPointPtr ppt = pptInit;
	int i = count;
	BoxRec box;

	DBG("FillPolygon\n");
	box.x2 = box.x1 = ppt->x;
	box.y2 = box.y1 = ppt->y;

	if(mode != CoordModeOrigin) {
	   int x = box.x1;
	   int y = box.y1;
	   while(--i) {
		ppt++;
		x += ppt->x;
		y += ppt->y;
		if(box.x1 > x) box.x1 = x;
		else if(box.x2 < x) box.x2 = x;
		if(box.y1 > y) box.y1 = y;
		else if(box.y2 < y) box.y2 = y;
	    }
	} else {
	   while(--i) {
		ppt++;
		if(box.x1 > ppt->x) box.x1 = ppt->x;
		else if(box.x2 < ppt->x) box.x2 = ppt->x;
		if(box.y1 > ppt->y) box.y1 = ppt->y;
		else if(box.y2 < ppt->y) box.y2 = ppt->y;
	    }
	}

	box.x2++;
	box.y2++;

	(*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit);

	TRANSLATE_AND_ADD_BOX(box, pGC);
    } else
	(*pGC->ops->FillPolygon)(pDraw, pGC, shape, mode, count, pptInit);

    XX_GC_OP_EPILOGUE(pGC, pDraw);
}

static void 
xxPolyFillRect(
    DrawablePtr	pDraw,
    GCPtr	pGC,
    int		nRectsInit, 
    xRectangle	*pRectsInit 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && nRectsInit) {
	BoxRec box;
	xRectangle *pRects = pRectsInit;
	int nRects = nRectsInit;

	DBG("PolyFillRect\n");
	box.x1 = pRects->x;
	box.x2 = box.x1 + pRects->width;
	box.y1 = pRects->y;
	box.y2 = box.y1 + pRects->height;

	while(--nRects) {
	    pRects++;
	    if(box.x1 > pRects->x) box.x1 = pRects->x;
	    if(box.x2 < (pRects->x + pRects->width))
		box.x2 = pRects->x + pRects->width;
	    if(box.y1 > pRects->y) box.y1 = pRects->y;
	    if(box.y2 < (pRects->y + pRects->height))
		box.y2 = pRects->y + pRects->height;
	}

	/* cfb messes with the pRectsInit so we have to do our
	   calculations first */

	(*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit);

	TRANSLATE_AND_ADD_BOX(box, pGC);
    } else
	(*pGC->ops->PolyFillRect)(pDraw, pGC, nRectsInit, pRectsInit);

    XX_GC_OP_EPILOGUE(pGC, pDraw);
}

static void
xxPolyFillArc(
    DrawablePtr	pDraw,
    GCPtr	pGC,
    int		narcs,
    xArc	*parcs 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PolyFillArc)(pDraw, pGC, narcs, parcs);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && narcs) {
	BoxRec box;

	DBG("PolyFillArc\n");
	box.x1 = parcs->x;
	box.x2 = box.x1 + parcs->width;
	box.y1 = parcs->y;
	box.y2 = box.y1 + parcs->height;

	/* should I break these up instead ? */

	while(--narcs) {
	   parcs++;
	   if(box.x1 > parcs->x) box.x1 = parcs->x;
	   if(box.x2 < (parcs->x + parcs->width))
		box.x2 = parcs->x + parcs->width;
	   if(box.y1 > parcs->y) box.y1 = parcs->y;
	   if(box.y2 < (parcs->y + parcs->height))
		box.y2 = parcs->y + parcs->height;
        }

	TRANSLATE_AND_ADD_BOX(box, pGC);
    }
}

static int
xxPolyText8(
    DrawablePtr pDraw,
    GCPtr	pGC,
    int		x, 
    int 	y,
    int 	count,
    char	*chars 
){
    int width;

    XX_GC_OP_PROLOGUE(pGC, pDraw);
    width = (*pGC->ops->PolyText8)(pDraw, pGC, x, y, count, chars);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    width -= x;

    if(IS_VISIBLE(pDraw) && (width > 0)) {
	BoxRec box;

	DBG("PolyText8\n");
	/* ugh */
	box.x1 = pDraw->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
	box.x2 = pDraw->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);

	if(count > 1) {
	   if(width > 0) box.x2 += width;
	   else box.x1 += width;
	}

	box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent);
	box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent);

	ADD_BOX(box,  pGC);
    }

    return (width + x);
}

static int
xxPolyText16(
    DrawablePtr pDraw,
    GCPtr	pGC,
    int		x,
    int		y,
    int 	count,
    unsigned short *chars 
){
    int width;

    XX_GC_OP_PROLOGUE(pGC, pDraw);
    width = (*pGC->ops->PolyText16)(pDraw, pGC, x, y, count, chars);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    width -= x;

    if(IS_VISIBLE(pDraw) && (width > 0)) {
	BoxRec box;

	DBG("PolyText16\n");
	/* ugh */
	box.x1 = pDraw->x + x + FONTMINBOUNDS(pGC->font, leftSideBearing);
	box.x2 = pDraw->x + x + FONTMAXBOUNDS(pGC->font, rightSideBearing);

	if(count > 1) {
	   if(width > 0) box.x2 += width;
	   else box.x1 += width;
	}

	box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent);
	box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent);

	ADD_BOX(box, pGC);
    }

    return (width + x);
}

static void
xxImageText8(
    DrawablePtr pDraw,
    GCPtr	pGC,
    int		x, 
    int		y,
    int 	count,
    char	*chars 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->ImageText8)(pDraw, pGC, x, y, count, chars);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && count) {
	int top, bot, Min, Max;
	BoxRec box;

	DBG("ImageText8\n");
	top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
	bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));

	Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
	if(Min > 0) Min = 0;
	Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);	
	if(Max < 0) Max = 0;

	/* ugh */
	box.x1 = pDraw->x + x + Min +
		FONTMINBOUNDS(pGC->font, leftSideBearing);
	box.x2 = pDraw->x + x + Max + 
		FONTMAXBOUNDS(pGC->font, rightSideBearing);

	box.y1 = pDraw->y + y - top;
	box.y2 = pDraw->y + y + bot;

	ADD_BOX(box, pGC);
    }
}

static void
xxImageText16(
    DrawablePtr pDraw,
    GCPtr	pGC,
    int		x,
    int		y,
    int 	count,
    unsigned short *chars 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->ImageText16)(pDraw, pGC, x, y, count, chars);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && count) {
	int top, bot, Min, Max;
	BoxRec box;

	DBG("ImageText16\n");
	top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
	bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));

	Min = count * FONTMINBOUNDS(pGC->font, characterWidth);
	if(Min > 0) Min = 0;
	Max = count * FONTMAXBOUNDS(pGC->font, characterWidth);	
	if(Max < 0) Max = 0;

	/* ugh */
	box.x1 = pDraw->x + x + Min +
		FONTMINBOUNDS(pGC->font, leftSideBearing);
	box.x2 = pDraw->x + x + Max + 
		FONTMAXBOUNDS(pGC->font, rightSideBearing);

	box.y1 = pDraw->y + y - top;
	box.y2 = pDraw->y + y + bot;

	ADD_BOX(box, pGC);
    }
}

static void
xxImageGlyphBlt(
    DrawablePtr pDraw,
    GCPtr pGC,
    int x, int y,
    unsigned int nglyph,
    CharInfoPtr *ppci,
    pointer pglyphBase 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->ImageGlyphBlt)(pDraw, pGC, x, y, nglyph, 
					ppci, pglyphBase);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && nglyph) {
	int top, bot, width = 0;
	BoxRec box;

	DBG("ImageGlyphBlt\n");
	top = max(FONTMAXBOUNDS(pGC->font, ascent), FONTASCENT(pGC->font));
	bot = max(FONTMAXBOUNDS(pGC->font, descent), FONTDESCENT(pGC->font));

	box.x1 = ppci[0]->metrics.leftSideBearing;
	if(box.x1 > 0) box.x1 = 0;
	box.x2 = ppci[nglyph - 1]->metrics.rightSideBearing - 
		ppci[nglyph - 1]->metrics.characterWidth;
	if(box.x2 < 0) box.x2 = 0;

	box.x2 += pDraw->x + x;
	box.x1 += pDraw->x + x;
	   
	while(nglyph--) {
	    width += (*ppci)->metrics.characterWidth;
	    ppci++;
	}

	if(width > 0) 
	   box.x2 += width;
	else 
	   box.x1 += width;

	box.y1 = pDraw->y + y - top;
	box.y2 = pDraw->y + y + bot;

	ADD_BOX(box, pGC);
    }
}

static void
xxPolyGlyphBlt(
    DrawablePtr pDraw,
    GCPtr pGC,
    int x, int y,
    unsigned int nglyph,
    CharInfoPtr *ppci,
    pointer pglyphBase 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PolyGlyphBlt)(pDraw, pGC, x, y, nglyph, 
				ppci, pglyphBase);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw) && nglyph) {
	BoxRec box;

	DBG("PolyGlyphBlt\n");
	/* ugh */
	box.x1 = pDraw->x + x + ppci[0]->metrics.leftSideBearing;
	box.x2 = pDraw->x + x + ppci[nglyph - 1]->metrics.rightSideBearing;

	if(nglyph > 1) {
	    int width = 0;

	    while(--nglyph) { 
		width += (*ppci)->metrics.characterWidth;
		ppci++;
	    }
	
	    if(width > 0) box.x2 += width;
	    else box.x1 += width;
	}

	box.y1 = pDraw->y + y - FONTMAXBOUNDS(pGC->font, ascent);
	box.y2 = pDraw->y + y + FONTMAXBOUNDS(pGC->font, descent);

	ADD_BOX(box, pGC);
    }
}

static void
xxPushPixels(
    GCPtr	pGC,
    PixmapPtr	pBitMap,
    DrawablePtr pDraw,
    int	dx, int dy, int xOrg, int yOrg 
){
    XX_GC_OP_PROLOGUE(pGC, pDraw);
    (*pGC->ops->PushPixels)(pGC, pBitMap, pDraw, dx, dy, xOrg, yOrg);
    XX_GC_OP_EPILOGUE(pGC, pDraw);

    if(IS_VISIBLE(pDraw)) {
	BoxRec box;

	DBG("PushPixels\n");
	box.x1 = xOrg + pDraw->x;
	box.x2 = box.x1 + dx;
	box.y1 = yOrg + pDraw->y;
	box.y2 = box.y1 + dy;

	ADD_BOX(box, pGC);
    }
}


#ifdef RENDER
#define RENDER_MAKE_BOX(pDrawable,X,Y,W,H) { \
    box.x1 = X + pDrawable->x; \
    box.x2 = X + pDrawable->x + W; \
    box.y1 = Y + pDrawable->y; \
    box.y2 = Y + pDrawable->y + H; \
}

#define RENDER_ADD_BOX(pScreen,box) {\
    if (BOX_NOT_EMPTY(box)) { \
       RegionRec region; \
       xxScrPriv(pScreen);\
       ScreenPtr pScreen = pScreen;\
       REGION_INIT (pScreen, &region, &box, 1); \
       PRINT_RECTS(pScrPriv->region);\
       REGION_UNION(pScreen,&pScrPriv->region,&pScrPriv->region,&region);\
       PRINT_RECTS(pScrPriv->region);\
       REGION_UNINIT(pScreen,&region);\
   }\
}

static void
xxComposite (CARD8 op, PicturePtr pSrc, PicturePtr pMask, PicturePtr pDst,
	     INT16 xSrc, INT16 ySrc, INT16 xMask, INT16 yMask,
    INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
{
    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
    PictureScreenPtr	ps = GetPictureScreen(pScreen);
    xxScrPriv(pScreen);
    BoxRec		box;

    unwrap (pScrPriv, ps, Composite);
    (*ps->Composite) (op, pSrc, pMask, pDst, xSrc, ySrc, xMask, yMask,
		      xDst, yDst, width, height);
    wrap (pScrPriv, ps, Composite, xxComposite);
    if (pDst->pDrawable->type == DRAWABLE_WINDOW) {
	RENDER_MAKE_BOX(pDst->pDrawable, xDst, yDst, width, height);
	RENDER_ADD_BOX(pScreen,box);
    }
}


static void
xxGlyphs (CARD8 op, PicturePtr pSrc, PicturePtr pDst,
	  PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, int nlist,
	  GlyphListPtr list, GlyphPtr *glyphs)
{
    ScreenPtr		pScreen = pDst->pDrawable->pScreen;
    PictureScreenPtr	ps = GetPictureScreen(pScreen);
    xxScrPriv(pScreen);
    int			x, y;
    int			n;
    GlyphPtr		glyph;
    BoxRec		box;

    unwrap (pScrPriv, ps, Glyphs);
    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc,
		   nlist, list, glyphs);
    wrap (pScrPriv, ps, Glyphs, xxGlyphs);
    if (pDst->pDrawable->type == DRAWABLE_WINDOW)
    {
	x = xSrc;
	y = ySrc;
	while (nlist--)
	{
	    x += list->xOff;
	    y += list->yOff;
	    n = list->len;
	    while (n--)
	    {
		glyph = *glyphs++;
		RENDER_MAKE_BOX(pDst->pDrawable,
				x - glyph->info.x, y - glyph->info.y,
				glyph->info.width, glyph->info.height);
		RENDER_ADD_BOX(pScreen,box);
		x += glyph->info.xOff;
		y += glyph->info.yOff;
	    }
	    list++;
	}
    }
}
#endif

void
xxPrintVisuals(void)
{
    int k,i,j;
    DepthPtr pDepth;
    VisualPtr pVisual;

    for (k = 0; k < screenInfo.numScreens; k++) {
	ScreenPtr pScreen = screenInfo.screens[k];
	
	pDepth = pScreen->allowedDepths;
	for (i = 0; i < pScreen->numDepths; i++, pDepth++)
	    for (j = 0; j < pDepth->numVids; j++) {
		ErrorF("depth: %i vid: 0x%lx\n",
		       pDepth->depth, pDepth->vids[j]);
	    }
	
	pVisual = pScreen->visuals;
	for (i = 0; i < pScreen->numVisuals; i++, pVisual++)
	    ErrorF("vid: 0x%x rm: 0x%lx gm: 0x%lx bm: 0x%lx\n",
		   (unsigned int)pVisual->vid,
		   pVisual->redMask,
		   pVisual->greenMask,
		   pVisual->blueMask);
    }
}


