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>
30 #include "windowstr.h"
36 #define CW_ASSERT(x) do { \
38 ErrorF("composite wrapper: assertion failed at %s:%d\n", __FUNC__, \
43 #define CW_ASSERT(x) do {} while (0)
52 static unsigned long cwGeneration
= 0;
56 cwCloseScreen (int i
, ScreenPtr pScreen
);
59 cwValidateGC(GCPtr pGC
, unsigned long stateChanges
, DrawablePtr pDrawable
);
61 cwChangeGC(GCPtr pGC
, unsigned long mask
);
63 cwCopyGC(GCPtr pGCSrc
, unsigned long mask
, GCPtr pGCDst
);
65 cwDestroyGC(GCPtr pGC
);
67 cwChangeClip(GCPtr pGC
, int type
, pointer pvalue
, int nrects
);
69 cwCopyClip(GCPtr pgcDst
, GCPtr pgcSrc
);
71 cwDestroyClip(GCPtr pGC
);
83 /* Find the real drawable to draw to, and provide offsets that will translate
84 * window coordinates to backing pixmap coordinates.
87 cwGetBackingDrawable(DrawablePtr pDrawable
, int *x_off
, int *y_off
)
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
;
103 #define FUNC_PROLOGUE(pGC, pPriv) do { \
104 (pGC)->funcs = (pPriv)->wrapFuncs; \
105 (pGC)->ops = (pPriv)->wrapOps; \
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; \
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
,
127 if (status
!= Success
)
130 pPriv
->serialNumber
= 0;
131 pPriv
->stateChanges
= (1 << (GCLastBit
+ 1)) - 1;
137 cwDestroyBackingGC(GCPtr pGC
)
141 pPriv
= (cwGCPtr
) getCwGC (pGC
);
143 if (pPriv
->pBackingGC
) {
144 FreeGC(pPriv
->pBackingGC
, (XID
)0);
145 pPriv
->pBackingGC
= NULL
;
150 cwValidateGC(GCPtr pGC
, unsigned long stateChanges
, DrawablePtr pDrawable
)
154 DrawablePtr pBackingDrawable
;
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
);
171 if (!pPriv
->pBackingGC
&& !cwCreateBackingGC(pGC
, pDrawable
)) {
172 FUNC_EPILOGUE(pGC
, pPriv
);
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
)))
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
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
)
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
);
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
);
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
);
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 */
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
);
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
);
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
);
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); \
324 cwCreateGC(GCPtr pGC
)
326 cwGCPtr pPriv
= getCwGC(pGC
);
327 ScreenPtr pScreen
= pGC
->pScreen
;
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
);
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
,
358 SCREEN_EPILOGUE(pScreen
, GetImage
, cwGetImage
);
362 cwGetSpans(DrawablePtr pSrc
, int wMax
, DDXPointPtr ppt
, int *pwidth
,
363 int nspans
, char *pdstStart
)
365 ScreenPtr pScreen
= pSrc
->pScreen
;
366 DrawablePtr pBackingDrawable
;
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
,
380 SCREEN_EPILOGUE(pScreen
, GetSpans
, cwGetSpans
);
384 cwFillRegionSolid(DrawablePtr pDrawable
, RegionPtr pRegion
, unsigned long pixel
)
386 ScreenPtr pScreen
= pDrawable
->pScreen
;
392 pGC
= GetScratchGC(pDrawable
->depth
, pScreen
);
395 v
[2].val
= FillSolid
;
396 dixChangeGC(NullClient
, pGC
, (GCFunction
| GCForeground
| GCFillStyle
),
398 ValidateGC(pDrawable
, pGC
);
400 pBox
= REGION_RECTS(pRegion
);
401 nbox
= REGION_NUM_RECTS(pRegion
);
403 for (i
= 0; i
< nbox
; i
++, pBox
++) {
407 rect
.width
= pBox
->x2
- pBox
->x1
;
408 rect
.height
= pBox
->y2
- pBox
->y1
;
409 (*pGC
->ops
->PolyFillRect
)(pDrawable
, pGC
, 1, &rect
);
416 cwFillRegionTiled(DrawablePtr pDrawable
, RegionPtr pRegion
, PixmapPtr pTile
,
417 int x_off
, int y_off
)
419 ScreenPtr pScreen
= pDrawable
->pScreen
;
425 pGC
= GetScratchGC(pDrawable
->depth
, pScreen
);
427 v
[1].val
= FillTiled
;
428 v
[2].ptr
= (pointer
) pTile
;
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
++) {
443 rect
.width
= pBox
->x2
- pBox
->x1
;
444 rect
.height
= pBox
->y2
- pBox
->y1
;
445 (*pGC
->ops
->PolyFillRect
)(pDrawable
, pGC
, 1, &rect
);
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
);
461 DrawablePtr pBackingDrawable
;
462 int x_off
, y_off
, x_screen
, y_screen
;
464 while (pWin
->backgroundState
== ParentRelative
)
467 pBackingDrawable
= cwGetBackingDrawable((DrawablePtr
)pWin
, &x_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
);
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
);
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
);
503 DrawablePtr pBackingDrawable
;
504 int x_off
, y_off
, x_screen
, y_screen
;
506 pBackingDrawable
= cwGetBackingDrawable((DrawablePtr
)pWin
, &x_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
);
517 cwFillRegionTiled(pBackingDrawable
, pRegion
, pWin
->border
.pixmap
,
521 REGION_TRANSLATE(pScreen
, pRegion
, -x_screen
, -y_screen
);
524 SCREEN_EPILOGUE(pScreen
, PaintWindowBorder
, cwPaintWindowBorder
);
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
);
541 PixmapPtr pBackingPixmap
;
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
,
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
;
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
);
586 SCREEN_EPILOGUE(pScreen
, CopyWindow
, cwCopyWindow
);
590 cwGetWindowPixmap (WindowPtr pWin
)
592 PixmapPtr pPixmap
= getCwPixmap (pWin
);
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
);
606 cwSetWindowPixmap (WindowPtr pWindow
, PixmapPtr pPixmap
)
608 ScreenPtr pScreen
= pWindow
->drawable
.pScreen
;
610 if (pPixmap
== (*pScreen
->GetScreenPixmap
) (pScreen
))
612 setCwPixmap (pWindow
, pPixmap
);
615 /* Screen initialization/teardown */
617 miInitializeCompositeWrapper(ScreenPtr pScreen
)
619 cwScreenPtr pScreenPriv
;
621 Bool has_render
= GetPictureScreenIfSet(pScreen
) != NULL
;
624 if (cwGeneration
!= serverGeneration
)
626 cwScreenIndex
= AllocateScreenPrivateIndex();
627 if (cwScreenIndex
< 0)
629 cwGCIndex
= AllocateGCPrivateIndex();
630 cwWindowIndex
= AllocateWindowPrivateIndex();
633 cwPictureIndex
= AllocatePicturePrivateIndex();
635 cwGeneration
= serverGeneration
;
637 if (!AllocateGCPrivate(pScreen
, cwGCIndex
, sizeof(cwGCRec
)))
639 if (!AllocateWindowPrivate(pScreen
, cwWindowIndex
, 0))
643 if (!AllocatePicturePrivate(pScreen
, cwPictureIndex
, 0))
647 pScreenPriv
= (cwScreenPtr
)xalloc(sizeof(cwScreenRec
));
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
);
666 cwInitializeRender(pScreen
);
671 cwCloseScreen (int i
, ScreenPtr pScreen
)
673 cwScreenPtr pScreenPriv
;
675 PictureScreenPtr ps
= GetPictureScreenIfSet(pScreen
);
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
;
690 cwFiniRender(pScreen
);
693 xfree((pointer
)pScreenPriv
);
695 return (*pScreen
->CloseScreen
)(i
, pScreen
);