First import
[xorg_rtime.git] / xorg-server-1.4 / miext / cw / cw.c
blob7ee013be15642f840e70734f1c83819a3f57bbea
1 /*
2 * Copyright © 2004 Eric Anholt
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Eric Anholt not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Eric Anholt makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
14 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
27 #include <string.h>
29 #include "gcstruct.h"
30 #include "windowstr.h"
31 #include "cw.h"
33 #define CW_DEBUG 1
35 #if CW_DEBUG
36 #define CW_ASSERT(x) do { \
37 if (!(x)) { \
38 ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \
39 __LINE__); \
40 } \
41 } while (0)
42 #else
43 #define CW_ASSERT(x) do {} while (0)
44 #endif
46 int cwGCIndex;
47 int cwScreenIndex;
48 int cwWindowIndex;
49 #ifdef RENDER
50 int cwPictureIndex;
51 #endif
52 static unsigned long cwGeneration = 0;
53 extern GCOps cwGCOps;
55 static Bool
56 cwCloseScreen (int i, ScreenPtr pScreen);
58 static void
59 cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable);
60 static void
61 cwChangeGC(GCPtr pGC, unsigned long mask);
62 static void
63 cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst);
64 static void
65 cwDestroyGC(GCPtr pGC);
66 static void
67 cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects);
68 static void
69 cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc);
70 static void
71 cwDestroyClip(GCPtr pGC);
73 GCFuncs cwGCFuncs = {
74 cwValidateGC,
75 cwChangeGC,
76 cwCopyGC,
77 cwDestroyGC,
78 cwChangeClip,
79 cwDestroyClip,
80 cwCopyClip,
83 /* Find the real drawable to draw to, and provide offsets that will translate
84 * window coordinates to backing pixmap coordinates.
86 DrawablePtr
87 cwGetBackingDrawable(DrawablePtr pDrawable, int *x_off, int *y_off)
89 PixmapPtr pPixmap;
91 if (pDrawable->type == DRAWABLE_WINDOW &&
92 (pPixmap = getCwPixmap ((WindowPtr) pDrawable)))
94 *x_off = pDrawable->x - pPixmap->screen_x;
95 *y_off = pDrawable->y - pPixmap->screen_y;
96 return &pPixmap->drawable;
97 } else {
98 *x_off = *y_off = 0;
99 return pDrawable;
103 #define FUNC_PROLOGUE(pGC, pPriv) do { \
104 (pGC)->funcs = (pPriv)->wrapFuncs; \
105 (pGC)->ops = (pPriv)->wrapOps; \
106 } while (0)
108 #define FUNC_EPILOGUE(pGC, pPriv) do { \
109 (pPriv)->wrapFuncs = (pGC)->funcs; \
110 (pPriv)->wrapOps = (pGC)->ops; \
111 (pGC)->funcs = &cwGCFuncs; \
112 (pGC)->ops = &cwGCOps; \
113 } while (0)
116 static Bool
117 cwCreateBackingGC(GCPtr pGC, DrawablePtr pDrawable)
119 cwGCRec *pPriv = getCwGC(pGC);
120 int status, x_off, y_off;
121 XID noexpose = xFalse;
122 DrawablePtr pBackingDrawable;
124 pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
125 pPriv->pBackingGC = CreateGC(pBackingDrawable, GCGraphicsExposures,
126 &noexpose, &status);
127 if (status != Success)
128 return FALSE;
130 pPriv->serialNumber = 0;
131 pPriv->stateChanges = (1 << (GCLastBit + 1)) - 1;
133 return TRUE;
136 static void
137 cwDestroyBackingGC(GCPtr pGC)
139 cwGCPtr pPriv;
141 pPriv = (cwGCPtr) getCwGC (pGC);
143 if (pPriv->pBackingGC) {
144 FreeGC(pPriv->pBackingGC, (XID)0);
145 pPriv->pBackingGC = NULL;
149 static void
150 cwValidateGC(GCPtr pGC, unsigned long stateChanges, DrawablePtr pDrawable)
152 GCPtr pBackingGC;
153 cwGCPtr pPriv;
154 DrawablePtr pBackingDrawable;
155 int x_off, y_off;
157 pPriv = (cwGCPtr) getCwGC (pGC);
159 FUNC_PROLOGUE(pGC, pPriv);
162 * Must call ValidateGC to ensure pGC->pCompositeClip is valid
164 (*pGC->funcs->ValidateGC)(pGC, stateChanges, pDrawable);
166 if (!cwDrawableIsRedirWindow(pDrawable)) {
167 cwDestroyBackingGC(pGC);
168 FUNC_EPILOGUE(pGC, pPriv);
169 return;
170 } else {
171 if (!pPriv->pBackingGC && !cwCreateBackingGC(pGC, pDrawable)) {
172 FUNC_EPILOGUE(pGC, pPriv);
173 return;
177 pBackingGC = pPriv->pBackingGC;
178 pBackingDrawable = cwGetBackingDrawable(pDrawable, &x_off, &y_off);
180 pPriv->stateChanges |= stateChanges;
183 * Copy the composite clip into the backing GC if either
184 * the drawable clip list has changed or the client has changed
185 * the client clip data
187 if (pDrawable->serialNumber != pPriv->serialNumber ||
188 (pPriv->stateChanges & (GCClipXOrigin|GCClipYOrigin|GCClipMask)))
190 XID vals[2];
191 RegionPtr pCompositeClip;
193 pCompositeClip = REGION_CREATE (pScreen, NULL, 0);
194 REGION_COPY (pScreen, pCompositeClip, pGC->pCompositeClip);
196 /* Either the drawable has changed, or the clip list in the drawable has
197 * changed. Copy the new clip list over and set the new translated
198 * offset for it.
201 (*pBackingGC->funcs->ChangeClip) (pBackingGC, CT_REGION,
202 (pointer) pCompositeClip, 0);
204 vals[0] = x_off - pDrawable->x;
205 vals[1] = y_off - pDrawable->y;
206 dixChangeGC(NullClient, pBackingGC,
207 (GCClipXOrigin | GCClipYOrigin), vals, NULL);
209 pPriv->serialNumber = pDrawable->serialNumber;
211 * Mask off any client clip changes to make sure
212 * the clip list set above remains in effect
214 pPriv->stateChanges &= ~(GCClipXOrigin|GCClipYOrigin|GCClipMask);
217 if (pPriv->stateChanges) {
218 CopyGC(pGC, pBackingGC, pPriv->stateChanges);
219 pPriv->stateChanges = 0;
222 if ((pGC->patOrg.x + x_off) != pBackingGC->patOrg.x ||
223 (pGC->patOrg.y + y_off) != pBackingGC->patOrg.y)
225 XID vals[2];
226 vals[0] = pGC->patOrg.x + x_off;
227 vals[1] = pGC->patOrg.y + y_off;
228 dixChangeGC(NullClient, pBackingGC,
229 (GCTileStipXOrigin | GCTileStipYOrigin), vals, NULL);
232 ValidateGC(pBackingDrawable, pBackingGC);
234 FUNC_EPILOGUE(pGC, pPriv);
237 static void
238 cwChangeGC(GCPtr pGC, unsigned long mask)
240 cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
242 FUNC_PROLOGUE(pGC, pPriv);
244 (*pGC->funcs->ChangeGC) (pGC, mask);
246 FUNC_EPILOGUE(pGC, pPriv);
249 static void
250 cwCopyGC(GCPtr pGCSrc, unsigned long mask, GCPtr pGCDst)
252 cwGCPtr pPriv = (cwGCPtr)(pGCDst)->devPrivates[cwGCIndex].ptr;
254 FUNC_PROLOGUE(pGCDst, pPriv);
256 (*pGCDst->funcs->CopyGC) (pGCSrc, mask, pGCDst);
258 FUNC_EPILOGUE(pGCDst, pPriv);
261 static void
262 cwDestroyGC(GCPtr pGC)
264 cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
266 FUNC_PROLOGUE(pGC, pPriv);
268 cwDestroyBackingGC(pGC);
270 (*pGC->funcs->DestroyGC) (pGC);
272 /* leave it unwrapped */
275 static void
276 cwChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects)
278 cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
280 FUNC_PROLOGUE(pGC, pPriv);
282 (*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
284 FUNC_EPILOGUE(pGC, pPriv);
287 static void
288 cwCopyClip(GCPtr pgcDst, GCPtr pgcSrc)
290 cwGCPtr pPriv = (cwGCPtr)(pgcDst)->devPrivates[cwGCIndex].ptr;
292 FUNC_PROLOGUE(pgcDst, pPriv);
294 (*pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
296 FUNC_EPILOGUE(pgcDst, pPriv);
299 static void
300 cwDestroyClip(GCPtr pGC)
302 cwGCPtr pPriv = (cwGCPtr)(pGC)->devPrivates[cwGCIndex].ptr;
304 FUNC_PROLOGUE(pGC, pPriv);
306 (*pGC->funcs->DestroyClip)(pGC);
308 FUNC_EPILOGUE(pGC, pPriv);
312 * Screen wrappers.
315 #define SCREEN_PROLOGUE(pScreen, field) \
316 ((pScreen)->field = getCwScreen(pScreen)->field)
318 #define SCREEN_EPILOGUE(pScreen, field, wrapper) do { \
319 getCwScreen(pScreen)->field = (pScreen)->field; \
320 (pScreen)->field = (wrapper); \
321 } while (0)
323 static Bool
324 cwCreateGC(GCPtr pGC)
326 cwGCPtr pPriv = getCwGC(pGC);
327 ScreenPtr pScreen = pGC->pScreen;
328 Bool ret;
330 bzero(pPriv, sizeof(cwGCRec));
331 SCREEN_PROLOGUE(pScreen, CreateGC);
333 if ( (ret = (*pScreen->CreateGC)(pGC)) )
334 FUNC_EPILOGUE(pGC, pPriv);
336 SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
338 return ret;
341 static void
342 cwGetImage(DrawablePtr pSrc, int x, int y, int w, int h, unsigned int format,
343 unsigned long planemask, char *pdstLine)
345 ScreenPtr pScreen = pSrc->pScreen;
346 DrawablePtr pBackingDrawable;
347 int src_off_x, src_off_y;
349 SCREEN_PROLOGUE(pScreen, GetImage);
351 pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
353 CW_OFFSET_XY_SRC(x, y);
355 (*pScreen->GetImage)(pBackingDrawable, x, y, w, h, format, planemask,
356 pdstLine);
358 SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
361 static void
362 cwGetSpans(DrawablePtr pSrc, int wMax, DDXPointPtr ppt, int *pwidth,
363 int nspans, char *pdstStart)
365 ScreenPtr pScreen = pSrc->pScreen;
366 DrawablePtr pBackingDrawable;
367 int i;
368 int src_off_x, src_off_y;
370 SCREEN_PROLOGUE(pScreen, GetSpans);
372 pBackingDrawable = cwGetBackingDrawable(pSrc, &src_off_x, &src_off_y);
374 for (i = 0; i < nspans; i++)
375 CW_OFFSET_XY_SRC(ppt[i].x, ppt[i].y);
377 (*pScreen->GetSpans)(pBackingDrawable, wMax, ppt, pwidth, nspans,
378 pdstStart);
380 SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
383 static void
384 cwFillRegionSolid(DrawablePtr pDrawable, RegionPtr pRegion, unsigned long pixel)
386 ScreenPtr pScreen = pDrawable->pScreen;
387 GCPtr pGC;
388 BoxPtr pBox;
389 int nbox, i;
390 ChangeGCVal v[3];
392 pGC = GetScratchGC(pDrawable->depth, pScreen);
393 v[0].val = GXcopy;
394 v[1].val = pixel;
395 v[2].val = FillSolid;
396 dixChangeGC(NullClient, pGC, (GCFunction | GCForeground | GCFillStyle),
397 NULL, v);
398 ValidateGC(pDrawable, pGC);
400 pBox = REGION_RECTS(pRegion);
401 nbox = REGION_NUM_RECTS(pRegion);
403 for (i = 0; i < nbox; i++, pBox++) {
404 xRectangle rect;
405 rect.x = pBox->x1;
406 rect.y = pBox->y1;
407 rect.width = pBox->x2 - pBox->x1;
408 rect.height = pBox->y2 - pBox->y1;
409 (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &rect);
412 FreeScratchGC(pGC);
415 static void
416 cwFillRegionTiled(DrawablePtr pDrawable, RegionPtr pRegion, PixmapPtr pTile,
417 int x_off, int y_off)
419 ScreenPtr pScreen = pDrawable->pScreen;
420 GCPtr pGC;
421 BoxPtr pBox;
422 int nbox, i;
423 ChangeGCVal v[5];
425 pGC = GetScratchGC(pDrawable->depth, pScreen);
426 v[0].val = GXcopy;
427 v[1].val = FillTiled;
428 v[2].ptr = (pointer) pTile;
429 v[3].val = x_off;
430 v[4].val = y_off;
431 dixChangeGC(NullClient, pGC, (GCFunction | GCFillStyle | GCTile |
432 GCTileStipXOrigin | GCTileStipYOrigin), NULL, v);
434 ValidateGC(pDrawable, pGC);
436 pBox = REGION_RECTS(pRegion);
437 nbox = REGION_NUM_RECTS(pRegion);
439 for (i = 0; i < nbox; i++, pBox++) {
440 xRectangle rect;
441 rect.x = pBox->x1;
442 rect.y = pBox->y1;
443 rect.width = pBox->x2 - pBox->x1;
444 rect.height = pBox->y2 - pBox->y1;
445 (*pGC->ops->PolyFillRect)(pDrawable, pGC, 1, &rect);
448 FreeScratchGC(pGC);
451 static void
452 cwPaintWindowBackground(WindowPtr pWin, RegionPtr pRegion, int what)
454 ScreenPtr pScreen = pWin->drawable.pScreen;
456 SCREEN_PROLOGUE(pScreen, PaintWindowBackground);
458 if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) {
459 (*pScreen->PaintWindowBackground)(pWin, pRegion, what);
460 } else {
461 DrawablePtr pBackingDrawable;
462 int x_off, y_off, x_screen, y_screen;
464 while (pWin->backgroundState == ParentRelative)
465 pWin = pWin->parent;
467 pBackingDrawable = cwGetBackingDrawable((DrawablePtr)pWin, &x_off,
468 &y_off);
470 x_screen = x_off - pWin->drawable.x;
471 y_screen = y_off - pWin->drawable.y;
473 if (pWin && (pWin->backgroundState == BackgroundPixel ||
474 pWin->backgroundState == BackgroundPixmap))
476 REGION_TRANSLATE(pScreen, pRegion, x_screen, y_screen);
478 if (pWin->backgroundState == BackgroundPixel) {
479 cwFillRegionSolid(pBackingDrawable, pRegion,
480 pWin->background.pixel);
481 } else {
482 cwFillRegionTiled(pBackingDrawable, pRegion,
483 pWin->background.pixmap, x_off, y_off);
486 REGION_TRANSLATE(pScreen, pRegion, -x_screen, -y_screen);
490 SCREEN_EPILOGUE(pScreen, PaintWindowBackground, cwPaintWindowBackground);
493 static void
494 cwPaintWindowBorder(WindowPtr pWin, RegionPtr pRegion, int what)
496 ScreenPtr pScreen = pWin->drawable.pScreen;
498 SCREEN_PROLOGUE(pScreen, PaintWindowBorder);
500 if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) {
501 (*pScreen->PaintWindowBorder)(pWin, pRegion, what);
502 } else {
503 DrawablePtr pBackingDrawable;
504 int x_off, y_off, x_screen, y_screen;
506 pBackingDrawable = cwGetBackingDrawable((DrawablePtr)pWin, &x_off,
507 &y_off);
509 x_screen = x_off - pWin->drawable.x;
510 y_screen = y_off - pWin->drawable.y;
512 REGION_TRANSLATE(pScreen, pRegion, x_screen, y_screen);
514 if (pWin->borderIsPixel) {
515 cwFillRegionSolid(pBackingDrawable, pRegion, pWin->border.pixel);
516 } else {
517 cwFillRegionTiled(pBackingDrawable, pRegion, pWin->border.pixmap,
518 x_off, y_off);
521 REGION_TRANSLATE(pScreen, pRegion, -x_screen, -y_screen);
524 SCREEN_EPILOGUE(pScreen, PaintWindowBorder, cwPaintWindowBorder);
527 static void
528 cwCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
530 ScreenPtr pScreen = pWin->drawable.pScreen;
532 SCREEN_PROLOGUE(pScreen, CopyWindow);
534 if (!cwDrawableIsRedirWindow((DrawablePtr)pWin)) {
535 (*pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
536 } else {
537 GCPtr pGC;
538 BoxPtr pExtents;
539 int x_off, y_off;
540 int dx, dy;
541 PixmapPtr pBackingPixmap;
542 RegionPtr pClip;
543 int src_x, src_y, dst_x, dst_y, w, h;
545 dx = ptOldOrg.x - pWin->drawable.x;
546 dy = ptOldOrg.y - pWin->drawable.y;
548 pExtents = REGION_EXTENTS(pScreen, prgnSrc);
550 pBackingPixmap = (PixmapPtr) cwGetBackingDrawable((DrawablePtr)pWin,
551 &x_off, &y_off);
553 src_x = pExtents->x1 - pBackingPixmap->screen_x;
554 src_y = pExtents->y1 - pBackingPixmap->screen_y;
555 w = pExtents->x2 - pExtents->x1;
556 h = pExtents->y2 - pExtents->y1;
557 dst_x = src_x - dx;
558 dst_y = src_y - dy;
560 /* Translate region (as required by API) */
561 REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);
563 pGC = GetScratchGC(pBackingPixmap->drawable.depth, pScreen);
565 * Copy region to GC as clip, aligning as dest clip
567 pClip = REGION_CREATE (pScreen, NULL, 0);
568 REGION_INTERSECT(pScreen, pClip, &pWin->borderClip, prgnSrc);
569 REGION_TRANSLATE(pScreen, pClip,
570 -pBackingPixmap->screen_x,
571 -pBackingPixmap->screen_y);
573 (*pGC->funcs->ChangeClip) (pGC, CT_REGION, pClip, 0);
575 ValidateGC(&pBackingPixmap->drawable, pGC);
577 (*pGC->ops->CopyArea) (&pBackingPixmap->drawable,
578 &pBackingPixmap->drawable, pGC,
579 src_x, src_y, w, h, dst_x, dst_y);
581 (*pGC->funcs->DestroyClip) (pGC);
583 FreeScratchGC(pGC);
586 SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow);
589 static PixmapPtr
590 cwGetWindowPixmap (WindowPtr pWin)
592 PixmapPtr pPixmap = getCwPixmap (pWin);
594 if (!pPixmap)
596 ScreenPtr pScreen = pWin->drawable.pScreen;
597 SCREEN_PROLOGUE(pScreen, GetWindowPixmap);
598 if (pScreen->GetWindowPixmap)
599 pPixmap = (*pScreen->GetWindowPixmap) (pWin);
600 SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap);
602 return pPixmap;
605 static void
606 cwSetWindowPixmap (WindowPtr pWindow, PixmapPtr pPixmap)
608 ScreenPtr pScreen = pWindow->drawable.pScreen;
610 if (pPixmap == (*pScreen->GetScreenPixmap) (pScreen))
611 pPixmap = NULL;
612 setCwPixmap (pWindow, pPixmap);
615 /* Screen initialization/teardown */
616 void
617 miInitializeCompositeWrapper(ScreenPtr pScreen)
619 cwScreenPtr pScreenPriv;
620 #ifdef RENDER
621 Bool has_render = GetPictureScreenIfSet(pScreen) != NULL;
622 #endif
624 if (cwGeneration != serverGeneration)
626 cwScreenIndex = AllocateScreenPrivateIndex();
627 if (cwScreenIndex < 0)
628 return;
629 cwGCIndex = AllocateGCPrivateIndex();
630 cwWindowIndex = AllocateWindowPrivateIndex();
631 #ifdef RENDER
632 if (has_render)
633 cwPictureIndex = AllocatePicturePrivateIndex();
634 #endif
635 cwGeneration = serverGeneration;
637 if (!AllocateGCPrivate(pScreen, cwGCIndex, sizeof(cwGCRec)))
638 return;
639 if (!AllocateWindowPrivate(pScreen, cwWindowIndex, 0))
640 return;
641 #ifdef RENDER
642 if (has_render) {
643 if (!AllocatePicturePrivate(pScreen, cwPictureIndex, 0))
644 return;
646 #endif
647 pScreenPriv = (cwScreenPtr)xalloc(sizeof(cwScreenRec));
648 if (!pScreenPriv)
649 return;
651 pScreen->devPrivates[cwScreenIndex].ptr = (pointer)pScreenPriv;
653 SCREEN_EPILOGUE(pScreen, CloseScreen, cwCloseScreen);
654 SCREEN_EPILOGUE(pScreen, GetImage, cwGetImage);
655 SCREEN_EPILOGUE(pScreen, GetSpans, cwGetSpans);
656 SCREEN_EPILOGUE(pScreen, CreateGC, cwCreateGC);
657 SCREEN_EPILOGUE(pScreen, PaintWindowBackground, cwPaintWindowBackground);
658 SCREEN_EPILOGUE(pScreen, PaintWindowBorder, cwPaintWindowBorder);
659 SCREEN_EPILOGUE(pScreen, CopyWindow, cwCopyWindow);
661 SCREEN_EPILOGUE(pScreen, SetWindowPixmap, cwSetWindowPixmap);
662 SCREEN_EPILOGUE(pScreen, GetWindowPixmap, cwGetWindowPixmap);
664 #ifdef RENDER
665 if (has_render)
666 cwInitializeRender(pScreen);
667 #endif
670 static Bool
671 cwCloseScreen (int i, ScreenPtr pScreen)
673 cwScreenPtr pScreenPriv;
674 #ifdef RENDER
675 PictureScreenPtr ps = GetPictureScreenIfSet(pScreen);
676 #endif
678 pScreenPriv = (cwScreenPtr)pScreen->devPrivates[cwScreenIndex].ptr;
680 pScreen->CloseScreen = pScreenPriv->CloseScreen;
681 pScreen->GetImage = pScreenPriv->GetImage;
682 pScreen->GetSpans = pScreenPriv->GetSpans;
683 pScreen->CreateGC = pScreenPriv->CreateGC;
684 pScreen->PaintWindowBackground = pScreenPriv->PaintWindowBackground;
685 pScreen->PaintWindowBorder = pScreenPriv->PaintWindowBorder;
686 pScreen->CopyWindow = pScreenPriv->CopyWindow;
688 #ifdef RENDER
689 if (ps)
690 cwFiniRender(pScreen);
691 #endif
693 xfree((pointer)pScreenPriv);
695 return (*pScreen->CloseScreen)(i, pScreen);