First import
[xorg_rtime.git] / xorg-server-1.4 / Xext / mbufbf.c
blob04fc487d80da85feddae56cff507dab2e171651e
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
9 documentation.
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.
28 #define NEED_REPLIES
29 #define NEED_EVENTS
30 #ifdef HAVE_DIX_CONFIG_H
31 #include <dix-config.h>
32 #endif
34 #include <stdio.h>
35 #include <X11/X.h>
36 #include <X11/Xproto.h>
37 #include "misc.h"
38 #include "os.h"
39 #include "windowstr.h"
40 #include "scrnintstr.h"
41 #include "pixmapstr.h"
42 #include "extnsionst.h"
43 #include "dixstruct.h"
44 #include "resource.h"
45 #include "opaque.h"
46 #include "regionstr.h"
47 #include "gcstruct.h"
48 #include "inputstr.h"
49 #include "validate.h"
50 #include <sys/time.h>
52 #define _MULTIBUF_SERVER_ /* don't want Xlib structures */
53 #define _MULTIBUF_BUFFER_
54 #include <X11/extensions/multibufst.h>
56 /*
57 Support for doublebuffer hardare
59 This code is designed to support doublebuffer hardware where the
60 displayed buffer is selected on a per-pixel basis by an additional bit
61 plane, called the select plane. It could probably be easily modified
62 to work with systems that use window-id planes.
64 This is done by creating a new drawable type, DRAWABLE_BUFFER. The
65 type has the same exact layout as a window drawable. Your code should
66 treat a DRAWABLE_BUFFER the same as it would tread a DRAWABLE_WINDOW
67 when handling the gc drawing functions. In addition, PaintWindowBackground,
68 CopyWindow, and all of the gc drawing functions to be able to draw into both
69 framebuffers. Which framebuffer to draw into is selected by the contents of
70 pWin->devPrivates[frameWindowPrivateIndex].
71 The content of the devPrivate is either from frameBuffer[0] or
72 frameBuffer[1], depending on which buffer is being drawn into. When
73 pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[0],
74 the functions should draw into the front framebuffer. When
75 pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[1],
76 the functions should draw into the back framebuffer.
78 In addition, you need to provide a function that allows you to copy
79 bits between the buffers (optional since CopyArea can be used) and a
80 function that draws into the select plane. Then, you need to register
81 your functions and other information, by calling:
83 void
84 RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
85 CopyBufferBitsFunc, DrawSelectPlaneFunc)
86 int nInfo;
87 xMbufBufferInfo *pInfo;
88 DevUnion *frameBuffer;
89 DevUnion selectPlane;
91 "pInfo" is an array indicating which visuals and depths that double
92 buffering is supported on. "nInfo" is the length of the array.
94 "frameBuffer" is array of length 2. The contents of the array element
95 is ddx-specific. The content of frameBuffer[0] should, when placed in
96 the window private, indicate that framebuffer 0 should be drawn into.
97 The contents of frameBuffer[1], when placed into the window private,
98 should indicate that framebuffer 1 should be drawn into.
100 "selectPlane" is ddx-specific. It should contain information
101 neccessary for your displayProc to access the select plane.
102 It is passed to DrawSelectPlaneFunc.
104 "CopyBufferBitsFunc" is a ddx-specific function that copies from one
105 buffer of a multibuffered window to another buffer. If the CopyBufferBitsFunc
106 is NULL, a default function will be used that calls pScreen->CopyArea.
108 void CopyBufferBitsFunc(pMBWindow, srcBufferNum, dstBufferNum)
109 mbufWindowPtr pMBWindow;
110 int srcBufferNum, dstBufferNum;
112 "DrawSelectPlaneFunc" is a ddx-specific function that fills the
113 regions "prgn" of select plane with the value "bufferNum". If
114 selectPlane is a DrawablePtr (such as a PixmapPtr), you can pass
115 NULL for DrawSelectPlaneFunc, a default function will be used that
116 calls FillRectangle on the selectPlane.
118 void DrawSelectPlaneFunc(pScreen, selectPlane, prgn, bufferNum)
119 ScreenPtr pScreen;
120 DevUnion selectPlane;
121 RegionPtr prgn;
122 long bufferNum;
130 #define MAX_BUFFERS 2 /* Only supports 2 buffers */
131 #define FRONT_BUFFER 0
132 #define BACK_BUFFER 1
135 /* Buffer drawables have the same structure as window drawables */
136 typedef WindowRec BufferRec;
137 typedef WindowPtr BufferPtr;
141 * Call RegisterHdwrBuffer for every screen that has doublebuffer hardware.
144 static int bufNumInfo[MAXSCREENS];
145 static xMbufBufferInfo *bufInfo[MAXSCREENS];
146 static DevUnion *bufFrameBuffer[MAXSCREENS];
147 static DevUnion bufselectPlane[MAXSCREENS];
148 static void (* bufCopyBufferBitsFunc[MAXSCREENS])();
149 static void (* bufDrawSelectPlaneFunc[MAXSCREENS])();
151 static Bool bufMultibufferInit();
154 void
155 RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
156 CopyBufferBitsFunc, DrawSelectPlaneFunc)
157 ScreenPtr pScreen;
158 int nInfo;
159 xMbufBufferInfo *pInfo;
160 DevUnion *frameBuffer;
161 DevUnion selectPlane;
162 void (* CopyBufferBitsFunc)();
163 void (* DrawSelectPlaneFunc)();
165 bufNumInfo[pScreen->myNum] = nInfo;
166 bufInfo[pScreen->myNum] = pInfo;
167 bufFrameBuffer[pScreen->myNum] = frameBuffer;
168 bufselectPlane[pScreen->myNum] = selectPlane;
170 bufCopyBufferBitsFunc[pScreen->myNum] = CopyBufferBitsFunc;
171 bufDrawSelectPlaneFunc[pScreen->myNum] = DrawSelectPlaneFunc;
173 /* Register ourselves with device-independent multibuffers code */
174 RegisterMultibufferInit(pScreen, bufMultibufferInit);
179 * Called by Multibuffer extension initialization.
180 * Initializes mbufScreenRec and its devPrivate.
183 static Bool NoopDDA_True() { return TRUE; }
184 static Bool bufPositionWindow();
185 static int bufCreateImageBuffers();
186 static void bufDestroyImageBuffers();
187 static void bufDisplayImageBuffers();
188 static void bufClearImageBufferArea();
189 static void bufDestroyBuffer();
190 static void bufCopyBufferBits();
191 static void bufDrawSelectPlane();
192 static void bufWrapScreenFuncs();
193 static void bufResetProc();
195 static void bufPostValidateTree();
196 static void bufClipNotify();
197 static void bufWindowExposures();
198 static Bool bufChangeWindowAttributes();
199 static void bufClearToBackground();
200 static void bufCopyWindow();
202 extern WindowPtr *WindowTable;
204 static Bool
205 bufMultibufferInit(pScreen, pMBScreen)
206 ScreenPtr pScreen;
207 mbufScreenPtr pMBScreen;
209 mbufBufferPrivPtr pMBPriv;
210 BoxRec box;
212 /* Multibuffer info */
213 pMBScreen->nInfo = bufNumInfo[pScreen->myNum];
214 pMBScreen->pInfo = bufInfo[pScreen->myNum];
216 /* Hooks */
217 pMBScreen->CreateImageBuffers = bufCreateImageBuffers;
218 pMBScreen->DestroyImageBuffers = bufDestroyImageBuffers;
219 pMBScreen->DisplayImageBuffers = bufDisplayImageBuffers;
220 pMBScreen->ClearImageBufferArea = bufClearImageBufferArea;
221 pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
222 pMBScreen->ChangeBufferAttributes = NoopDDA_True;
223 pMBScreen->DeleteBufferDrawable = bufDestroyBuffer;
224 pMBScreen->WrapScreenFuncs = bufWrapScreenFuncs;
225 pMBScreen->ResetProc = bufResetProc;
226 /* Create devPrivate part */
227 pMBPriv = (mbufBufferPrivPtr) xalloc(sizeof *pMBPriv);
228 if (!pMBPriv)
229 return (FALSE);
231 pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
232 pMBPriv->frameBuffer = bufFrameBuffer[pScreen->myNum];
233 pMBPriv->selectPlane = bufselectPlane[pScreen->myNum];
236 * Initializing the subtractRgn to the screen area will ensure that
237 * the selectPlane will get cleared on the first PostValidateTree.
240 box.x1 = 0;
241 box.y1 = 0;
242 box.x2 = pScreen->width;
243 box.y2 = pScreen->height;
245 pMBPriv->rgnChanged = TRUE;
246 REGION_INIT(pScreen, &pMBPriv->backBuffer, &box, 1);
247 REGION_INIT(pScreen, &pMBPriv->subtractRgn, &box, 1);
248 REGION_NULL(pScreen, &pMBPriv->unionRgn);
250 /* Misc functions */
251 pMBPriv->CopyBufferBits = bufCopyBufferBitsFunc[pScreen->myNum];
252 pMBPriv->DrawSelectPlane = bufDrawSelectPlaneFunc[pScreen->myNum];
254 if (!pMBPriv->CopyBufferBits)
255 pMBPriv->CopyBufferBits = bufCopyBufferBits;
257 if (!pMBPriv->DrawSelectPlane)
258 pMBPriv->DrawSelectPlane = bufDrawSelectPlane;
260 /* screen functions */
261 pMBPriv->funcsWrapped = 0;
262 pMBPriv->inClearToBackground = FALSE;
263 pMBPriv->WindowExposures = NULL;
264 pMBPriv->CopyWindow = NULL;
265 pMBPriv->ClearToBackground = NULL;
266 pMBPriv->ClipNotify = NULL;
267 pMBPriv->ChangeWindowAttributes = NULL;
269 /* Start out wrapped to clear select plane */
270 WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
271 return TRUE;
274 static void
275 UpdateBufferFromWindow(pBuffer, pWin)
276 BufferPtr pBuffer;
277 WindowPtr pWin;
279 pBuffer->drawable.x = pWin->drawable.x;
280 pBuffer->drawable.y = pWin->drawable.y;
281 pBuffer->drawable.width = pWin->drawable.width;
282 pBuffer->drawable.height = pWin->drawable.height;
284 pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
286 /* Update for PaintWindowBackground */
287 pBuffer->parent = pWin->parent;
290 * Make the borderClip the same as the clipList so
291 * NotClippedByChildren comes out with just clipList.
294 pBuffer->clipList = pWin->clipList;
295 pBuffer->borderClip = pWin->clipList;
296 pBuffer->winSize = pWin->winSize;
297 pBuffer->borderSize = pWin->borderSize;
299 pBuffer->origin = pWin->origin;
302 static BufferPtr
303 bufCreateBuffer(pScreen, pWin, bufferNum)
304 ScreenPtr pScreen;
305 WindowPtr pWin;
306 int bufferNum;
308 mbufBufferPrivPtr pMBPriv;
309 DevUnion *devPrivates;
310 BufferPtr pBuffer;
311 int i;
313 pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
315 pBuffer = AllocateWindow(pWin->drawable.pScreen);
316 if (!pBuffer)
317 return (NULL);
319 /* XXX- Until we know what is needed, copy everything. */
320 devPrivates = pBuffer->devPrivates;
321 *pBuffer = *pWin;
322 pBuffer->devPrivates = devPrivates;
324 pBuffer->drawable.type = DRAWABLE_BUFFER;
325 pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
327 pBuffer->nextSib = NULL;
328 pBuffer->prevSib = NULL;
329 pBuffer->firstChild = NULL;
330 pBuffer->lastChild = NULL;
332 /* XXX - Worry about backingstore later */
333 pBuffer->backStorage = NULL;
334 pBuffer->backingStore = NotUseful;
336 /* XXX - Need to call pScreen->CreateWindow for tile/stipples
337 * or should I just copy the devPrivates?
340 for (i=0; i < pScreen->WindowPrivateLen; i++)
341 pBuffer->devPrivates[i] = pWin->devPrivates[i];
343 pBuffer->devPrivates[frameWindowPrivateIndex] =
344 pMBPriv->frameBuffer[bufferNum];
346 return pBuffer;
349 static void
350 bufDestroyBuffer(pDrawable)
351 DrawablePtr pDrawable;
353 xfree(pDrawable);
356 /*ARGSUSED*/
357 static int
358 bufCreateImageBuffers (pWin, nbuf, ids, action, hint)
359 WindowPtr pWin;
360 int nbuf;
361 XID *ids;
362 int action;
363 int hint;
365 ScreenPtr pScreen;
366 mbufScreenPtr pMBScreen;
367 mbufWindowPtr pMBWindow;
368 mbufBufferPtr pMBBuffer;
369 int i;
371 pScreen = pWin->drawable.pScreen;
372 pMBScreen = MB_SCREEN_PRIV(pScreen);
373 pMBWindow = MB_WINDOW_PRIV(pWin);
375 pMBWindow->devPrivate.ptr = (pointer) REGION_CREATE(pScreen, 0,0);
376 if (!pMBWindow->devPrivate.ptr)
377 return(0);
378 REGION_COPY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr,
379 &pWin->clipList);
381 for (i = 0; i < nbuf; i++)
383 pMBBuffer = pMBWindow->buffers + i;
384 pMBBuffer->pDrawable = (DrawablePtr) bufCreateBuffer(pScreen,pWin,i);
386 if (!pMBBuffer->pDrawable)
387 break;
389 if (!AddResource (ids[i], MultibufferDrawableResType,
390 (pointer) pMBBuffer->pDrawable))
392 bufDestroyBuffer((BufferPtr) pMBBuffer->pDrawable);
393 break;
395 pMBBuffer->pDrawable->id = ids[i];
398 * If window is already mapped, generate exposures and
399 * clear the area of the newly buffers.
402 if ((pWin->realized) && (i != pMBWindow->displayedMultibuffer))
403 (* pMBScreen->ClearImageBufferArea)(pMBBuffer, 0,0, 0,0, TRUE);
406 return i;
409 static void
410 bufDestroyImageBuffers(pWin)
411 WindowPtr pWin;
413 ScreenPtr pScreen;
414 mbufWindowPtr pMBWindow;
416 pScreen = pWin->drawable.pScreen;
418 if (pMBWindow = MB_WINDOW_PRIV(pWin))
420 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
423 * if the backbuffer is currently being displayed, move the bits
424 * to the frontbuffer and display it instead.
427 if (pWin->realized && (pMBWindow->displayedMultibuffer == BACK_BUFFER))
429 (* pMBPriv->CopyBufferBits)(pMBWindow, BACK_BUFFER, FRONT_BUFFER);
430 REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer,
431 &pMBPriv->backBuffer, &pWin->clipList);
432 (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
433 &pWin->clipList, FRONT_BUFFER);
436 /* Switch window rendering to front buffer */
437 pWin->devPrivates[frameWindowPrivateIndex] =
438 pMBPriv->frameBuffer[FRONT_BUFFER];
440 REGION_DESTROY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr);
441 pMBWindow->devPrivate.ptr = NULL;
446 * Can be replaced by pScreen->ClearToBackground if pBuffer->eventMask
447 * and wOtherEventsMasks(pBuffer) were setup.
450 static void
451 bufClearImageBufferArea(pMBBuffer, x,y, w,h, generateExposures)
452 mbufBufferPtr pMBBuffer;
453 short x,y;
454 unsigned short w,h;
455 Bool generateExposures;
457 BoxRec box;
458 RegionRec reg;
459 RegionPtr pBSReg = NullRegion;
460 ScreenPtr pScreen;
461 BoxPtr extents;
462 int x1, y1, x2, y2;
463 BufferPtr pBuffer;
465 pBuffer = (BufferPtr) pMBBuffer->pDrawable;
466 /* compute everything using ints to avoid overflow */
468 x1 = pBuffer->drawable.x + x;
469 y1 = pBuffer->drawable.y + y;
470 if (w)
471 x2 = x1 + (int) w;
472 else
473 x2 = x1 + (int) pBuffer->drawable.width - (int) x;
474 if (h)
475 y2 = y1 + h;
476 else
477 y2 = y1 + (int) pBuffer->drawable.height - (int) y;
479 extents = &pBuffer->clipList.extents;
481 /* clip the resulting rectangle to the window clipList extents. This
482 * makes sure that the result will fit in a box, given that the
483 * screen is < 32768 on a side.
486 if (x1 < extents->x1)
487 x1 = extents->x1;
488 if (x2 > extents->x2)
489 x2 = extents->x2;
490 if (y1 < extents->y1)
491 y1 = extents->y1;
492 if (y2 > extents->y2)
493 y2 = extents->y2;
495 if (x2 <= x1 || y2 <= y1)
497 x2 = x1 = 0;
498 y2 = y1 = 0;
501 box.x1 = x1;
502 box.x2 = x2;
503 box.y1 = y1;
504 box.y2 = y2;
506 pScreen = pBuffer->drawable.pScreen;
507 REGION_INIT(pScreen, &reg, &box, 1);
508 if (pBuffer->backStorage)
511 * If the window has backing-store on, call through the
512 * ClearToBackground vector to handle the special semantics
513 * (i.e. things backing store is to be cleared out and
514 * an Expose event is to be generated for those areas in backing
515 * store if generateExposures is TRUE).
517 pBSReg = (* pScreen->ClearBackingStore)(pBuffer, x, y, w, h,
518 generateExposures);
521 REGION_INTERSECT(pScreen, &reg, &reg, &pBuffer->clipList);
522 if (pBuffer->backgroundState != None)
523 (*pScreen->PaintWindowBackground)(pBuffer, &reg, PW_BACKGROUND);
524 if (generateExposures)
525 MultibufferExpose(pMBBuffer, &reg);
526 #ifdef _notdef
527 /* XXBS - This is the original miClearToBackground code.
528 * WindowExposures needs to be called (or the functionality emulated)
529 * in order for backingStore to work, but first, pBuffer->eventMask
530 * and wOtherEventsMasks(pBuffer) need to be setup correctly.
533 if (generateExposures)
534 (*pScreen->WindowExposures)(pBuffer, &reg, pBSReg);
535 else if (pBuffer->backgroundState != None)
536 (*pScreen->PaintWindowBackground)(pBuffer, &reg, PW_BACKGROUND);
537 #endif
538 REGION_UNINIT(pScreen, &reg);
539 if (pBSReg)
540 REGION_DESTROY(pScreen, pBSReg);
543 static void
544 bufWrapScreenFuncs(pScreen)
545 ScreenPtr pScreen;
547 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
549 WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
550 WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClipNotify, bufClipNotify);
551 WRAP_SCREEN_FUNC(pScreen,pMBPriv,WindowExposures,bufWindowExposures);
552 WRAP_SCREEN_FUNC(pScreen,pMBPriv,ChangeWindowAttributes, bufChangeWindowAttributes);
553 WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClearToBackground,bufClearToBackground);
554 WRAP_SCREEN_FUNC(pScreen,pMBPriv,CopyWindow,bufCopyWindow);
557 static void
558 bufResetProc(pScreen)
559 ScreenPtr pScreen;
561 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
564 * frameBuffer, selectPlane, and pInfo should be freed by
565 * whoever called RegisterDoubleBufferHardware
568 REGION_UNINIT(pScreen, &pMBPriv->backBuffer);
569 REGION_UNINIT(pScreen, &pMBPriv->subtractRgn);
570 REGION_UNINIT(pScreen, &pMBPriv->unionRgn);
571 xfree(pMBPriv);
574 /*---------------------------------------------------------------------------*/
577 * Used if CopyBufferBitsFunc is not provided when registering.
578 * This should work for everybody since CopyArea needs to support
579 * copying between buffers anyway.
582 static void
583 bufCopyBufferBits(pMBWindow, srcBufferNum, dstBufferNum)
584 mbufWindowPtr pMBWindow;
585 int srcBufferNum, dstBufferNum;
587 DrawablePtr pSrcBuffer, pDstBuffer;
588 GCPtr pGC;
590 pSrcBuffer = pMBWindow->buffers[srcBufferNum].pDrawable;
591 pDstBuffer = pMBWindow->buffers[dstBufferNum].pDrawable;
593 pGC = GetScratchGC (pDstBuffer->depth, pDstBuffer->pScreen);
594 if (!pGC)
595 return;
597 ValidateGC (pDstBuffer, pGC);
598 (* pGC->ops->CopyArea) (pSrcBuffer, pDstBuffer, pGC,
599 0,0, pDstBuffer->width, pDstBuffer->height, 0,0);
600 FreeScratchGC (pGC);
604 * Used if DrawSelectPlanFunc is not provided for when registering.
605 * However, it only works if selectPlane.ptr is a drawable. Also
606 * assumes that painting with color 0 selects the front buffer,
607 * while color 1 selects the back buffer.
610 static void
611 bufDrawSelectPlane(pScreen, selectPlane, prgn, bufferNum)
612 ScreenPtr pScreen;
613 DevUnion selectPlane;
614 RegionPtr prgn;
615 long bufferNum;
617 DrawablePtr pDrawable;
618 GCPtr pGC;
619 register int i;
620 register BoxPtr pbox;
621 register xRectangle *prect;
622 int numRects;
623 XID value;
625 if (REGION_NUM_RECTS(prgn) == 0)
626 return;
628 pDrawable = (DrawablePtr) selectPlane.ptr;
629 pGC = GetScratchGC (pDrawable->depth, pScreen);
630 if (!pGC)
631 return;
633 prect = (xRectangle *)ALLOCATE_LOCAL(REGION_NUM_RECTS(prgn) *
634 sizeof(xRectangle));
635 if (!prect)
637 FreeScratchGC(pGC);
638 return;
641 value = (XID) bufferNum;
642 DoChangeGC(pGC, GCForeground, &value, 0);
643 ValidateGC(pDrawable, pGC);
645 numRects = REGION_NUM_RECTS(prgn);
646 pbox = REGION_RECTS(prgn);
647 for (i= numRects; --i >= 0; pbox++, prect++)
649 prect->x = pbox->x1;
650 prect->y = pbox->y1;
651 prect->width = pbox->x2 - pbox->x1;
652 prect->height = pbox->y2 - pbox->y1;
654 prect -= numRects;
655 (* pGC->ops->PolyFillRect)(pDrawable, pGC, numRects, prect);
657 DEALLOCATE_LOCAL(prect);
658 FreeScratchGC (pGC);
662 static void
663 bufDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
664 ScreenPtr pScreen;
665 mbufBufferPtr *ppMBBuffer;
666 mbufWindowPtr *ppMBWindow;
667 int nbuf;
669 WindowPtr pWin;
670 BufferPtr pPrevBuffer, pNewBuffer;
671 int i, number;
672 mbufBufferPrivPtr pMBPriv;
673 mbufBufferPtr pPrevMBBuffer;
675 pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
677 for (i = 0; i < nbuf; i++)
679 number = ppMBBuffer[i]->number; /* 0=frontbuffer, 1=backbuffer */
680 pWin = ppMBWindow[i]->pWindow;
681 pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
683 pPrevBuffer = (BufferPtr) pPrevMBBuffer->pDrawable;
684 pNewBuffer = (BufferPtr) ppMBBuffer[i]->pDrawable;
686 if (pPrevBuffer != pNewBuffer)
688 RegionPtr backBuffer = &pMBPriv->backBuffer;
691 * Update the select plane and the backBuffer region.
694 (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
695 &pWin->clipList, number);
697 if (number == BACK_BUFFER)
698 REGION_UNION(pScreen, backBuffer, backBuffer,
699 &pWin->clipList);
700 else
701 REGION_SUBTRACT(pScreen, backBuffer, backBuffer,
702 &pWin->clipList);
704 /* Switch which framebuffer the window draws into */
705 pWin->devPrivates[frameWindowPrivateIndex] =
706 pMBPriv->frameBuffer[number];
709 switch (ppMBWindow[i]->updateAction)
711 case MultibufferUpdateActionUndefined:
712 break;
713 case MultibufferUpdateActionBackground:
714 (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
715 (pPrevMBBuffer, 0,0, 0,0, FALSE);
716 break;
717 case MultibufferUpdateActionUntouched:
718 break;
719 case MultibufferUpdateActionCopied:
720 if (pPrevBuffer != pNewBuffer)
722 (* pMBPriv->CopyBufferBits) (ppMBWindow[i],
723 ppMBBuffer[i]->number, pPrevMBBuffer->number);
725 break;
730 /* Updates the backBuffer region and paints the selectPlane. */
732 static void
733 bufPostValidateTree(pParent, pChild, kind)
734 WindowPtr pParent, pChild;
735 VTKind kind;
737 ScreenPtr pScreen;
738 mbufBufferPrivPtr pMBPriv;
740 if (pParent)
741 pScreen = pParent->drawable.pScreen;
742 else if (pChild)
743 pScreen = pChild->drawable.pScreen;
744 else
745 return; /* Hopeless */
747 pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
749 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
750 if (pScreen->PostValidateTree)
751 (* pScreen->PostValidateTree)(pParent, pChild, kind);
752 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
754 /* Does backBuffer need to change? */
755 if (pMBPriv->rgnChanged)
757 RegionRec exposed;
758 RegionPtr pSubtractRgn, pUnionRgn;
759 Bool overlap;
761 pMBPriv->rgnChanged = FALSE;
763 pSubtractRgn = &pMBPriv->subtractRgn;
764 pUnionRgn = &pMBPriv->unionRgn;
765 REGION_VALIDATE(pScreen, pSubtractRgn, &overlap);
766 #ifdef DEBUG
767 if (overlap)
768 FatalError("bufPostValidateTree: subtractRgn overlaps");
769 #endif
770 REGION_VALIDATE(pScreen, pUnionRgn, &overlap);
771 #ifdef DEBUG
772 if (overlap)
773 FatalError("bufPostValidateTree: unionRgn overlaps");
774 #endif
776 /* Update backBuffer: subtract must come before union */
777 REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
778 pSubtractRgn);
779 REGION_UNION(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
780 pUnionRgn);
782 /* Paint gained and lost backbuffer areas in select plane */
783 REGION_NULL(pScreen, &exposed);
784 REGION_SUBTRACT(pScreen, &exposed, pSubtractRgn, pUnionRgn);
785 (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
786 &exposed, FRONT_BUFFER);
788 REGION_SUBTRACT(pScreen, &exposed, pUnionRgn, pSubtractRgn);
789 (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
790 &exposed, BACK_BUFFER);
792 REGION_UNINIT(pScreen, &exposed);
793 REGION_EMPTY(pScreen, pSubtractRgn);
794 REGION_EMPTY(pScreen, pUnionRgn);
799 * If the window is multibuffered and displaying the backbuffer,
800 * add the old clipList to the subtractRgn and add the new clipList
801 * to the unionRgn. PostValidateTree will use subtractRgn and unionRgn
802 * to update the backBuffer region and the selectPlane.
804 * Copy changes to the window structure into the buffers.
805 * Send ClobberNotify events.
808 static void
809 bufClipNotify(pWin, dx,dy)
810 WindowPtr pWin;
811 int dx,dy;
813 ScreenPtr pScreen = pWin->drawable.pScreen;
814 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
815 mbufWindowPtr pMBWindow;
816 int i;
818 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
819 if (pScreen->ClipNotify)
820 (* pScreen->ClipNotify)(pWin, dx,dy);
821 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
823 if (pMBWindow = MB_WINDOW_PRIV(pWin))
825 RegionPtr pOldClipList = (RegionPtr) pMBWindow->devPrivate.ptr;
827 if (! REGION_EQUAL(pScreen, pOldClipList, &pWin->clipList))
829 if (pMBWindow->displayedMultibuffer == BACK_BUFFER)
831 pMBPriv->rgnChanged = TRUE;
832 REGION_APPEND(pScreen, &pMBPriv->subtractRgn, pOldClipList);
833 REGION_APPEND(pScreen, &pMBPriv->unionRgn, &pWin->clipList);
836 REGION_COPY(pScreen, pOldClipList,&pWin->clipList);
839 /* Update buffer x,y,w,h, and clipList */
840 for (i=0; i<pMBWindow->numMultibuffer; i++)
842 mbufBufferPtr pMBBuffer = pMBWindow->buffers + i;
843 if (pMBBuffer->clobber != pWin->visibility)
845 pMBBuffer->clobber = pWin->visibility;
846 MultibufferClobber(pMBBuffer);
848 UpdateBufferFromWindow(pMBBuffer->pDrawable, pWin);
854 * Updates buffer's background fields when the window's changes.
855 * This is necessary because pScreen->PaintWindowBackground
856 * is used to paint the buffer.
858 * XXBS - Backingstore state will have be tracked too if it is supported.
861 static Bool
862 bufChangeWindowAttributes(pWin, mask)
863 WindowPtr pWin;
864 unsigned long mask;
866 ScreenPtr pScreen = pWin->drawable.pScreen;
867 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
868 mbufWindowPtr pMBWindow;
869 Bool ret;
871 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
872 ret = (* pScreen->ChangeWindowAttributes)(pWin, mask);
873 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
875 if (pMBWindow = MB_WINDOW_PRIV(pWin))
877 if (mask & (CWBackPixmap | CWBackPixel))
879 BufferPtr pBuffer;
880 int i;
882 for (i=0; i<pMBWindow->displayedMultibuffer; i++)
884 pBuffer = (BufferPtr) pMBWindow->buffers[i].pDrawable;
885 pBuffer->backgroundState = pWin->backgroundState;
886 pBuffer->background = pWin->background;
890 return ret;
894 * Send exposures and clear the background for a buffer whenever
895 * its corresponding window is exposed, except when called by
896 * ClearToBackground.
899 static void
900 bufWindowExposures(pWin, prgn, other_exposed)
901 WindowPtr pWin;
902 register RegionPtr prgn, other_exposed;
904 ScreenPtr pScreen = pWin->drawable.pScreen;
905 mbufWindowPtr pMBWindow = MB_WINDOW_PRIV(pWin);
906 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
907 RegionRec tmp_rgn;
908 int i;
909 Bool handleBuffers;
911 handleBuffers = (!pMBPriv->inClearToBackground) &&
912 (pWin->drawable.type == DRAWABLE_WINDOW) &&
913 pMBWindow && (prgn && !REGION_NIL(prgn));
915 /* miWindowExposures munges prgn and other_exposed. */
916 if (handleBuffers)
918 REGION_NULL(pScreen, &tmp_rgn);
919 REGION_COPY(pScreen, &tmp_rgn, prgn);
922 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
923 (* pScreen->WindowExposures) (pWin, prgn, other_exposed);
924 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
926 if (!handleBuffers)
927 return;
930 * Send expose events to all clients. Paint the exposed region for all
931 * buffers except the displayed buffer since it is handled when the
932 * window is painted.
934 * XXBS - Will have to be re-written to handle BackingStore on buffers.
937 for (i=0; i<pMBWindow->numMultibuffer; i++)
939 mbufBufferPtr pMBBuffer;
940 BufferPtr pBuffer;
942 pMBBuffer = pMBWindow->buffers + i;
943 pBuffer = (BufferPtr) pMBBuffer->pDrawable;
945 if (i != pMBWindow->displayedMultibuffer)
946 (* pScreen->PaintWindowBackground)(pBuffer,&tmp_rgn,PW_BACKGROUND);
947 if ((pMBBuffer->otherEventMask | pMBBuffer->eventMask) & ExposureMask)
948 MultibufferExpose(pMBBuffer, &tmp_rgn);
951 REGION_UNINIT(pScreen, &tmp_rgn);
955 * Set ``inClearToBackground'' so that WindowExposures does not attempt
956 * to send expose events or clear the background on the buffers.
959 static void
960 bufClearToBackground(pWin, x,y,w,h, sendExpose)
961 WindowPtr pWin;
962 int x,y, w,h;
963 Bool sendExpose;
965 ScreenPtr pScreen = pWin->drawable.pScreen;
966 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
968 pMBPriv->inClearToBackground = TRUE;
970 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
971 (* pScreen->ClearToBackground)(pWin, x,y,w,h, sendExpose);
972 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
974 pMBPriv->inClearToBackground = FALSE;
978 * Move bits in both buffers. It does this by calling pScreen->CopyWindow
979 * twice, once with the root window's devPrivate[frameWindowPrivateIndex]
980 * pointing to the frontbuffer pixmap and once with it pointed to the
981 * backbuffer pixmap. It does this if there are *any* existing multibuffered
982 * window... a possible optimization is to copy the backbuffer only if this
983 * window or its inferiors are multibuffered. May be faster, maybe not.
985 * XXX - Only works if your CopyWindow checks the root window's devPrivate
986 * to see which buffer to draw into. Works for cfbPaintWindow.
989 /*ARGSUSED*/
990 static void
991 bufCopyWindow(pWin, ptOldOrg, prgnSrc)
992 WindowPtr pWin;
993 DDXPointRec ptOldOrg;
994 RegionPtr prgnSrc;
996 ScreenPtr pScreen = pWin->drawable.pScreen;
997 mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
998 WindowPtr pwinroot;
999 DevUnion save;
1001 UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
1003 pwinroot = WindowTable[pScreen->myNum];
1004 save = pwinroot->devPrivates[frameWindowPrivateIndex];
1007 * Copy front buffer
1010 pwinroot->devPrivates[frameWindowPrivateIndex] =
1011 pMBPriv->frameBuffer[FRONT_BUFFER];
1012 (* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
1015 * Copy back buffer
1018 /* CopyWindow translates prgnSrc... translate it back for 2nd call. */
1019 REGION_TRANSLATE(pScreen, prgnSrc,
1020 ptOldOrg.x - pWin->drawable.x,
1021 ptOldOrg.y - pWin->drawable.y);
1022 pwinroot->devPrivates[frameWindowPrivateIndex] =
1023 pMBPriv->frameBuffer[BACK_BUFFER];
1024 (* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
1026 pwinroot->devPrivates[frameWindowPrivateIndex] = save;
1027 REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);