1 /************************************************************
3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 ********************************************************/
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
35 #include <X11/Xproto.h>
38 #include "windowstr.h"
39 #include "scrnintstr.h"
40 #include "pixmapstr.h"
41 #include "extnsionst.h"
42 #include "dixstruct.h"
45 #include "regionstr.h"
50 #define _MULTIBUF_SERVER_ /* don't want Xlib structures */
51 #define _MULTIBUF_PIXMAP_
52 #include <X11/extensions/multibufst.h>
55 static Bool
NoopDDA_True() { return TRUE
; }
57 static Bool
pixPositionWindow();
58 static int pixCreateImageBuffers();
59 static void pixDisplayImageBuffers();
60 static void pixClearImageBufferArea();
61 static void pixDeleteBufferDrawable();
62 static void pixWrapScreenFuncs();
63 static void pixResetProc();
66 pixMultibufferInit(pScreen
, pMBScreen
)
68 mbufScreenPtr pMBScreen
;
71 xMbufBufferInfo
*pInfo
;
74 mbufPixmapPrivPtr pMBPriv
;
76 pMBScreen
->CreateImageBuffers
= pixCreateImageBuffers
;
77 pMBScreen
->DestroyImageBuffers
= (void (*)())NoopDDA
;
78 pMBScreen
->DisplayImageBuffers
= pixDisplayImageBuffers
;
79 pMBScreen
->ClearImageBufferArea
= pixClearImageBufferArea
;
80 pMBScreen
->ChangeMBufferAttributes
= NoopDDA_True
;
81 pMBScreen
->ChangeBufferAttributes
= NoopDDA_True
;
82 pMBScreen
->DeleteBufferDrawable
= pixDeleteBufferDrawable
;
83 pMBScreen
->WrapScreenFuncs
= pixWrapScreenFuncs
;
84 pMBScreen
->ResetProc
= pixResetProc
;
86 /* Support every depth and visual combination that the screen does */
89 for (i
= 0; i
< pScreen
->numDepths
; i
++)
91 pDepth
= &pScreen
->allowedDepths
[i
];
92 nInfo
+= pDepth
->numVids
;
95 pInfo
= (xMbufBufferInfo
*) xalloc (nInfo
* sizeof (xMbufBufferInfo
));
100 for (i
= 0; i
< pScreen
->numDepths
; i
++)
102 pDepth
= &pScreen
->allowedDepths
[i
];
103 for (j
= 0; j
< pDepth
->numVids
; j
++)
105 pInfo
[k
].visualID
= pDepth
->vids
[j
];
106 pInfo
[k
].maxBuffers
= 0;
107 pInfo
[k
].depth
= pDepth
->depth
;
112 pMBScreen
->nInfo
= nInfo
;
113 pMBScreen
->pInfo
= pInfo
;
116 * Setup the devPrivate to mbufScreenRec
119 pMBPriv
= (mbufPixmapPrivPtr
) xalloc(sizeof(* pMBPriv
));
125 pMBScreen
->devPrivate
.ptr
= (pointer
) pMBPriv
;
126 pMBPriv
->PositionWindow
= NULL
;
127 pMBPriv
->funcsWrapped
= 0;
134 pixCreateImageBuffers (pWin
, nbuf
, ids
, action
, hint
)
141 mbufWindowPtr pMBWindow
;
142 mbufBufferPtr pMBBuffer
;
144 int width
, height
, depth
;
147 pMBWindow
= MB_WINDOW_PRIV(pWin
);
149 width
= pWin
->drawable
.width
;
150 height
= pWin
->drawable
.height
;
151 depth
= pWin
->drawable
.depth
;
152 pScreen
= pWin
->drawable
.pScreen
;
154 for (i
= 0; i
< nbuf
; i
++)
156 pMBBuffer
= &pMBWindow
->buffers
[i
];
157 pMBBuffer
->pDrawable
= (DrawablePtr
)
158 (*pScreen
->CreatePixmap
) (pScreen
, width
, height
, depth
);
159 if (!pMBBuffer
->pDrawable
)
162 if (!AddResource (ids
[i
], MultibufferDrawableResType
,
163 (pointer
) pMBBuffer
->pDrawable
))
165 (*pScreen
->DestroyPixmap
) ((PixmapPtr
) pMBBuffer
->pDrawable
);
168 pMBBuffer
->pDrawable
->id
= ids
[i
];
171 * In the description of the CreateImageBuffers request:
172 * "If the window is mapped, or if these image buffers have
173 * backing store, their contents will be tiled with the window
174 * background, and zero or more expose events will be generated
175 * for each of these buffers."
178 (* MB_SCREEN_PRIV(pScreen
)->ClearImageBufferArea
)
179 (pMBBuffer
, 0,0, 0,0, TRUE
);
186 * set up the gc to clear the pixmaps;
189 SetupBackgroundPainter (pWin
, pGC
)
194 int ts_x_origin
, ts_y_origin
;
200 * First take care of any ParentRelative stuff by altering the
201 * tile/stipple origin to match the coordinates of the upper-left
202 * corner of the first ancestor without a ParentRelative background.
203 * This coordinate is, of course, negative.
206 ts_x_origin
= ts_y_origin
= 0;
207 while (pWin
->backgroundState
== ParentRelative
) {
208 ts_x_origin
-= pWin
->origin
.x
;
209 ts_y_origin
-= pWin
->origin
.y
;
212 backgroundState
= pWin
->backgroundState
;
213 background
= pWin
->background
;
215 switch (backgroundState
)
217 case BackgroundPixel
:
218 gcvalues
[0] = (XID
) background
.pixel
;
219 gcvalues
[1] = FillSolid
;
220 gcmask
= GCForeground
|GCFillStyle
;
223 case BackgroundPixmap
:
224 gcvalues
[0] = FillTiled
;
225 gcvalues
[1] = (XID
) background
.pixmap
;
226 gcvalues
[2] = ts_x_origin
;
227 gcvalues
[3] = ts_y_origin
;
228 gcmask
= GCFillStyle
|GCTile
|GCTileStipXOrigin
|GCTileStipYOrigin
;
234 DoChangeGC(pGC
, gcmask
, gcvalues
, TRUE
);
239 MultibufferPaintBackgroundRectangles(pWin
, pDrawable
, nrects
, pRects
)
241 DrawablePtr pDrawable
;
247 pGC
= GetScratchGC (pWin
->drawable
.depth
, pWin
->drawable
.pScreen
);
248 if (SetupBackgroundPainter(pWin
, pGC
))
250 ValidateGC(pDrawable
, pGC
);
251 (*pGC
->ops
->PolyFillRect
) (pDrawable
, pGC
, nrects
, pRects
);
257 MultibufferPaintBackgroundRegion(pWin
, pDrawable
, pRegion
)
259 DrawablePtr pDrawable
;
263 int nrects
= REGION_NUM_RECTS(pRegion
);
264 BoxPtr pbox
= REGION_RECTS(pRegion
);
266 pRects
= (xRectangle
*)ALLOCATE_LOCAL(nrects
* sizeof(xRectangle
));
270 for (i
= 0; i
< nrects
; i
++)
272 pRects
[i
].x
= pbox
->x1
;
273 pRects
[i
].y
= pbox
->y1
;
274 pRects
[i
].width
= pbox
->x2
- pbox
->x1
;
275 pRects
[i
].height
= pbox
->y2
- pbox
->y1
;
277 MultibufferPaintBackgroundRectangles(pWin
, pDrawable
, nrects
, pRects
);
278 DEALLOCATE_LOCAL(pRects
);
283 pixDisplayImageBuffers(pScreen
, ppMBWindow
, ppMBBuffer
, nbuf
)
284 mbufBufferPtr
*ppMBBuffer
;
285 mbufWindowPtr
*ppMBWindow
;
289 PixmapPtr pPrevPixmap
, pNewPixmap
;
293 mbufBufferPtr pPrevMBBuffer
;
297 UpdateCurrentTime ();
298 for (i
= 0; i
< nbuf
; i
++)
300 pWin
= ppMBWindow
[i
]->pWindow
;
302 /* Time to get a different scratch GC? */
305 || pGC
->depth
!= pWin
->drawable
.depth
306 || pGC
->pScreen
!= pWin
->drawable
.pScreen
)
308 if (pGC
) FreeScratchGC(pGC
);
309 pGC
= GetScratchGC (pWin
->drawable
.depth
, pWin
->drawable
.pScreen
);
311 pPrevMBBuffer
= MB_DISPLAYED_BUFFER(ppMBWindow
[i
]);
312 pPrevPixmap
= (PixmapPtr
) pPrevMBBuffer
->pDrawable
;
313 pNewPixmap
= (PixmapPtr
) ppMBBuffer
[i
]->pDrawable
;
315 if (pPrevPixmap
== pNewPixmap
)
317 /* "If a specified buffer is already displayed, any delays and
318 * update action will still be performed for that buffer."
320 * We special-case this because applications do occasionally
321 * request a redundant DisplayImageBuffers, and we can save
322 * strokes by recognizing that the only update action that will
323 * change the buffer contents in this case is Background.
325 if (ppMBWindow
[i
]->updateAction
== MultibufferUpdateActionBackground
)
328 r
.width
= pWin
->drawable
.width
;
329 r
.height
= pWin
->drawable
.height
;
330 MultibufferPaintBackgroundRectangles(pWin
, (DrawablePtr
)pWin
,
334 else /* different buffer is being displayed */
336 /* perform update action */
338 switch (ppMBWindow
[i
]->updateAction
)
340 case MultibufferUpdateActionUndefined
:
343 case MultibufferUpdateActionBackground
:
346 r
.width
= pPrevPixmap
->drawable
.width
;
347 r
.height
= pPrevPixmap
->drawable
.height
;
348 MultibufferPaintBackgroundRectangles(pWin
,
349 (DrawablePtr
)pPrevPixmap
,
353 case MultibufferUpdateActionUntouched
:
355 /* copy the window to the pixmap that represents the
356 * currently displayed buffer
359 if (pPrevMBBuffer
->eventMask
& ExposureMask
)
362 DoChangeGC (pGC
, GCGraphicsExposures
, &bool, FALSE
);
364 ValidateGC ((DrawablePtr
)pPrevPixmap
, pGC
);
365 pExposed
= (*pGC
->ops
->CopyArea
)((DrawablePtr
) pWin
,
366 (DrawablePtr
) pPrevPixmap
,
369 pWin
->drawable
.width
,
370 pWin
->drawable
.height
,
373 /* if we couldn't copy the whole window to the buffer,
374 * send expose events (if any client wants them)
377 if (pPrevMBBuffer
->eventMask
& ExposureMask
)
378 { /* some client wants expose events */
382 extern RegionPtr
CreateUnclippedWinSize();
383 ScreenPtr pScreen
= pWin
->drawable
.pScreen
;
384 pWinSize
= CreateUnclippedWinSize (pWin
);
386 * pExposed is window-relative, but at this point
387 * pWinSize is screen-relative. Make pWinSize be
388 * window-relative so that region ops involving
389 * pExposed and pWinSize behave sensibly.
391 REGION_TRANSLATE(pScreen
, pWinSize
,
394 REGION_INTERSECT(pScreen
, pExposed
, pExposed
, pWinSize
);
395 REGION_DESTROY(pScreen
, pWinSize
);
396 MultibufferExpose (pPrevMBBuffer
, pExposed
);
397 REGION_DESTROY(pScreen
, pExposed
);
400 DoChangeGC (pGC
, GCGraphicsExposures
, &bool, FALSE
);
401 } /* end some client wants expose events */
403 break; /* end case MultibufferUpdateActionUntouched */
405 case MultibufferUpdateActionCopied
:
407 ValidateGC ((DrawablePtr
)pPrevPixmap
, pGC
);
408 (*pGC
->ops
->CopyArea
) ((DrawablePtr
)pNewPixmap
,
409 (DrawablePtr
)pPrevPixmap
, pGC
,
410 0, 0, pWin
->drawable
.width
,
411 pWin
->drawable
.height
, 0, 0);
414 } /* end switch on update action */
416 /* display the new buffer */
418 ValidateGC ((DrawablePtr
)pWin
, pGC
);
419 (*pGC
->ops
->CopyArea
) ((DrawablePtr
)pNewPixmap
, (DrawablePtr
)pWin
,
421 pWin
->drawable
.width
, pWin
->drawable
.height
,
425 ppMBWindow
[i
]->lastUpdate
= currentTime
;
428 if (pGC
) FreeScratchGC (pGC
);
433 * resize the buffers when the window is resized
437 pixPositionWindow (pWin
, x
, y
)
442 mbufPixmapPrivPtr pMBPriv
;
443 mbufWindowPtr pMBWindow
;
444 mbufBufferPtr pMBBuffer
;
448 int sourcex
, sourcey
;
452 int savewidth
, saveheight
;
454 RegionRec exposedRegion
;
457 pScreen
= pWin
->drawable
.pScreen
;
458 pMBPriv
= MB_SCREEN_PRIV_PIXMAP(pScreen
);
460 UNWRAP_SCREEN_FUNC(pScreen
, pMBPriv
, Bool
, PositionWindow
);
461 ret
= (* pScreen
->PositionWindow
) (pWin
, x
, y
);
462 REWRAP_SCREEN_FUNC(pScreen
, pMBPriv
, Bool
, PositionWindow
);
464 if (!(pMBWindow
= MB_WINDOW_PRIV(pWin
)))
467 /* if new size is same as old, we're done */
469 if (pMBWindow
->width
== pWin
->drawable
.width
&&
470 pMBWindow
->height
== pWin
->drawable
.height
)
473 width
= pWin
->drawable
.width
;
474 height
= pWin
->drawable
.height
;
475 dx
= pWin
->drawable
.x
- pMBWindow
->x
;
476 dy
= pWin
->drawable
.x
- pMBWindow
->y
;
477 dw
= width
- pMBWindow
->width
;
478 dh
= height
- pMBWindow
->height
;
479 GravityTranslate (0, 0, -dx
, -dy
, dw
, dh
,
480 pWin
->bitGravity
, &destx
, &desty
);
482 /* if the window grew, remember to paint the window background,
483 * and maybe send expose events, for the new areas of the buffers
486 clear
= pMBWindow
->width
< width
|| pMBWindow
->height
< height
||
487 pWin
->bitGravity
== ForgetGravity
;
491 savewidth
= pMBWindow
->width
;
492 saveheight
= pMBWindow
->height
;
493 /* clip rectangle to source and destination */
500 if (destx
+ savewidth
> width
)
501 savewidth
= width
- destx
;
508 if (desty
+ saveheight
> height
)
509 saveheight
= height
- desty
;
511 pMBWindow
->width
= width
;
512 pMBWindow
->height
= height
;
513 pMBWindow
->x
= pWin
->drawable
.x
;
514 pMBWindow
->y
= pWin
->drawable
.y
;
523 REGION_INIT(pScreen
, &exposedRegion
, &box
, 1);
524 if (pWin
->bitGravity
!= ForgetGravity
)
526 RegionRec preservedRegion
;
529 box
.x2
= destx
+ savewidth
;
530 box
.y2
= desty
+ saveheight
;
531 REGION_INIT(pScreen
, &preservedRegion
, &box
, 1);
532 REGION_SUBTRACT(pScreen
, &exposedRegion
, &exposedRegion
, &preservedRegion
);
533 REGION_UNINIT(pScreen
, &preservedRegion
);
536 } /* end if (clear) */
538 pGC
= GetScratchGC (pWin
->drawable
.depth
, pScreen
);
540 /* create buffers with new window size */
542 for (i
= 0; i
< pMBWindow
->numMultibuffer
; i
++)
544 pMBBuffer
= &pMBWindow
->buffers
[i
];
545 pPixmap
= (*pScreen
->CreatePixmap
) (pScreen
, width
, height
, pWin
->drawable
.depth
);
548 (* MB_SCREEN_PRIV(pScreen
)->DestroyImageBuffers
)(pWin
);
553 MultibufferPaintBackgroundRegion(pWin
, (DrawablePtr
)pPixmap
, &exposedRegion
);
554 MultibufferExpose(pMBBuffer
, &exposedRegion
);
556 if (pWin
->bitGravity
!= ForgetGravity
)
558 ValidateGC ((DrawablePtr
)pPixmap
, pGC
);
559 (*pGC
->ops
->CopyArea
) (pMBBuffer
->pDrawable
, (DrawablePtr
)pPixmap
,
561 sourcex
, sourcey
, savewidth
, saveheight
,
564 pPixmap
->drawable
.id
= pMBBuffer
->pDrawable
->id
;
565 (*pScreen
->DestroyPixmap
) ((PixmapPtr
) pMBBuffer
->pDrawable
);
566 pMBBuffer
->pDrawable
= (DrawablePtr
) pPixmap
;
567 if (i
!= pMBWindow
->displayedMultibuffer
)
569 ChangeResourceValue (pPixmap
->drawable
.id
,
570 MultibufferDrawableResType
,
576 REGION_UNINIT(pScreen
, &exposedRegion
);
581 pixWrapScreenFuncs(pScreen
)
584 mbufPixmapPrivPtr pMBPriv
= MB_SCREEN_PRIV_PIXMAP(pScreen
);
585 WRAP_SCREEN_FUNC(pScreen
, pMBPriv
, PositionWindow
, pixPositionWindow
);
589 pixResetProc(pScreen
)
592 mbufScreenPtr pMBScreen
= MB_SCREEN_PRIV(pScreen
);
593 mbufPixmapPrivPtr pMBPriv
= MB_SCREEN_PRIV_PIXMAP(pScreen
);
595 xfree(pMBScreen
->pInfo
);
600 pixClearImageBufferArea(pMBBuffer
, x
,y
, width
,height
, exposures
)
601 mbufBufferPtr pMBBuffer
;
603 unsigned short width
, height
;
610 int w_width
, w_height
;
611 DrawablePtr pDrawable
;
613 pWin
= pMBBuffer
->pMBWindow
->pWindow
;
614 pScreen
= pWin
->drawable
.pScreen
;
616 w_width
= pWin
->drawable
.width
;
617 w_height
= pWin
->drawable
.height
;
621 box
.x2
= width
? (box
.x1
+ width
) : w_width
;
622 box
.y2
= height
? (box
.y1
+ height
) : w_height
;
624 if (box
.x1
< 0) box
.x1
= 0;
625 if (box
.y1
< 0) box
.y1
= 0;
626 if (box
.x2
> w_width
) box
.x2
= w_width
;
627 if (box
.y2
> w_height
) box
.y2
= w_height
;
629 REGION_INIT(pScreen
, ®ion
, &box
, 1);
631 if (pMBBuffer
->number
== pMBBuffer
->pMBWindow
->displayedMultibuffer
)
632 pDrawable
= (DrawablePtr
) pWin
;
634 pDrawable
= pMBBuffer
->pDrawable
;
636 MultibufferPaintBackgroundRegion(pWin
, pDrawable
, ®ion
);
639 MultibufferExpose(pMBBuffer
, ®ion
);
641 REGION_UNINIT(pScreen
, ®ion
);
645 pixDeleteBufferDrawable(pDrawable
)
646 DrawablePtr pDrawable
;
648 (* pDrawable
->pScreen
->DestroyPixmap
)((PixmapPtr
) pDrawable
);