525 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			525 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2004 Eric Anholt
 | |
|  *
 | |
|  * 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 Eric Anholt not be used in
 | |
|  * advertising or publicity pertaining to distribution of the software without
 | |
|  * specific, written prior permission.  Eric Anholt makes no
 | |
|  * representations about the suitability of this software for any purpose.  It
 | |
|  * is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL ERIC ANHOLT 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.
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include "gcstruct.h"
 | |
| #include "windowstr.h"
 | |
| #include "cw.h"
 | |
| 
 | |
| #define CW_DEBUG 1
 | |
| 
 | |
| #if CW_DEBUG
 | |
| #define CW_ASSERT(x) do {						\
 | |
|     if (!(x)) {								\
 | |
| 	ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \
 | |
| 	    __LINE__);							\
 | |
|     }									\
 | |
| } while (0)
 | |
| #else
 | |
| #define CW_ASSERT(x) do {} while (0)
 | |
| #endif
 | |
| 
 | |
| DevPrivateKeyRec cwGCKeyRec;
 | |
| DevPrivateKeyRec cwScreenKeyRec;
 | |
| DevPrivateKeyRec cwWindowKeyRec;
 | |
| DevPrivateKeyRec cwPictureKeyRec;
 | |
| 
 | |
| extern GCOps cwGCOps;
 | |
| 
 | |
| static Bool
 | |
|  cwCloseScreen(int i, ScreenPtr pScreen);
 | |
| 
 | |
| static void
 | |
|  cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable);
 | |
| static void
 | |
|  cwChangeGC(GCPtr pGC, unsigned long mask);
 | |
| static void
 | |
|  cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
 | |
| static void
 | |
|  cwDestroyGC(GCPtr pGC);
 | |
| static void
 | |
|  cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
 | |
| static void
 | |
|  cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
 | |
| static void
 | |
|  cwDestroyClip(GCPtr pGC);
 | |
| 
 | |
| GCFuncs cwGCFuncs = {
 | |
|     cwValidateGC,
 | |
|     cwChangeGC,
 | |
|     cwCopyGC,
 | |
|     cwDestroyGC,
 | |
|     cwChangeClip,
 | |
|     cwDestroyClip,
 | |
|     cwCopyClip,
 | |
| };
 | |
| 
 | |
| /* Find the real drawable to draw to, and provide offsets that will translate
 | |
|  * window coordinates to backing pixmap coordinates.
 | |
|  */
 | |
| DrawablePtr
 | |
| cwGetBackingDrawable(DrawablePtr pDrawable, int *x_off, int *y_off)
 | |
| {
 | |
|     PixmapPtr pPixmap;
 | |
| 
 | |
|     if (pDrawable->type == DRAWABLE_WINDOW &&
 | |
|         (pPixmap = getCwPixmap((WindowPtr) pDrawable))) {
 | |
|         *x_off = pDrawable->x - pPixmap->screen_x;
 | |
|         *y_off = pDrawable->y - pPixmap->screen_y;
 | |
|         return &pPixmap->drawable;
 | |
|     }
 | |
|     else {
 | |
|         *x_off = *y_off = 0;
 | |
|         return pDrawable;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #define FUNC_PROLOGUE(pGC, pPriv) do {					\
 | |
|     (pGC)->funcs = (pPriv)->wrapFuncs;					\
 | |
|     (pGC)->ops = (pPriv)->wrapOps;					\
 | |
| } while (0)
 | |
| 
 | |
| #define FUNC_EPILOGUE(pGC, pPriv) do {					\
 | |
|     (pPriv)->wrapFuncs = (pGC)->funcs;					\
 | |
|     (pPriv)->wrapOps = (pGC)->ops;					\
 | |
|     (pGC)->funcs = &cwGCFuncs;						\
 | |
|     (pGC)->ops = &cwGCOps;						\
 | |
| } while (0)
 | |
| 
 | |
| static Bool
 | |
| cwCreateBackingGC(GCPtr pGC, DrawablePtr pDrawable)
 | |
| {
 | |
|     cwGCRec *pPriv = getCwGC(pGC);
 | |
|     int status, x_off, y_off;
 | |
|     XID noexpose = xFalse;
 | |
|     DrawablePtr pBackingDrawable;
 | |
| 
 | |
|     pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
 | |
|     pPriv->pBackingGC = CreateGC(pBackingDrawable, GCGraphicsExposures,
 | |
|                                  &noexpose, &status, (XID) 0, serverClient);
 | |
|     if (status != Success)
 | |
|         return FALSE;
 | |
| 
 | |
|     pPriv->serialNumber = 0;
 | |
|     pPriv->stateChanges = GCAllBits;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwDestroyBackingGC(GCPtr pGC)
 | |
| {
 | |
|     cwGCPtr pPriv;
 | |
| 
 | |
|     pPriv = (cwGCPtr) getCwGC(pGC);
 | |
| 
 | |
|     if (pPriv->pBackingGC) {
 | |
|         FreeGC(pPriv->pBackingGC, (XID) 0);
 | |
|         pPriv->pBackingGC = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable)
 | |
| {
 | |
|     GCPtr pBackingGC;
 | |
|     cwGCPtr pPriv;
 | |
|     DrawablePtr pBackingDrawable;
 | |
|     int x_off, y_off;
 | |
| 
 | |
|     pPriv = (cwGCPtr) getCwGC(pGC);
 | |
| 
 | |
|     FUNC_PROLOGUE(pGC, pPriv);
 | |
| 
 | |
|     /*
 | |
|      * Must call ValidateGC to ensure pGC->pCompositeClip is valid
 | |
|      */
 | |
|     (*pGC->funcs->ValidateGC) (pGC, stateChanges, pDrawable);
 | |
| 
 | |
|     if (!cwDrawableIsRedirWindow(pDrawable)) {
 | |
|         cwDestroyBackingGC(pGC);
 | |
|         FUNC_EPILOGUE(pGC, pPriv);
 | |
|         return;
 | |
|     }
 | |
|     else {
 | |
|         if (!pPriv->pBackingGC && !cwCreateBackingGC(pGC, pDrawable)) {
 | |
|             FUNC_EPILOGUE(pGC, pPriv);
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pBackingGC = pPriv->pBackingGC;
 | |
|     pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
 | |
| 
 | |
|     pPriv->stateChanges |= stateChanges;
 | |
| 
 | |
|     /*
 | |
|      * Copy the composite clip into the backing GC if either
 | |
|      * the drawable clip list has changed or the client has changed
 | |
|      * the client clip data
 | |
|      */
 | |
|     if (pDrawable->serialNumber != pPriv->serialNumber ||
 | |
|         (pPriv->stateChanges & (GCClipXOrigin | GCClipYOrigin | GCClipMask))) {
 | |
|         ChangeGCVal vals[2];
 | |
|         RegionPtr pCompositeClip;
 | |
| 
 | |
|         pCompositeClip = RegionCreate(NULL, 0);
 | |
|         RegionCopy(pCompositeClip, pGC->pCompositeClip);
 | |
| 
 | |
|         /* Either the drawable has changed, or the clip list in the drawable has
 | |
|          * changed.  Copy the new clip list over and set the new translated
 | |
|          * offset for it.
 | |
|          */
 | |
| 
 | |
|         (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION,
 | |
|                                           (pointer) pCompositeClip, 0);
 | |
| 
 | |
|         vals[0].val = x_off - pDrawable->x;
 | |
|         vals[1].val = y_off - pDrawable->y;
 | |
|         ChangeGC(NullClient, pBackingGC, (GCClipXOrigin | GCClipYOrigin), vals);
 | |
| 
 | |
|         pPriv->serialNumber = pDrawable->serialNumber;
 | |
|         /*
 | |
|          * Mask off any client clip changes to make sure
 | |
|          * the clip list set above remains in effect
 | |
|          */
 | |
|         pPriv->stateChanges &= ~(GCClipXOrigin | GCClipYOrigin | GCClipMask);
 | |
|     }
 | |
| 
 | |
|     if (pPriv->stateChanges) {
 | |
|         CopyGC(pGC, pBackingGC, pPriv->stateChanges);
 | |
|         pPriv->stateChanges = 0;
 | |
|     }
 | |
| 
 | |
|     if ((pGC->patOrg.x + x_off) != pBackingGC->patOrg.x ||
 | |
|         (pGC->patOrg.y + y_off) != pBackingGC->patOrg.y) {
 | |
|         ChangeGCVal vals[2];
 | |
| 
 | |
|         vals[0].val = pGC->patOrg.x + x_off;
 | |
|         vals[1].val = pGC->patOrg.y + y_off;
 | |
|         ChangeGC(NullClient, pBackingGC,
 | |
|                  (GCTileStipXOrigin | GCTileStipYOrigin), vals);
 | |
|     }
 | |
| 
 | |
|     ValidateGC(pBackingDrawable, pBackingGC);
 | |
| 
 | |
|     FUNC_EPILOGUE(pGC, pPriv);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwChangeGC(GCPtr pGC, unsigned long mask)
 | |
| {
 | |
|     cwGCPtr pPriv = (cwGCPtr) dixLookupPrivate(&pGC->devPrivates, cwGCKey);
 | |
| 
 | |
|     FUNC_PROLOGUE(pGC, pPriv);
 | |
| 
 | |
|     (*pGC->funcs->ChangeGC) (pGC, mask);
 | |
| 
 | |
|     FUNC_EPILOGUE(pGC, pPriv);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
 | |
| {
 | |
|     cwGCPtr pPriv = (cwGCPtr) dixLookupPrivate(&pGCDst->devPrivates, cwGCKey);
 | |
| 
 | |
|     FUNC_PROLOGUE(pGCDst, pPriv);
 | |
| 
 | |
|     (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
 | |
| 
 | |
|     FUNC_EPILOGUE(pGCDst, pPriv);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwDestroyGC(GCPtr pGC)
 | |
| {
 | |
|     cwGCPtr pPriv = (cwGCPtr) dixLookupPrivate(&pGC->devPrivates, cwGCKey);
 | |
| 
 | |
|     FUNC_PROLOGUE(pGC, pPriv);
 | |
| 
 | |
|     cwDestroyBackingGC(pGC);
 | |
| 
 | |
|     (*pGC->funcs->DestroyGC) (pGC);
 | |
| 
 | |
|     /* leave it unwrapped */
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
 | |
| {
 | |
|     cwGCPtr pPriv = (cwGCPtr) dixLookupPrivate(&pGC->devPrivates, cwGCKey);
 | |
| 
 | |
|     FUNC_PROLOGUE(pGC, pPriv);
 | |
| 
 | |
|     (*pGC->funcs->ChangeClip) (pGC, type, pvalue, nrects);
 | |
| 
 | |
|     FUNC_EPILOGUE(pGC, pPriv);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
 | |
| {
 | |
|     cwGCPtr pPriv = (cwGCPtr) dixLookupPrivate(&pgcDst->devPrivates, cwGCKey);
 | |
| 
 | |
|     FUNC_PROLOGUE(pgcDst, pPriv);
 | |
| 
 | |
|     (*pgcDst->funcs->CopyClip) (pgcDst, pgcSrc);
 | |
| 
 | |
|     FUNC_EPILOGUE(pgcDst, pPriv);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwDestroyClip(GCPtr pGC)
 | |
| {
 | |
|     cwGCPtr pPriv = (cwGCPtr) dixLookupPrivate(&pGC->devPrivates, cwGCKey);
 | |
| 
 | |
|     FUNC_PROLOGUE(pGC, pPriv);
 | |
| 
 | |
|     (*pGC->funcs->DestroyClip) (pGC);
 | |
| 
 | |
|     FUNC_EPILOGUE(pGC, pPriv);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Screen wrappers.
 | |
|  */
 | |
| 
 | |
| #define SCREEN_PROLOGUE(pScreen, field)				\
 | |
|   ((pScreen)->field = getCwScreen(pScreen)->field)
 | |
| 
 | |
| #define SCREEN_EPILOGUE(pScreen, field, wrapper) do {		\
 | |
|     getCwScreen(pScreen)->field = (pScreen)->field;		\
 | |
|     (pScreen)->field = (wrapper);				\
 | |
| } while (0)
 | |
| 
 | |
| static Bool
 | |
| cwCreateGC(GCPtr pGC)
 | |
| {
 | |
|     cwGCPtr pPriv = getCwGC(pGC);
 | |
|     ScreenPtr pScreen = pGC->pScreen;
 | |
|     Bool ret;
 | |
| 
 | |
|     SCREEN_PROLOGUE(pScreen, CreateGC);
 | |
| 
 | |
|     if ((ret = (*pScreen->CreateGC) (pGC)))
 | |
|         FUNC_EPILOGUE(pGC, pPriv);
 | |
| 
 | |
|     SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwGetImage(DrawablePtr pSrc, int x, int y, int w, int h, unsigned int format,
 | |
|            unsigned long planemask, char *pdstLine)
 | |
| {
 | |
|     ScreenPtr pScreen = pSrc->pScreen;
 | |
|     DrawablePtr pBackingDrawable;
 | |
|     int src_off_x, src_off_y;
 | |
| 
 | |
|     SCREEN_PROLOGUE(pScreen, GetImage);
 | |
| 
 | |
|     pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
 | |
| 
 | |
|     CW_OFFSET_XY_SRC(x, y);
 | |
| 
 | |
|     (*pScreen->GetImage) (pBackingDrawable, x, y, w, h, format, planemask,
 | |
|                           pdstLine);
 | |
| 
 | |
|     SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwGetSpans(DrawablePtr pSrc, int wMax, DDXPointPtr ppt, int *pwidth,
 | |
|            int nspans, char *pdstStart)
 | |
| {
 | |
|     ScreenPtr pScreen = pSrc->pScreen;
 | |
|     DrawablePtr pBackingDrawable;
 | |
|     int i;
 | |
|     int src_off_x, src_off_y;
 | |
| 
 | |
|     SCREEN_PROLOGUE(pScreen, GetSpans);
 | |
| 
 | |
|     pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
 | |
| 
 | |
|     for (i = 0; i < nspans; i++)
 | |
|         CW_OFFSET_XY_SRC(ppt[i].x, ppt[i].y);
 | |
| 
 | |
|     (*pScreen->GetSpans) (pBackingDrawable, wMax, ppt, pwidth, nspans,
 | |
|                           pdstStart);
 | |
| 
 | |
|     SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
 | |
| {
 | |
|     ScreenPtr pScreen = pWin->drawable.pScreen;
 | |
| 
 | |
|     SCREEN_PROLOGUE(pScreen, CopyWindow);
 | |
| 
 | |
|     if (!cwDrawableIsRedirWindow((DrawablePtr) pWin)) {
 | |
|         (*pScreen->CopyWindow) (pWin, ptOldOrg, prgnSrc);
 | |
|     }
 | |
|     else {
 | |
|         GCPtr pGC;
 | |
|         BoxPtr pExtents;
 | |
|         int x_off, y_off;
 | |
|         int dx, dy;
 | |
|         PixmapPtr pBackingPixmap;
 | |
|         RegionPtr pClip;
 | |
|         int src_x, src_y, dst_x, dst_y, w, h;
 | |
| 
 | |
|         dx = ptOldOrg.x - pWin->drawable.x;
 | |
|         dy = ptOldOrg.y - pWin->drawable.y;
 | |
| 
 | |
|         pExtents = RegionExtents(prgnSrc);
 | |
| 
 | |
|         pBackingPixmap = (PixmapPtr) cwGetBackingDrawable((DrawablePtr) pWin,
 | |
|                                                           &x_off, &y_off);
 | |
| 
 | |
|         src_x = pExtents->x1 - pBackingPixmap->screen_x;
 | |
|         src_y = pExtents->y1 - pBackingPixmap->screen_y;
 | |
|         w = pExtents->x2 - pExtents->x1;
 | |
|         h = pExtents->y2 - pExtents->y1;
 | |
|         dst_x = src_x - dx;
 | |
|         dst_y = src_y - dy;
 | |
| 
 | |
|         /* Translate region (as required by API) */
 | |
|         RegionTranslate(prgnSrc, -dx, -dy);
 | |
| 
 | |
|         pGC = GetScratchGC(pBackingPixmap->drawable.depth, pScreen);
 | |
|         /*
 | |
|          * Copy region to GC as clip, aligning as dest clip
 | |
|          */
 | |
|         pClip = RegionCreate(NULL, 0);
 | |
|         RegionIntersect(pClip, &pWin->borderClip, prgnSrc);
 | |
|         RegionTranslate(pClip,
 | |
|                         -pBackingPixmap->screen_x, -pBackingPixmap->screen_y);
 | |
| 
 | |
|         (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0);
 | |
| 
 | |
|         ValidateGC(&pBackingPixmap->drawable, pGC);
 | |
| 
 | |
|         (*pGC->ops->CopyArea) (&pBackingPixmap->drawable,
 | |
|                                &pBackingPixmap->drawable, pGC,
 | |
|                                src_x, src_y, w, h, dst_x, dst_y);
 | |
| 
 | |
|         (*pGC->funcs->DestroyClip) (pGC);
 | |
| 
 | |
|         FreeScratchGC(pGC);
 | |
|     }
 | |
| 
 | |
|     SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow);
 | |
| }
 | |
| 
 | |
| static PixmapPtr
 | |
| cwGetWindowPixmap(WindowPtr pWin)
 | |
| {
 | |
|     PixmapPtr pPixmap = getCwPixmap(pWin);
 | |
| 
 | |
|     if (!pPixmap) {
 | |
|         ScreenPtr pScreen = pWin->drawable.pScreen;
 | |
| 
 | |
|         SCREEN_PROLOGUE(pScreen, GetWindowPixmap);
 | |
|         if (pScreen->GetWindowPixmap)
 | |
|             pPixmap = (*pScreen->GetWindowPixmap) (pWin);
 | |
|         SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap);
 | |
|     }
 | |
|     return pPixmap;
 | |
| }
 | |
| 
 | |
| static void
 | |
| cwSetWindowPixmap(WindowPtr pWindow, PixmapPtr pPixmap)
 | |
| {
 | |
|     ScreenPtr pScreen = pWindow->drawable.pScreen;
 | |
| 
 | |
|     if (pPixmap == (*pScreen->GetScreenPixmap) (pScreen))
 | |
|         pPixmap = NULL;
 | |
|     setCwPixmap(pWindow, pPixmap);
 | |
| }
 | |
| 
 | |
| /* Screen initialization/teardown */
 | |
| void
 | |
| miInitializeCompositeWrapper(ScreenPtr pScreen)
 | |
| {
 | |
|     cwScreenPtr pScreenPriv;
 | |
|     Bool has_render = GetPictureScreenIfSet(pScreen) != NULL;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&cwScreenKeyRec, PRIVATE_SCREEN, 0))
 | |
|         return;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&cwGCKeyRec, PRIVATE_GC, sizeof(cwGCRec)))
 | |
|         return;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&cwWindowKeyRec, PRIVATE_WINDOW, 0))
 | |
|         return;
 | |
| 
 | |
|     if (!dixRegisterPrivateKey(&cwPictureKeyRec, PRIVATE_PICTURE, 0))
 | |
|         return;
 | |
| 
 | |
|     pScreenPriv = malloc(sizeof(cwScreenRec));
 | |
|     if (!pScreenPriv)
 | |
|         return;
 | |
| 
 | |
|     dixSetPrivate(&pScreen->devPrivates, cwScreenKey, pScreenPriv);
 | |
| 
 | |
|     SCREEN_EPILOGUE(pScreen, CloseScreen, cwCloseScreen);
 | |
|     SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
 | |
|     SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
 | |
|     SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
 | |
|     SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow);
 | |
| 
 | |
|     SCREEN_EPILOGUE(pScreen, SetWindowPixmap, cwSetWindowPixmap);
 | |
|     SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap);
 | |
| 
 | |
|     if (has_render)
 | |
|         cwInitializeRender(pScreen);
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| cwCloseScreen(int i, ScreenPtr pScreen)
 | |
| {
 | |
|     cwScreenPtr pScreenPriv;
 | |
|     PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
 | |
| 
 | |
|     pScreenPriv = (cwScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
 | |
|                                                  cwScreenKey);
 | |
|     pScreen->CloseScreen = pScreenPriv->CloseScreen;
 | |
|     pScreen->GetImage = pScreenPriv->GetImage;
 | |
|     pScreen->GetSpans = pScreenPriv->GetSpans;
 | |
|     pScreen->CreateGC = pScreenPriv->CreateGC;
 | |
|     pScreen->CopyWindow = pScreenPriv->CopyWindow;
 | |
| 
 | |
|     if (ps)
 | |
|         cwFiniRender(pScreen);
 | |
| 
 | |
|     free((pointer) pScreenPriv);
 | |
| 
 | |
|     return (*pScreen->CloseScreen) (i, pScreen);
 | |
| }
 |