1 /************************************************************
3 Copyright (c) 1989 X Consortium
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
26 ********************************************************/
28 /* $XConsortium: mbufpx.c,v 1.5 94/04/17 20:32:54 dpw Exp $ */
29 /* $XFree86: xc/programs/Xserver/Xext/mbufpx.c,v 3.0 1994/05/08 05:17:32 dawes Exp $ */
37 #include "windowstr.h"
38 #include "scrnintstr.h"
39 #include "pixmapstr.h"
40 #include "extnsionst.h"
41 #include "dixstruct.h"
44 #include "regionstr.h"
51 #define _MULTIBUF_SERVER_ /* don't want Xlib structures */
52 #define _MULTIBUF_PIXMAP_
53 #include "multibufst.h"
56 static Bool NoopDDA_True() { return TRUE; }
58 static Bool pixPositionWindow();
59 static int pixCreateImageBuffers();
60 static void pixDisplayImageBuffers();
61 static void pixClearImageBufferArea();
62 static void pixDeleteBufferDrawable();
63 static void pixWrapScreenFuncs();
64 static void pixResetProc();
67 pixMultibufferInit(pScreen, pMBScreen)
69 mbufScreenPtr pMBScreen;
72 xMbufBufferInfo *pInfo;
75 mbufPixmapPrivPtr pMBPriv;
77 pMBScreen->CreateImageBuffers = pixCreateImageBuffers;
78 pMBScreen->DestroyImageBuffers = (void (*)())NoopDDA;
79 pMBScreen->DisplayImageBuffers = pixDisplayImageBuffers;
80 pMBScreen->ClearImageBufferArea = pixClearImageBufferArea;
81 pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
82 pMBScreen->ChangeBufferAttributes = NoopDDA_True;
83 pMBScreen->DeleteBufferDrawable = pixDeleteBufferDrawable;
84 pMBScreen->WrapScreenFuncs = pixWrapScreenFuncs;
85 pMBScreen->ResetProc = pixResetProc;
87 /* Support every depth and visual combination that the screen does */
90 for (i = 0; i < pScreen->numDepths; i++)
92 pDepth = &pScreen->allowedDepths[i];
93 nInfo += pDepth->numVids;
96 pInfo = (xMbufBufferInfo *) xalloc (nInfo * sizeof (xMbufBufferInfo));
101 for (i = 0; i < pScreen->numDepths; i++)
103 pDepth = &pScreen->allowedDepths[i];
104 for (j = 0; j < pDepth->numVids; j++)
106 pInfo[k].visualID = pDepth->vids[j];
107 pInfo[k].maxBuffers = 0;
108 pInfo[k].depth = pDepth->depth;
113 pMBScreen->nInfo = nInfo;
114 pMBScreen->pInfo = pInfo;
117 * Setup the devPrivate to mbufScreenRec
120 pMBPriv = (mbufPixmapPrivPtr) xalloc(sizeof(* pMBPriv));
126 pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
127 pMBPriv->PositionWindow = NULL;
128 pMBPriv->funcsWrapped = 0;
135 pixCreateImageBuffers (pWin, nbuf, ids, action, hint)
142 mbufWindowPtr pMBWindow;
143 mbufBufferPtr pMBBuffer;
145 int width, height, depth;
148 pMBWindow = MB_WINDOW_PRIV(pWin);
150 width = pWin->drawable.width;
151 height = pWin->drawable.height;
152 depth = pWin->drawable.depth;
153 pScreen = pWin->drawable.pScreen;
155 for (i = 0; i < nbuf; i++)
157 pMBBuffer = &pMBWindow->buffers[i];
158 pMBBuffer->pDrawable = (DrawablePtr)
159 (*pScreen->CreatePixmap) (pScreen, width, height, depth);
160 if (!pMBBuffer->pDrawable)
163 if (!AddResource (ids[i], MultibufferDrawableResType,
164 (pointer) pMBBuffer->pDrawable))
166 (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
169 pMBBuffer->pDrawable->id = ids[i];
172 * In the description of the CreateImageBuffers request:
173 * "If the window is mapped, or if these image buffers have
174 * backing store, their contents will be tiled with the window
175 * background, and zero or more expose events will be generated
176 * for each of these buffers."
179 (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
180 (pMBBuffer, 0,0, 0,0, TRUE);
187 * set up the gc to clear the pixmaps;
190 SetupBackgroundPainter (pWin, pGC)
195 int ts_x_origin, ts_y_origin;
201 * First take care of any ParentRelative stuff by altering the
202 * tile/stipple origin to match the coordinates of the upper-left
203 * corner of the first ancestor without a ParentRelative background.
204 * This coordinate is, of course, negative.
207 ts_x_origin = ts_y_origin = 0;
208 while (pWin->backgroundState == ParentRelative) {
209 ts_x_origin -= pWin->origin.x;
210 ts_y_origin -= pWin->origin.y;
213 backgroundState = pWin->backgroundState;
214 background = pWin->background;
216 switch (backgroundState)
218 case BackgroundPixel:
219 gcvalues[0] = (XID) background.pixel;
220 gcvalues[1] = FillSolid;
221 gcmask = GCForeground|GCFillStyle;
224 case BackgroundPixmap:
225 gcvalues[0] = FillTiled;
226 gcvalues[1] = (XID) background.pixmap;
227 gcvalues[2] = ts_x_origin;
228 gcvalues[3] = ts_y_origin;
229 gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin;
235 DoChangeGC(pGC, gcmask, gcvalues, TRUE);
240 MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects)
242 DrawablePtr pDrawable;
248 pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
249 if (SetupBackgroundPainter(pWin, pGC))
251 ValidateGC(pDrawable, pGC);
252 (*pGC->ops->PolyFillRect) (pDrawable, pGC, nrects, pRects);
258 MultibufferPaintBackgroundRegion(pWin, pDrawable, pRegion)
260 DrawablePtr pDrawable;
264 int nrects = REGION_NUM_RECTS(pRegion);
265 BoxPtr pbox = REGION_RECTS(pRegion);
267 pRects = (xRectangle *)ALLOCATE_LOCAL(nrects * sizeof(xRectangle));
271 for (i = 0; i < nrects; i++)
273 pRects[i].x = pbox->x1;
274 pRects[i].y = pbox->y1;
275 pRects[i].width = pbox->x2 - pbox->x1;
276 pRects[i].height = pbox->y2 - pbox->y1;
278 MultibufferPaintBackgroundRectangles(pWin, pDrawable, nrects, pRects);
279 DEALLOCATE_LOCAL(pRects);
284 pixDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
285 mbufBufferPtr *ppMBBuffer;
286 mbufWindowPtr *ppMBWindow;
290 PixmapPtr pPrevPixmap, pNewPixmap;
294 mbufBufferPtr pPrevMBBuffer;
298 UpdateCurrentTime ();
299 for (i = 0; i < nbuf; i++)
301 pWin = ppMBWindow[i]->pWindow;
303 /* Time to get a different scratch GC? */
306 || pGC->depth != pWin->drawable.depth
307 || pGC->pScreen != pWin->drawable.pScreen)
309 if (pGC) FreeScratchGC(pGC);
310 pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
312 pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
313 pPrevPixmap = (PixmapPtr) pPrevMBBuffer->pDrawable;
314 pNewPixmap = (PixmapPtr) ppMBBuffer[i]->pDrawable;
316 if (pPrevPixmap == pNewPixmap)
318 /* "If a specified buffer is already displayed, any delays and
319 * update action will still be performed for that buffer."
321 * We special-case this because applications do occasionally
322 * request a redundant DisplayImageBuffers, and we can save
323 * strokes by recognizing that the only update action that will
324 * change the buffer contents in this case is Background.
326 if (ppMBWindow[i]->updateAction == MultibufferUpdateActionBackground)
329 r.width = pWin->drawable.width;
330 r.height = pWin->drawable.height;
331 MultibufferPaintBackgroundRectangles(pWin, (DrawablePtr)pWin,
335 else /* different buffer is being displayed */
337 /* perform update action */
339 switch (ppMBWindow[i]->updateAction)
341 case MultibufferUpdateActionUndefined:
344 case MultibufferUpdateActionBackground:
347 r.width = pPrevPixmap->drawable.width;
348 r.height = pPrevPixmap->drawable.height;
349 MultibufferPaintBackgroundRectangles(pWin,
350 (DrawablePtr)pPrevPixmap,
354 case MultibufferUpdateActionUntouched:
356 /* copy the window to the pixmap that represents the
357 * currently displayed buffer
360 if (pPrevMBBuffer->eventMask & ExposureMask)
363 DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
365 ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
366 pExposed = (*pGC->ops->CopyArea)((DrawablePtr) pWin,
367 (DrawablePtr) pPrevPixmap,
370 pWin->drawable.width,
371 pWin->drawable.height,
374 /* if we couldn't copy the whole window to the buffer,
375 * send expose events (if any client wants them)
378 if (pPrevMBBuffer->eventMask & ExposureMask)
379 { /* some client wants expose events */
383 extern RegionPtr CreateUnclippedWinSize();
384 ScreenPtr pScreen = pWin->drawable.pScreen;
385 pWinSize = CreateUnclippedWinSize (pWin);
387 * pExposed is window-relative, but at this point
388 * pWinSize is screen-relative. Make pWinSize be
389 * window-relative so that region ops involving
390 * pExposed and pWinSize behave sensibly.
392 REGION_TRANSLATE(pScreen, pWinSize,
395 REGION_INTERSECT(pScreen, pExposed, pExposed, pWinSize);
396 REGION_DESTROY(pScreen, pWinSize);
397 MultibufferExpose (pPrevMBBuffer, pExposed);
398 REGION_DESTROY(pScreen, pExposed);
401 DoChangeGC (pGC, GCGraphicsExposures, &bool, FALSE);
402 } /* end some client wants expose events */
404 break; /* end case MultibufferUpdateActionUntouched */
406 case MultibufferUpdateActionCopied:
408 ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
409 (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap,
410 (DrawablePtr)pPrevPixmap, pGC,
411 0, 0, pWin->drawable.width,
412 pWin->drawable.height, 0, 0);
415 } /* end switch on update action */
417 /* display the new buffer */
419 ValidateGC ((DrawablePtr)pWin, pGC);
420 (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap, (DrawablePtr)pWin,
422 pWin->drawable.width, pWin->drawable.height,
426 ppMBWindow[i]->lastUpdate = currentTime;
429 if (pGC) FreeScratchGC (pGC);
434 * resize the buffers when the window is resized
438 pixPositionWindow (pWin, x, y)
443 mbufPixmapPrivPtr pMBPriv;
444 mbufWindowPtr pMBWindow;
445 mbufBufferPtr pMBBuffer;
449 int sourcex, sourcey;
453 int savewidth, saveheight;
455 RegionRec exposedRegion;
458 pScreen = pWin->drawable.pScreen;
459 pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
461 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
462 ret = (* pScreen->PositionWindow) (pWin, x, y);
463 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, PositionWindow);
465 if (!(pMBWindow = MB_WINDOW_PRIV(pWin)))
468 /* if new size is same as old, we're done */
470 if (pMBWindow->width == pWin->drawable.width &&
471 pMBWindow->height == pWin->drawable.height)
474 width = pWin->drawable.width;
475 height = pWin->drawable.height;
476 dx = pWin->drawable.x - pMBWindow->x;
477 dy = pWin->drawable.x - pMBWindow->y;
478 dw = width - pMBWindow->width;
479 dh = height - pMBWindow->height;
480 GravityTranslate (0, 0, -dx, -dy, dw, dh,
481 pWin->bitGravity, &destx, &desty);
483 /* if the window grew, remember to paint the window background,
484 * and maybe send expose events, for the new areas of the buffers
487 clear = pMBWindow->width < width || pMBWindow->height < height ||
488 pWin->bitGravity == ForgetGravity;
492 savewidth = pMBWindow->width;
493 saveheight = pMBWindow->height;
494 /* clip rectangle to source and destination */
501 if (destx + savewidth > width)
502 savewidth = width - destx;
509 if (desty + saveheight > height)
510 saveheight = height - desty;
512 pMBWindow->width = width;
513 pMBWindow->height = height;
514 pMBWindow->x = pWin->drawable.x;
515 pMBWindow->y = pWin->drawable.y;
524 REGION_INIT(pScreen, &exposedRegion, &box, 1);
525 if (pWin->bitGravity != ForgetGravity)
527 RegionRec preservedRegion;
530 box.x2 = destx + savewidth;
531 box.y2 = desty + saveheight;
532 REGION_INIT(pScreen, &preservedRegion, &box, 1);
533 REGION_SUBTRACT(pScreen, &exposedRegion, &exposedRegion, &preservedRegion);
534 REGION_UNINIT(pScreen, &preservedRegion);
537 } /* end if (clear) */
539 pGC = GetScratchGC (pWin->drawable.depth, pScreen);
541 /* create buffers with new window size */
543 for (i = 0; i < pMBWindow->numMultibuffer; i++)
545 pMBBuffer = &pMBWindow->buffers[i];
546 pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, pWin->drawable.depth);
549 (* MB_SCREEN_PRIV(pScreen)->DestroyImageBuffers)(pWin);
554 MultibufferPaintBackgroundRegion(pWin, (DrawablePtr)pPixmap, &exposedRegion);
555 MultibufferExpose(pMBBuffer, &exposedRegion);
557 if (pWin->bitGravity != ForgetGravity)
559 ValidateGC ((DrawablePtr)pPixmap, pGC);
560 (*pGC->ops->CopyArea) (pMBBuffer->pDrawable, (DrawablePtr)pPixmap,
562 sourcex, sourcey, savewidth, saveheight,
565 pPixmap->drawable.id = pMBBuffer->pDrawable->id;
566 (*pScreen->DestroyPixmap) ((PixmapPtr) pMBBuffer->pDrawable);
567 pMBBuffer->pDrawable = (DrawablePtr) pPixmap;
568 if (i != pMBWindow->displayedMultibuffer)
570 ChangeResourceValue (pPixmap->drawable.id,
571 MultibufferDrawableResType,
577 REGION_UNINIT(pScreen, &exposedRegion);
582 pixWrapScreenFuncs(pScreen)
585 mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
586 WRAP_SCREEN_FUNC(pScreen, pMBPriv, PositionWindow, pixPositionWindow);
590 pixResetProc(pScreen)
593 mbufScreenPtr pMBScreen = MB_SCREEN_PRIV(pScreen);
594 mbufPixmapPrivPtr pMBPriv = MB_SCREEN_PRIV_PIXMAP(pScreen);
596 xfree(pMBScreen->pInfo);
601 pixClearImageBufferArea(pMBBuffer, x,y, width,height, exposures)
602 mbufBufferPtr pMBBuffer;
604 unsigned short width, height;
611 int w_width, w_height;
612 DrawablePtr pDrawable;
614 pWin = pMBBuffer->pMBWindow->pWindow;
615 pScreen = pWin->drawable.pScreen;
617 w_width = pWin->drawable.width;
618 w_height = pWin->drawable.height;
622 box.x2 = width ? (box.x1 + width) : w_width;
623 box.y2 = height ? (box.y1 + height) : w_height;
625 if (box.x1 < 0) box.x1 = 0;
626 if (box.y1 < 0) box.y1 = 0;
627 if (box.x2 > w_width) box.x2 = w_width;
628 if (box.y2 > w_height) box.y2 = w_height;
630 REGION_INIT(pScreen, ®ion, &box, 1);
632 if (pMBBuffer->number == pMBBuffer->pMBWindow->displayedMultibuffer)
633 pDrawable = (DrawablePtr) pWin;
635 pDrawable = pMBBuffer->pDrawable;
637 MultibufferPaintBackgroundRegion(pWin, pDrawable, ®ion);
640 MultibufferExpose(pMBBuffer, ®ion);
642 REGION_UNINIT(pScreen, ®ion);
646 pixDeleteBufferDrawable(pDrawable)
647 DrawablePtr pDrawable;
649 (* pDrawable->pScreen->DestroyPixmap)((PixmapPtr) pDrawable);