summaryrefslogtreecommitdiff
path: root/mi
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:57 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:57 +0000
commit9508a382f8a9f241dab097d921b6d290c1c3a776 (patch)
treefa456480bae7040c3f971a70b390f2d091c680b5 /mi
parentded6147bfb5d75ff1e67c858040a628b61bc17d1 (diff)
Initial revision
Diffstat (limited to 'mi')
-rw-r--r--mi/mibank.c2573
-rw-r--r--mi/mibank.h119
-rw-r--r--mi/micmap.c674
-rw-r--r--mi/micmap.h65
-rw-r--r--mi/micoord.h71
-rw-r--r--mi/mioverlay.c2078
-rw-r--r--mi/mioverlay.h29
-rw-r--r--mi/mizerclip.c632
8 files changed, 6241 insertions, 0 deletions
diff --git a/mi/mibank.c b/mi/mibank.c
new file mode 100644
index 000000000..a6e1942c2
--- /dev/null
+++ b/mi/mibank.c
@@ -0,0 +1,2573 @@
+/*
+ * Copyright 1997 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Copyright 1990,91,92,93 by Thomas Roell, Germany.
+ * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation, and that the name of Thomas Roell nor
+ * SGCS be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ * Thomas Roell nor SGCS makes no representations about the suitability
+ * of this software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ *
+ * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $XFree86: xc/programs/Xserver/mi/mibank.c,v 1.13 2003/01/01 19:16:42 tsi Exp $ */
+
+/*
+ * This thing originated from an idea of Edwin Goei and his bank switching
+ * code for the DEC TX board.
+ */
+
+/*
+ * Heavily modified for the XFree86 Project to turn this into an mi wrapper.
+ * --- Marc Aurele La France (tsi@xfree86.org)
+ */
+
+/*
+ * "Heavily modified", indeed! By the time this is finalized, there probably
+ * won't be much left of Roell's code...
+ *
+ * Miscellaneous notes:
+ * - Pixels with imbedded bank boundaries are required to be off-screen. There
+ * >might< be a way to fool the underlying framebuffer into dealing with
+ * partial pixels.
+ * - Plans to generalise this to do (hardware) colour plane switching have been
+ * dropped due to colour flashing concerns.
+ *
+ * TODO:
+ * - Allow miModifyBanking() to change BankSize and nBankDepth.
+ * - Re-instate shared and double banking for framebuffers whose pixmap formats
+ * don't describe how the server "sees" the screen.
+ * - Remove remaining assumptions that a pixmap's devPrivate field points
+ * directly to its pixel data.
+ */
+
+/* #define NO_ALLOCA 1 */
+
+#include "servermd.h"
+#include "gcstruct.h"
+#include "pixmapstr.h"
+#include "scrnintstr.h"
+#include "windowstr.h"
+#include "mi.h"
+#include "mibank.h"
+
+#define BANK_SINGLE 0
+#define BANK_SHARED 1
+#define BANK_DOUBLE 2
+#define BANK_NOBANK 3
+
+typedef struct _miBankScreen
+{
+ miBankInfoRec BankInfo;
+ unsigned int nBankBPP;
+ unsigned int type;
+
+ unsigned long nBitsPerBank;
+ unsigned long nBitsPerScanline;
+ unsigned long nPixelsPerScanlinePadUnit;
+
+ PixmapPtr pScreenPixmap;
+ PixmapPtr pBankPixmap;
+ GCPtr pBankGC;
+
+ int nBanks, maxRects;
+ RegionPtr *pBanks;
+
+ pointer pbits;
+
+ /*
+ * Screen Wrappers
+ */
+ CreateScreenResourcesProcPtr CreateScreenResources;
+ ModifyPixmapHeaderProcPtr ModifyPixmapHeader;
+ CloseScreenProcPtr CloseScreen;
+ GetImageProcPtr GetImage;
+ GetSpansProcPtr GetSpans;
+ CreateGCProcPtr CreateGC;
+ PaintWindowBackgroundProcPtr PaintWindowBackground;
+ PaintWindowBorderProcPtr PaintWindowBorder;
+ CopyWindowProcPtr CopyWindow;
+ BSFuncRec BackingStoreFuncs;
+} miBankScreenRec, *miBankScreenPtr;
+
+typedef struct _miBankGC
+{
+ GCOps *wrappedOps, *unwrappedOps;
+ GCFuncs *wrappedFuncs, *unwrappedFuncs;
+
+ Bool fastCopy, fastPlane;
+
+ RegionPtr pBankedClips[1];
+} miBankGCRec, *miBankGCPtr;
+
+typedef struct _miBankQueue
+{
+ Bool fastBlit;
+ unsigned short srcBankNo;
+ unsigned short dstBankNo;
+ short x;
+ short y;
+ short w;
+ short h;
+} miBankQueue;
+
+/*
+ * CAVEAT: This banking scheme requires that the DDX store Pixmap data in the
+ * server's address space.
+ */
+
+#define ModifyPixmap(_pPix, _width, _devKind, _pbits) \
+ (*pScreen->ModifyPixmapHeader)((_pPix), \
+ (_width), -1, -1, -1, (_devKind), (_pbits))
+
+#define SET_SINGLE_BANK(_pPix, _width, _devKind, _no) \
+ ModifyPixmap(_pPix, _width, _devKind, \
+ (char *)pScreenPriv->BankInfo.pBankA + \
+ (*pScreenPriv->BankInfo.SetSourceAndDestinationBanks)(pScreen, (_no)) - \
+ (pScreenPriv->BankInfo.BankSize * (_no)))
+
+#define SET_SOURCE_BANK(_pPix, _width, _devKind, _no) \
+ ModifyPixmap(_pPix, _width, _devKind, \
+ (char *)pScreenPriv->BankInfo.pBankA + \
+ (*pScreenPriv->BankInfo.SetSourceBank)(pScreen, (_no)) - \
+ (pScreenPriv->BankInfo.BankSize * (_no)))
+
+#define SET_DESTINATION_BANK(_pPix, _width, _devKind, _no) \
+ ModifyPixmap(_pPix, _width, _devKind, \
+ (char *)pScreenPriv->BankInfo.pBankB + \
+ (*pScreenPriv->BankInfo.SetDestinationBank)(pScreen, (_no)) - \
+ (pScreenPriv->BankInfo.BankSize * (_no)))
+
+#define ALLOCATE_LOCAL_ARRAY(atype, ntype) \
+ (atype *)ALLOCATE_LOCAL((ntype) * sizeof(atype))
+
+static int miBankScreenIndex;
+static int miBankGCIndex;
+static unsigned long miBankGeneration = 0;
+
+#define BANK_SCRPRIVLVAL pScreen->devPrivates[miBankScreenIndex].ptr
+
+#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL))
+
+#define BANK_GCPRIVLVAL(pGC) (pGC)->devPrivates[miBankGCIndex].ptr
+
+#define BANK_GCPRIVATE(pGC) ((miBankGCPtr)(BANK_GCPRIVLVAL(pGC)))
+
+#define PIXMAP_STATUS(_pPix) \
+ pointer pbits = (_pPix)->devPrivate.ptr
+
+#define PIXMAP_SAVE(_pPix) \
+ PIXMAP_STATUS(_pPix); \
+ if (pbits == (pointer)pScreenPriv) \
+ (_pPix)->devPrivate.ptr = pScreenPriv->pbits
+
+#define PIXMAP_RESTORE(_pPix) \
+ (_pPix)->devPrivate.ptr = pbits
+
+#define BANK_SAVE \
+ int width = pScreenPriv->pBankPixmap->drawable.width; \
+ int devKind = pScreenPriv->pBankPixmap->devKind; \
+ PIXMAP_SAVE(pScreenPriv->pBankPixmap)
+
+#define BANK_RESTORE \
+ pScreenPriv->pBankPixmap->drawable.width = width; \
+ pScreenPriv->pBankPixmap->devKind = devKind; \
+ PIXMAP_RESTORE(pScreenPriv->pBankPixmap)
+
+#define SCREEN_STATUS \
+ PIXMAP_STATUS(pScreenPriv->pScreenPixmap)
+
+#define SCREEN_SAVE \
+ PIXMAP_SAVE(pScreenPriv->pScreenPixmap)
+
+#define SCREEN_RESTORE \
+ PIXMAP_RESTORE(pScreenPriv->pScreenPixmap)
+
+#define SCREEN_INIT \
+ miBankScreenPtr pScreenPriv = BANK_SCRPRIVATE
+
+#define SCREEN_UNWRAP(field) \
+ pScreen->field = pScreenPriv->field
+
+#define SCREEN_WRAP(field, wrapper) \
+ pScreenPriv->field = pScreen->field; \
+ pScreen->field = wrapper
+
+#define GC_INIT(pGC) \
+ miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC)
+
+#define GC_UNWRAP(pGC) \
+ pGCPriv->unwrappedOps = (pGC)->ops; \
+ pGCPriv->unwrappedFuncs = (pGC)->funcs; \
+ (pGC)->ops = pGCPriv->wrappedOps; \
+ (pGC)->funcs = pGCPriv->wrappedFuncs
+
+#define GC_WRAP(pGC) \
+ pGCPriv->wrappedOps = (pGC)->ops; \
+ pGCPriv->wrappedFuncs = (pGC)->funcs; \
+ (pGC)->ops = pGCPriv->unwrappedOps; \
+ (pGC)->funcs = pGCPriv->unwrappedFuncs
+
+#define IS_BANKED(pDrawable) \
+ ((pbits == (pointer)pScreenPriv) && \
+ (((DrawablePtr)(pDrawable))->type == DRAWABLE_WINDOW))
+
+#define CLIP_SAVE \
+ RegionPtr pOrigCompositeClip = pGC->pCompositeClip
+
+#define CLIP_RESTORE \
+ pGC->pCompositeClip = pOrigCompositeClip
+
+#define GCOP_INIT \
+ ScreenPtr pScreen = pGC->pScreen; \
+ SCREEN_INIT; \
+ GC_INIT(pGC)
+
+#define GCOP_UNWRAP \
+ GC_UNWRAP(pGC)
+
+#define GCOP_WRAP \
+ GC_WRAP(pGC)
+
+#define GCOP_TOP_PART \
+ for (i = 0; i < pScreenPriv->nBanks; i++) \
+ { \
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) \
+ continue; \
+ GCOP_UNWRAP; \
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i)
+
+#define GCOP_BOTTOM_PART \
+ GCOP_WRAP; \
+ }
+
+#define GCOP_SIMPLE(statement) \
+ if (nArray > 0) \
+ { \
+ GCOP_INIT; \
+ SCREEN_SAVE; \
+ if (!IS_BANKED(pDrawable)) \
+ { \
+ GCOP_UNWRAP; \
+ statement; \
+ GCOP_WRAP; \
+ } \
+ else \
+ { \
+ int i; \
+ CLIP_SAVE; \
+ GCOP_TOP_PART; \
+ statement; \
+ GCOP_BOTTOM_PART; \
+ CLIP_RESTORE; \
+ } \
+ SCREEN_RESTORE; \
+ }
+
+#define GCOP_0D_ARGS mode,
+#define GCOP_1D_ARGS
+#define GCOP_2D_ARGS shape, mode,
+
+#define GCOP_COMPLEX(aop, atype) \
+ if (nArray > 0) \
+ { \
+ GCOP_INIT; \
+ SCREEN_SAVE; \
+ if (!IS_BANKED(pDrawable)) \
+ { \
+ GCOP_UNWRAP; \
+ (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, pArray); \
+ GCOP_WRAP; \
+ } \
+ else \
+ { \
+ atype *aarg = pArray, *acopy; \
+ int i; \
+ CLIP_SAVE; \
+ if ((acopy = ALLOCATE_LOCAL_ARRAY(atype, nArray))) \
+ aarg = acopy; \
+ GCOP_TOP_PART; \
+ if (acopy) \
+ memcpy(acopy, pArray, nArray * sizeof(atype)); \
+ (*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, aarg); \
+ GCOP_BOTTOM_PART; \
+ DEALLOCATE_LOCAL(acopy); \
+ CLIP_RESTORE; \
+ } \
+ SCREEN_RESTORE; \
+ }
+
+/*********************
+ * Utility functions *
+ *********************/
+
+static int
+miBankOf(
+ miBankScreenPtr pScreenPriv,
+ int x,
+ int y
+)
+{
+ int iBank = ((x * (int)pScreenPriv->nBankBPP) +
+ (y * (long)pScreenPriv->nBitsPerScanline)) /
+ (long)pScreenPriv->nBitsPerBank;
+
+ if (iBank < 0)
+ iBank = 0;
+ else if (iBank >= pScreenPriv->nBanks)
+ iBank = pScreenPriv->nBanks - 1;
+
+ return iBank;
+}
+
+#define FirstBankOf(_x, _y) miBankOf(pScreenPriv, (_x), (_y))
+#define LastBankOf(_x, _y) miBankOf(pScreenPriv, (_x) - 1, (_y))
+
+/* Determine banking type from the BankInfoRec */
+static unsigned int
+miBankDeriveType(
+ ScreenPtr pScreen,
+ miBankInfoPtr pBankInfo
+)
+{
+ unsigned int type;
+
+ if (pBankInfo->pBankA == pBankInfo->pBankB)
+ {
+ if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks !=
+ pBankInfo->SetSourceBank)
+ return BANK_NOBANK;
+
+ type = BANK_SINGLE;
+ }
+ else
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks ==
+ pBankInfo->SetDestinationBank)
+ return BANK_NOBANK;
+ if (pBankInfo->SetSourceAndDestinationBanks ==
+ pBankInfo->SetSourceBank)
+ return BANK_NOBANK;
+
+ type = BANK_SHARED;
+ }
+ }
+ else
+ {
+ if ((unsigned long)abs((char *)pBankInfo->pBankA -
+ (char *)pBankInfo->pBankB) < pBankInfo->BankSize)
+ return BANK_NOBANK;
+
+ if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks !=
+ pBankInfo->SetSourceBank)
+ return BANK_NOBANK;
+ }
+ else
+ {
+ if (pBankInfo->SetSourceAndDestinationBanks ==
+ pBankInfo->SetDestinationBank)
+ return BANK_NOBANK;
+ }
+
+ type = BANK_DOUBLE;
+ }
+
+ /*
+ * Internal limitation: Currently, only single banking is supported when
+ * the pixmap format and the screen's pixel format are different. The
+ * following test is only partially successful at detecting this condition.
+ */
+ if (pBankInfo->nBankDepth != pScreen->rootDepth)
+ type = BANK_SINGLE;
+
+ return type;
+}
+
+/* Least common multiple */
+static unsigned int
+miLCM(
+ unsigned int x,
+ unsigned int y
+)
+{
+ unsigned int m = x, n = y, o;
+
+ while ((o = m % n))
+ {
+ m = n;
+ n = o;
+ }
+
+ return (x / n) * y;
+}
+
+/******************
+ * GCOps wrappers *
+ ******************/
+
+static void
+miBankFillSpans(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ DDXPointPtr pptInit,
+ int *pwidthInit,
+ int fSorted
+)
+{
+ GCOP_SIMPLE((*pGC->ops->FillSpans)(pDrawable, pGC,
+ nArray, pptInit, pwidthInit, fSorted));
+}
+
+static void
+miBankSetSpans(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ char *psrc,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nArray,
+ int fSorted
+)
+{
+ GCOP_SIMPLE((*pGC->ops->SetSpans)(pDrawable, pGC, psrc,
+ ppt, pwidth, nArray, fSorted));
+}
+
+static void
+miBankPutImage(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int depth,
+ int x,
+ int y,
+ int w,
+ int h,
+ int leftPad,
+ int format,
+ char *pImage
+)
+{
+ if ((w > 0) && (h > 0))
+ {
+ GCOP_INIT;
+ SCREEN_SAVE;
+
+ if (!IS_BANKED(pDrawable))
+ {
+ GCOP_UNWRAP;
+
+ (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
+ leftPad, format, pImage);
+
+ GCOP_WRAP;
+ }
+ else
+ {
+ int i, j;
+
+ CLIP_SAVE;
+
+ i = FirstBankOf(x + pDrawable->x, y + pDrawable->y);
+ j = LastBankOf(x + pDrawable->x + w, y + pDrawable->y + h);
+ for (; i <= j; i++)
+ {
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
+ leftPad, format, pImage);
+
+ GCOP_WRAP;
+ }
+
+ CLIP_RESTORE;
+ }
+
+ SCREEN_RESTORE;
+ }
+}
+
+/*
+ * Here the CopyArea/CopyPlane wrappers. First off, we have to clip against
+ * the source in order to make the minimal number of copies in case of slow
+ * systems. Also the exposure handling is quite tricky. Special attention
+ * is to be given to the way the copies are sequenced. The list of boxes after
+ * the source clip is used to build a workqueue, that contains the atomic
+ * copies (i.e. only from one bank to one bank). Doing so produces a minimal
+ * list of things to do.
+ */
+static RegionPtr
+miBankCopy(
+ DrawablePtr pSrc,
+ DrawablePtr pDst,
+ GCPtr pGC,
+ int srcx,
+ int srcy,
+ int w,
+ int h,
+ int dstx,
+ int dsty,
+ unsigned long plane,
+ Bool SinglePlane
+)
+{
+ int cx1, cy1, cx2, cy2;
+ int ns, nd, nse, nde, dx, dy, xorg = 0, yorg = 0;
+ int maxWidth = 0, maxHeight = 0, paddedWidth = 0;
+ int nBox, nBoxClipSrc, nBoxClipDst, nQueue;
+ BoxPtr pBox, pBoxClipSrc, pBoxClipDst;
+ BoxRec fastBox, ccBox;
+ RegionPtr ret = NULL, prgnSrcClip = NULL;
+ RegionRec rgnDst;
+ char *pImage = NULL;
+ miBankQueue *pQueue, *pQueueNew, *Queue;
+ miBankQueue *pQueueTmp, *pQueueNext, *pQueueBase;
+ Bool fastBlit, freeSrcClip, fastClip;
+ Bool fExpose = FALSE, fastExpose = FALSE;
+
+ GCOP_INIT;
+ SCREEN_SAVE;
+
+ if (!IS_BANKED(pSrc) && !IS_BANKED(pDst))
+ {
+ GCOP_UNWRAP;
+
+ if (SinglePlane)
+ ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ srcx, srcy, w, h, dstx, dsty, plane);
+ else
+ ret = (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ srcx, srcy, w, h, dstx, dsty);
+
+ GCOP_WRAP;
+ }
+ else if (!IS_BANKED(pDst))
+ {
+ fExpose = pGC->fExpose;
+ pGC->fExpose = FALSE;
+
+ xorg = pSrc->x;
+ yorg = pSrc->y;
+ dx = dstx - srcx;
+ dy = dsty - srcy;
+ srcx += xorg;
+ srcy += yorg;
+
+ ns = FirstBankOf(srcx, srcy);
+ nse = LastBankOf(srcx + w, srcy + h);
+ for (; ns <= nse; ns++)
+ {
+ if (!pScreenPriv->pBanks[ns])
+ continue;
+
+ nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
+ pBox = REGION_RECTS(pScreenPriv->pBanks[ns]);
+
+ for (; nBox--; pBox++)
+ {
+ cx1 = max(pBox->x1, srcx);
+ cy1 = max(pBox->y1, srcy);
+ cx2 = min(pBox->x2, srcx + w);
+ cy2 = min(pBox->y2, srcy + h);
+
+ if ((cx1 >= cx2) || (cy1 >= cy2))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, ns);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ cx1 - xorg, cy1 - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 + dx - xorg, cy1 + dy - yorg, plane);
+ else
+ (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ cx1 - xorg, cy1 - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 + dx - xorg, cy1 + dy - yorg);
+
+ GCOP_WRAP;
+ }
+ }
+
+ pGC->fExpose = fExpose;
+ srcx -= xorg;
+ srcy -= yorg;
+ }
+ else if (!IS_BANKED(pSrc))
+ {
+ CLIP_SAVE;
+
+ if (pGC->miTranslate)
+ {
+ xorg = pDst->x;
+ yorg = pDst->y;
+ }
+ dx = srcx - dstx;
+ dy = srcy - dsty;
+ dstx += xorg;
+ dsty += yorg;
+
+ nd = FirstBankOf(dstx, dsty);
+ nde = LastBankOf(dstx + w, dsty + h);
+ for (; nd <= nde; nd++)
+ {
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[nd]))
+ continue;
+
+ /*
+ * It's faster to let the lower-level CopyArea do the clipping
+ * within each bank.
+ */
+ nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
+ pBox = REGION_RECTS(pScreenPriv->pBanks[nd]);
+
+ for (; nBox--; pBox++)
+ {
+ cx1 = max(pBox->x1, dstx);
+ cy1 = max(pBox->y1, dsty);
+ cx2 = min(pBox->x2, dstx + w);
+ cy2 = min(pBox->y2, dsty + h);
+
+ if ((cx1 >= cx2) || (cy1 >= cy2))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, nd);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ cx1 + dx - xorg, cy1 + dy - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 - xorg, cy1 - yorg, plane);
+ else
+ (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ cx1 + dx - xorg, cy1 + dy - yorg,
+ cx2 - cx1, cy2 - cy1,
+ cx1 - xorg, cy1 - yorg);
+
+ GCOP_WRAP;
+ }
+ }
+
+ CLIP_RESTORE;
+ }
+ else /* IS_BANKED(pSrc) && IS_BANKED(pDst) */
+ {
+ CLIP_SAVE;
+
+ fExpose = pGC->fExpose;
+
+ fastBox.x1 = srcx + pSrc->x;
+ fastBox.y1 = srcy + pSrc->y;
+ fastBox.x2 = fastBox.x1 + w;
+ fastBox.y2 = fastBox.y1 + h;
+
+ dx = dstx - fastBox.x1;
+ dy = dsty - fastBox.y1;
+ if (pGC->miTranslate)
+ {
+ xorg = pDst->x;
+ yorg = pDst->y;
+ }
+
+ /*
+ * Clip against the source. Otherwise we will blit too much for SINGLE
+ * and SHARED banked systems.
+ */
+ freeSrcClip = FALSE;
+ fastClip = FALSE;
+ fastExpose = FALSE;
+
+ if (pGC->subWindowMode != IncludeInferiors)
+ prgnSrcClip = &((WindowPtr)pSrc)->clipList;
+ else if (!((WindowPtr)pSrc)->parent)
+ fastClip = TRUE;
+ else if ((pSrc == pDst) && (pGC->clientClipType == CT_NONE))
+ prgnSrcClip = pGC->pCompositeClip;
+ else
+ {
+ prgnSrcClip = NotClippedByChildren((WindowPtr)pSrc);
+ freeSrcClip = TRUE;
+ }
+
+ if (fastClip)
+ {
+ fastExpose = TRUE;
+
+ /*
+ * Clip the source. If regions extend beyond the source size, make
+ * sure exposure events get sent.
+ */
+ if (fastBox.x1 < pSrc->x)
+ {
+ fastBox.x1 = pSrc->x;
+ fastExpose = FALSE;
+ }
+ if (fastBox.y1 < pSrc->y)
+ {
+ fastBox.y1 = pSrc->y;
+ fastExpose = FALSE;
+ }
+ if (fastBox.x2 > pSrc->x + (int) pSrc->width)
+ {
+ fastBox.x2 = pSrc->x + (int) pSrc->width;
+ fastExpose = FALSE;
+ }
+ if (fastBox.y2 > pSrc->y + (int) pSrc->height)
+ {
+ fastBox.y2 = pSrc->y + (int) pSrc->height;
+ fastExpose = FALSE;
+ }
+
+ nBox = 1;
+ pBox = &fastBox;
+ }
+ else
+ {
+ REGION_INIT(pScreen, &rgnDst, &fastBox, 1);
+ REGION_INTERSECT(pScreen, &rgnDst, &rgnDst, prgnSrcClip);
+ pBox = REGION_RECTS(&rgnDst);
+ nBox = REGION_NUM_RECTS(&rgnDst);
+ }
+
+ /*
+ * fastBlit can only be TRUE if we don't need to worry about attempts
+ * to read partial pixels through the destination bank.
+ */
+ if (SinglePlane)
+ fastBlit = pGCPriv->fastPlane;
+ else
+ fastBlit = pGCPriv->fastCopy;
+
+ nQueue = nBox * pScreenPriv->maxRects * 2;
+ pQueue = Queue = ALLOCATE_LOCAL_ARRAY(miBankQueue, nQueue);
+
+ if (Queue)
+ {
+ for (; nBox--; pBox++)
+ {
+ ns = FirstBankOf(pBox->x1, pBox->y1);
+ nse = LastBankOf(pBox->x2, pBox->y2);
+ for (; ns <= nse; ns++)
+ {
+ if (!pScreenPriv->pBanks[ns])
+ continue;
+
+ nBoxClipSrc = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
+ pBoxClipSrc = REGION_RECTS(pScreenPriv->pBanks[ns]);
+
+ for (; nBoxClipSrc--; pBoxClipSrc++)
+ {
+ cx1 = max(pBox->x1, pBoxClipSrc->x1);
+ cy1 = max(pBox->y1, pBoxClipSrc->y1);
+ cx2 = min(pBox->x2, pBoxClipSrc->x2);
+ cy2 = min(pBox->y2, pBoxClipSrc->y2);
+
+ /* Check to see if the region is empty */
+ if ((cx1 >= cx2) || (cy1 >= cy2))
+ continue;
+
+ /* Translate c[xy]* to destination coordinates */
+ cx1 += dx + xorg;
+ cy1 += dy + yorg;
+ cx2 += dx + xorg;
+ cy2 += dy + yorg;
+
+ nd = FirstBankOf(cx1, cy1);
+ nde = LastBankOf(cx2, cy2);
+ for (; nd <= nde; nd++)
+ {
+ if (!pGCPriv->pBankedClips[nd])
+ continue;
+
+ /*
+ * Clients can send quite large clip descriptions,
+ * so use the bank clips here instead.
+ */
+ nBoxClipDst =
+ REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
+ pBoxClipDst =
+ REGION_RECTS(pScreenPriv->pBanks[nd]);
+
+ for (; nBoxClipDst--; pBoxClipDst++)
+ {
+ ccBox.x1 = max(cx1, pBoxClipDst->x1);
+ ccBox.y1 = max(cy1, pBoxClipDst->y1);
+ ccBox.x2 = min(cx2, pBoxClipDst->x2);
+ ccBox.y2 = min(cy2, pBoxClipDst->y2);
+
+ /* Check to see if the region is empty */
+ if ((ccBox.x1 >= ccBox.x2) ||
+ (ccBox.y1 >= ccBox.y2))
+ continue;
+
+ pQueue->srcBankNo = ns;
+ pQueue->dstBankNo = nd;
+ pQueue->x = ccBox.x1 - xorg;
+ pQueue->y = ccBox.y1 - yorg;
+ pQueue->w = ccBox.x2 - ccBox.x1;
+ pQueue->h = ccBox.y2 - ccBox.y1;
+
+ if (maxWidth < pQueue->w)
+ maxWidth = pQueue->w;
+ if (maxHeight < pQueue->h)
+ maxHeight = pQueue->h;
+
+ /*
+ * When shared banking is used and the source
+ * and destination banks differ, prevent
+ * attempts to fetch partial scanline pad units
+ * through the destination bank.
+ */
+ pQueue->fastBlit = fastBlit;
+ if (fastBlit &&
+ (pScreenPriv->type == BANK_SHARED) &&
+ (ns != nd) &&
+ ((ccBox.x1 %
+ pScreenPriv->nPixelsPerScanlinePadUnit) ||
+ (ccBox.x2 %
+ pScreenPriv->nPixelsPerScanlinePadUnit) ||
+ (RECT_IN_REGION(pScreen,
+ pGCPriv->pBankedClips[nd], &ccBox) !=
+ rgnIN)))
+ pQueue->fastBlit = FALSE;
+ pQueue++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!fastClip)
+ {
+ REGION_UNINIT(pScreen, &rgnDst);
+ if (freeSrcClip)
+ REGION_DESTROY(pScreen, prgnSrcClip);
+ }
+
+ pQueueNew = pQueue;
+ nQueue = pQueue - Queue;
+
+ if (nQueue > 0)
+ {
+ BANK_SAVE;
+
+ pQueue = Queue;
+
+ if ((nQueue > 1) &&
+ ((pSrc == pDst) || (pGC->subWindowMode == IncludeInferiors)))
+ {
+ if ((srcy + pSrc->y) < (dsty + yorg))
+ {
+ /* Sort from bottom to top */
+ pQueueBase = pQueueNext = pQueue + nQueue - 1;
+
+ while (pQueueBase >= pQueue)
+ {
+ while ((pQueueNext >= pQueue) &&
+ (pQueueBase->y == pQueueNext->y))
+ pQueueNext--;
+
+ pQueueTmp = pQueueNext + 1;
+ while (pQueueTmp <= pQueueBase)
+ *pQueueNew++ = *pQueueTmp++;
+
+ pQueueBase = pQueueNext;
+ }
+
+ pQueueNew -= nQueue;
+ pQueue = pQueueNew;
+ pQueueNew = Queue;
+ }
+
+ if ((srcx + pSrc->x) < (dstx + xorg))
+ {
+ /* Sort from right to left */
+ pQueueBase = pQueueNext = pQueue;
+
+ while (pQueueBase < pQueue + nQueue)
+ {
+ while ((pQueueNext < pQueue + nQueue) &&
+ (pQueueNext->y == pQueueBase->y))
+ pQueueNext++;
+
+ pQueueTmp = pQueueNext;
+ while (pQueueTmp != pQueueBase)
+ *pQueueNew++ = *--pQueueTmp;
+
+ pQueueBase = pQueueNext;
+ }
+
+ pQueueNew -= nQueue;
+ pQueue = pQueueNew;
+ }
+ }
+
+ paddedWidth = PixmapBytePad(maxWidth,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ pImage = (char *)ALLOCATE_LOCAL(paddedWidth * maxHeight);
+
+ pGC->fExpose = FALSE;
+
+ while (nQueue--)
+ {
+ pGC->pCompositeClip = pGCPriv->pBankedClips[pQueue->dstBankNo];
+
+ GCOP_UNWRAP;
+
+ if (pQueue->srcBankNo == pQueue->dstBankNo)
+ {
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->srcBankNo);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
+ pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
+ else
+ (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
+ pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y);
+ }
+ else if (pQueue->fastBlit)
+ {
+ SET_SOURCE_BANK (pScreenPriv->pBankPixmap,
+ pScreenPriv->pScreenPixmap->drawable.width,
+ pScreenPriv->pScreenPixmap->devKind,
+ pQueue->srcBankNo);
+ SET_DESTINATION_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->dstBankNo);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(
+ (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
+ pQueue->x - dx, pQueue->y - dy,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
+ else
+ (*pGC->ops->CopyArea)(
+ (DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
+ pQueue->x - dx, pQueue->y - dy,
+ pQueue->w, pQueue->h, pQueue->x, pQueue->y);
+ }
+ else if (pImage)
+ {
+ ModifyPixmap(pScreenPriv->pBankPixmap,
+ maxWidth, paddedWidth, pImage);
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->srcBankNo);
+
+ (*pScreenPriv->pBankGC->ops->CopyArea)(
+ pSrc, (DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC,
+ pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
+ pQueue->w, pQueue->h, 0, 0);
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
+ -1, -1, pQueue->dstBankNo);
+
+ if (SinglePlane)
+ (*pGC->ops->CopyPlane)(
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pDst, pGC, 0, 0, pQueue->w, pQueue->h,
+ pQueue->x, pQueue->y, plane);
+ else
+ (*pGC->ops->CopyArea)(
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pDst, pGC, 0, 0, pQueue->w, pQueue->h,
+ pQueue->x, pQueue->y);
+ }
+
+ GCOP_WRAP;
+
+ pQueue++;
+ }
+
+ DEALLOCATE_LOCAL(pImage);
+
+ BANK_RESTORE;
+ }
+
+ CLIP_RESTORE;
+
+ pGC->fExpose = fExpose;
+
+ DEALLOCATE_LOCAL(Queue);
+ }
+
+ SCREEN_RESTORE;
+
+ if (!fExpose || fastExpose)
+ return ret;
+
+ return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0);
+}
+
+static RegionPtr
+miBankCopyArea(
+ DrawablePtr pSrc,
+ DrawablePtr pDst,
+ GCPtr pGC,
+ int srcx,
+ int srcy,
+ int w,
+ int h,
+ int dstx,
+ int dsty
+)
+{
+ return miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0, FALSE);
+}
+
+static RegionPtr
+miBankCopyPlane(
+ DrawablePtr pSrc,
+ DrawablePtr pDst,
+ GCPtr pGC,
+ int srcx,
+ int srcy,
+ int w,
+ int h,
+ int dstx,
+ int dsty,
+ unsigned long plane
+)
+{
+ return
+ miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane, TRUE);
+}
+
+static void
+miBankPolyPoint(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int mode,
+ int nArray,
+ xPoint *pArray
+)
+{
+# define GCOP_ARGS GCOP_0D_ARGS
+ GCOP_COMPLEX(PolyPoint, xPoint);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolylines(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int mode,
+ int nArray,
+ DDXPointPtr pArray
+)
+{
+# define GCOP_ARGS GCOP_0D_ARGS
+ GCOP_COMPLEX(Polylines, DDXPointRec);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolySegment(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xSegment *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolySegment, xSegment);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyRectangle(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xRectangle *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyRectangle, xRectangle);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyArc(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xArc *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyArc, xArc);
+# undef GCOP_ARGS
+}
+
+static void
+miBankFillPolygon(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int shape,
+ int mode,
+ int nArray,
+ DDXPointRec *pArray
+)
+{
+# define GCOP_ARGS GCOP_2D_ARGS
+ GCOP_COMPLEX(FillPolygon, DDXPointRec);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyFillRect(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xRectangle *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyFillRect, xRectangle);
+# undef GCOP_ARGS
+}
+
+static void
+miBankPolyFillArc(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int nArray,
+ xArc *pArray
+)
+{
+# define GCOP_ARGS GCOP_1D_ARGS
+ GCOP_COMPLEX(PolyFillArc, xArc);
+# undef GCOP_ARGS
+}
+
+static int
+miBankPolyText8(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ char *pchar
+)
+{
+ int retval = x;
+
+ GCOP_SIMPLE(retval =
+ (*pGC->ops->PolyText8)(pDrawable, pGC, x, y, nArray, pchar));
+
+ return retval;
+}
+
+static int
+miBankPolyText16(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ unsigned short *pchar
+)
+{
+ int retval = x;
+
+ GCOP_SIMPLE(retval =
+ (*pGC->ops->PolyText16)(pDrawable, pGC, x, y, nArray, pchar));
+
+ return retval;
+}
+
+static void
+miBankImageText8(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ char *pchar
+)
+{
+ GCOP_SIMPLE((*pGC->ops->ImageText8)(pDrawable, pGC, x, y, nArray, pchar));
+}
+
+static void
+miBankImageText16(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ int nArray,
+ unsigned short *pchar
+)
+{
+ GCOP_SIMPLE((*pGC->ops->ImageText16)(pDrawable, pGC, x, y, nArray, pchar));
+}
+
+static void
+miBankImageGlyphBlt(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nArray,
+ CharInfoPtr *ppci,
+ pointer pglyphBase
+)
+{
+ GCOP_SIMPLE((*pGC->ops->ImageGlyphBlt)(pDrawable, pGC,
+ x, y, nArray, ppci, pglyphBase));
+}
+
+static void
+miBankPolyGlyphBlt(
+ DrawablePtr pDrawable,
+ GCPtr pGC,
+ int x,
+ int y,
+ unsigned int nArray,
+ CharInfoPtr *ppci,
+ pointer pglyphBase
+)
+{
+ GCOP_SIMPLE((*pGC->ops->PolyGlyphBlt)(pDrawable, pGC,
+ x, y, nArray, ppci, pglyphBase));
+}
+
+static void
+miBankPushPixels(
+ GCPtr pGC,
+ PixmapPtr pBitmap,
+ DrawablePtr pDrawable,
+ int w,
+ int h,
+ int x,
+ int y
+)
+{
+ if ((w > 0) && (h > 0))
+ {
+ GCOP_INIT;
+ SCREEN_SAVE;
+
+ if (!IS_BANKED(pDrawable))
+ {
+ GCOP_UNWRAP;
+
+ (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
+
+ GCOP_WRAP;
+ }
+ else
+ {
+ int i, j;
+
+ CLIP_SAVE;
+
+ i = FirstBankOf(x, y);
+ j = LastBankOf(x + w, y + h);
+ for (; i <= j; i++)
+ {
+ if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
+ continue;
+
+ GCOP_UNWRAP;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
+
+ GCOP_WRAP;
+ }
+
+ CLIP_RESTORE;
+ }
+
+ SCREEN_RESTORE;
+ }
+}
+
+static GCOps miBankGCOps =
+{
+ miBankFillSpans,
+ miBankSetSpans,
+ miBankPutImage,
+ miBankCopyArea,
+ miBankCopyPlane,
+ miBankPolyPoint,
+ miBankPolylines,
+ miBankPolySegment,
+ miBankPolyRectangle,
+ miBankPolyArc,
+ miBankFillPolygon,
+ miBankPolyFillRect,
+ miBankPolyFillArc,
+ miBankPolyText8,
+ miBankPolyText16,
+ miBankImageText8,
+ miBankImageText16,
+ miBankImageGlyphBlt,
+ miBankPolyGlyphBlt,
+ miBankPushPixels,
+#ifdef NEED_LINEHELPER
+ NULL, /* LineHelper */
+#endif
+ {NULL} /* devPrivate */
+};
+
+/********************
+ * GCFuncs wrappers *
+ ********************/
+
+static void
+miBankValidateGC(
+ GCPtr pGC,
+ unsigned long changes,
+ DrawablePtr pDrawable
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
+
+ if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
+ (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)))
+ {
+ ScreenPtr pScreen = pGC->pScreen;
+ RegionPtr prgnClip;
+ unsigned long planemask;
+ int i;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+
+ if (IS_BANKED(pDrawable))
+ {
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ if (!(prgnClip = pGCPriv->pBankedClips[i]))
+ prgnClip = REGION_CREATE(pScreen, NULL, 1);
+
+ REGION_INTERSECT(pScreen, prgnClip,
+ pScreenPriv->pBanks[i], pGC->pCompositeClip);
+
+ if ((REGION_NUM_RECTS(prgnClip) <= 1) &&
+ ((prgnClip->extents.x1 == prgnClip->extents.x2) ||
+ (prgnClip->extents.y1 == prgnClip->extents.y2)))
+ {
+ REGION_DESTROY(pScreen, prgnClip);
+ pGCPriv->pBankedClips[i] = NULL;
+ }
+ else
+ pGCPriv->pBankedClips[i] = prgnClip;
+ }
+
+ /*
+ * fastCopy and fastPlane can only be TRUE if we don't need to
+ * worry about attempts to read partial pixels through the
+ * destination bank.
+ */
+ switch (pScreenPriv->type)
+ {
+ case BANK_SHARED:
+ pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
+
+ if ((pGC->alu != GXclear) && (pGC->alu != GXcopy) &&
+ (pGC->alu != GXcopyInverted) && (pGC->alu != GXset))
+ break;
+
+ if (pScreen->rootDepth == 1)
+ pGCPriv->fastPlane = TRUE;
+
+ /* This is probably paranoia */
+ if ((pDrawable->depth != pScreen->rootDepth) ||
+ (pDrawable->depth != pGC->depth))
+ break;
+
+ planemask = (1 << pGC->depth) - 1;
+ if ((pGC->planemask & planemask) == planemask)
+ pGCPriv->fastCopy = TRUE;
+
+ break;
+
+ case BANK_DOUBLE:
+ pGCPriv->fastCopy = pGCPriv->fastPlane = TRUE;
+ break;
+
+ default:
+ pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Here we are on a pixmap and don't need all that special clipping
+ * stuff, hence free it.
+ */
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pGCPriv->pBankedClips[i])
+ continue;
+
+ REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
+ pGCPriv->pBankedClips[i] = NULL;
+ }
+ }
+
+ SCREEN_RESTORE;
+ }
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankChangeGC(
+ GCPtr pGC,
+ unsigned long mask
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->ChangeGC)(pGC, mask);
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankCopyGC(
+ GCPtr pGCSrc,
+ unsigned long mask,
+ GCPtr pGCDst
+)
+{
+ GC_INIT(pGCDst);
+ GC_UNWRAP(pGCDst);
+
+ (*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst);
+
+ GC_WRAP(pGCDst);
+}
+
+static void
+miBankDestroyGC(
+ GCPtr pGC
+)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ int i;
+
+ SCREEN_INIT;
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->DestroyGC)(pGC);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pGCPriv->pBankedClips[i])
+ continue;
+
+ REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
+ pGCPriv->pBankedClips[i] = NULL;
+ }
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankChangeClip(
+ GCPtr pGC,
+ int type,
+ pointer pvalue,
+ int nrects
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankDestroyClip(
+ GCPtr pGC
+)
+{
+ GC_INIT(pGC);
+ GC_UNWRAP(pGC);
+
+ (*pGC->funcs->DestroyClip)(pGC);
+
+ GC_WRAP(pGC);
+}
+
+static void
+miBankCopyClip(
+ GCPtr pGCDst,
+ GCPtr pGCSrc
+)
+{
+ GC_INIT(pGCDst);
+ GC_UNWRAP(pGCDst);
+
+ (*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc);
+
+ GC_WRAP(pGCDst);
+}
+
+static GCFuncs miBankGCFuncs =
+{
+ miBankValidateGC,
+ miBankChangeGC,
+ miBankCopyGC,
+ miBankDestroyGC,
+ miBankChangeClip,
+ miBankDestroyClip,
+ miBankCopyClip
+};
+
+/*******************
+ * Screen Wrappers *
+ *******************/
+
+static Bool
+miBankCreateScreenResources(
+ ScreenPtr pScreen
+)
+{
+ Bool retval;
+
+ SCREEN_INIT;
+ SCREEN_UNWRAP(CreateScreenResources);
+
+ if ((retval = (*pScreen->CreateScreenResources)(pScreen)))
+ {
+ /* Set screen buffer address to something recognizable */
+ pScreenPriv->pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen);
+ pScreenPriv->pbits = pScreenPriv->pScreenPixmap->devPrivate.ptr;
+ pScreenPriv->pScreenPixmap->devPrivate.ptr = (pointer)pScreenPriv;
+
+ /* Get shadow pixmap; width & height of 0 means no pixmap data */
+ pScreenPriv->pBankPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ if (!pScreenPriv->pBankPixmap)
+ retval = FALSE;
+ }
+
+ /* Shadow the screen */
+ if (retval)
+ retval = (*pScreen->ModifyPixmapHeader)(pScreenPriv->pBankPixmap,
+ pScreenPriv->pScreenPixmap->drawable.width,
+ pScreenPriv->pScreenPixmap->drawable.height,
+ pScreenPriv->pScreenPixmap->drawable.depth,
+ pScreenPriv->pScreenPixmap->drawable.bitsPerPixel,
+ pScreenPriv->pScreenPixmap->devKind, NULL);
+
+ /* Create shadow GC */
+ if (retval)
+ {
+ pScreenPriv->pBankGC = CreateScratchGC(pScreen,
+ pScreenPriv->pBankPixmap->drawable.depth);
+ if (!pScreenPriv->pBankGC)
+ retval = FALSE;
+ }
+
+ /* Validate shadow GC */
+ if (retval)
+ {
+ pScreenPriv->pBankGC->graphicsExposures = FALSE;
+ pScreenPriv->pBankGC->subWindowMode = IncludeInferiors;
+ ValidateGC((DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC);
+ }
+
+ SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
+
+ return retval;
+}
+
+static Bool
+miBankModifyPixmapHeader(
+ PixmapPtr pPixmap,
+ int width,
+ int height,
+ int depth,
+ int bitsPerPixel,
+ int devKind,
+ pointer pPixData
+)
+{
+ Bool retval = FALSE;
+
+ if (pPixmap)
+ {
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+
+ SCREEN_INIT;
+ PIXMAP_SAVE(pPixmap);
+ SCREEN_UNWRAP(ModifyPixmapHeader);
+
+ retval = (*pScreen->ModifyPixmapHeader)(pPixmap, width, height,
+ depth, bitsPerPixel, devKind, pPixData);
+
+ SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
+
+ if (pbits == (pointer)pScreenPriv)
+ {
+ pScreenPriv->pbits = pPixmap->devPrivate.ptr;
+ pPixmap->devPrivate.ptr = pbits;
+ }
+ }
+
+ return retval;
+}
+
+static Bool
+miBankCloseScreen(
+ int nIndex,
+ ScreenPtr pScreen
+)
+{
+ int i;
+
+ SCREEN_INIT;
+
+ /* Free shadow GC */
+ FreeScratchGC(pScreenPriv->pBankGC);
+
+ /* Free shadow pixmap */
+ (*pScreen->DestroyPixmap)(pScreenPriv->pBankPixmap);
+
+ /* Restore screen pixmap devPrivate pointer */
+ pScreenPriv->pScreenPixmap->devPrivate.ptr = pScreenPriv->pbits;
+
+ /* Delete bank clips */
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ if (pScreenPriv->pBanks[i])
+ REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
+
+ Xfree(pScreenPriv->pBanks);
+
+ SCREEN_UNWRAP(CreateScreenResources);
+ SCREEN_UNWRAP(ModifyPixmapHeader);
+ SCREEN_UNWRAP(CloseScreen);
+ SCREEN_UNWRAP(GetImage);
+ SCREEN_UNWRAP(GetSpans);
+ SCREEN_UNWRAP(CreateGC);
+ SCREEN_UNWRAP(PaintWindowBackground);
+ SCREEN_UNWRAP(PaintWindowBorder);
+ SCREEN_UNWRAP(CopyWindow);
+ SCREEN_UNWRAP(BackingStoreFuncs);
+
+ Xfree(pScreenPriv);
+ return (*pScreen->CloseScreen)(nIndex, pScreen);
+}
+
+static void
+miBankGetImage(
+ DrawablePtr pDrawable,
+ int sx,
+ int sy,
+ int w,
+ int h,
+ unsigned int format,
+ unsigned long planemask,
+ char *pImage
+)
+{
+ if ((w > 0) && (h > 0))
+ {
+ ScreenPtr pScreen = pDrawable->pScreen;
+
+ SCREEN_INIT;
+ SCREEN_STATUS;
+ SCREEN_UNWRAP(GetImage);
+
+ if (!IS_BANKED(pDrawable))
+ {
+ (*pScreen->GetImage)(pDrawable, sx, sy, w, h,
+ format, planemask, pImage);
+ }
+ else
+ {
+ int paddedWidth;
+ char *pBankImage;
+
+ paddedWidth = PixmapBytePad(w,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth * h);
+
+ if (pBankImage)
+ {
+ BANK_SAVE;
+
+ ModifyPixmap(pScreenPriv->pBankPixmap, w, paddedWidth,
+ pBankImage);
+
+ (*pScreenPriv->pBankGC->ops->CopyArea)(
+ (DrawablePtr)WindowTable[pScreen->myNum],
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC,
+ sx + pDrawable->x, sy + pDrawable->y, w, h, 0, 0);
+
+ (*pScreen->GetImage)((DrawablePtr)pScreenPriv->pBankPixmap,
+ 0, 0, w, h, format, planemask, pImage);
+
+ BANK_RESTORE;
+
+ DEALLOCATE_LOCAL(pBankImage);
+ }
+ }
+
+ SCREEN_WRAP(GetImage, miBankGetImage);
+ }
+}
+
+static void
+miBankGetSpans(
+ DrawablePtr pDrawable,
+ int wMax,
+ DDXPointPtr ppt,
+ int *pwidth,
+ int nspans,
+ char *pImage
+)
+{
+ if (nspans > 0)
+ {
+ ScreenPtr pScreen = pDrawable->pScreen;
+
+ SCREEN_INIT;
+ SCREEN_STATUS;
+ SCREEN_UNWRAP(GetSpans);
+
+ if (!IS_BANKED(pDrawable))
+ {
+ (*pScreen->GetSpans)(pDrawable, wMax, ppt, pwidth, nspans, pImage);
+ }
+ else
+ {
+ char *pBankImage;
+ int paddedWidth;
+ DDXPointRec pt;
+
+ pt.x = pt.y = 0;
+
+ paddedWidth =
+ PixmapBytePad(pScreenPriv->pScreenPixmap->drawable.width,
+ pScreenPriv->pScreenPixmap->drawable.depth);
+ pBankImage = (char *)ALLOCATE_LOCAL(paddedWidth);
+
+ if (pBankImage)
+ {
+ BANK_SAVE;
+
+ ModifyPixmap(pScreenPriv->pBankPixmap,
+ pScreenPriv->pScreenPixmap->drawable.width,
+ paddedWidth, pBankImage);
+
+ for (; nspans--; ppt++, pwidth++)
+ {
+ if (*pwidth <= 0)
+ continue;
+
+ (*pScreenPriv->pBankGC->ops->CopyArea)(
+ (DrawablePtr)WindowTable[pScreen->myNum],
+ (DrawablePtr)pScreenPriv->pBankPixmap,
+ pScreenPriv->pBankGC,
+ ppt->x, ppt->y, *pwidth, 1, 0, 0);
+
+ (*pScreen->GetSpans)((DrawablePtr)pScreenPriv->pBankPixmap,
+ wMax, &pt, pwidth, 1, pImage);
+
+ pImage = pImage + PixmapBytePad(*pwidth, pDrawable->depth);
+ }
+
+ BANK_RESTORE;
+
+ DEALLOCATE_LOCAL(pBankImage);
+ }
+ }
+
+ SCREEN_WRAP(GetSpans, miBankGetSpans);
+ }
+}
+
+static Bool
+miBankCreateGC(
+ GCPtr pGC
+)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC);
+ Bool ret;
+
+ SCREEN_INIT;
+ SCREEN_UNWRAP(CreateGC);
+
+ if ((ret = (*pScreen->CreateGC)(pGC)))
+ {
+ pGCPriv->unwrappedOps = &miBankGCOps;
+ pGCPriv->unwrappedFuncs = &miBankGCFuncs;
+ GC_WRAP(pGC);
+
+ memset(&pGCPriv->pBankedClips, 0,
+ pScreenPriv->nBanks * sizeof(pGCPriv->pBankedClips));
+ }
+
+ SCREEN_WRAP(CreateGC, miBankCreateGC);
+
+ return ret;
+}
+
+static void
+miBankPaintWindow(
+ WindowPtr pWin,
+ RegionPtr pRegion,
+ int what
+)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ RegionRec tmpReg;
+ int i;
+ PaintWindowProcPtr PaintWindow;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+
+ if (what == PW_BORDER)
+ {
+ SCREEN_UNWRAP(PaintWindowBorder);
+ PaintWindow = pScreen->PaintWindowBorder;
+ }
+ else
+ {
+ SCREEN_UNWRAP(PaintWindowBackground);
+ PaintWindow = pScreen->PaintWindowBackground;
+ }
+
+ if (!IS_BANKED(pWin))
+ {
+ (*PaintWindow)(pWin, pRegion, what);
+ }
+ else
+ {
+ REGION_INIT(pScreen, &tmpReg, NullBox, 0);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ REGION_INTERSECT(pScreen, &tmpReg, pRegion,
+ pScreenPriv->pBanks[i]);
+
+ if (REGION_NIL(&tmpReg))
+ continue;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*PaintWindow)(pWin, &tmpReg, what);
+ }
+
+ REGION_UNINIT(pScreen, &tmpReg);
+ }
+
+ if (what == PW_BORDER)
+ {
+ SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow);
+ }
+ else
+ {
+ SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow);
+ }
+
+ SCREEN_RESTORE;
+}
+
+static void
+miBankCopyWindow(
+ WindowPtr pWindow,
+ DDXPointRec ptOldOrg,
+ RegionPtr pRgnSrc
+)
+{
+ ScreenPtr pScreen = pWindow->drawable.pScreen;
+ GCPtr pGC;
+ int dx, dy, nBox;
+ DrawablePtr pDrawable = (DrawablePtr)WindowTable[pScreen->myNum];
+ RegionPtr pRgnDst;
+ BoxPtr pBox, pBoxTmp, pBoxNext, pBoxBase, pBoxNew1, pBoxNew2;
+ XID subWindowMode = IncludeInferiors;
+
+ pGC = GetScratchGC(pDrawable->depth, pScreen);
+
+ ChangeGC(pGC, GCSubwindowMode, &subWindowMode);
+ ValidateGC(pDrawable, pGC);
+
+ pRgnDst = REGION_CREATE(pScreen, NULL, 1);
+
+ dx = ptOldOrg.x - pWindow->drawable.x;
+ dy = ptOldOrg.y - pWindow->drawable.y;
+ REGION_TRANSLATE(pScreen, pRgnSrc, -dx, -dy);
+ REGION_INTERSECT(pScreen, pRgnDst, &pWindow->borderClip, pRgnSrc);
+
+ pBox = REGION_RECTS(pRgnDst);
+ nBox = REGION_NUM_RECTS(pRgnDst);
+
+ pBoxNew1 = NULL;
+ pBoxNew2 = NULL;
+
+ if (nBox > 1)
+ {
+ if (dy < 0)
+ {
+ /* Sort boxes from bottom to top */
+ pBoxNew1 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox);
+
+ if (pBoxNew1)
+ {
+ pBoxBase = pBoxNext = pBox + nBox - 1;
+
+ while (pBoxBase >= pBox)
+ {
+ while ((pBoxNext >= pBox) &&
+ (pBoxBase->y1 == pBoxNext->y1))
+ pBoxNext--;
+
+ pBoxTmp = pBoxNext + 1;
+
+ while (pBoxTmp <= pBoxBase)
+ *pBoxNew1++ = *pBoxTmp++;
+
+ pBoxBase = pBoxNext;
+ }
+
+ pBoxNew1 -= nBox;
+ pBox = pBoxNew1;
+ }
+ }
+
+ if (dx < 0)
+ {
+ /* Sort boxes from right to left */
+ pBoxNew2 = ALLOCATE_LOCAL_ARRAY(BoxRec, nBox);
+
+ if (pBoxNew2)
+ {
+ pBoxBase = pBoxNext = pBox;
+
+ while (pBoxBase < pBox + nBox)
+ {
+ while ((pBoxNext < pBox + nBox) &&
+ (pBoxNext->y1 == pBoxBase->y1))
+ pBoxNext++;
+
+ pBoxTmp = pBoxNext;
+
+ while (pBoxTmp != pBoxBase)
+ *pBoxNew2++ = *--pBoxTmp;
+
+ pBoxBase = pBoxNext;
+ }
+
+ pBoxNew2 -= nBox;
+ pBox = pBoxNew2;
+ }
+ }
+ }
+
+ while (nBox--)
+ {
+ (*pGC->ops->CopyArea)(pDrawable, pDrawable, pGC,
+ pBox->x1 + dx, pBox->y1 + dy,
+ pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
+ pBox->x1, pBox->y1);
+
+ pBox++;
+ }
+
+ FreeScratchGC(pGC);
+
+ REGION_DESTROY(pScreen, pRgnDst);
+
+ DEALLOCATE_LOCAL(pBoxNew2);
+ DEALLOCATE_LOCAL(pBoxNew1);
+}
+
+/**************************
+ * Backing store wrappers *
+ **************************/
+
+static void
+miBankSaveAreas(
+ PixmapPtr pPixmap,
+ RegionPtr prgnSave,
+ int xorg,
+ int yorg,
+ WindowPtr pWin
+)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ RegionRec rgnClipped;
+ int i;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+ SCREEN_UNWRAP(BackingStoreFuncs.SaveAreas);
+
+ if (!IS_BANKED(pWin))
+ {
+ (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, prgnSave, xorg, yorg,
+ pWin);
+ }
+ else
+ {
+ REGION_INIT(pScreen, &rgnClipped, NullBox, 0);
+ REGION_TRANSLATE(pScreen, prgnSave, xorg, yorg);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ REGION_INTERSECT(pScreen, &rgnClipped,
+ prgnSave, pScreenPriv->pBanks[i]);
+
+ if (REGION_NIL(&rgnClipped))
+ continue;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ REGION_TRANSLATE(pScreen, &rgnClipped, -xorg, -yorg);
+
+ (*pScreen->BackingStoreFuncs.SaveAreas)(pPixmap, &rgnClipped,
+ xorg, yorg, pWin);
+ }
+
+ REGION_TRANSLATE(pScreen, prgnSave, -xorg, -yorg);
+ REGION_UNINIT(pScreen, &rgnClipped);
+ }
+
+ SCREEN_WRAP(BackingStoreFuncs.SaveAreas, miBankSaveAreas);
+ SCREEN_RESTORE;
+}
+
+static void
+miBankRestoreAreas(
+ PixmapPtr pPixmap,
+ RegionPtr prgnRestore,
+ int xorg,
+ int yorg,
+ WindowPtr pWin
+)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ RegionRec rgnClipped;
+ int i;
+
+ SCREEN_INIT;
+ SCREEN_SAVE;
+ SCREEN_UNWRAP(BackingStoreFuncs.RestoreAreas);
+
+ if (!IS_BANKED(pWin))
+ {
+ (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, prgnRestore,
+ xorg, yorg, pWin);
+ }
+ else
+ {
+ REGION_INIT(pScreen, &rgnClipped, NullBox, 0);
+
+ for (i = 0; i < pScreenPriv->nBanks; i++)
+ {
+ if (!pScreenPriv->pBanks[i])
+ continue;
+
+ REGION_INTERSECT(pScreen, &rgnClipped,
+ prgnRestore, pScreenPriv->pBanks[i]);
+
+ if (REGION_NIL(&rgnClipped))
+ continue;
+
+ SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
+
+ (*pScreen->BackingStoreFuncs.RestoreAreas)(pPixmap, &rgnClipped,
+ xorg, yorg, pWin);
+ }
+
+ REGION_UNINIT(pScreen, &rgnClipped);
+ }
+
+ SCREEN_WRAP(BackingStoreFuncs.RestoreAreas, miBankRestoreAreas);
+ SCREEN_RESTORE;
+}
+
+Bool
+miInitializeBanking(
+ ScreenPtr pScreen,
+ unsigned int xsize,
+ unsigned int ysize,
+ unsigned int width,
+ miBankInfoPtr pBankInfo
+)
+{
+ miBankScreenPtr pScreenPriv;
+ unsigned long nBitsPerBank, nBitsPerScanline, nPixelsPerScanlinePadUnit;
+ unsigned long BankBase, ServerPad;
+ unsigned int type, iBank, nBanks, maxRects, we, nBankBPP;
+ int i;
+
+ if (!pBankInfo || !pBankInfo->BankSize)
+ return TRUE; /* No banking required */
+
+ /* Sanity checks */
+
+ if (!pScreen || !xsize || !ysize || (xsize > width) ||
+ !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
+ !pBankInfo->SetSourceAndDestinationBanks ||
+ !pBankInfo->pBankA || !pBankInfo->pBankB ||
+ !pBankInfo->nBankDepth)
+ return FALSE;
+
+ /*
+ * DDX *must* have registered a pixmap format whose depth is
+ * pBankInfo->nBankDepth. This is not necessarily the rootDepth
+ * pixmap format.
+ */
+ i = 0;
+ while (screenInfo.formats[i].depth != pBankInfo->nBankDepth)
+ if (++i >= screenInfo.numPixmapFormats)
+ return FALSE;
+ nBankBPP = screenInfo.formats[i].bitsPerPixel;
+
+ i = 0;
+ while (screenInfo.formats[i].depth != pScreen->rootDepth)
+ if (++i >= screenInfo.numPixmapFormats)
+ return FALSE;
+
+ if (nBankBPP > screenInfo.formats[i].bitsPerPixel)
+ return FALSE;
+
+ /* Determine banking type */
+ if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
+ return FALSE;
+
+ /* Internal data */
+
+ nBitsPerBank = pBankInfo->BankSize * 8;
+ ServerPad = PixmapBytePad(1, pBankInfo->nBankDepth) * 8;
+ if (nBitsPerBank % ServerPad)
+ return FALSE;
+ nBitsPerScanline = PixmapBytePad(width, pBankInfo->nBankDepth) * 8;
+ nBanks = ((nBitsPerScanline * (ysize - 1)) +
+ (nBankBPP * xsize) + nBitsPerBank - 1) / nBitsPerBank;
+ nPixelsPerScanlinePadUnit = miLCM(ServerPad, nBankBPP) / nBankBPP;
+
+ /* Private areas */
+
+ if (miBankGeneration != serverGeneration)
+ {
+ if (((miBankScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
+ ((miBankGCIndex = AllocateGCPrivateIndex()) < 0))
+ return FALSE;
+
+ miBankGeneration = serverGeneration;
+ }
+
+ if (!AllocateGCPrivate(pScreen, miBankGCIndex,
+ (nBanks * sizeof(RegionPtr)) +
+ (sizeof(miBankGCRec) - sizeof(RegionPtr))))
+ return FALSE;
+
+ if (!(pScreenPriv = (miBankScreenPtr)Xcalloc(sizeof(miBankScreenRec))))
+ return FALSE;
+
+ if (!(pScreenPriv->pBanks = /* Allocate and clear */
+ (RegionPtr *)Xcalloc(nBanks * sizeof(RegionPtr))))
+ {
+ Xfree(pScreenPriv);
+ return FALSE;
+ }
+
+ /*
+ * Translate banks into clipping regions which are themselves clipped
+ * against the screen. This also ensures that pixels with imbedded bank
+ * boundaries are off-screen.
+ */
+
+ BankBase = 0;
+ maxRects = 0;
+ we = 0;
+ for (iBank = 0; iBank < nBanks; iBank++)
+ {
+ xRectangle pRects[3], *pRect = pRects;
+ unsigned int xb, yb, xe, ye;
+
+ xb = ((BankBase + nBankBPP - 1) % nBitsPerScanline) / nBankBPP;
+ yb = (BankBase + nBankBPP - 1) / nBitsPerScanline;
+ if (xb >= xsize)
+ {
+ xb = we = 0;
+ yb++;
+ }
+ if (yb >= ysize)
+ {
+ we = 0;
+ break;
+ }
+
+ if (we)
+ break;
+
+ BankBase += nBitsPerBank;
+
+ we = (BankBase % nBitsPerScanline) % nBankBPP;
+ xe = (BankBase % nBitsPerScanline) / nBankBPP;
+ ye = BankBase / nBitsPerScanline;
+ if (xe >= xsize)
+ {
+ we = xe = 0;
+ ye++;
+ }
+ if (ye >= ysize)
+ {
+ we = xe = 0;
+ ye = ysize;
+ }
+
+ if (yb == ye)
+ {
+ if (xb >= xe)
+ continue;
+
+ pRect->x = xb;
+ pRect->y = yb;
+ pRect->width = xe - xb;
+ pRect->height = 1;
+ maxRects += 2;
+ pRect++;
+ }
+ else
+ {
+ if (xb)
+ {
+ pRect->x = xb;
+ pRect->y = yb++;
+ pRect->width = xsize - xb;
+ pRect->height = 1;
+ maxRects += 2;
+ pRect++;
+ }
+
+ if (yb < ye)
+ {
+ pRect->x = 0;
+ pRect->y = yb;
+ pRect->width = xsize;
+ pRect->height = ye - yb;
+ maxRects += min(pRect->height, 3) + 1;
+ pRect++;
+ }
+
+ if (xe)
+ {
+ pRect->x = 0;
+ pRect->y = ye;
+ pRect->width = xe;
+ pRect->height = 1;
+ maxRects += 2;
+ pRect++;
+ }
+ }
+
+ pScreenPriv->pBanks[iBank] =
+ RECTS_TO_REGION(pScreen, pRect - pRects, pRects, 0);
+ if (!pScreenPriv->pBanks[iBank] ||
+ REGION_NAR(pScreenPriv->pBanks[iBank]))
+ {
+ we = 1;
+ break;
+ }
+ }
+
+ if (we && (iBank < nBanks))
+ {
+ for (i = iBank; i >= 0; i--)
+ if (pScreenPriv->pBanks[i])
+ REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
+
+ Xfree(pScreenPriv->pBanks);
+ Xfree(pScreenPriv);
+
+ return FALSE;
+ }
+
+ /* Open for business */
+
+ pScreenPriv->type = type;
+ pScreenPriv->nBanks = nBanks;
+ pScreenPriv->maxRects = maxRects;
+ pScreenPriv->nBankBPP = nBankBPP;
+ pScreenPriv->BankInfo = *pBankInfo;
+ pScreenPriv->nBitsPerBank = nBitsPerBank;
+ pScreenPriv->nBitsPerScanline = nBitsPerScanline;
+ pScreenPriv->nPixelsPerScanlinePadUnit = nPixelsPerScanlinePadUnit;
+
+ SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
+ SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
+ SCREEN_WRAP(CloseScreen, miBankCloseScreen);
+ SCREEN_WRAP(GetImage, miBankGetImage);
+ SCREEN_WRAP(GetSpans, miBankGetSpans);
+ SCREEN_WRAP(CreateGC, miBankCreateGC);
+ SCREEN_WRAP(PaintWindowBackground, miBankPaintWindow);
+ SCREEN_WRAP(PaintWindowBorder, miBankPaintWindow);
+ SCREEN_WRAP(CopyWindow, miBankCopyWindow);
+
+ pScreenPriv->BackingStoreFuncs = pScreen->BackingStoreFuncs;
+
+ pScreen->BackingStoreFuncs.SaveAreas = miBankSaveAreas;
+ pScreen->BackingStoreFuncs.RestoreAreas = miBankRestoreAreas;
+ /* ??????????????????????????????????????????????????????????????
+ pScreen->BackingStoreFuncs.SetClipmaskRgn = miBankSetClipmaskRgn;
+ ?????????????????????????????????????????????????????????????? */
+
+ BANK_SCRPRIVLVAL = (pointer)pScreenPriv;
+
+ return TRUE;
+}
+
+/* This is used to force GC revalidation when the banking type is changed */
+/*ARGSUSED*/
+static int
+miBankNewSerialNumber(
+ WindowPtr pWin,
+ pointer unused
+)
+{
+ pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ return WT_WALKCHILDREN;
+}
+
+/* This entry modifies the banking interface */
+Bool
+miModifyBanking(
+ ScreenPtr pScreen,
+ miBankInfoPtr pBankInfo
+)
+{
+ unsigned int type;
+
+ if (!pScreen)
+ return FALSE;
+
+ if (miBankGeneration == serverGeneration)
+ {
+ SCREEN_INIT;
+
+ if (pScreenPriv)
+ {
+ if (!pBankInfo || !pBankInfo->BankSize ||
+ !pBankInfo->pBankA || !pBankInfo->pBankB ||
+ !pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
+ !pBankInfo->SetSourceAndDestinationBanks)
+ return FALSE;
+
+ /* BankSize and nBankDepth cannot, as yet, be changed */
+ if ((pScreenPriv->BankInfo.BankSize != pBankInfo->BankSize) ||
+ (pScreenPriv->BankInfo.nBankDepth != pBankInfo->nBankDepth))
+ return FALSE;
+
+ if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
+ return FALSE;
+
+ /* Reset banking info */
+ pScreenPriv->BankInfo = *pBankInfo;
+ if (type != pScreenPriv->type)
+ {
+ /*
+ * Banking type is changing. Revalidate all window GC's.
+ */
+ pScreenPriv->type = type;
+ WalkTree(pScreen, miBankNewSerialNumber, 0);
+ }
+
+ return TRUE;
+ }
+ }
+
+ if (!pBankInfo || !pBankInfo->BankSize)
+ return TRUE; /* No change requested */
+
+ return FALSE;
+}
+
+/*
+ * Given various screen attributes, determine the minimum scanline width such
+ * that each scanline is server and DDX padded and any pixels with imbedded
+ * bank boundaries are off-screen. This function returns -1 if such a width
+ * cannot exist. This function exists because the DDX needs to be able to
+ * determine this width before initializing a frame buffer.
+ */
+int
+miScanLineWidth(
+ unsigned int xsize, /* pixels */
+ unsigned int ysize, /* pixels */
+ unsigned int width, /* pixels */
+ unsigned long BankSize, /* char's */
+ PixmapFormatRec *pBankFormat,
+ unsigned int nWidthUnit /* bits */
+)
+{
+ unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit;
+ unsigned long minBitsPerScanline, maxBitsPerScanline;
+
+ /* Sanity checks */
+
+ if (!nWidthUnit || !pBankFormat)
+ return -1;
+
+ nBitsPerBank = BankSize * 8;
+ if (nBitsPerBank % pBankFormat->scanlinePad)
+ return -1;
+
+ if (xsize > width)
+ width = xsize;
+ nBitsPerScanlinePadUnit = miLCM(pBankFormat->scanlinePad, nWidthUnit);
+ nBitsPerScanline =
+ (((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) /
+ nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit;
+ width = nBitsPerScanline / pBankFormat->bitsPerPixel;
+
+ if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel))
+ return (int)width;
+
+ /*
+ * Scanlines will be server-pad aligned at this point. They will also be
+ * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
+ * bank boundaries are off-screen.
+ *
+ * It seems reasonable to limit total frame buffer size to 1/16 of the
+ * theoretical maximum address space size. On a machine with 32-bit
+ * addresses (to 8-bit quantities) this turns out to be 256MB. Not only
+ * does this provide a simple limiting condition for the loops below, but
+ * it also prevents unsigned long wraparounds.
+ */
+ if (!ysize)
+ return -1;
+
+ minBitsPerScanline = xsize * pBankFormat->bitsPerPixel;
+ if (minBitsPerScanline > nBitsPerBank)
+ return -1;
+
+ if (ysize == 1)
+ return (int)width;
+
+ maxBitsPerScanline =
+ (((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1);
+ while (nBitsPerScanline <= maxBitsPerScanline)
+ {
+ unsigned long BankBase, BankUnit;
+
+ BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) *
+ nBitsPerBank;
+ if (!(BankUnit % nBitsPerScanline))
+ return (int)width;
+
+ for (BankBase = BankUnit; ; BankBase += nBitsPerBank)
+ {
+ unsigned long x, y;
+
+ y = BankBase / nBitsPerScanline;
+ if (y >= ysize)
+ return (int)width;
+
+ x = BankBase % nBitsPerScanline;
+ if (!(x % pBankFormat->bitsPerPixel))
+ continue;
+
+ if (x < minBitsPerScanline)
+ {
+ /*
+ * Skip ahead certain widths by dividing the excess scanline
+ * amongst the y's.
+ */
+ y *= nBitsPerScanlinePadUnit;
+ nBitsPerScanline +=
+ ((x + y - 1) / y) * nBitsPerScanlinePadUnit;
+ width = nBitsPerScanline / pBankFormat->bitsPerPixel;
+ break;
+ }
+
+ if (BankBase != BankUnit)
+ continue;
+
+ if (!(nBitsPerScanline % x))
+ return (int)width;
+
+ BankBase = ((nBitsPerScanline - minBitsPerScanline) /
+ (nBitsPerScanline - x)) * BankUnit;
+ }
+ }
+
+ return -1;
+}
diff --git a/mi/mibank.h b/mi/mibank.h
new file mode 100644
index 000000000..c3aa69379
--- /dev/null
+++ b/mi/mibank.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 1997 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of Marc Aurele La France not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Marc Aurele La France makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as-is" without express or implied warranty.
+ *
+ * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $XFree86: xc/programs/Xserver/mi/mibank.h,v 1.10 2003/01/01 19:16:42 tsi Exp $ */
+
+#ifndef __MIBANK_H__
+#define __MIBANK_H__ 1
+
+#include "scrnintstr.h"
+
+/*
+ * Banking external interface.
+ */
+
+/*
+ * This is the banking function type. The return value is normally zero.
+ * Non-zero returns can be used to implement the likes of scanline interleave,
+ * etc.
+ */
+typedef int miBankProc(
+ ScreenPtr /*pScreen*/,
+ unsigned int /*iBank*/
+);
+
+typedef miBankProc *miBankProcPtr;
+
+typedef struct _miBankInfo
+{
+ /*
+ * Banking refers to the use of one or more apertures (in the server's
+ * address space) to access various parts of a potentially larger hardware
+ * frame buffer.
+ *
+ * Three different banking schemes are supported:
+ *
+ * Single banking is indicated when pBankA and pBankB are equal and all
+ * three miBankProcPtr's point to the same function. Here, both reads and
+ * writes through the aperture access the same hardware location.
+ *
+ * Shared banking is indicated when pBankA and pBankB are equal but the
+ * source and destination functions differ. Here reads through the
+ * aperture do not necessarily access the same hardware location as writes.
+ *
+ * Double banking is indicated when pBankA and pBankB differ. Here two
+ * independent apertures are used to provide read/write access to
+ * potentially different hardware locations.
+ *
+ * Any other combination will result in no banking.
+ */
+ miBankProcPtr SetSourceBank; /* Set pBankA bank number */
+ miBankProcPtr SetDestinationBank; /* Set pBankB bank number */
+ miBankProcPtr SetSourceAndDestinationBanks; /* Set both bank numbers */
+
+ pointer pBankA; /* First aperture location */
+ pointer pBankB; /* First or second aperture location */
+
+ /*
+ * BankSize is in units of sizeof(char) and is the size of each bank.
+ */
+ unsigned long BankSize;
+
+ /*
+ * nBankDepth is the colour depth associated with the maximum number of a
+ * pixel's bits that are simultaneously accessible through the frame buffer
+ * aperture.
+ */
+ unsigned int nBankDepth;
+} miBankInfoRec, *miBankInfoPtr;
+
+Bool
+miInitializeBanking(
+ ScreenPtr /*pScreen*/,
+ unsigned int /*xsize*/,
+ unsigned int /*ysize*/,
+ unsigned int /*width*/,
+ miBankInfoPtr /*pBankInfo*/
+);
+
+Bool
+miModifyBanking(
+ ScreenPtr /*pScreen*/,
+ miBankInfoPtr /*pBankInfo*/
+);
+
+/*
+ * This function determines the minimum screen width, given a initial estimate
+ * and various screen attributes. DDX needs to determine this width before
+ * initializing the screen.
+ */
+int
+miScanLineWidth(
+ unsigned int /*xsize*/,
+ unsigned int /*ysize*/,
+ unsigned int /*width*/,
+ unsigned long /*BankSize*/,
+ PixmapFormatRec * /*pBankFormat*/,
+ unsigned int /*nWidthUnit*/
+);
+
+#endif /* __MIBANK_H__ */
diff --git a/mi/micmap.c b/mi/micmap.c
new file mode 100644
index 000000000..b3e925a09
--- /dev/null
+++ b/mi/micmap.c
@@ -0,0 +1,674 @@
+/* $XConsortium: cfbcmap.c,v 4.19 94/04/17 20:28:46 dpw Exp $ */
+/************************************************************
+Copyright 1987 by Sun Microsystems, Inc. Mountain View, CA.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright no-
+tice appear in all copies and that both that copyright no-
+tice and this permission notice appear in supporting docu-
+mentation, and that the names of Sun or X Consortium
+not be used in advertising or publicity pertaining to
+distribution of the software without specific prior
+written permission. Sun and X Consortium make no
+representations about the suitability of this software for
+any purpose. It is provided "as is" without any express or
+implied warranty.
+
+SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
+NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE LI-
+ABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+********************************************************/
+/* $XFree86: xc/programs/Xserver/mi/micmap.c,v 1.11 2001/05/29 22:24:06 dawes Exp $ */
+
+/*
+ * This is based on cfbcmap.c. The functions here are useful independently
+ * of cfb, which is the reason for including them here. How "mi" these
+ * are may be debatable.
+ */
+
+
+#include "X.h"
+#include "Xproto.h"
+#include "scrnintstr.h"
+#include "colormapst.h"
+#include "resource.h"
+#include "globals.h"
+#include "micmap.h"
+
+ColormapPtr miInstalledMaps[MAXSCREENS];
+
+static Bool miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
+ int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
+ unsigned long sizes, int bitsPerRGB, int preferredVis);
+
+miInitVisualsProcPtr miInitVisualsProc = miDoInitVisuals;
+
+int
+miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps)
+{
+ /* By the time we are processing requests, we can guarantee that there
+ * is always a colormap installed */
+ *pmaps = miInstalledMaps[pScreen->myNum]->mid;
+ return (1);
+}
+
+void
+miInstallColormap(ColormapPtr pmap)
+{
+ int index = pmap->pScreen->myNum;
+ ColormapPtr oldpmap = miInstalledMaps[index];
+
+ if(pmap != oldpmap)
+ {
+ /* Uninstall pInstalledMap. No hardware changes required, just
+ * notify all interested parties. */
+ if(oldpmap != (ColormapPtr)None)
+ WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid);
+ /* Install pmap */
+ miInstalledMaps[index] = pmap;
+ WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid);
+
+ }
+}
+
+void
+miUninstallColormap(ColormapPtr pmap)
+{
+ int index = pmap->pScreen->myNum;
+ ColormapPtr curpmap = miInstalledMaps[index];
+
+ if(pmap == curpmap)
+ {
+ if (pmap->mid != pmap->pScreen->defColormap)
+ {
+ curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap,
+ RT_COLORMAP);
+ (*pmap->pScreen->InstallColormap)(curpmap);
+ }
+ }
+}
+
+void
+miResolveColor(unsigned short *pred, unsigned short *pgreen,
+ unsigned short *pblue, VisualPtr pVisual)
+{
+ int shift = 16 - pVisual->bitsPerRGBValue;
+ unsigned lim = (1 << pVisual->bitsPerRGBValue) - 1;
+
+ if ((pVisual->class | DynamicClass) == GrayScale)
+ {
+ /* rescale to gray then rgb bits */
+ *pred = (30L * *pred + 59L * *pgreen + 11L * *pblue) / 100;
+ *pblue = *pgreen = *pred = ((*pred >> shift) * 65535) / lim;
+ }
+ else
+ {
+ /* rescale to rgb bits */
+ *pred = ((*pred >> shift) * 65535) / lim;
+ *pgreen = ((*pgreen >> shift) * 65535) / lim;
+ *pblue = ((*pblue >> shift) * 65535) / lim;
+ }
+}
+
+Bool
+miInitializeColormap(ColormapPtr pmap)
+{
+ register unsigned i;
+ register VisualPtr pVisual;
+ unsigned lim, maxent, shift;
+
+ pVisual = pmap->pVisual;
+ lim = (1 << pVisual->bitsPerRGBValue) - 1;
+ shift = 16 - pVisual->bitsPerRGBValue;
+ maxent = pVisual->ColormapEntries - 1;
+ if (pVisual->class == TrueColor)
+ {
+ unsigned limr, limg, limb;
+
+ limr = pVisual->redMask >> pVisual->offsetRed;
+ limg = pVisual->greenMask >> pVisual->offsetGreen;
+ limb = pVisual->blueMask >> pVisual->offsetBlue;
+ for(i = 0; i <= maxent; i++)
+ {
+ /* rescale to [0..65535] then rgb bits */
+ pmap->red[i].co.local.red =
+ ((((i * 65535) / limr) >> shift) * 65535) / lim;
+ pmap->green[i].co.local.green =
+ ((((i * 65535) / limg) >> shift) * 65535) / lim;
+ pmap->blue[i].co.local.blue =
+ ((((i * 65535) / limb) >> shift) * 65535) / lim;
+ }
+ }
+ else if (pVisual->class == StaticColor)
+ {
+ unsigned limr, limg, limb;
+
+ limr = pVisual->redMask >> pVisual->offsetRed;
+ limg = pVisual->greenMask >> pVisual->offsetGreen;
+ limb = pVisual->blueMask >> pVisual->offsetBlue;
+ for(i = 0; i <= maxent; i++)
+ {
+ /* rescale to [0..65535] then rgb bits */
+ pmap->red[i].co.local.red =
+ ((((((i & pVisual->redMask) >> pVisual->offsetRed)
+ * 65535) / limr) >> shift) * 65535) / lim;
+ pmap->red[i].co.local.green =
+ ((((((i & pVisual->greenMask) >> pVisual->offsetGreen)
+ * 65535) / limg) >> shift) * 65535) / lim;
+ pmap->red[i].co.local.blue =
+ ((((((i & pVisual->blueMask) >> pVisual->offsetBlue)
+ * 65535) / limb) >> shift) * 65535) / lim;
+ }
+ }
+ else if (pVisual->class == StaticGray)
+ {
+ for(i = 0; i <= maxent; i++)
+ {
+ /* rescale to [0..65535] then rgb bits */
+ pmap->red[i].co.local.red = ((((i * 65535) / maxent) >> shift)
+ * 65535) / lim;
+ pmap->red[i].co.local.green = pmap->red[i].co.local.red;
+ pmap->red[i].co.local.blue = pmap->red[i].co.local.red;
+ }
+ }
+ return TRUE;
+}
+
+/* When simulating DirectColor on PseudoColor hardware, multiple
+ entries of the colormap must be updated
+ */
+
+#define AddElement(mask) { \
+ pixel = red | green | blue; \
+ for (i = 0; i < nresult; i++) \
+ if (outdefs[i].pixel == pixel) \
+ break; \
+ if (i == nresult) \
+ { \
+ nresult++; \
+ outdefs[i].pixel = pixel; \
+ outdefs[i].flags = 0; \
+ } \
+ outdefs[i].flags |= (mask); \
+ outdefs[i].red = pmap->red[red >> pVisual->offsetRed].co.local.red; \
+ outdefs[i].green = pmap->green[green >> pVisual->offsetGreen].co.local.green; \
+ outdefs[i].blue = pmap->blue[blue >> pVisual->offsetBlue].co.local.blue; \
+}
+
+int
+miExpandDirectColors(ColormapPtr pmap, int ndef, xColorItem *indefs,
+ xColorItem *outdefs)
+{
+ register int red, green, blue;
+ int maxred, maxgreen, maxblue;
+ int stepred, stepgreen, stepblue;
+ VisualPtr pVisual;
+ register int pixel;
+ register int nresult;
+ register int i;
+
+ pVisual = pmap->pVisual;
+
+ stepred = 1 << pVisual->offsetRed;
+ stepgreen = 1 << pVisual->offsetGreen;
+ stepblue = 1 << pVisual->offsetBlue;
+ maxred = pVisual->redMask;
+ maxgreen = pVisual->greenMask;
+ maxblue = pVisual->blueMask;
+ nresult = 0;
+ for (;ndef--; indefs++)
+ {
+ if (indefs->flags & DoRed)
+ {
+ red = indefs->pixel & pVisual->redMask;
+ for (green = 0; green <= maxgreen; green += stepgreen)
+ {
+ for (blue = 0; blue <= maxblue; blue += stepblue)
+ {
+ AddElement (DoRed)
+ }
+ }
+ }
+ if (indefs->flags & DoGreen)
+ {
+ green = indefs->pixel & pVisual->greenMask;
+ for (red = 0; red <= maxred; red += stepred)
+ {
+ for (blue = 0; blue <= maxblue; blue += stepblue)
+ {
+ AddElement (DoGreen)
+ }
+ }
+ }
+ if (indefs->flags & DoBlue)
+ {
+ blue = indefs->pixel & pVisual->blueMask;
+ for (red = 0; red <= maxred; red += stepred)
+ {
+ for (green = 0; green <= maxgreen; green += stepgreen)
+ {
+ AddElement (DoBlue)
+ }
+ }
+ }
+ }
+ return nresult;
+}
+
+Bool
+miCreateDefColormap(ScreenPtr pScreen)
+{
+/*
+ * In the following sources PC X server vendors may want to delete
+ * "_not_tog" from "#ifdef WIN32_not_tog"
+ */
+#ifdef WIN32_not_tog
+ /*
+ * these are the MS-Windows desktop colors, adjusted for X's 16-bit
+ * color specifications.
+ */
+ static xColorItem citems[] = {
+ { 0, 0, 0, 0, 0, 0 },
+ { 1, 0x8000, 0, 0, 0, 0 },
+ { 2, 0, 0x8000, 0, 0, 0 },
+ { 3, 0x8000, 0x8000, 0, 0, 0 },
+ { 4, 0, 0, 0x8000, 0, 0 },
+ { 5, 0x8000, 0, 0x8000, 0, 0 },
+ { 6, 0, 0x8000, 0x8000, 0, 0 },
+ { 7, 0xc000, 0xc000, 0xc000, 0, 0 },
+ { 8, 0xc000, 0xdc00, 0xc000, 0, 0 },
+ { 9, 0xa600, 0xca00, 0xf000, 0, 0 },
+ { 246, 0xff00, 0xfb00, 0xf000, 0, 0 },
+ { 247, 0xa000, 0xa000, 0xa400, 0, 0 },
+ { 248, 0x8000, 0x8000, 0x8000, 0, 0 },
+ { 249, 0xff00, 0, 0, 0, 0 },
+ { 250, 0, 0xff00, 0, 0, 0 },
+ { 251, 0xff00, 0xff00, 0, 0, 0 },
+ { 252, 0, 0, 0xff00, 0, 0 },
+ { 253, 0xff00, 0, 0xff00, 0, 0 },
+ { 254, 0, 0xff00, 0xff00, 0, 0 },
+ { 255, 0xff00, 0xff00, 0xff00, 0, 0 }
+ };
+#define NUM_DESKTOP_COLORS sizeof citems / sizeof citems[0]
+ int i;
+#else
+ unsigned short zero = 0, ones = 0xFFFF;
+#endif
+ Pixel wp, bp;
+ VisualPtr pVisual;
+ ColormapPtr cmap;
+ int alloctype;
+
+ for (pVisual = pScreen->visuals;
+ pVisual->vid != pScreen->rootVisual;
+ pVisual++)
+ ;
+
+ if (pScreen->rootDepth == 1 || (pVisual->class & DynamicClass))
+ alloctype = AllocNone;
+ else
+ alloctype = AllocAll;
+
+ if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &cmap,
+ alloctype, 0) != Success)
+ return FALSE;
+
+ if (pScreen->rootDepth > 1) {
+ wp = pScreen->whitePixel;
+ bp = pScreen->blackPixel;
+#ifdef WIN32_not_tog
+ for (i = 0; i < NUM_DESKTOP_COLORS; i++) {
+ if (AllocColor (cmap,
+ &citems[i].red, &citems[i].green, &citems[i].blue,
+ &citems[i].pixel, 0) != Success)
+ return FALSE;
+ }
+#else
+ if ((AllocColor(cmap, &ones, &ones, &ones, &wp, 0) !=
+ Success) ||
+ (AllocColor(cmap, &zero, &zero, &zero, &bp, 0) !=
+ Success))
+ return FALSE;
+ pScreen->whitePixel = wp;
+ pScreen->blackPixel = bp;
+#endif
+ }
+
+ (*pScreen->InstallColormap)(cmap);
+ return TRUE;
+}
+
+/*
+ * Default true color bitmasks, should be overridden by
+ * driver
+ */
+
+#define _RZ(d) ((d + 2) / 3)
+#define _RS(d) 0
+#define _RM(d) ((1 << _RZ(d)) - 1)
+#define _GZ(d) ((d - _RZ(d) + 1) / 2)
+#define _GS(d) _RZ(d)
+#define _GM(d) (((1 << _GZ(d)) - 1) << _GS(d))
+#define _BZ(d) (d - _RZ(d) - _GZ(d))
+#define _BS(d) (_RZ(d) + _GZ(d))
+#define _BM(d) (((1 << _BZ(d)) - 1) << _BS(d))
+#define _CE(d) (1 << _RZ(d))
+
+typedef struct _miVisuals {
+ struct _miVisuals *next;
+ int depth;
+ int bitsPerRGB;
+ int visuals;
+ int count;
+ int preferredCVC;
+ Pixel redMask, greenMask, blueMask;
+} miVisualsRec, *miVisualsPtr;
+
+static int miVisualPriority[] = {
+ PseudoColor, GrayScale, StaticColor, TrueColor, DirectColor, StaticGray
+};
+
+#define NUM_PRIORITY 6
+
+static miVisualsPtr miVisuals;
+
+void
+miClearVisualTypes()
+{
+ miVisualsPtr v;
+
+ while ((v = miVisuals)) {
+ miVisuals = v->next;
+ xfree(v);
+ }
+}
+
+
+Bool
+miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
+ int preferredCVC,
+ Pixel redMask, Pixel greenMask, Pixel blueMask)
+{
+ miVisualsPtr new, *prev, v;
+ int count;
+
+ new = (miVisualsPtr) xalloc (sizeof *new);
+ if (!new)
+ return FALSE;
+ if (!redMask || !greenMask || !blueMask)
+ {
+ redMask = _RM(depth);
+ greenMask = _GM(depth);
+ blueMask = _BM(depth);
+ }
+ new->next = 0;
+ new->depth = depth;
+ new->visuals = visuals;
+ new->bitsPerRGB = bitsPerRGB;
+ new->preferredCVC = preferredCVC;
+ new->redMask = redMask;
+ new->greenMask = greenMask;
+ new->blueMask = blueMask;
+ count = (visuals >> 1) & 033333333333;
+ count = visuals - count - ((count >> 1) & 033333333333);
+ count = (((count + (count >> 3)) & 030707070707) % 077); /* HAKMEM 169 */
+ new->count = count;
+ for (prev = &miVisuals; (v = *prev); prev = &v->next);
+ *prev = new;
+ return TRUE;
+}
+
+Bool
+miSetVisualTypes(int depth, int visuals, int bitsPerRGB, int preferredCVC)
+{
+ return miSetVisualTypesAndMasks (depth, visuals, bitsPerRGB,
+ preferredCVC, 0, 0, 0);
+}
+
+int
+miGetDefaultVisualMask(int depth)
+{
+ if (depth > MAX_PSEUDO_DEPTH)
+ return LARGE_VISUALS;
+ else if (depth >= MIN_TRUE_DEPTH)
+ return ALL_VISUALS;
+ else if (depth == 1)
+ return StaticGrayMask;
+ else
+ return SMALL_VISUALS;
+}
+
+static Bool
+miVisualTypesSet (int depth)
+{
+ miVisualsPtr visuals;
+
+ for (visuals = miVisuals; visuals; visuals = visuals->next)
+ if (visuals->depth == depth)
+ return TRUE;
+ return FALSE;
+}
+
+Bool
+miSetPixmapDepths (void)
+{
+ int d, f;
+
+ /* Add any unlisted depths from the pixmap formats */
+ for (f = 0; f < screenInfo.numPixmapFormats; f++)
+ {
+ d = screenInfo.formats[f].depth;
+ if (!miVisualTypesSet (d))
+ {
+ if (!miSetVisualTypes (d, 0, 0, -1))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+Bool
+miInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
+ int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
+ unsigned long sizes, int bitsPerRGB, int preferredVis)
+
+{
+ if (miInitVisualsProc)
+ return miInitVisualsProc(visualp, depthp, nvisualp, ndepthp,
+ rootDepthp, defaultVisp, sizes, bitsPerRGB,
+ preferredVis);
+ else
+ return FALSE;
+}
+
+/*
+ * Distance to least significant one bit
+ */
+static int
+maskShift (Pixel p)
+{
+ int s;
+
+ if (!p) return 0;
+ s = 0;
+ while (!(p & 1))
+ {
+ s++;
+ p >>= 1;
+ }
+ return s;
+}
+
+/*
+ * Given a list of formats for a screen, create a list
+ * of visuals and depths for the screen which corespond to
+ * the set which can be used with this version of cfb.
+ */
+
+static Bool
+miDoInitVisuals(VisualPtr *visualp, DepthPtr *depthp, int *nvisualp,
+ int *ndepthp, int *rootDepthp, VisualID *defaultVisp,
+ unsigned long sizes, int bitsPerRGB, int preferredVis)
+{
+ int i, j = 0, k;
+ VisualPtr visual;
+ DepthPtr depth;
+ VisualID *vid;
+ int d, b;
+ int f;
+ int ndepth, nvisual;
+ int nvtype;
+ int vtype;
+ miVisualsPtr visuals, nextVisuals;
+ int *preferredCVCs, *prefp;
+
+ /* none specified, we'll guess from pixmap formats */
+ if (!miVisuals)
+ {
+ for (f = 0; f < screenInfo.numPixmapFormats; f++)
+ {
+ d = screenInfo.formats[f].depth;
+ b = screenInfo.formats[f].bitsPerPixel;
+ if (sizes & (1 << (b - 1)))
+ vtype = miGetDefaultVisualMask(d);
+ else
+ vtype = 0;
+ if (!miSetVisualTypes (d, vtype, bitsPerRGB, -1))
+ return FALSE;
+ }
+ }
+ nvisual = 0;
+ ndepth = 0;
+ for (visuals = miVisuals; visuals; visuals = nextVisuals)
+ {
+ nextVisuals = visuals->next;
+ ndepth++;
+ nvisual += visuals->count;
+ }
+ depth = (DepthPtr) xalloc (ndepth * sizeof (DepthRec));
+ visual = (VisualPtr) xalloc (nvisual * sizeof (VisualRec));
+ preferredCVCs = (int *)xalloc(ndepth * sizeof(int));
+ if (!depth || !visual || !preferredCVCs)
+ {
+ xfree (depth);
+ xfree (visual);
+ xfree (preferredCVCs);
+ return FALSE;
+ }
+ *depthp = depth;
+ *visualp = visual;
+ *ndepthp = ndepth;
+ *nvisualp = nvisual;
+ prefp = preferredCVCs;
+ for (visuals = miVisuals; visuals; visuals = nextVisuals)
+ {
+ nextVisuals = visuals->next;
+ d = visuals->depth;
+ vtype = visuals->visuals;
+ nvtype = visuals->count;
+ *prefp = visuals->preferredCVC;
+ prefp++;
+ vid = NULL;
+ if (nvtype)
+ {
+ vid = (VisualID *) xalloc (nvtype * sizeof (VisualID));
+ if (!vid)
+ return FALSE;
+ }
+ depth->depth = d;
+ depth->numVids = nvtype;
+ depth->vids = vid;
+ depth++;
+ for (i = 0; i < NUM_PRIORITY; i++) {
+ if (! (vtype & (1 << miVisualPriority[i])))
+ continue;
+ visual->class = miVisualPriority[i];
+ visual->bitsPerRGBValue = visuals->bitsPerRGB;
+ visual->ColormapEntries = 1 << d;
+ visual->nplanes = d;
+ visual->vid = *vid = FakeClientID (0);
+ switch (visual->class) {
+ case PseudoColor:
+ case GrayScale:
+ case StaticGray:
+ visual->redMask = 0;
+ visual->greenMask = 0;
+ visual->blueMask = 0;
+ visual->offsetRed = 0;
+ visual->offsetGreen = 0;
+ visual->offsetBlue = 0;
+ break;
+ case DirectColor:
+ case TrueColor:
+ visual->ColormapEntries = _CE(d);
+ /* fall through */
+ case StaticColor:
+ visual->redMask = visuals->redMask;
+ visual->greenMask = visuals->greenMask;
+ visual->blueMask = visuals->blueMask;
+ visual->offsetRed = maskShift (visuals->redMask);
+ visual->offsetGreen = maskShift (visuals->greenMask);
+ visual->offsetBlue = maskShift (visuals->blueMask);
+ }
+ vid++;
+ visual++;
+ }
+ xfree (visuals);
+ }
+ miVisuals = NULL;
+ visual = *visualp;
+ depth = *depthp;
+ for (i = 0; i < ndepth; i++)
+ {
+ int prefColorVisualClass = -1;
+
+ if (defaultColorVisualClass >= 0)
+ prefColorVisualClass = defaultColorVisualClass;
+ else if (preferredVis >= 0)
+ prefColorVisualClass = preferredVis;
+ else if (preferredCVCs[i] >= 0)
+ prefColorVisualClass = preferredCVCs[i];
+
+ if (*rootDepthp && *rootDepthp != depth[i].depth)
+ continue;
+
+ for (j = 0; j < depth[i].numVids; j++)
+ {
+ for (k = 0; k < nvisual; k++)
+ if (visual[k].vid == depth[i].vids[j])
+ break;
+ if (k == nvisual)
+ continue;
+ if (prefColorVisualClass < 0 ||
+ visual[k].class == prefColorVisualClass)
+ break;
+ }
+ if (j != depth[i].numVids)
+ break;
+ }
+ if (i == ndepth) {
+ i = 0;
+ j = 0;
+ }
+ *rootDepthp = depth[i].depth;
+ *defaultVisp = depth[i].vids[j];
+ xfree(preferredCVCs);
+
+ return TRUE;
+}
+
+void
+miResetInitVisuals()
+{
+ miInitVisualsProc = miDoInitVisuals;
+}
+
diff --git a/mi/micmap.h b/mi/micmap.h
new file mode 100644
index 000000000..557ae63d5
--- /dev/null
+++ b/mi/micmap.h
@@ -0,0 +1,65 @@
+/* $XFree86: xc/programs/Xserver/mi/micmap.h,v 1.7 2000/09/20 00:09:15 keithp Exp $ */
+
+#include "colormapst.h"
+
+#ifndef _MICMAP_H_
+#define _MICMAP_H_
+
+extern ColormapPtr miInstalledMaps[MAXSCREENS];
+
+typedef Bool (* miInitVisualsProcPtr)(VisualPtr *, DepthPtr *, int *, int *,
+ int *, VisualID *, unsigned long, int,
+ int);
+
+extern miInitVisualsProcPtr miInitVisualsProc;
+
+int miListInstalledColormaps(ScreenPtr pScreen, Colormap *pmaps);
+void miInstallColormap(ColormapPtr pmap);
+void miUninstallColormap(ColormapPtr pmap);
+
+void miResolveColor(unsigned short *, unsigned short *, unsigned short *,
+ VisualPtr);
+Bool miInitializeColormap(ColormapPtr);
+int miExpandDirectColors(ColormapPtr, int, xColorItem *, xColorItem *);
+Bool miCreateDefColormap(ScreenPtr);
+void miClearVisualTypes(void);
+Bool miSetVisualTypes(int, int, int, int);
+Bool miSetPixmapDepths(void);
+Bool miSetVisualTypesAndMasks(int depth, int visuals, int bitsPerRGB,
+ int preferredCVC,
+ Pixel redMask, Pixel greenMask, Pixel blueMask);
+int miGetDefaultVisualMask(int);
+Bool miInitVisuals(VisualPtr *, DepthPtr *, int *, int *, int *, VisualID *,
+ unsigned long, int, int);
+void miResetInitVisuals(void);
+
+void miHookInitVisuals(void (**old)(miInitVisualsProcPtr *),
+ void (*new)(miInitVisualsProcPtr *));
+
+
+#define MAX_PSEUDO_DEPTH 10
+#define MIN_TRUE_DEPTH 6
+
+#define StaticGrayMask (1 << StaticGray)
+#define GrayScaleMask (1 << GrayScale)
+#define StaticColorMask (1 << StaticColor)
+#define PseudoColorMask (1 << PseudoColor)
+#define TrueColorMask (1 << TrueColor)
+#define DirectColorMask (1 << DirectColor)
+
+#define ALL_VISUALS (StaticGrayMask|\
+ GrayScaleMask|\
+ StaticColorMask|\
+ PseudoColorMask|\
+ TrueColorMask|\
+ DirectColorMask)
+
+#define LARGE_VISUALS (TrueColorMask|\
+ DirectColorMask)
+
+#define SMALL_VISUALS (StaticGrayMask|\
+ GrayScaleMask|\
+ StaticColorMask|\
+ PseudoColorMask)
+
+#endif /* _MICMAP_H_ */
diff --git a/mi/micoord.h b/mi/micoord.h
new file mode 100644
index 000000000..f31c88c83
--- /dev/null
+++ b/mi/micoord.h
@@ -0,0 +1,71 @@
+/* $XFree86: xc/programs/Xserver/mi/micoord.h,v 1.5 2002/05/22 21:38:31 herrb Exp $ */
+/*
+ * Copyright (C) 2000 The XFree86 Project, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the XFree86 Project shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization from the
+ * XFree86 Project.
+ *
+ */
+
+#ifndef _MICOORD_H_
+#define _MICOORD_H_ 1
+
+#include "servermd.h"
+
+/* Macros which handle a coordinate in a single register */
+
+/*
+ * Most compilers will convert divisions by 65536 into shifts, if signed
+ * shifts exist. If your machine does arithmetic shifts and your compiler
+ * can't get it right, add to this line.
+ */
+
+/*
+ * mips compiler - what a joke - it CSEs the 65536 constant into a reg
+ * forcing as to use div instead of shift. Let's be explicit.
+ */
+
+#if defined(mips) || \
+ defined(sparc) || defined(__sparc64__) || \
+ defined(__alpha) || defined(__alpha__) || \
+ defined(__i386__) || defined(i386) || \
+ defined(__ia64__) || defined(ia64) || \
+ defined(__s390x__) || defined(__s390__) || \
+ defined(__x86_64__) || defined(x86_64)
+#define GetHighWord(x) (((int) (x)) >> 16)
+#else
+#define GetHighWord(x) (((int) (x)) / 65536)
+#endif
+
+#if IMAGE_BYTE_ORDER == MSBFirst
+#define intToCoord(i,x,y) (((x) = GetHighWord(i)), ((y) = (int) ((short) (i))))
+#define coordToInt(x,y) (((x) << 16) | ((y) & 0xffff))
+#define intToX(i) (GetHighWord(i))
+#define intToY(i) ((int) ((short) i))
+#else
+#define intToCoord(i,x,y) (((x) = (int) ((short) (i))), ((y) = GetHighWord(i)))
+#define coordToInt(x,y) (((y) << 16) | ((x) & 0xffff))
+#define intToX(i) ((int) ((short) (i)))
+#define intToY(i) (GetHighWord(i))
+#endif
+
+#endif /* _MICOORD_H_ */
diff --git a/mi/mioverlay.c b/mi/mioverlay.c
new file mode 100644
index 000000000..9e765b206
--- /dev/null
+++ b/mi/mioverlay.c
@@ -0,0 +1,2078 @@
+/* $XFree86: xc/programs/Xserver/mi/mioverlay.c,v 3.14 2002/10/18 00:07:13 mvojkovi Exp $ */
+
+#include "X.h"
+#include "scrnintstr.h"
+#include "validate.h"
+#include "windowstr.h"
+#include "mi.h"
+#include "gcstruct.h"
+#include "regionstr.h"
+#include "mivalidate.h"
+#include "mioverlay.h"
+#include "migc.h"
+
+#include "globals.h"
+
+
+typedef struct {
+ RegionRec exposed;
+ RegionRec borderExposed;
+ RegionPtr borderVisible;
+ DDXPointRec oldAbsCorner;
+} miOverlayValDataRec, *miOverlayValDataPtr;
+
+typedef struct _TreeRec {
+ WindowPtr pWin;
+ struct _TreeRec *parent;
+ struct _TreeRec *firstChild;
+ struct _TreeRec *lastChild;
+ struct _TreeRec *prevSib;
+ struct _TreeRec *nextSib;
+ RegionRec borderClip;
+ RegionRec clipList;
+ unsigned visibility;
+ miOverlayValDataPtr valdata;
+} miOverlayTreeRec, *miOverlayTreePtr;
+
+typedef struct {
+ miOverlayTreePtr tree;
+} miOverlayWindowRec, *miOverlayWindowPtr;
+
+typedef struct {
+ CloseScreenProcPtr CloseScreen;
+ CreateWindowProcPtr CreateWindow;
+ DestroyWindowProcPtr DestroyWindow;
+ UnrealizeWindowProcPtr UnrealizeWindow;
+ RealizeWindowProcPtr RealizeWindow;
+ miOverlayTransFunc MakeTransparent;
+ miOverlayInOverlayFunc InOverlay;
+ Bool underlayMarked;
+ Bool copyUnderlay;
+} miOverlayScreenRec, *miOverlayScreenPtr;
+
+static unsigned long miOverlayGeneration = 0;
+int miOverlayWindowIndex = -1;
+int miOverlayScreenIndex = -1;
+
+static void RebuildTree(WindowPtr);
+static Bool HasUnderlayChildren(WindowPtr);
+static void MarkUnderlayWindow(WindowPtr);
+static Bool CollectUnderlayChildrenRegions(WindowPtr, RegionPtr);
+
+static Bool miOverlayCloseScreen(int, ScreenPtr);
+static Bool miOverlayCreateWindow(WindowPtr);
+static Bool miOverlayDestroyWindow(WindowPtr);
+static Bool miOverlayUnrealizeWindow(WindowPtr);
+static Bool miOverlayRealizeWindow(WindowPtr);
+static void miOverlayMarkWindow(WindowPtr);
+static void miOverlayReparentWindow(WindowPtr, WindowPtr);
+static void miOverlayRestackWindow(WindowPtr, WindowPtr);
+static Bool miOverlayMarkOverlappedWindows(WindowPtr, WindowPtr, WindowPtr*);
+static void miOverlayMarkUnrealizedWindow(WindowPtr, WindowPtr, Bool);
+static int miOverlayValidateTree(WindowPtr, WindowPtr, VTKind);
+static void miOverlayHandleExposures(WindowPtr);
+static void miOverlayMoveWindow(WindowPtr, int, int, WindowPtr, VTKind);
+static void miOverlayWindowExposures(WindowPtr, RegionPtr, RegionPtr);
+static void miOverlayResizeWindow(WindowPtr, int, int, unsigned int,
+ unsigned int, WindowPtr);
+static void miOverlayClearToBackground(WindowPtr, int, int, int, int, Bool);
+
+#ifdef SHAPE
+static void miOverlaySetShape(WindowPtr);
+#endif
+static void miOverlayChangeBorderWidth(WindowPtr, unsigned int);
+
+#define MIOVERLAY_GET_SCREEN_PRIVATE(pScreen) \
+ ((miOverlayScreenPtr)((pScreen)->devPrivates[miOverlayScreenIndex].ptr))
+#define MIOVERLAY_GET_WINDOW_PRIVATE(pWin) \
+ ((miOverlayWindowPtr)((pWin)->devPrivates[miOverlayWindowIndex].ptr))
+#define MIOVERLAY_GET_WINDOW_TREE(pWin) \
+ (MIOVERLAY_GET_WINDOW_PRIVATE(pWin)->tree)
+
+#define IN_UNDERLAY(w) MIOVERLAY_GET_WINDOW_TREE(w)
+#define IN_OVERLAY(w) !MIOVERLAY_GET_WINDOW_TREE(w)
+
+#define MARK_OVERLAY(w) miMarkWindow(w)
+#define MARK_UNDERLAY(w) MarkUnderlayWindow(w)
+
+#define HasParentRelativeBorder(w) (!(w)->borderIsPixel && \
+ HasBorder(w) && \
+ (w)->backgroundState == ParentRelative)
+
+Bool
+miInitOverlay(
+ ScreenPtr pScreen,
+ miOverlayInOverlayFunc inOverlayFunc,
+ miOverlayTransFunc transFunc
+){
+ miOverlayScreenPtr pScreenPriv;
+
+ if(!inOverlayFunc || !transFunc) return FALSE;
+
+ if(miOverlayGeneration != serverGeneration) {
+ if(((miOverlayScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
+ ((miOverlayWindowIndex = AllocateWindowPrivateIndex()) < 0))
+ return FALSE;
+
+ miOverlayGeneration = serverGeneration;
+ }
+
+ if(!AllocateWindowPrivate(pScreen, miOverlayWindowIndex,
+ sizeof(miOverlayWindowRec)))
+ return FALSE;
+
+ if(!(pScreenPriv = xalloc(sizeof(miOverlayScreenRec))))
+ return FALSE;
+
+ pScreen->devPrivates[miOverlayScreenIndex].ptr = (pointer)pScreenPriv;
+
+ pScreenPriv->InOverlay = inOverlayFunc;
+ pScreenPriv->MakeTransparent = transFunc;
+ pScreenPriv->underlayMarked = FALSE;
+
+
+ pScreenPriv->CloseScreen = pScreen->CloseScreen;
+ pScreenPriv->CreateWindow = pScreen->CreateWindow;
+ pScreenPriv->DestroyWindow = pScreen->DestroyWindow;
+ pScreenPriv->UnrealizeWindow = pScreen->UnrealizeWindow;
+ pScreenPriv->RealizeWindow = pScreen->RealizeWindow;
+
+ pScreen->CloseScreen = miOverlayCloseScreen;
+ pScreen->CreateWindow = miOverlayCreateWindow;
+ pScreen->DestroyWindow = miOverlayDestroyWindow;
+ pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
+ pScreen->RealizeWindow = miOverlayRealizeWindow;
+
+ pScreen->ReparentWindow = miOverlayReparentWindow;
+ pScreen->RestackWindow = miOverlayRestackWindow;
+ pScreen->MarkOverlappedWindows = miOverlayMarkOverlappedWindows;
+ pScreen->MarkUnrealizedWindow = miOverlayMarkUnrealizedWindow;
+ pScreen->ValidateTree = miOverlayValidateTree;
+ pScreen->HandleExposures = miOverlayHandleExposures;
+ pScreen->MoveWindow = miOverlayMoveWindow;
+ pScreen->WindowExposures = miOverlayWindowExposures;
+ pScreen->ResizeWindow = miOverlayResizeWindow;
+ pScreen->MarkWindow = miOverlayMarkWindow;
+ pScreen->ClearToBackground = miOverlayClearToBackground;
+#ifdef SHAPE
+ pScreen->SetShape = miOverlaySetShape;
+#endif
+ pScreen->ChangeBorderWidth = miOverlayChangeBorderWidth;
+
+ return TRUE;
+}
+
+
+static Bool
+miOverlayCloseScreen(int i, ScreenPtr pScreen)
+{
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+
+ pScreen->CloseScreen = pScreenPriv->CloseScreen;
+ pScreen->CreateWindow = pScreenPriv->CreateWindow;
+ pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
+ pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
+ pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
+
+ xfree(pScreenPriv);
+
+ return (*pScreen->CloseScreen)(i, pScreen);
+}
+
+
+static Bool
+miOverlayCreateWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayWindowPtr pWinPriv = MIOVERLAY_GET_WINDOW_PRIVATE(pWin);
+ miOverlayTreePtr pTree = NULL;
+ Bool result = TRUE;
+
+ pWinPriv->tree = NULL;
+
+ if(!pWin->parent || !((*pScreenPriv->InOverlay)(pWin))) {
+ if(!(pTree = (miOverlayTreePtr)xcalloc(1, sizeof(miOverlayTreeRec))))
+ return FALSE;
+ }
+
+ if(pScreenPriv->CreateWindow) {
+ pScreen->CreateWindow = pScreenPriv->CreateWindow;
+ result = (*pScreen->CreateWindow)(pWin);
+ pScreen->CreateWindow = miOverlayCreateWindow;
+ }
+
+ if (pTree) {
+ if(result) {
+ pTree->pWin = pWin;
+ pTree->visibility = VisibilityNotViewable;
+ pWinPriv->tree = pTree;
+ if(pWin->parent) {
+ REGION_INIT(pScreen, &(pTree->borderClip), NullBox, 1);
+ REGION_INIT(pScreen, &(pTree->clipList), NullBox, 1);
+ RebuildTree(pWin);
+ } else {
+ BoxRec fullBox;
+ fullBox.x1 = 0;
+ fullBox.y1 = 0;
+ fullBox.x2 = pScreen->width;
+ fullBox.y2 = pScreen->height;
+ REGION_INIT(pScreen, &(pTree->borderClip), &fullBox, 1);
+ REGION_INIT(pScreen, &(pTree->clipList), &fullBox, 1);
+ }
+ } else xfree(pTree);
+ }
+
+ return TRUE;
+}
+
+
+static Bool
+miOverlayDestroyWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ Bool result = TRUE;
+
+ if (pTree) {
+ if(pTree->prevSib)
+ pTree->prevSib->nextSib = pTree->nextSib;
+ else if(pTree->parent)
+ pTree->parent->firstChild = pTree->nextSib;
+
+ if(pTree->nextSib)
+ pTree->nextSib->prevSib = pTree->prevSib;
+ else if(pTree->parent)
+ pTree->parent->lastChild = pTree->prevSib;
+
+ REGION_UNINIT(pScreen, &(pTree->borderClip));
+ REGION_UNINIT(pScreen, &(pTree->clipList));
+ xfree(pTree);
+ }
+
+ if(pScreenPriv->DestroyWindow) {
+ pScreen->DestroyWindow = pScreenPriv->DestroyWindow;
+ result = (*pScreen->DestroyWindow)(pWin);
+ pScreen->DestroyWindow = miOverlayDestroyWindow;
+ }
+
+ return result;
+}
+
+static Bool
+miOverlayUnrealizeWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ Bool result = TRUE;
+
+ if(pTree) pTree->visibility = VisibilityNotViewable;
+
+ if(pScreenPriv->UnrealizeWindow) {
+ pScreen->UnrealizeWindow = pScreenPriv->UnrealizeWindow;
+ result = (*pScreen->UnrealizeWindow)(pWin);
+ pScreen->UnrealizeWindow = miOverlayUnrealizeWindow;
+ }
+
+ return result;
+}
+
+
+static Bool
+miOverlayRealizeWindow(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ Bool result = TRUE;
+
+ if(pScreenPriv->RealizeWindow) {
+ pScreen->RealizeWindow = pScreenPriv->RealizeWindow;
+ result = (*pScreen->RealizeWindow)(pWin);
+ pScreen->RealizeWindow = miOverlayRealizeWindow;
+ }
+
+ /* we only need to catch the root window realization */
+
+ if(result && !pWin->parent && !((*pScreenPriv->InOverlay)(pWin)))
+ {
+ BoxRec box;
+ box.x1 = box.y1 = 0;
+ box.x2 = pWin->drawable.width;
+ box.y2 = pWin->drawable.height;
+ (*pScreenPriv->MakeTransparent)(pScreen, 1, &box);
+ }
+
+ return result;
+}
+
+
+static void
+miOverlayReparentWindow(WindowPtr pWin, WindowPtr pPriorParent)
+{
+ if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
+ /* This could probably be more optimal */
+ RebuildTree(WindowTable[pWin->drawable.pScreen->myNum]->firstChild);
+ }
+}
+
+static void
+miOverlayRestackWindow(WindowPtr pWin, WindowPtr oldNextSib)
+{
+ if(IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin)) {
+ /* This could probably be more optimal */
+ RebuildTree(pWin);
+ }
+}
+
+
+static Bool
+miOverlayMarkOverlappedWindows(
+ WindowPtr pWin,
+ WindowPtr pFirst,
+ WindowPtr *pLayerWin
+){
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ WindowPtr pChild, pLast;
+ Bool overMarked, underMarked, doUnderlay, markAll;
+ miOverlayTreePtr pTree = NULL, tLast, tChild;
+ BoxPtr box;
+
+ overMarked = underMarked = markAll = FALSE;
+
+ if(pLayerWin) *pLayerWin = pWin; /* hah! */
+
+ doUnderlay = (IN_UNDERLAY(pWin) || HasUnderlayChildren(pWin));
+
+ box = REGION_EXTENTS(pScreen, &pWin->borderSize);
+
+ if((pChild = pFirst)) {
+ pLast = pChild->parent->lastChild;
+ while (1) {
+ if (pChild == pWin) markAll = TRUE;
+
+ if(doUnderlay && IN_UNDERLAY(pChild))
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+
+ if(pChild->viewable) {
+ if (REGION_BROKEN (pScreen, &pChild->winSize))
+ SetWinSize (pChild);
+ if (REGION_BROKEN (pScreen, &pChild->borderSize))
+ SetBorderSize (pChild);
+
+ if (markAll ||
+ RECT_IN_REGION(pScreen, &pChild->borderSize, box))
+ {
+ MARK_OVERLAY(pChild);
+ overMarked = TRUE;
+ if(doUnderlay && IN_UNDERLAY(pChild)) {
+ MARK_UNDERLAY(pChild);
+ underMarked = TRUE;
+ }
+ if (pChild->firstChild) {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ }
+ while (!pChild->nextSib && (pChild != pLast)) {
+ pChild = pChild->parent;
+ if(doUnderlay && IN_UNDERLAY(pChild))
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ }
+
+ if(pChild == pWin) markAll = FALSE;
+
+ if (pChild == pLast) break;
+
+ pChild = pChild->nextSib;
+ }
+ if(overMarked)
+ MARK_OVERLAY(pWin->parent);
+ }
+
+ if(doUnderlay && !pTree) {
+ if(!(pTree = MIOVERLAY_GET_WINDOW_TREE(pWin))) {
+ pChild = pWin->lastChild;
+ while(1) {
+ if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild)))
+ break;
+
+ if(pChild->lastChild) {
+ pChild = pChild->lastChild;
+ continue;
+ }
+
+ while(!pChild->prevSib) pChild = pChild->parent;
+
+ pChild = pChild->prevSib;
+ }
+ }
+ }
+
+ if(pTree && pTree->nextSib) {
+ tChild = pTree->parent->lastChild;
+ tLast = pTree->nextSib;
+
+ while(1) {
+ if(tChild->pWin->viewable) {
+ if (REGION_BROKEN (pScreen, &tChild->pWin->winSize))
+ SetWinSize (tChild->pWin);
+ if (REGION_BROKEN (pScreen, &tChild->pWin->borderSize))
+ SetBorderSize (tChild->pWin);
+
+ if(RECT_IN_REGION(pScreen, &(tChild->pWin->borderSize), box))
+ {
+ MARK_UNDERLAY(tChild->pWin);
+ underMarked = TRUE;
+ }
+ }
+
+ if(tChild->lastChild) {
+ tChild = tChild->lastChild;
+ continue;
+ }
+
+ while(!tChild->prevSib && (tChild != tLast))
+ tChild = tChild->parent;
+
+ if(tChild == tLast) break;
+
+ tChild = tChild->prevSib;
+ }
+ }
+
+ if(underMarked) {
+ MARK_UNDERLAY(pTree->parent->pWin);
+ MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->underlayMarked = TRUE;
+ }
+
+ return (underMarked || overMarked);
+}
+
+
+static void
+miOverlayComputeClips(
+ WindowPtr pParent,
+ RegionPtr universe,
+ VTKind kind,
+ RegionPtr exposed
+){
+ ScreenPtr pScreen = pParent->drawable.pScreen;
+ int oldVis, newVis, dx, dy;
+ BoxRec borderSize;
+ RegionPtr borderVisible;
+ RegionRec childUniverse, childUnion;
+ miOverlayTreePtr tParent = MIOVERLAY_GET_WINDOW_TREE(pParent);
+ miOverlayTreePtr tChild;
+ Bool overlap;
+
+ borderSize.x1 = pParent->drawable.x - wBorderWidth(pParent);
+ borderSize.y1 = pParent->drawable.y - wBorderWidth(pParent);
+ dx = (int) pParent->drawable.x + (int) pParent->drawable.width +
+ wBorderWidth(pParent);
+ if (dx > 32767) dx = 32767;
+ borderSize.x2 = dx;
+ dy = (int) pParent->drawable.y + (int) pParent->drawable.height +
+ wBorderWidth(pParent);
+ if (dy > 32767) dy = 32767;
+ borderSize.y2 = dy;
+
+ oldVis = tParent->visibility;
+ switch (RECT_IN_REGION( pScreen, universe, &borderSize)) {
+ case rgnIN:
+ newVis = VisibilityUnobscured;
+ break;
+ case rgnPART:
+ newVis = VisibilityPartiallyObscured;
+#ifdef SHAPE
+ {
+ RegionPtr pBounding;
+
+ if ((pBounding = wBoundingShape (pParent))) {
+ switch (miShapedWindowIn (pScreen, universe, pBounding,
+ &borderSize,
+ pParent->drawable.x,
+ pParent->drawable.y))
+ {
+ case rgnIN:
+ newVis = VisibilityUnobscured;
+ break;
+ case rgnOUT:
+ newVis = VisibilityFullyObscured;
+ break;
+ }
+ }
+ }
+#endif
+ break;
+ default:
+ newVis = VisibilityFullyObscured;
+ break;
+ }
+ tParent->visibility = newVis;
+
+ dx = pParent->drawable.x - tParent->valdata->oldAbsCorner.x;
+ dy = pParent->drawable.y - tParent->valdata->oldAbsCorner.y;
+
+ switch (kind) {
+ case VTMap:
+ case VTStack:
+ case VTUnmap:
+ break;
+ case VTMove:
+ if ((oldVis == newVis) &&
+ ((oldVis == VisibilityFullyObscured) ||
+ (oldVis == VisibilityUnobscured)))
+ {
+ tChild = tParent;
+ while (1) {
+ if (tChild->pWin->viewable) {
+ if (tChild->visibility != VisibilityFullyObscured) {
+ REGION_TRANSLATE( pScreen, &tChild->borderClip, dx, dy);
+ REGION_TRANSLATE( pScreen, &tChild->clipList, dx, dy);
+
+ tChild->pWin->drawable.serialNumber =
+ NEXT_SERIAL_NUMBER;
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (tChild->pWin, dx, dy);
+ }
+ if (tChild->valdata) {
+ REGION_INIT(pScreen, &tChild->valdata->borderExposed,
+ NullBox, 0);
+ if (HasParentRelativeBorder(tChild->pWin)){
+ REGION_SUBTRACT(pScreen,
+ &tChild->valdata->borderExposed,
+ &tChild->borderClip,
+ &tChild->pWin->winSize);
+ }
+ REGION_INIT( pScreen, &tChild->valdata->exposed,
+ NullBox, 0);
+ }
+ if (tChild->firstChild) {
+ tChild = tChild->firstChild;
+ continue;
+ }
+ }
+ while (!tChild->nextSib && (tChild != tParent))
+ tChild = tChild->parent;
+ if (tChild == tParent)
+ break;
+ tChild = tChild->nextSib;
+ }
+ return;
+ }
+ /* fall through */
+ default:
+ if (dx || dy) {
+ REGION_TRANSLATE( pScreen, &tParent->borderClip, dx, dy);
+ REGION_TRANSLATE( pScreen, &tParent->clipList, dx, dy);
+ }
+ break;
+ case VTBroken:
+ REGION_EMPTY (pScreen, &tParent->borderClip);
+ REGION_EMPTY (pScreen, &tParent->clipList);
+ break;
+ }
+
+ borderVisible = tParent->valdata->borderVisible;
+ REGION_INIT( pScreen, &tParent->valdata->borderExposed, NullBox, 0);
+ REGION_INIT( pScreen, &tParent->valdata->exposed, NullBox, 0);
+
+ if (HasBorder (pParent)) {
+ if (borderVisible) {
+ REGION_SUBTRACT( pScreen, exposed, universe, borderVisible);
+ REGION_DESTROY( pScreen, borderVisible);
+ } else
+ REGION_SUBTRACT( pScreen, exposed, universe, &tParent->borderClip);
+
+ if (HasParentRelativeBorder(pParent) && (dx || dy))
+ REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed,
+ universe, &pParent->winSize);
+ else
+ REGION_SUBTRACT( pScreen, &tParent->valdata->borderExposed,
+ exposed, &pParent->winSize);
+
+ REGION_COPY( pScreen, &tParent->borderClip, universe);
+ REGION_INTERSECT( pScreen, universe, universe, &pParent->winSize);
+ }
+ else
+ REGION_COPY( pScreen, &tParent->borderClip, universe);
+
+ if ((tChild = tParent->firstChild) && pParent->mapped) {
+ REGION_INIT(pScreen, &childUniverse, NullBox, 0);
+ REGION_INIT(pScreen, &childUnion, NullBox, 0);
+
+ for (; tChild; tChild = tChild->nextSib) {
+ if (tChild->pWin->viewable)
+ REGION_APPEND( pScreen, &childUnion, &tChild->pWin->borderSize);
+ }
+
+ REGION_VALIDATE( pScreen, &childUnion, &overlap);
+
+ for (tChild = tParent->firstChild;
+ tChild;
+ tChild = tChild->nextSib)
+ {
+ if (tChild->pWin->viewable) {
+ if (tChild->valdata) {
+ REGION_INTERSECT( pScreen, &childUniverse, universe,
+ &tChild->pWin->borderSize);
+ miOverlayComputeClips (tChild->pWin, &childUniverse,
+ kind, exposed);
+ }
+ if (overlap)
+ REGION_SUBTRACT( pScreen, universe, universe,
+ &tChild->pWin->borderSize);
+ }
+ }
+ if (!overlap)
+ REGION_SUBTRACT( pScreen, universe, universe, &childUnion);
+ REGION_UNINIT( pScreen, &childUnion);
+ REGION_UNINIT( pScreen, &childUniverse);
+ }
+
+ if (oldVis == VisibilityFullyObscured ||
+ oldVis == VisibilityNotViewable)
+ {
+ REGION_COPY( pScreen, &tParent->valdata->exposed, universe);
+ }
+ else if (newVis != VisibilityFullyObscured &&
+ newVis != VisibilityNotViewable)
+ {
+ REGION_SUBTRACT( pScreen, &tParent->valdata->exposed,
+ universe, &tParent->clipList);
+ }
+
+ /* HACK ALERT - copying contents of regions, instead of regions */
+ {
+ RegionRec tmp;
+
+ tmp = tParent->clipList;
+ tParent->clipList = *universe;
+ *universe = tmp;
+ }
+
+ pParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+
+ if (pScreen->ClipNotify)
+ (* pScreen->ClipNotify) (pParent, dx, dy);
+}
+
+
+static void
+miOverlayMarkWindow(WindowPtr pWin)
+{
+ miOverlayTreePtr pTree = NULL;
+ WindowPtr pChild, pGrandChild;
+
+ miMarkWindow(pWin);
+
+ /* look for UnmapValdata among immediate children */
+
+ if(!(pChild = pWin->firstChild)) return;
+
+ for( ; pChild; pChild = pChild->nextSib) {
+ if(pChild->valdata == UnmapValData) {
+ if(IN_UNDERLAY(pChild)) {
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ pTree->valdata = (miOverlayValDataPtr)UnmapValData;
+ continue;
+ } else {
+ if(!(pGrandChild = pChild->firstChild))
+ continue;
+
+ while(1) {
+ if(IN_UNDERLAY(pGrandChild)) {
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pGrandChild);
+ pTree->valdata = (miOverlayValDataPtr)UnmapValData;
+ } else if(pGrandChild->firstChild) {
+ pGrandChild = pGrandChild->firstChild;
+ continue;
+ }
+
+ while(!pGrandChild->nextSib && (pGrandChild != pChild))
+ pGrandChild = pGrandChild->parent;
+
+ if(pChild == pGrandChild) break;
+
+ pGrandChild = pGrandChild->nextSib;
+ }
+ }
+ }
+ }
+
+ if(pTree) {
+ MARK_UNDERLAY(pTree->parent->pWin);
+ MIOVERLAY_GET_SCREEN_PRIVATE(
+ pWin->drawable.pScreen)->underlayMarked = TRUE;
+ }
+}
+
+static void
+miOverlayMarkUnrealizedWindow(
+ WindowPtr pChild,
+ WindowPtr pWin,
+ Bool fromConfigure
+){
+ if ((pChild != pWin) || fromConfigure) {
+ miOverlayTreePtr pTree;
+
+ REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList);
+ if (pChild->drawable.pScreen->ClipNotify)
+ (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0);
+ REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip);
+ if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
+ if(pTree->valdata != (miOverlayValDataPtr)UnmapValData) {
+ REGION_EMPTY(pChild->drawable.pScreen, &pTree->clipList);
+ REGION_EMPTY(pChild->drawable.pScreen, &pTree->borderClip);
+ }
+ }
+ }
+}
+
+
+static int
+miOverlayValidateTree(
+ WindowPtr pParent,
+ WindowPtr pChild, /* first child effected */
+ VTKind kind
+){
+ ScreenPtr pScreen = pParent->drawable.pScreen;
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ RegionRec totalClip, childClip, exposed;
+ miOverlayTreePtr tParent, tChild, tWin;
+ Bool overlap;
+ WindowPtr newParent;
+
+ if(!pPriv->underlayMarked)
+ goto SKIP_UNDERLAY;
+
+ if (!pChild) pChild = pParent->firstChild;
+
+ REGION_INIT(pScreen, &totalClip, NullBox, 0);
+ REGION_INIT(pScreen, &childClip, NullBox, 0);
+ REGION_INIT(pScreen, &exposed, NullBox, 0);
+
+ newParent = pParent;
+
+ while(IN_OVERLAY(newParent))
+ newParent = newParent->parent;
+
+ tParent = MIOVERLAY_GET_WINDOW_TREE(newParent);
+
+ if(IN_UNDERLAY(pChild))
+ tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ else
+ tChild = tParent->firstChild;
+
+ if (REGION_BROKEN (pScreen, &tParent->clipList) &&
+ !REGION_BROKEN (pScreen, &tParent->borderClip))
+ {
+ kind = VTBroken;
+ REGION_COPY (pScreen, &totalClip, &tParent->borderClip);
+ REGION_INTERSECT (pScreen, &totalClip, &totalClip,
+ &tParent->pWin->winSize);
+
+ for (tWin = tParent->firstChild; tWin != tChild; tWin = tWin->nextSib) {
+ if (tWin->pWin->viewable)
+ REGION_SUBTRACT (pScreen, &totalClip, &totalClip,
+ &tWin->pWin->borderSize);
+ }
+ REGION_EMPTY (pScreen, &tParent->clipList);
+ } else {
+ for(tWin = tChild; tWin; tWin = tWin->nextSib) {
+ if(tWin->valdata)
+ REGION_APPEND(pScreen, &totalClip, &tWin->borderClip);
+ }
+ REGION_VALIDATE(pScreen, &totalClip, &overlap);
+ }
+
+ if(kind != VTStack)
+ REGION_UNION(pScreen, &totalClip, &totalClip, &tParent->clipList);
+
+ for(tWin = tChild; tWin; tWin = tWin->nextSib) {
+ if(tWin->valdata) {
+ if(tWin->pWin->viewable) {
+ REGION_INTERSECT(pScreen, &childClip, &totalClip,
+ &tWin->pWin->borderSize);
+ miOverlayComputeClips(tWin->pWin, &childClip, kind, &exposed);
+ REGION_SUBTRACT(pScreen, &totalClip, &totalClip,
+ &tWin->pWin->borderSize);
+ } else { /* Means we are unmapping */
+ REGION_EMPTY(pScreen, &tWin->clipList);
+ REGION_EMPTY( pScreen, &tWin->borderClip);
+ tWin->valdata = NULL;
+ }
+ }
+ }
+
+ REGION_UNINIT(pScreen, &childClip);
+
+ if(!((*pPriv->InOverlay)(newParent))) {
+ REGION_INIT(pScreen, &tParent->valdata->exposed, NullBox, 0);
+ REGION_INIT(pScreen, &tParent->valdata->borderExposed, NullBox, 0);
+ }
+
+ switch (kind) {
+ case VTStack:
+ break;
+ default:
+ if(!((*pPriv->InOverlay)(newParent)))
+ REGION_SUBTRACT(pScreen, &tParent->valdata->exposed, &totalClip,
+ &tParent->clipList);
+ /* fall through */
+ case VTMap:
+ REGION_COPY( pScreen, &tParent->clipList, &totalClip);
+ if(!((*pPriv->InOverlay)(newParent)))
+ newParent->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+ break;
+ }
+
+ REGION_UNINIT( pScreen, &totalClip);
+ REGION_UNINIT( pScreen, &exposed);
+
+SKIP_UNDERLAY:
+
+ miValidateTree(pParent, pChild, kind);
+
+ return 1;
+}
+
+
+static void
+miOverlayHandleExposures(WindowPtr pWin)
+{
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ WindowPtr pChild;
+ ValidatePtr val;
+ void (* WindowExposures)(WindowPtr, RegionPtr, RegionPtr);
+
+ WindowExposures = pWin->drawable.pScreen->WindowExposures;
+ if(pPriv->underlayMarked) {
+ miOverlayTreePtr pTree;
+ miOverlayValDataPtr mival;
+
+ pChild = pWin;
+ while(IN_OVERLAY(pChild))
+ pChild = pChild->parent;
+
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pChild);
+
+ while (1) {
+ if((mival = pTree->valdata)) {
+ if(!((*pPriv->InOverlay)(pTree->pWin))) {
+ if (REGION_NOTEMPTY(pScreen, &mival->borderExposed))
+ (*pWin->drawable.pScreen->PaintWindowBorder)(
+ pTree->pWin, &mival->borderExposed, PW_BORDER);
+ REGION_UNINIT(pScreen, &mival->borderExposed);
+
+ (*WindowExposures)(pTree->pWin,&mival->exposed,NullRegion);
+ REGION_UNINIT(pScreen, &mival->exposed);
+ }
+ xfree(mival);
+ pTree->valdata = NULL;
+ if (pTree->firstChild) {
+ pTree = pTree->firstChild;
+ continue;
+ }
+ }
+ while (!pTree->nextSib && (pTree->pWin != pChild))
+ pTree = pTree->parent;
+ if (pTree->pWin == pChild)
+ break;
+ pTree = pTree->nextSib;
+ }
+ pPriv->underlayMarked = FALSE;
+ }
+
+ pChild = pWin;
+ while (1) {
+ if ( (val = pChild->valdata) ) {
+ if(!((*pPriv->InOverlay)(pChild))) {
+ REGION_UNION(pScreen, &val->after.exposed, &val->after.exposed,
+ &val->after.borderExposed);
+
+ if (REGION_NOTEMPTY(pScreen, &val->after.exposed)) {
+ (*(MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent))(
+ pScreen,
+ REGION_NUM_RECTS(&val->after.exposed),
+ REGION_RECTS(&val->after.exposed));
+ }
+ } else {
+ if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed))
+ (*pChild->drawable.pScreen->PaintWindowBorder)(pChild,
+ &val->after.borderExposed,
+ PW_BORDER);
+ (*WindowExposures)(pChild, &val->after.exposed, NullRegion);
+ }
+ REGION_UNINIT(pScreen, &val->after.borderExposed);
+ REGION_UNINIT(pScreen, &val->after.exposed);
+ xfree(val);
+ pChild->valdata = (ValidatePtr)NULL;
+ if (pChild->firstChild)
+ {
+ pChild = pChild->firstChild;
+ continue;
+ }
+ }
+ while (!pChild->nextSib && (pChild != pWin))
+ pChild = pChild->parent;
+ if (pChild == pWin)
+ break;
+ pChild = pChild->nextSib;
+ }
+}
+
+
+static void
+miOverlayMoveWindow(
+ WindowPtr pWin,
+ int x,
+ int y,
+ WindowPtr pNextSib,
+ VTKind kind
+){
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ WindowPtr pParent, windowToValidate;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ short bw;
+ RegionRec overReg, underReg;
+ DDXPointRec oldpt;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+
+ if (!(pParent = pWin->parent))
+ return ;
+ bw = wBorderWidth (pWin);
+
+ oldpt.x = pWin->drawable.x;
+ oldpt.y = pWin->drawable.y;
+ if (WasViewable) {
+ REGION_INIT(pScreen, &overReg, NullBox, 1);
+ REGION_INIT(pScreen, &underReg, NullBox, 0);
+ if(pTree) {
+ REGION_COPY(pScreen, &overReg, &pWin->borderClip);
+ REGION_COPY(pScreen, &underReg, &pTree->borderClip);
+ } else {
+ REGION_COPY(pScreen, &overReg, &pWin->borderClip);
+ CollectUnderlayChildrenRegions(pWin, &underReg);
+ }
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+ }
+ pWin->origin.x = x + (int)bw;
+ pWin->origin.y = y + (int)bw;
+ x = pWin->drawable.x = pParent->drawable.x + x + (int)bw;
+ y = pWin->drawable.y = pParent->drawable.y + y + (int)bw;
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ (*pScreen->PositionWindow)(pWin, x, y);
+
+ windowToValidate = MoveWindowInStack(pWin, pNextSib);
+
+ ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0);
+
+ if (WasViewable) {
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ (*pScreen->MarkOverlappedWindows) (pWin, windowToValidate, NULL);
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, windowToValidate);
+#endif /* DO_SAVE_UNDERS */
+
+ (*pScreen->ValidateTree)(pWin->parent, NullWindow, kind);
+ if(REGION_NOTEMPTY(pScreen, &underReg)) {
+ pPriv->copyUnderlay = TRUE;
+ (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &underReg);
+ }
+ REGION_UNINIT(pScreen, &underReg);
+ if(REGION_NOTEMPTY(pScreen, &overReg)) {
+ pPriv->copyUnderlay = FALSE;
+ (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, &overReg);
+ }
+ REGION_UNINIT(pScreen, &overReg);
+ (*pScreen->HandleExposures)(pWin->parent);
+
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, windowToValidate);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, NullWindow, kind);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+#ifndef RECTLIMIT
+#define RECTLIMIT 25
+#endif
+
+static void
+miOverlayWindowExposures(
+ WindowPtr pWin,
+ register RegionPtr prgn,
+ RegionPtr other_exposed
+){
+ RegionPtr exposures = prgn;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+
+ if (pWin->backStorage && prgn)
+ exposures = (*pScreen->RestoreAreas)(pWin, prgn);
+ if ((prgn && !REGION_NIL(prgn)) ||
+ (exposures && !REGION_NIL(exposures)) || other_exposed)
+ {
+ RegionRec expRec;
+ int clientInterested;
+
+ clientInterested = (pWin->eventMask|wOtherEventMasks(pWin)) &
+ ExposureMask;
+ if (other_exposed) {
+ if (exposures) {
+ REGION_UNION(pScreen, other_exposed, exposures, other_exposed);
+ if (exposures != prgn)
+ REGION_DESTROY(pScreen, exposures);
+ }
+ exposures = other_exposed;
+ }
+ if (clientInterested && exposures &&
+ (REGION_NUM_RECTS(exposures) > RECTLIMIT))
+ {
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ BoxRec box;
+
+ box = *REGION_EXTENTS(pScreen, exposures);
+ if (exposures == prgn) {
+ exposures = &expRec;
+ REGION_INIT(pScreen, exposures, &box, 1);
+ REGION_RESET(pScreen, prgn, &box);
+ } else {
+ REGION_RESET(pScreen, exposures, &box);
+ REGION_UNION(pScreen, prgn, prgn, exposures);
+ }
+ /* This is the only reason why we are replacing mi's version
+ of this file */
+
+ if(!((*pPriv->InOverlay)(pWin))) {
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ REGION_INTERSECT(pScreen, prgn, prgn, &pTree->clipList);
+ } else
+ REGION_INTERSECT(pScreen, prgn, prgn, &pWin->clipList);
+
+ /* need to clear out new areas of backing store, too */
+ if (pWin->backStorage)
+ (void) (*pScreen->ClearBackingStore)(
+ pWin,
+ box.x1 - pWin->drawable.x,
+ box.y1 - pWin->drawable.y,
+ box.x2 - box.x1,
+ box.y2 - box.y1,
+ FALSE);
+ }
+ if (prgn && !REGION_NIL(prgn))
+ (*pScreen->PaintWindowBackground)(
+ pWin, prgn, PW_BACKGROUND);
+ if (clientInterested && exposures && !REGION_NIL(exposures))
+ miSendExposures(pWin, exposures,
+ pWin->drawable.x, pWin->drawable.y);
+ if (exposures == &expRec) {
+ REGION_UNINIT(pScreen, exposures);
+ }
+ else if (exposures && exposures != prgn && exposures != other_exposed)
+ REGION_DESTROY(pScreen, exposures);
+ if (prgn)
+ REGION_EMPTY(pScreen, prgn);
+ }
+ else if (exposures && exposures != prgn)
+ REGION_DESTROY(pScreen, exposures);
+}
+
+
+typedef struct {
+ RegionPtr over;
+ RegionPtr under;
+} miOverlayTwoRegions;
+
+static int
+miOverlayRecomputeExposures (
+ WindowPtr pWin,
+ pointer value
+){
+ register ScreenPtr pScreen;
+ miOverlayTwoRegions *pValid = (miOverlayTwoRegions*)value;
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ /* This prevents warning about pScreen not being used. */
+ pWin->drawable.pScreen = pScreen = pWin->drawable.pScreen;
+
+ if (pWin->valdata) {
+ /*
+ * compute exposed regions of this window
+ */
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
+ &pWin->clipList, pValid->over);
+ /*
+ * compute exposed regions of the border
+ */
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
+ &pWin->borderClip, &pWin->winSize);
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
+ &pWin->valdata->after.borderExposed, pValid->over);
+ }
+
+ if(pTree && pTree->valdata) {
+ REGION_SUBTRACT(pScreen, &pTree->valdata->exposed,
+ &pTree->clipList, pValid->under);
+ REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed,
+ &pTree->borderClip, &pWin->winSize);
+ REGION_SUBTRACT(pScreen, &pTree->valdata->borderExposed,
+ &pTree->valdata->borderExposed, pValid->under);
+ } else if (!pWin->valdata)
+ return WT_NOMATCH;
+
+ return WT_WALKCHILDREN;
+}
+
+static void
+miOverlayResizeWindow(
+ WindowPtr pWin,
+ int x, int y,
+ unsigned int w, unsigned int h,
+ WindowPtr pSib
+){
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ WindowPtr pParent;
+ miOverlayTreePtr tChild, pTree;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ unsigned short width = pWin->drawable.width;
+ unsigned short height = pWin->drawable.height;
+ short oldx = pWin->drawable.x;
+ short oldy = pWin->drawable.y;
+ int bw = wBorderWidth (pWin);
+ short dw, dh;
+ DDXPointRec oldpt;
+ RegionPtr oldRegion = NULL, oldRegion2 = NULL;
+ WindowPtr pFirstChange;
+ register WindowPtr pChild;
+ RegionPtr gravitate[StaticGravity + 1];
+ RegionPtr gravitate2[StaticGravity + 1];
+ register unsigned g;
+ int nx, ny; /* destination x,y */
+ int newx, newy; /* new inner window position */
+ RegionPtr pRegion = NULL;
+ RegionPtr destClip, destClip2;
+ RegionPtr oldWinClip = NULL, oldWinClip2 = NULL;
+ RegionPtr borderVisible = NullRegion;
+ RegionPtr borderVisible2 = NullRegion;
+ RegionPtr bsExposed = NullRegion; /* backing store exposures */
+ Bool shrunk = FALSE; /* shrunk in an inner dimension */
+ Bool moved = FALSE; /* window position changed */
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+ Bool doUnderlay;
+
+ /* if this is a root window, can't be resized */
+ if (!(pParent = pWin->parent))
+ return ;
+
+ pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ doUnderlay = ((pTree) || HasUnderlayChildren(pWin));
+ newx = pParent->drawable.x + x + bw;
+ newy = pParent->drawable.y + y + bw;
+ if (WasViewable)
+ {
+ /*
+ * save the visible region of the window
+ */
+ oldRegion = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldRegion, &pWin->winSize);
+ if(doUnderlay) {
+ oldRegion2 = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldRegion2, &pWin->winSize);
+ }
+
+ /*
+ * categorize child windows into regions to be moved
+ */
+ for (g = 0; g <= StaticGravity; g++)
+ gravitate[g] = gravitate2[g] = NULL;
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
+ g = pChild->winGravity;
+ if (g != UnmapGravity) {
+ if (!gravitate[g])
+ gravitate[g] = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_UNION(pScreen, gravitate[g],
+ gravitate[g], &pChild->borderClip);
+
+ if(doUnderlay) {
+ if (!gravitate2[g])
+ gravitate2[g] = REGION_CREATE(pScreen, NullBox, 0);
+
+ if((tChild = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
+ REGION_UNION(pScreen, gravitate2[g],
+ gravitate2[g], &tChild->borderClip);
+ } else
+ CollectUnderlayChildrenRegions(pChild, gravitate2[g]);
+ }
+ } else {
+ UnmapWindow(pChild, TRUE);
+ }
+ }
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+
+ oldWinClip = oldWinClip2 = NULL;
+ if (pWin->bitGravity != ForgetGravity) {
+ oldWinClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldWinClip, &pWin->clipList);
+ if(pTree) {
+ oldWinClip2 = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, oldWinClip2, &pTree->clipList);
+ }
+ }
+ /*
+ * if the window is changing size, borderExposed
+ * can't be computed correctly without some help.
+ */
+ if (pWin->drawable.height > h || pWin->drawable.width > w)
+ shrunk = TRUE;
+
+ if (newx != oldx || newy != oldy)
+ moved = TRUE;
+
+ if ((pWin->drawable.height != h || pWin->drawable.width != w) &&
+ HasBorder (pWin))
+ {
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ if(pTree)
+ borderVisible2 = REGION_CREATE(pScreen, NullBox, 1);
+ /* for tiled borders, we punt and draw the whole thing */
+ if (pWin->borderIsPixel || !moved)
+ {
+ if (shrunk || moved)
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip,
+ &pWin->winSize);
+ else
+ REGION_COPY(pScreen, borderVisible,
+ &pWin->borderClip);
+ if(pTree) {
+ if (shrunk || moved)
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pTree->borderClip,
+ &pWin->winSize);
+ else
+ REGION_COPY(pScreen, borderVisible,
+ &pTree->borderClip);
+ }
+ }
+ }
+ }
+ pWin->origin.x = x + bw;
+ pWin->origin.y = y + bw;
+ pWin->drawable.height = h;
+ pWin->drawable.width = w;
+
+ x = pWin->drawable.x = newx;
+ y = pWin->drawable.y = newy;
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ dw = (int)w - (int)width;
+ dh = (int)h - (int)height;
+ ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh);
+
+ /* let the hardware adjust background and border pixmaps, if any */
+ (*pScreen->PositionWindow)(pWin, x, y);
+
+ pFirstChange = MoveWindowInStack(pWin, pSib);
+
+ if (WasViewable) {
+ pRegion = REGION_CREATE(pScreen, NullBox, 1);
+ if (pWin->backStorage)
+ REGION_COPY(pScreen, pRegion, &pWin->clipList);
+
+ (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange, NULL);
+
+ pWin->valdata->before.resized = TRUE;
+ pWin->valdata->before.borderVisible = borderVisible;
+ if(pTree)
+ pTree->valdata->borderVisible = borderVisible2;
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, pFirstChange);
+#endif /* DO_SAVE_UNDERS */
+
+ (*pScreen->ValidateTree)(pWin->parent, pFirstChange, VTOther);
+ /*
+ * the entire window is trashed unless bitGravity
+ * recovers portions of it
+ */
+ REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList);
+ if(pTree)
+ REGION_COPY(pScreen, &pTree->valdata->exposed, &pTree->clipList);
+ }
+
+ GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny);
+
+ if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) {
+ if (!WasViewable)
+ pRegion = &pWin->clipList; /* a convenient empty region */
+ if (pWin->bitGravity == ForgetGravity)
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, NullRegion, oldx, oldy);
+ else
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, nx - x, ny - y, pRegion, oldx, oldy);
+ }
+
+ if (WasViewable) {
+ miOverlayScreenPtr pPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ miOverlayTwoRegions TwoRegions;
+
+ /* avoid the border */
+ if (HasBorder (pWin)) {
+ int offx, offy, dx, dy;
+
+ /* kruft to avoid double translates for each gravity */
+ offx = 0;
+ offy = 0;
+ for (g = 0; g <= StaticGravity; g++) {
+ if (!gravitate[g] && !gravitate2[g])
+ continue;
+
+ /* align winSize to gravitate[g].
+ * winSize is in new coordinates,
+ * gravitate[g] is still in old coordinates */
+ GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
+
+ dx = (oldx - nx) - offx;
+ dy = (oldy - ny) - offy;
+ if (dx || dy) {
+ REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy);
+ offx += dx;
+ offy += dy;
+ }
+ if(gravitate[g])
+ REGION_INTERSECT(pScreen, gravitate[g], gravitate[g],
+ &pWin->winSize);
+ if(gravitate2[g])
+ REGION_INTERSECT(pScreen, gravitate2[g], gravitate2[g],
+ &pWin->winSize);
+ }
+ /* get winSize back where it belongs */
+ if (offx || offy)
+ REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy);
+ }
+ /*
+ * add screen bits to the appropriate bucket
+ */
+
+ if (oldWinClip2)
+ {
+ REGION_COPY(pScreen, pRegion, oldWinClip2);
+ REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
+ REGION_INTERSECT(pScreen, oldWinClip2, pRegion, &pTree->clipList);
+
+ for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
+ if (gravitate2[g])
+ REGION_SUBTRACT(pScreen, oldWinClip2, oldWinClip2,
+ gravitate2[g]);
+ }
+ REGION_TRANSLATE(pScreen, oldWinClip2, oldx - nx, oldy - ny);
+ g = pWin->bitGravity;
+ if (!gravitate2[g])
+ gravitate2[g] = oldWinClip2;
+ else {
+ REGION_UNION(pScreen,gravitate2[g],gravitate2[g],oldWinClip2);
+ REGION_DESTROY(pScreen, oldWinClip2);
+ }
+ }
+
+ if (oldWinClip)
+ {
+ /*
+ * clip to new clipList
+ */
+ REGION_COPY(pScreen, pRegion, oldWinClip);
+ REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
+ REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList);
+ /*
+ * don't step on any gravity bits which will be copied after this
+ * region. Note -- this assumes that the regions will be copied
+ * in gravity order.
+ */
+ for (g = pWin->bitGravity + 1; g <= StaticGravity; g++) {
+ if (gravitate[g])
+ REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip,
+ gravitate[g]);
+ }
+ REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny);
+ g = pWin->bitGravity;
+ if (!gravitate[g])
+ gravitate[g] = oldWinClip;
+ else {
+ REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip);
+ REGION_DESTROY(pScreen, oldWinClip);
+ }
+ }
+
+ /*
+ * move the bits on the screen
+ */
+
+ destClip = destClip2 = NULL;
+
+ for (g = 0; g <= StaticGravity; g++) {
+ if (!gravitate[g] && !gravitate2[g])
+ continue;
+
+ GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
+
+ oldpt.x = oldx + (x - nx);
+ oldpt.y = oldy + (y - ny);
+
+ /* Note that gravitate[g] is *translated* by CopyWindow */
+
+ /* only copy the remaining useful bits */
+
+ if(gravitate[g])
+ REGION_INTERSECT(pScreen, gravitate[g],
+ gravitate[g], oldRegion);
+ if(gravitate2[g])
+ REGION_INTERSECT(pScreen, gravitate2[g],
+ gravitate2[g], oldRegion2);
+
+ /* clip to not overwrite already copied areas */
+
+ if (destClip && gravitate[g]) {
+ REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y);
+ REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip);
+ REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y);
+ }
+ if (destClip2 && gravitate2[g]) {
+ REGION_TRANSLATE(pScreen, destClip2, oldpt.x - x, oldpt.y - y);
+ REGION_SUBTRACT(pScreen,gravitate2[g],gravitate2[g],destClip2);
+ REGION_TRANSLATE(pScreen, destClip2, x - oldpt.x, y - oldpt.y);
+ }
+
+ /* and move those bits */
+
+ if (oldpt.x != x || oldpt.y != y) {
+ if(gravitate2[g]) {
+ pPriv->copyUnderlay = TRUE;
+ (*pWin->drawable.pScreen->CopyWindow)(
+ pWin, oldpt, gravitate2[g]);
+ }
+ if(gravitate[g]) {
+ pPriv->copyUnderlay = FALSE;
+ (*pWin->drawable.pScreen->CopyWindow)(
+ pWin, oldpt, gravitate[g]);
+ }
+ }
+
+ /* remove any overwritten bits from the remaining useful bits */
+
+ if(gravitate[g])
+ REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]);
+ if(gravitate2[g])
+ REGION_SUBTRACT(pScreen, oldRegion2, oldRegion2, gravitate2[g]);
+
+ /*
+ * recompute exposed regions of child windows
+ */
+
+
+ for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) {
+ if (pChild->winGravity != g)
+ continue;
+
+ TwoRegions.over = gravitate[g];
+ TwoRegions.under = gravitate2[g];
+
+ TraverseTree (pChild, miOverlayRecomputeExposures,
+ (pointer)(&TwoRegions));
+ }
+
+ /*
+ * remove the successfully copied regions of the
+ * window from its exposed region
+ */
+
+ if (g == pWin->bitGravity) {
+ if(gravitate[g])
+ REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
+ &pWin->valdata->after.exposed, gravitate[g]);
+ if(gravitate2[g] && pTree)
+ REGION_SUBTRACT(pScreen, &pTree->valdata->exposed,
+ &pTree->valdata->exposed, gravitate2[g]);
+ }
+ if(gravitate[g]) {
+ if (!destClip)
+ destClip = gravitate[g];
+ else {
+ REGION_UNION(pScreen, destClip, destClip, gravitate[g]);
+ REGION_DESTROY(pScreen, gravitate[g]);
+ }
+ }
+ if(gravitate2[g]) {
+ if (!destClip2)
+ destClip2 = gravitate2[g];
+ else {
+ REGION_UNION(pScreen, destClip2, destClip2, gravitate2[g]);
+ REGION_DESTROY(pScreen, gravitate2[g]);
+ }
+ }
+ }
+
+ REGION_DESTROY(pScreen, pRegion);
+ REGION_DESTROY(pScreen, oldRegion);
+ if(doUnderlay)
+ REGION_DESTROY(pScreen, oldRegion2);
+ if (destClip)
+ REGION_DESTROY(pScreen, destClip);
+ if (destClip2)
+ REGION_DESTROY(pScreen, destClip2);
+ if (bsExposed) {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ (*pScreen->HandleExposures)(pWin->parent);
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, pFirstChange);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, pFirstChange, VTOther);
+ }
+ else if (bsExposed) {
+ (*pScreen->WindowExposures) (pWin, NullRegion, bsExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+
+#ifdef SHAPE
+static void
+miOverlaySetShape(WindowPtr pWin)
+{
+ Bool WasViewable = (Bool)(pWin->viewable);
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ RegionPtr pOldClip = NULL, bsExposed;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+
+ if (WasViewable) {
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+ if (HasBorder (pWin)) {
+ RegionPtr borderVisible;
+
+ borderVisible = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ pWin->valdata->before.resized = TRUE;
+ if(IN_UNDERLAY(pWin)) {
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ RegionPtr borderVisible2;
+
+ borderVisible2 = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible2,
+ &pTree->borderClip, &pWin->winSize);
+ pTree->valdata->borderVisible = borderVisible2;
+ }
+ }
+ }
+
+ SetWinSize (pWin);
+ SetBorderSize (pWin);
+
+ ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
+
+ if (WasViewable) {
+ if (pWin->backStorage) {
+ pOldClip = REGION_CREATE(pScreen, NullBox, 1);
+ REGION_COPY(pScreen, pOldClip, &pWin->clipList);
+ }
+
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin);
+#endif /* DO_SAVE_UNDERS */
+
+ (*pScreen->ValidateTree)(pWin->parent, NullWindow, VTOther);
+ }
+
+ if (pWin->backStorage && ((pWin->backingStore == Always) || WasViewable)) {
+ if (!WasViewable)
+ pOldClip = &pWin->clipList; /* a convenient empty region */
+ bsExposed = (*pScreen->TranslateBackingStore)
+ (pWin, 0, 0, pOldClip,
+ pWin->drawable.x, pWin->drawable.y);
+ if (WasViewable)
+ REGION_DESTROY(pScreen, pOldClip);
+ if (bsExposed)
+ {
+ RegionPtr valExposed = NullRegion;
+
+ if (pWin->valdata)
+ valExposed = &pWin->valdata->after.exposed;
+ (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
+ if (valExposed)
+ REGION_EMPTY(pScreen, valExposed);
+ REGION_DESTROY(pScreen, bsExposed);
+ }
+ }
+ if (WasViewable) {
+ (*pScreen->HandleExposures)(pWin->parent);
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, pWin);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, NullWindow, VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+ CheckCursorConfinement(pWin);
+}
+#endif
+
+
+
+static void
+miOverlayChangeBorderWidth(
+ WindowPtr pWin,
+ unsigned int width
+){
+ WindowPtr pParent;
+ int oldwidth;
+ register ScreenPtr pScreen;
+ Bool WasViewable = (Bool)(pWin->viewable);
+ Bool HadBorder;
+#ifdef DO_SAVE_UNDERS
+ Bool dosave = FALSE;
+#endif
+
+ oldwidth = wBorderWidth (pWin);
+ if (oldwidth == width)
+ return;
+ HadBorder = HasBorder(pWin);
+ pScreen = pWin->drawable.pScreen;
+ pParent = pWin->parent;
+ if (WasViewable && (width < oldwidth))
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+ pWin->borderWidth = width;
+ SetBorderSize (pWin);
+
+ if (WasViewable) {
+ if (width > oldwidth) {
+ (*pScreen->MarkOverlappedWindows)(pWin, pWin, NULL);
+
+ if (HadBorder) {
+ RegionPtr borderVisible;
+ borderVisible = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible,
+ &pWin->borderClip, &pWin->winSize);
+ pWin->valdata->before.borderVisible = borderVisible;
+ if(IN_UNDERLAY(pWin)) {
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ RegionPtr borderVisible2;
+
+ borderVisible2 = REGION_CREATE(pScreen, NULL, 1);
+ REGION_SUBTRACT(pScreen, borderVisible2,
+ &pTree->borderClip, &pWin->winSize);
+ pTree->valdata->borderVisible = borderVisible2;
+ }
+ }
+ }
+#ifdef DO_SAVE_UNDERS
+ if (DO_SAVE_UNDERS(pWin))
+ dosave = (*pScreen->ChangeSaveUnder)(pWin, pWin->nextSib);
+#endif /* DO_SAVE_UNDERS */
+ (*pScreen->ValidateTree)(pWin->parent, pWin, VTOther);
+ (*pScreen->HandleExposures)(pWin->parent);
+
+#ifdef DO_SAVE_UNDERS
+ if (dosave)
+ (*pScreen->PostChangeSaveUnder)(pWin, pWin->nextSib);
+#endif /* DO_SAVE_UNDERS */
+ if (pScreen->PostValidateTree)
+ (*pScreen->PostValidateTree)(pWin->parent, pWin, VTOther);
+ }
+ if (pWin->realized)
+ WindowsRestructured ();
+}
+
+/* We need this as an addition since the xf86 common code doesn't
+ know about the second tree which is static to this file. */
+
+void
+miOverlaySetRootClip(ScreenPtr pScreen, Bool enable)
+{
+ WindowPtr pRoot = WindowTable[pScreen->myNum];
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pRoot);
+
+ MARK_UNDERLAY(pRoot);
+
+ if(enable) {
+ BoxRec box;
+
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = pScreen->width;
+ box.y2 = pScreen->height;
+
+ REGION_RESET(pScreen, &pTree->borderClip, &box);
+ } else
+ REGION_EMPTY(pScreen, &pTree->borderClip);
+
+ REGION_BREAK(pScreen, &pTree->clipList);
+}
+
+static void
+miOverlayClearToBackground(
+ WindowPtr pWin,
+ int x, int y,
+ int w, int h,
+ Bool generateExposures
+)
+{
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ BoxRec box;
+ RegionRec reg;
+ RegionPtr pBSReg = NullRegion;
+ ScreenPtr pScreen = pWin->drawable.pScreen;
+ miOverlayScreenPtr pScreenPriv = MIOVERLAY_GET_SCREEN_PRIVATE(pScreen);
+ RegionPtr clipList;
+ BoxPtr extents;
+ int x1, y1, x2, y2;
+
+ x1 = pWin->drawable.x + x;
+ y1 = pWin->drawable.y + y;
+ if (w)
+ x2 = x1 + (int) w;
+ else
+ x2 = x1 + (int) pWin->drawable.width - (int) x;
+ if (h)
+ y2 = y1 + h;
+ else
+ y2 = y1 + (int) pWin->drawable.height - (int) y;
+
+ clipList = ((*pScreenPriv->InOverlay)(pWin)) ? &pWin->clipList :
+ &pTree->clipList;
+
+ extents = REGION_EXTENTS(pScreen, clipList);
+
+ if (x1 < extents->x1) x1 = extents->x1;
+ if (x2 > extents->x2) x2 = extents->x2;
+ if (y1 < extents->y1) y1 = extents->y1;
+ if (y2 > extents->y2) y2 = extents->y2;
+
+ if (x2 <= x1 || y2 <= y1)
+ x2 = x1 = y2 = y1 = 0;
+
+ box.x1 = x1; box.x2 = x2;
+ box.y1 = y1; box.y2 = y2;
+
+ REGION_INIT(pScreen, &reg, &box, 1);
+ if (pWin->backStorage) {
+ pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h,
+ generateExposures);
+ }
+
+ REGION_INTERSECT(pScreen, &reg, &reg, clipList);
+ if (generateExposures)
+ (*pScreen->WindowExposures)(pWin, &reg, pBSReg);
+ else if (pWin->backgroundState != None)
+ (*pScreen->PaintWindowBackground)(pWin, &reg, PW_BACKGROUND);
+ REGION_UNINIT(pScreen, &reg);
+ if (pBSReg)
+ REGION_DESTROY(pScreen, pBSReg);
+}
+
+
+/****************************************************************/
+
+/* not used */
+Bool
+miOverlayGetPrivateClips(
+ WindowPtr pWin,
+ RegionPtr *borderClip,
+ RegionPtr *clipList
+){
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ if(pTree) {
+ *borderClip = &(pTree->borderClip);
+ *clipList = &(pTree->clipList);
+ return TRUE;
+ }
+
+ *borderClip = *clipList = NULL;
+
+ return FALSE;
+}
+
+void
+miOverlaySetTransFunction (
+ ScreenPtr pScreen,
+ miOverlayTransFunc transFunc
+){
+ MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->MakeTransparent = transFunc;
+}
+
+Bool
+miOverlayCopyUnderlay(ScreenPtr pScreen)
+{
+ return MIOVERLAY_GET_SCREEN_PRIVATE(pScreen)->copyUnderlay;
+}
+
+void
+miOverlayComputeCompositeClip(GCPtr pGC, WindowPtr pWin)
+{
+ ScreenPtr pScreen = pGC->pScreen;
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+ RegionPtr pregWin;
+ Bool freeTmpClip, freeCompClip;
+
+ if(!pTree) {
+ miComputeCompositeClip(pGC, &pWin->drawable);
+ return;
+ }
+
+ if (pGC->subWindowMode == IncludeInferiors) {
+ pregWin = REGION_CREATE(pScreen, NullBox, 1);
+ freeTmpClip = TRUE;
+ if (pWin->parent || (screenIsSaved != SCREEN_SAVER_ON) ||
+ !HasSaverWindow (pScreen->myNum))
+ {
+ REGION_INTERSECT(pScreen,pregWin,&pTree->borderClip,&pWin->winSize);
+ }
+ } else {
+ pregWin = &pTree->clipList;
+ freeTmpClip = FALSE;
+ }
+ freeCompClip = pGC->freeCompClip;
+ if (pGC->clientClipType == CT_NONE) {
+ if (freeCompClip)
+ REGION_DESTROY(pScreen, pGC->pCompositeClip);
+ pGC->pCompositeClip = pregWin;
+ pGC->freeCompClip = freeTmpClip;
+ } else {
+ REGION_TRANSLATE(pScreen, pGC->clientClip,
+ pWin->drawable.x + pGC->clipOrg.x,
+ pWin->drawable.y + pGC->clipOrg.y);
+
+ if (freeCompClip) {
+ REGION_INTERSECT(pGC->pScreen, pGC->pCompositeClip,
+ pregWin, pGC->clientClip);
+ if (freeTmpClip)
+ REGION_DESTROY(pScreen, pregWin);
+ } else if (freeTmpClip) {
+ REGION_INTERSECT(pScreen, pregWin, pregWin, pGC->clientClip);
+ pGC->pCompositeClip = pregWin;
+ } else {
+ pGC->pCompositeClip = REGION_CREATE(pScreen, NullBox, 0);
+ REGION_INTERSECT(pScreen, pGC->pCompositeClip,
+ pregWin, pGC->clientClip);
+ }
+ pGC->freeCompClip = TRUE;
+ REGION_TRANSLATE(pScreen, pGC->clientClip,
+ -(pWin->drawable.x + pGC->clipOrg.x),
+ -(pWin->drawable.y + pGC->clipOrg.y));
+ }
+}
+
+Bool
+miOverlayCollectUnderlayRegions(
+ WindowPtr pWin,
+ RegionPtr *region
+){
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ if(pTree) {
+ *region = &pTree->borderClip;
+ return FALSE;
+ }
+
+ *region = REGION_CREATE(pWin->drawable.pScreen, NullBox, 0);
+
+ CollectUnderlayChildrenRegions(pWin, *region);
+
+ return TRUE;
+}
+
+
+static miOverlayTreePtr
+DoLeaf(
+ WindowPtr pWin,
+ miOverlayTreePtr parent,
+ miOverlayTreePtr prevSib
+){
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ pTree->parent = parent;
+ pTree->firstChild = NULL;
+ pTree->lastChild = NULL;
+ pTree->prevSib = prevSib;
+ pTree->nextSib = NULL;
+
+ if(prevSib)
+ prevSib->nextSib = pTree;
+
+ if(!parent->firstChild)
+ parent->firstChild = parent->lastChild = pTree;
+ else if(parent->lastChild == prevSib)
+ parent->lastChild = pTree;
+
+ return pTree;
+}
+
+static void
+RebuildTree(WindowPtr pWin)
+{
+ miOverlayTreePtr parent, prevSib, tChild;
+ WindowPtr pChild;
+
+ prevSib = tChild = NULL;
+
+ pWin = pWin->parent;
+
+ while(IN_OVERLAY(pWin))
+ pWin = pWin->parent;
+
+ parent = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ pChild = pWin->firstChild;
+ parent->firstChild = parent->lastChild = NULL;
+
+ while(1) {
+ if(IN_UNDERLAY(pChild))
+ prevSib = tChild = DoLeaf(pChild, parent, prevSib);
+
+ if(pChild->firstChild) {
+ if(IN_UNDERLAY(pChild)) {
+ parent = tChild;
+ prevSib = NULL;
+ }
+ pChild = pChild->firstChild;
+ continue;
+ }
+
+ while(!pChild->nextSib) {
+ pChild = pChild->parent;
+ if(pChild == pWin) return;
+ if(IN_UNDERLAY(pChild)) {
+ prevSib = tChild = MIOVERLAY_GET_WINDOW_TREE(pChild);
+ parent = tChild->parent;
+ }
+ }
+
+ pChild = pChild->nextSib;
+ }
+}
+
+
+static Bool
+HasUnderlayChildren(WindowPtr pWin)
+{
+ WindowPtr pChild;
+
+ if(!(pChild = pWin->firstChild))
+ return FALSE;
+
+ while(1) {
+ if(IN_UNDERLAY(pChild))
+ return TRUE;
+
+ if(pChild->firstChild) {
+ pChild = pChild->firstChild;
+ continue;
+ }
+
+ while(!pChild->nextSib && (pWin != pChild))
+ pChild = pChild->parent;
+
+ if(pChild == pWin) break;
+
+ pChild = pChild->nextSib;
+ }
+
+ return FALSE;
+}
+
+
+static Bool
+CollectUnderlayChildrenRegions(WindowPtr pWin, RegionPtr pReg)
+{
+ WindowPtr pChild;
+ miOverlayTreePtr pTree;
+ Bool hasUnderlay;
+
+ if(!(pChild = pWin->firstChild))
+ return FALSE;
+
+ hasUnderlay = FALSE;
+
+ while(1) {
+ if((pTree = MIOVERLAY_GET_WINDOW_TREE(pChild))) {
+ REGION_APPEND(pScreen, pReg, &pTree->borderClip);
+ hasUnderlay = TRUE;
+ } else
+ if(pChild->firstChild) {
+ pChild = pChild->firstChild;
+ continue;
+ }
+
+ while(!pChild->nextSib && (pWin != pChild))
+ pChild = pChild->parent;
+
+ if(pChild == pWin) break;
+
+ pChild = pChild->nextSib;
+ }
+
+ if(hasUnderlay) {
+ Bool overlap;
+ REGION_VALIDATE(pScreen, pReg, &overlap);
+ }
+
+ return hasUnderlay;
+}
+
+
+static void
+MarkUnderlayWindow(WindowPtr pWin)
+{
+ miOverlayTreePtr pTree = MIOVERLAY_GET_WINDOW_TREE(pWin);
+
+ if(pTree->valdata) return;
+ pTree->valdata = (miOverlayValDataPtr)xnfalloc(sizeof(miOverlayValDataRec));
+ pTree->valdata->oldAbsCorner.x = pWin->drawable.x;
+ pTree->valdata->oldAbsCorner.y = pWin->drawable.y;
+ pTree->valdata->borderVisible = NullRegion;
+}
diff --git a/mi/mioverlay.h b/mi/mioverlay.h
new file mode 100644
index 000000000..6098f9c39
--- /dev/null
+++ b/mi/mioverlay.h
@@ -0,0 +1,29 @@
+/* $XFree86: xc/programs/Xserver/mi/mioverlay.h,v 3.4 2001/04/14 21:15:26 mvojkovi Exp $ */
+
+#ifndef __MIOVERLAY_H
+#define __MIOVERLAY_H
+
+typedef void (*miOverlayTransFunc)(ScreenPtr, int, BoxPtr);
+typedef Bool (*miOverlayInOverlayFunc)(WindowPtr);
+
+Bool
+miInitOverlay(
+ ScreenPtr pScreen,
+ miOverlayInOverlayFunc inOverlay,
+ miOverlayTransFunc trans
+);
+
+Bool
+miOverlayGetPrivateClips(
+ WindowPtr pWin,
+ RegionPtr *borderClip,
+ RegionPtr *clipList
+);
+
+Bool miOverlayCollectUnderlayRegions(WindowPtr, RegionPtr*);
+void miOverlayComputeCompositeClip(GCPtr, WindowPtr);
+Bool miOverlayCopyUnderlay(ScreenPtr);
+void miOverlaySetTransFunction(ScreenPtr, miOverlayTransFunc);
+void miOverlaySetRootClip(ScreenPtr, Bool);
+
+#endif /* __MIOVERLAY_H */
diff --git a/mi/mizerclip.c b/mi/mizerclip.c
new file mode 100644
index 000000000..fa1863b54
--- /dev/null
+++ b/mi/mizerclip.c
@@ -0,0 +1,632 @@
+/* $XFree86: xc/programs/Xserver/mi/mizerclip.c,v 1.3 2001/12/14 20:00:29 dawes Exp $ */
+/***********************************************************
+
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+#include "X.h"
+
+#include "misc.h"
+#include "scrnintstr.h"
+#include "gcstruct.h"
+#include "windowstr.h"
+#include "pixmap.h"
+#include "mi.h"
+#include "miline.h"
+
+/*
+
+The bresenham error equation used in the mi/mfb/cfb line routines is:
+
+ e = error
+ dx = difference in raw X coordinates
+ dy = difference in raw Y coordinates
+ M = # of steps in X direction
+ N = # of steps in Y direction
+ B = 0 to prefer diagonal steps in a given octant,
+ 1 to prefer axial steps in a given octant
+
+ For X major lines:
+ e = 2Mdy - 2Ndx - dx - B
+ -2dx <= e < 0
+
+ For Y major lines:
+ e = 2Ndx - 2Mdy - dy - B
+ -2dy <= e < 0
+
+At the start of the line, we have taken 0 X steps and 0 Y steps,
+so M = 0 and N = 0:
+
+ X major e = 2Mdy - 2Ndx - dx - B
+ = -dx - B
+
+ Y major e = 2Ndx - 2Mdy - dy - B
+ = -dy - B
+
+At the end of the line, we have taken dx X steps and dy Y steps,
+so M = dx and N = dy:
+
+ X major e = 2Mdy - 2Ndx - dx - B
+ = 2dxdy - 2dydx - dx - B
+ = -dx - B
+ Y major e = 2Ndx - 2Mdy - dy - B
+ = 2dydx - 2dxdy - dy - B
+ = -dy - B
+
+Thus, the error term is the same at the start and end of the line.
+
+Let us consider clipping an X coordinate. There are 4 cases which
+represent the two independent cases of clipping the start vs. the
+end of the line and an X major vs. a Y major line. In any of these
+cases, we know the number of X steps (M) and we wish to find the
+number of Y steps (N). Thus, we will solve our error term equation.
+If we are clipping the start of the line, we will find the smallest
+N that satisfies our error term inequality. If we are clipping the
+end of the line, we will find the largest number of Y steps that
+satisfies the inequality. In that case, since we are representing
+the Y steps as (dy - N), we will actually want to solve for the
+smallest N in that equation.
+
+Case 1: X major, starting X coordinate moved by M steps
+
+ -2dx <= 2Mdy - 2Ndx - dx - B < 0
+ 2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B
+ 2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx
+ N <= (2Mdy + dx - B) / 2dx
+
+Since we are trying to find the smallest N that satisfies these
+equations, we should use the > inequality to find the smallest:
+
+ N = floor((2Mdy - dx - B) / 2dx) + 1
+ = floor((2Mdy - dx - B + 2dx) / 2dx)
+ = floor((2Mdy + dx - B) / 2dx)
+
+Case 1b: X major, ending X coordinate moved to M steps
+
+Same derivations as Case 1, but we want the largest N that satisfies
+the equations, so we use the <= inequality:
+
+ N = floor((2Mdy + dx - B) / 2dx)
+
+Case 2: X major, ending X coordinate moved by M steps
+
+ -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
+ -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
+ -2dx <= 2Ndx - 2Mdy - dx - B < 0
+ 2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B
+ 2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx
+ N >= (2Mdy - dx + B) / 2dx
+
+Since we are trying to find the highest number of Y steps that
+satisfies these equations, we need to find the smallest N, so
+we should use the >= inequality to find the smallest:
+
+ N = ceiling((2Mdy - dx + B) / 2dx)
+ = floor((2Mdy - dx + B + 2dx - 1) / 2dx)
+ = floor((2Mdy + dx + B - 1) / 2dx)
+
+Case 2b: X major, starting X coordinate moved to M steps from end
+
+Same derivations as Case 2, but we want the smallest number of Y
+steps, so we want the highest N, so we use the < inequality:
+
+ N = ceiling((2Mdy + dx + B) / 2dx) - 1
+ = floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
+ = floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
+ = floor((2Mdy + dx + B - 1) / 2dx)
+
+Case 3: Y major, starting X coordinate moved by M steps
+
+ -2dy <= 2Ndx - 2Mdy - dy - B < 0
+ 2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B
+ 2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx
+ N >= (2Mdy - dy + B) / 2dx
+
+Since we are trying to find the smallest N that satisfies these
+equations, we should use the >= inequality to find the smallest:
+
+ N = ceiling((2Mdy - dy + B) / 2dx)
+ = floor((2Mdy - dy + B + 2dx - 1) / 2dx)
+ = floor((2Mdy - dy + B - 1) / 2dx) + 1
+
+Case 3b: Y major, ending X coordinate moved to M steps
+
+Same derivations as Case 3, but we want the largest N that satisfies
+the equations, so we use the < inequality:
+
+ N = ceiling((2Mdy + dy + B) / 2dx) - 1
+ = floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1
+ = floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx)
+ = floor((2Mdy + dy + B - 1) / 2dx)
+
+Case 4: Y major, ending X coordinate moved by M steps
+
+ -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
+ -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
+ -2dy <= 2Mdy - 2Ndx - dy - B < 0
+ 2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B
+ 2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx
+ N <= (2Mdy + dy - B) / 2dx
+
+Since we are trying to find the highest number of Y steps that
+satisfies these equations, we need to find the smallest N, so
+we should use the > inequality to find the smallest:
+
+ N = floor((2Mdy - dy - B) / 2dx) + 1
+
+Case 4b: Y major, starting X coordinate moved to M steps from end
+
+Same analysis as Case 4, but we want the smallest number of Y steps
+which means the largest N, so we use the <= inequality:
+
+ N = floor((2Mdy + dy - B) / 2dx)
+
+Now let's try the Y coordinates, we have the same 4 cases.
+
+Case 5: X major, starting Y coordinate moved by N steps
+
+ -2dx <= 2Mdy - 2Ndx - dx - B < 0
+ 2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B
+ 2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy
+ M >= (2Ndx - dx + B) / 2dy
+
+Since we are trying to find the smallest M, we use the >= inequality:
+
+ M = ceiling((2Ndx - dx + B) / 2dy)
+ = floor((2Ndx - dx + B + 2dy - 1) / 2dy)
+ = floor((2Ndx - dx + B - 1) / 2dy) + 1
+
+Case 5b: X major, ending Y coordinate moved to N steps
+
+Same derivations as Case 5, but we want the largest M that satisfies
+the equations, so we use the < inequality:
+
+ M = ceiling((2Ndx + dx + B) / 2dy) - 1
+ = floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1
+ = floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy)
+ = floor((2Ndx + dx + B - 1) / 2dy)
+
+Case 6: X major, ending Y coordinate moved by N steps
+
+ -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
+ -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
+ -2dx <= 2Ndx - 2Mdy - dx - B < 0
+ 2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B
+ 2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy
+ M <= (2Ndx + dx - B) / 2dy
+
+Largest # of X steps means smallest M, so use the > inequality:
+
+ M = floor((2Ndx - dx - B) / 2dy) + 1
+
+Case 6b: X major, starting Y coordinate moved to N steps from end
+
+Same derivations as Case 6, but we want the smallest # of X steps
+which means the largest M, so use the <= inequality:
+
+ M = floor((2Ndx + dx - B) / 2dy)
+
+Case 7: Y major, starting Y coordinate moved by N steps
+
+ -2dy <= 2Ndx - 2Mdy - dy - B < 0
+ 2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B
+ 2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy
+ M <= (2Ndx + dy - B) / 2dy
+
+To find the smallest M, use the > inequality:
+
+ M = floor((2Ndx - dy - B) / 2dy) + 1
+ = floor((2Ndx - dy - B + 2dy) / 2dy)
+ = floor((2Ndx + dy - B) / 2dy)
+
+Case 7b: Y major, ending Y coordinate moved to N steps
+
+Same derivations as Case 7, but we want the largest M that satisfies
+the equations, so use the <= inequality:
+
+ M = floor((2Ndx + dy - B) / 2dy)
+
+Case 8: Y major, ending Y coordinate moved by N steps
+
+ -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
+ -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
+ -2dy <= 2Mdy - 2Ndx - dy - B < 0
+ 2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B
+ 2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy
+ M >= (2Ndx - dy + B) / 2dy
+
+To find the highest X steps, find the smallest M, use the >= inequality:
+
+ M = ceiling((2Ndx - dy + B) / 2dy)
+ = floor((2Ndx - dy + B + 2dy - 1) / 2dy)
+ = floor((2Ndx + dy + B - 1) / 2dy)
+
+Case 8b: Y major, starting Y coordinate moved to N steps from the end
+
+Same derivations as Case 8, but we want to find the smallest # of X
+steps which means the largest M, so we use the < inequality:
+
+ M = ceiling((2Ndx + dy + B) / 2dy) - 1
+ = floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
+ = floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
+ = floor((2Ndx + dy + B - 1) / 2dy)
+
+So, our equations are:
+
+ 1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
+ 1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx)
+ 2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
+ 2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
+
+ 3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1
+ 3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx)
+ 4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1
+ 4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx)
+
+ 5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1
+ 5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy)
+ 6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1
+ 6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy)
+
+ 7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy)
+ 7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy)
+ 8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
+ 8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
+
+We have the following constraints on all of the above terms:
+
+ 0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine
+ 0 <= dx/dy <= 2^16 - 1
+ 0 <= B <= 1
+
+The floor in all of the above equations can be accomplished with a
+simple C divide operation provided that both numerator and denominator
+are positive.
+
+Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0
+and moving a Y coordinate implies dy != 0, we know that the denominators
+are all > 0.
+
+For all lines, (-B) and (B-1) are both either 0 or -1, depending on the
+bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1
+or > 0 to prove that the numerators are positive (or zero).
+
+For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the
+constraints, the first four equations all have numerators >= 0.
+
+For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy
+So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy
+or (2Mdy + dy) > 0. So all of their numerators are >= 0.
+
+For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx)
+>= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0.
+
+For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators
+are > 0.
+
+To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This
+is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1)
+ <= 2^16 * (2^16 - 1) + (2^16 - 1)
+ <= 2^32 - 2^16 + 2^16 - 1
+ <= 2^32 - 1
+Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of
+the numerator is therefore (2^32 - 1), which does not overflow an unsigned
+32 bit variable.
+
+*/
+
+/* Bit codes for the terms of the 16 clipping equations defined below. */
+
+#define T_2NDX (1 << 0)
+#define T_2MDY (0) /* implicit term */
+#define T_DXNOTY (1 << 1)
+#define T_DYNOTX (0) /* implicit term */
+#define T_SUBDXORY (1 << 2)
+#define T_ADDDX (T_DXNOTY) /* composite term */
+#define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */
+#define T_ADDDY (T_DYNOTX) /* composite term */
+#define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */
+#define T_BIASSUBONE (1 << 3)
+#define T_SUBBIAS (0) /* implicit term */
+#define T_DIV2DX (1 << 4)
+#define T_DIV2DY (0) /* implicit term */
+#define T_ADDONE (1 << 5)
+
+/* Bit masks defining the 16 equations used in miZeroClipLine. */
+
+#define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
+#define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
+#define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
+#define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
+
+#define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE)
+#define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX)
+#define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE)
+#define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX)
+
+#define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE)
+#define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY)
+#define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE)
+#define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY)
+
+#define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
+#define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
+#define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
+#define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
+
+/* miZeroClipLine
+ *
+ * returns: 1 for partially clipped line
+ * -1 for completely clipped line
+ *
+ */
+int
+miZeroClipLine(xmin, ymin, xmax, ymax,
+ new_x1, new_y1, new_x2, new_y2,
+ adx, ady,
+ pt1_clipped, pt2_clipped, octant, bias, oc1, oc2)
+ int xmin, ymin, xmax, ymax;
+ int *new_x1, *new_y1, *new_x2, *new_y2;
+ int *pt1_clipped, *pt2_clipped;
+ unsigned int adx, ady;
+ int octant;
+ unsigned int bias;
+ int oc1, oc2;
+{
+ int swapped = 0;
+ int clipDone = 0;
+ CARD32 utmp = 0;
+ int clip1, clip2;
+ int x1, y1, x2, y2;
+ int x1_orig, y1_orig, x2_orig, y2_orig;
+ int xmajor;
+ int negslope = 0, anchorval = 0;
+ unsigned int eqn = 0;
+
+ x1 = x1_orig = *new_x1;
+ y1 = y1_orig = *new_y1;
+ x2 = x2_orig = *new_x2;
+ y2 = y2_orig = *new_y2;
+
+ clip1 = 0;
+ clip2 = 0;
+
+ xmajor = IsXMajorOctant(octant);
+ bias = ((bias >> octant) & 1);
+
+ while (1)
+ {
+ if ((oc1 & oc2) != 0) /* trivial reject */
+ {
+ clipDone = -1;
+ clip1 = oc1;
+ clip2 = oc2;
+ break;
+ }
+ else if ((oc1 | oc2) == 0) /* trivial accept */
+ {
+ clipDone = 1;
+ if (swapped)
+ {
+ SWAPINT_PAIR(x1, y1, x2, y2);
+ SWAPINT(clip1, clip2);
+ }
+ break;
+ }
+ else /* have to clip */
+ {
+ /* only clip one point at a time */
+ if (oc1 == 0)
+ {
+ SWAPINT_PAIR(x1, y1, x2, y2);
+ SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig);
+ SWAPINT(oc1, oc2);
+ SWAPINT(clip1, clip2);
+ swapped = !swapped;
+ }
+
+ clip1 |= oc1;
+ if (oc1 & OUT_LEFT)
+ {
+ negslope = IsYDecreasingOctant(octant);
+ utmp = xmin - x1_orig;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN2 : EQN1;
+ else
+ eqn = (swapped) ? EQN4 : EQN3;
+ anchorval = y1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ utmp = x2_orig - xmin;
+ if (xmajor)
+ eqn = (swapped) ? EQN1B : EQN2B;
+ else
+ eqn = (swapped) ? EQN3B : EQN4B;
+ anchorval = y2_orig;
+ negslope = !negslope;
+ }
+ x1 = xmin;
+ }
+ else if (oc1 & OUT_ABOVE)
+ {
+ negslope = IsXDecreasingOctant(octant);
+ utmp = ymin - y1_orig;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN6 : EQN5;
+ else
+ eqn = (swapped) ? EQN8 : EQN7;
+ anchorval = x1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ utmp = y2_orig - ymin;
+ if (xmajor)
+ eqn = (swapped) ? EQN5B : EQN6B;
+ else
+ eqn = (swapped) ? EQN7B : EQN8B;
+ anchorval = x2_orig;
+ negslope = !negslope;
+ }
+ y1 = ymin;
+ }
+ else if (oc1 & OUT_RIGHT)
+ {
+ negslope = IsYDecreasingOctant(octant);
+ utmp = x1_orig - xmax;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN2 : EQN1;
+ else
+ eqn = (swapped) ? EQN4 : EQN3;
+ anchorval = y1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ /*
+ * Technically since the equations can handle
+ * utmp == 32768, this overflow code isn't
+ * needed since X11 protocol can't generate
+ * a line which goes more than 32768 pixels
+ * to the right of a clip rectangle.
+ */
+ utmp = xmax - x2_orig;
+ if (xmajor)
+ eqn = (swapped) ? EQN1B : EQN2B;
+ else
+ eqn = (swapped) ? EQN3B : EQN4B;
+ anchorval = y2_orig;
+ negslope = !negslope;
+ }
+ x1 = xmax;
+ }
+ else if (oc1 & OUT_BELOW)
+ {
+ negslope = IsXDecreasingOctant(octant);
+ utmp = y1_orig - ymax;
+ if (utmp <= 32767) /* clip based on near endpt */
+ {
+ if (xmajor)
+ eqn = (swapped) ? EQN6 : EQN5;
+ else
+ eqn = (swapped) ? EQN8 : EQN7;
+ anchorval = x1_orig;
+ }
+ else /* clip based on far endpt */
+ {
+ /*
+ * Technically since the equations can handle
+ * utmp == 32768, this overflow code isn't
+ * needed since X11 protocol can't generate
+ * a line which goes more than 32768 pixels
+ * below the bottom of a clip rectangle.
+ */
+ utmp = ymax - y2_orig;
+ if (xmajor)
+ eqn = (swapped) ? EQN5B : EQN6B;
+ else
+ eqn = (swapped) ? EQN7B : EQN8B;
+ anchorval = x2_orig;
+ negslope = !negslope;
+ }
+ y1 = ymax;
+ }
+
+ if (swapped)
+ negslope = !negslope;
+
+ utmp <<= 1; /* utmp = 2N or 2M */
+ if (eqn & T_2NDX)
+ utmp = (utmp * adx);
+ else /* (eqn & T_2MDY) */
+ utmp = (utmp * ady);
+ if (eqn & T_DXNOTY)
+ if (eqn & T_SUBDXORY)
+ utmp -= adx;
+ else
+ utmp += adx;
+ else /* (eqn & T_DYNOTX) */
+ if (eqn & T_SUBDXORY)
+ utmp -= ady;
+ else
+ utmp += ady;
+ if (eqn & T_BIASSUBONE)
+ utmp += bias - 1;
+ else /* (eqn & T_SUBBIAS) */
+ utmp -= bias;
+ if (eqn & T_DIV2DX)
+ utmp /= (adx << 1);
+ else /* (eqn & T_DIV2DY) */
+ utmp /= (ady << 1);
+ if (eqn & T_ADDONE)
+ utmp++;
+
+ if (negslope)
+ utmp = -utmp;
+
+ if (eqn & T_2NDX) /* We are calculating X steps */
+ x1 = anchorval + utmp;
+ else /* else, Y steps */
+ y1 = anchorval + utmp;
+
+ oc1 = 0;
+ MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax);
+ }
+ }
+
+ *new_x1 = x1;
+ *new_y1 = y1;
+ *new_x2 = x2;
+ *new_y2 = y2;
+
+ *pt1_clipped = clip1;
+ *pt2_clipped = clip2;
+
+ return clipDone;
+}