]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/Xext/mbufbf.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / Xext / mbufbf.c
1 /*
2
3 Copyright (c) 1989  X Consortium
4
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:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
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.
21
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.
25
26 */
27
28 /* $XConsortium: mbufbf.c,v 1.5 94/04/17 20:32:53 dpw Exp $ */
29 /* $XFree86: xc/programs/Xserver/Xext/mbufbf.c,v 3.0 1994/05/08 05:17:30 dawes Exp $ */
30
31 #define NEED_REPLIES
32 #define NEED_EVENTS
33 #include <stdio.h>
34 #include "X.h"
35 #include "Xproto.h"
36 #include "misc.h"
37 #include "os.h"
38 #include "windowstr.h"
39 #include "scrnintstr.h"
40 #include "pixmapstr.h"
41 #include "extnsionst.h"
42 #include "dixstruct.h"
43 #include "resource.h"
44 #include "opaque.h"
45 #include "regionstr.h"
46 #include "gcstruct.h"
47 #include "inputstr.h"
48 #include "validate.h"
49 #ifndef MINIX
50 #include <sys/time.h>
51 #endif
52
53 #define _MULTIBUF_SERVER_       /* don't want Xlib structures */
54 #define _MULTIBUF_BUFFER_
55 #include "multibufst.h"
56
57 /* 
58 Support for doublebuffer hardare
59
60 This code is designed to support doublebuffer hardware where the
61 displayed buffer is selected on a per-pixel basis by an additional bit
62 plane, called the select plane. It could probably be easily modified
63 to work with systems that use window-id planes.
64
65 This is done by creating a new drawable type, DRAWABLE_BUFFER. The
66 type has the same exact layout as a window drawable. Your code should
67 treat a DRAWABLE_BUFFER the same as it would tread a DRAWABLE_WINDOW
68 when handling the gc drawing functions. In addition, PaintWindowBackground,
69 CopyWindow, and all of the gc drawing functions to be able to draw into both
70 framebuffers. Which framebuffer to draw into is selected by the contents of
71         pWin->devPrivates[frameWindowPrivateIndex].
72 The content of the devPrivate is either from frameBuffer[0] or
73 frameBuffer[1], depending on which buffer is being drawn into. When
74         pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[0],
75 the functions should draw into the front framebuffer. When
76         pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[1],
77 the functions should draw into the back framebuffer.
78
79 In addition, you need to provide a function that allows you to copy
80 bits between the buffers (optional since CopyArea can be used) and a
81 function that draws into the select plane. Then, you need to register
82 your functions and other information, by calling:
83
84 void
85 RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
86                              CopyBufferBitsFunc, DrawSelectPlaneFunc)
87     int                 nInfo;
88     xMbufBufferInfo     *pInfo;
89     DevUnion            *frameBuffer;
90     DevUnion            selectPlane;
91
92 "pInfo" is an array indicating which visuals and depths that double
93 buffering is supported on. "nInfo" is the length of the array.
94
95 "frameBuffer" is array of length 2. The contents of the array element
96 is ddx-specific. The content of frameBuffer[0] should, when placed in
97 the window private, indicate that framebuffer 0 should be drawn into.
98 The contents of frameBuffer[1], when placed into the window private,
99 should indicate that framebuffer 1 should be drawn into.
100
101 "selectPlane" is ddx-specific. It should contain information
102 neccessary for your displayProc to access the select plane.
103 It is passed to DrawSelectPlaneFunc.
104
105 "CopyBufferBitsFunc" is a ddx-specific function that copies from one
106 buffer of a multibuffered window to another buffer. If the CopyBufferBitsFunc
107 is NULL, a default function will be used that calls pScreen->CopyArea.
108
109     void CopyBufferBitsFunc(pMBWindow, srcBufferNum, dstBufferNum)
110         mbufWindowPtr pMBWindow;
111         int srcBufferNum, dstBufferNum;
112
113 "DrawSelectPlaneFunc" is a ddx-specific function that fills the
114 regions "prgn" of select plane with the value "bufferNum". If 
115 selectPlane is a DrawablePtr (such as a PixmapPtr), you can pass
116 NULL for DrawSelectPlaneFunc, a default function will be used that
117 calls FillRectangle on the selectPlane.
118
119     void DrawSelectPlaneFunc(pScreen, selectPlane, prgn, bufferNum)
120         ScreenPtr       pScreen;
121         DevUnion        selectPlane;
122         RegionPtr       prgn;
123         long            bufferNum;
124
125 ...
126 ...
127 ...
128
129 */
130
131 #define MAX_BUFFERS  2  /* Only supports 2 buffers */
132 #define FRONT_BUFFER 0
133 #define BACK_BUFFER  1
134
135
136 /* Buffer drawables have the same structure as window drawables */
137 typedef WindowRec BufferRec;
138 typedef WindowPtr BufferPtr;
139
140
141 /*
142  * Call RegisterHdwrBuffer for every screen that has doublebuffer hardware. 
143  */
144
145 static int              bufNumInfo[MAXSCREENS];
146 static xMbufBufferInfo  *bufInfo[MAXSCREENS];
147 static DevUnion         *bufFrameBuffer[MAXSCREENS];
148 static DevUnion         bufselectPlane[MAXSCREENS];
149 static void             (* bufCopyBufferBitsFunc[MAXSCREENS])();
150 static void             (* bufDrawSelectPlaneFunc[MAXSCREENS])();
151
152 static Bool bufMultibufferInit();
153
154
155 void
156 RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
157                              CopyBufferBitsFunc, DrawSelectPlaneFunc)
158     ScreenPtr           pScreen;
159     int                 nInfo;
160     xMbufBufferInfo     *pInfo;
161     DevUnion            *frameBuffer;
162     DevUnion            selectPlane;
163     void                (* CopyBufferBitsFunc)();
164     void                (* DrawSelectPlaneFunc)();
165 {
166     bufNumInfo[pScreen->myNum]     = nInfo;
167     bufInfo[pScreen->myNum]        = pInfo;
168     bufFrameBuffer[pScreen->myNum] = frameBuffer;
169     bufselectPlane[pScreen->myNum] = selectPlane;
170
171     bufCopyBufferBitsFunc[pScreen->myNum]  = CopyBufferBitsFunc;
172     bufDrawSelectPlaneFunc[pScreen->myNum] = DrawSelectPlaneFunc;
173
174     /* Register ourselves with device-independent multibuffers code */
175     RegisterMultibufferInit(pScreen, bufMultibufferInit);
176 }
177
178
179 /*
180  * Called by Multibuffer extension initialization.
181  * Initializes mbufScreenRec and its devPrivate.
182  */
183     
184 static Bool NoopDDA_True() { return TRUE; }
185 static Bool bufPositionWindow();
186 static int  bufCreateImageBuffers();
187 static void bufDestroyImageBuffers();
188 static void bufDisplayImageBuffers();
189 static void bufClearImageBufferArea();
190 static void bufDestroyBuffer();
191 static void bufCopyBufferBits();
192 static void bufDrawSelectPlane();
193 static void bufWrapScreenFuncs();
194 static void bufResetProc();
195
196 static void bufPostValidateTree();
197 static void bufClipNotify();
198 static void bufWindowExposures();
199 static Bool bufChangeWindowAttributes();
200 static void bufClearToBackground();
201 static void bufCopyWindow();
202
203 extern WindowPtr *WindowTable;
204
205 static Bool
206 bufMultibufferInit(pScreen, pMBScreen)
207     ScreenPtr pScreen;
208     mbufScreenPtr pMBScreen;
209 {
210     mbufBufferPrivPtr   pMBPriv;
211     BoxRec              box;
212
213     /* Multibuffer info */
214     pMBScreen->nInfo = bufNumInfo[pScreen->myNum];
215     pMBScreen->pInfo = bufInfo[pScreen->myNum];
216
217     /* Hooks */
218     pMBScreen->CreateImageBuffers = bufCreateImageBuffers;
219     pMBScreen->DestroyImageBuffers = bufDestroyImageBuffers;
220     pMBScreen->DisplayImageBuffers = bufDisplayImageBuffers;
221     pMBScreen->ClearImageBufferArea = bufClearImageBufferArea;
222     pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
223     pMBScreen->ChangeBufferAttributes = NoopDDA_True;
224     pMBScreen->DeleteBufferDrawable = bufDestroyBuffer;
225     pMBScreen->WrapScreenFuncs = bufWrapScreenFuncs;
226     pMBScreen->ResetProc = bufResetProc;
227     /* Create devPrivate part */
228     pMBPriv = (mbufBufferPrivPtr) xalloc(sizeof *pMBPriv);
229     if (!pMBPriv)
230         return (FALSE);
231
232     pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
233     pMBPriv->frameBuffer  = bufFrameBuffer[pScreen->myNum];
234     pMBPriv->selectPlane = bufselectPlane[pScreen->myNum];
235
236     /*
237      * Initializing the subtractRgn to the screen area will ensure that
238      * the selectPlane will get cleared on the first PostValidateTree.
239      */
240
241     box.x1 = 0;
242     box.y1 = 0;
243     box.x2 = pScreen->width;
244     box.y2 = pScreen->height;
245
246     pMBPriv->rgnChanged = TRUE;
247     REGION_INIT(pScreen, &pMBPriv->backBuffer, &box, 1);
248     REGION_INIT(pScreen, &pMBPriv->subtractRgn, &box, 1);
249     REGION_INIT(pScreen, &pMBPriv->unionRgn, NullBox, 0);
250
251     /* Misc functions */
252     pMBPriv->CopyBufferBits  = bufCopyBufferBitsFunc[pScreen->myNum];
253     pMBPriv->DrawSelectPlane = bufDrawSelectPlaneFunc[pScreen->myNum];
254
255     if (!pMBPriv->CopyBufferBits)
256         pMBPriv->CopyBufferBits = bufCopyBufferBits;
257
258     if (!pMBPriv->DrawSelectPlane)
259         pMBPriv->DrawSelectPlane = bufDrawSelectPlane;
260
261     /* screen functions */
262     pMBPriv->funcsWrapped = 0;
263     pMBPriv->inClearToBackground = FALSE;
264     pMBPriv->WindowExposures = NULL;
265     pMBPriv->CopyWindow = NULL;
266     pMBPriv->ClearToBackground = NULL;
267     pMBPriv->ClipNotify = NULL;
268     pMBPriv->ChangeWindowAttributes = NULL;
269
270     /* Start out wrapped to clear select plane */
271     WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
272     return TRUE;
273 }
274
275 static void
276 UpdateBufferFromWindow(pBuffer, pWin)
277     BufferPtr   pBuffer;
278     WindowPtr   pWin;
279 {
280     pBuffer->drawable.x      = pWin->drawable.x;
281     pBuffer->drawable.y      = pWin->drawable.y;
282     pBuffer->drawable.width  = pWin->drawable.width;
283     pBuffer->drawable.height = pWin->drawable.height;
284
285     pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
286
287     /* Update for PaintWindowBackground */
288     pBuffer->parent = pWin->parent;
289
290     /*
291      * Make the borderClip the same as the clipList so
292      * NotClippedByChildren comes out with just clipList.
293      */
294
295     pBuffer->clipList   = pWin->clipList;
296     pBuffer->borderClip = pWin->clipList;
297     pBuffer->winSize    = pWin->winSize;
298     pBuffer->borderSize = pWin->borderSize;
299
300     pBuffer->origin = pWin->origin;
301 }
302
303 static BufferPtr
304 bufCreateBuffer(pScreen, pWin, bufferNum)
305     ScreenPtr   pScreen;
306     WindowPtr   pWin;
307     int         bufferNum;
308 {
309     mbufBufferPrivPtr   pMBPriv;
310     DevUnion    *devPrivates;
311     BufferPtr   pBuffer;
312     int         i;
313
314     pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
315
316     pBuffer = AllocateWindow(pWin->drawable.pScreen);
317     if (!pBuffer)
318         return (NULL);
319
320     /* XXX- Until we know what is needed, copy everything. */
321     devPrivates = pBuffer->devPrivates;
322     *pBuffer = *pWin;
323     pBuffer->devPrivates   = devPrivates;
324
325     pBuffer->drawable.type = DRAWABLE_BUFFER;
326     pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
327
328     pBuffer->nextSib    = NULL;
329     pBuffer->prevSib    = NULL;
330     pBuffer->firstChild = NULL;
331     pBuffer->lastChild  = NULL;
332
333     /* XXX - Worry about backingstore later */
334     pBuffer->backStorage   = NULL;
335     pBuffer->backingStore  = NotUseful;
336
337     /* XXX - Need to call pScreen->CreateWindow for tile/stipples
338      *       or should I just copy the devPrivates?
339      */
340     
341     for (i=0; i < pScreen->WindowPrivateLen; i++)
342         pBuffer->devPrivates[i] = pWin->devPrivates[i];
343
344     pBuffer->devPrivates[frameWindowPrivateIndex] =
345         pMBPriv->frameBuffer[bufferNum];
346
347     return pBuffer;
348 }
349
350 static void
351 bufDestroyBuffer(pDrawable)
352     DrawablePtr pDrawable;
353 {
354     xfree(pDrawable);
355 }
356
357 /*ARGSUSED*/
358 static int
359 bufCreateImageBuffers (pWin, nbuf, ids, action, hint)
360     WindowPtr   pWin;
361     int         nbuf;
362     XID         *ids;
363     int         action;
364     int         hint;
365 {
366     ScreenPtr           pScreen;
367     mbufScreenPtr       pMBScreen;
368     mbufWindowPtr       pMBWindow;
369     mbufBufferPtr       pMBBuffer;
370     int                 i;
371
372     pScreen   = pWin->drawable.pScreen;
373     pMBScreen = MB_SCREEN_PRIV(pScreen);
374     pMBWindow = MB_WINDOW_PRIV(pWin);
375
376     pMBWindow->devPrivate.ptr = (pointer) REGION_CREATE(pScreen, 0,0);
377     if (!pMBWindow->devPrivate.ptr)
378         return(0);
379     REGION_COPY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr,
380                             &pWin->clipList);
381
382     for (i = 0; i < nbuf; i++)
383     {
384         pMBBuffer = pMBWindow->buffers + i;
385         pMBBuffer->pDrawable = (DrawablePtr) bufCreateBuffer(pScreen,pWin,i);
386
387         if (!pMBBuffer->pDrawable)
388             break;
389
390         if (!AddResource (ids[i], MultibufferDrawableResType,
391                           (pointer) pMBBuffer->pDrawable))
392         {
393             bufDestroyBuffer((BufferPtr) pMBBuffer->pDrawable);
394             break;
395         }
396         pMBBuffer->pDrawable->id = ids[i];
397
398         /*
399          * If window is already mapped, generate exposures and
400          * clear the area of the newly buffers.
401          */
402
403         if ((pWin->realized) && (i != pMBWindow->displayedMultibuffer))
404             (* pMBScreen->ClearImageBufferArea)(pMBBuffer, 0,0, 0,0, TRUE);
405     }
406
407     return i;
408 }
409
410 static void
411 bufDestroyImageBuffers(pWin)
412     WindowPtr   pWin;
413 {
414     ScreenPtr           pScreen;
415     mbufWindowPtr       pMBWindow;
416
417     pScreen   = pWin->drawable.pScreen;
418
419     if (pMBWindow = MB_WINDOW_PRIV(pWin))
420     {
421         mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
422
423         /*
424          * if the backbuffer is currently being displayed, move the bits
425          * to the frontbuffer and display it instead.
426          */
427
428         if (pWin->realized && (pMBWindow->displayedMultibuffer == BACK_BUFFER))
429         {
430             (* pMBPriv->CopyBufferBits)(pMBWindow, BACK_BUFFER, FRONT_BUFFER);
431             REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer,
432                                   &pMBPriv->backBuffer, &pWin->clipList);
433             (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
434                             &pWin->clipList, FRONT_BUFFER);
435         }
436
437         /* Switch window rendering to front buffer */
438         pWin->devPrivates[frameWindowPrivateIndex] =
439             pMBPriv->frameBuffer[FRONT_BUFFER];
440
441         REGION_DESTROY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr);
442         pMBWindow->devPrivate.ptr = NULL;
443     }
444 }
445
446 /*
447  * Can be replaced by pScreen->ClearToBackground if pBuffer->eventMask
448  * and wOtherEventsMasks(pBuffer) were setup.
449  */
450
451 static void
452 bufClearImageBufferArea(pMBBuffer, x,y, w,h, generateExposures)
453     mbufBufferPtr       pMBBuffer;
454     short               x,y;
455     unsigned short      w,h;
456     Bool                generateExposures;
457 {
458     BoxRec box;
459     RegionRec   reg;
460     RegionPtr pBSReg = NullRegion;
461     ScreenPtr   pScreen;
462     BoxPtr  extents;
463     int     x1, y1, x2, y2;
464     BufferPtr pBuffer;
465
466     pBuffer = (BufferPtr) pMBBuffer->pDrawable;
467     /* compute everything using ints to avoid overflow */
468
469     x1 = pBuffer->drawable.x + x;
470     y1 = pBuffer->drawable.y + y;
471     if (w)
472         x2 = x1 + (int) w;
473     else
474         x2 = x1 + (int) pBuffer->drawable.width - (int) x;
475     if (h)
476         y2 = y1 + h;    
477     else
478         y2 = y1 + (int) pBuffer->drawable.height - (int) y;
479
480     extents = &pBuffer->clipList.extents;
481     
482     /* clip the resulting rectangle to the window clipList extents.  This
483      * makes sure that the result will fit in a box, given that the
484      * screen is < 32768 on a side.
485      */
486
487     if (x1 < extents->x1)
488         x1 = extents->x1;
489     if (x2 > extents->x2)
490         x2 = extents->x2;
491     if (y1 < extents->y1)
492         y1 = extents->y1;
493     if (y2 > extents->y2)
494         y2 = extents->y2;
495
496     if (x2 <= x1 || y2 <= y1)
497     {
498         x2 = x1 = 0;
499         y2 = y1 = 0;
500     }
501
502     box.x1 = x1;
503     box.x2 = x2;
504     box.y1 = y1;
505     box.y2 = y2;
506
507     pScreen = pBuffer->drawable.pScreen;
508     REGION_INIT(pScreen, &reg, &box, 1);
509     if (pBuffer->backStorage)
510     {
511         /*
512          * If the window has backing-store on, call through the
513          * ClearToBackground vector to handle the special semantics
514          * (i.e. things backing store is to be cleared out and
515          * an Expose event is to be generated for those areas in backing
516          * store if generateExposures is TRUE).
517          */
518         pBSReg = (* pScreen->ClearBackingStore)(pBuffer, x, y, w, h,
519                                                  generateExposures);
520     }
521
522     REGION_INTERSECT(pScreen, &reg, &reg, &pBuffer->clipList);
523     if (pBuffer->backgroundState != None)
524         (*pScreen->PaintWindowBackground)(pBuffer, &reg, PW_BACKGROUND);
525     if (generateExposures)
526         MultibufferExpose(pMBBuffer, &reg);
527 #ifdef _notdef
528     /* XXBS - This is the original miClearToBackground code.
529      * WindowExposures needs to be called (or the functionality emulated)
530      * in order for backingStore to work, but first, pBuffer->eventMask
531      * and wOtherEventsMasks(pBuffer) need to be setup correctly.
532      */
533
534     if (generateExposures)
535         (*pScreen->WindowExposures)(pBuffer, &reg, pBSReg);
536     else if (pBuffer->backgroundState != None)
537         (*pScreen->PaintWindowBackground)(pBuffer, &reg, PW_BACKGROUND);
538 #endif
539     REGION_UNINIT(pScreen, &reg);
540     if (pBSReg)
541         REGION_DESTROY(pScreen, pBSReg);
542 }
543
544 static void
545 bufWrapScreenFuncs(pScreen)
546     ScreenPtr pScreen;
547 {
548     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
549
550     WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
551     WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClipNotify, bufClipNotify);
552     WRAP_SCREEN_FUNC(pScreen,pMBPriv,WindowExposures,bufWindowExposures);
553     WRAP_SCREEN_FUNC(pScreen,pMBPriv,ChangeWindowAttributes, bufChangeWindowAttributes);
554     WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClearToBackground,bufClearToBackground);
555     WRAP_SCREEN_FUNC(pScreen,pMBPriv,CopyWindow,bufCopyWindow);
556 }
557
558 static void
559 bufResetProc(pScreen)
560     ScreenPtr pScreen;
561 {
562     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
563
564     /*
565      * frameBuffer, selectPlane, and pInfo should be freed by
566      * whoever called RegisterDoubleBufferHardware
567      */
568
569     REGION_UNINIT(pScreen, &pMBPriv->backBuffer);
570     REGION_UNINIT(pScreen, &pMBPriv->subtractRgn);
571     REGION_UNINIT(pScreen, &pMBPriv->unionRgn);
572     xfree(pMBPriv);
573 }
574
575 /*---------------------------------------------------------------------------*/
576
577 /* 
578  * Used if CopyBufferBitsFunc is not provided when registering.
579  * This should work for everybody since CopyArea needs to support
580  * copying between buffers anyway.
581  */
582
583 static void
584 bufCopyBufferBits(pMBWindow, srcBufferNum, dstBufferNum)
585     mbufWindowPtr pMBWindow;
586     int srcBufferNum, dstBufferNum;
587 {
588     DrawablePtr pSrcBuffer, pDstBuffer;
589     GCPtr pGC;
590
591     pSrcBuffer = pMBWindow->buffers[srcBufferNum].pDrawable;
592     pDstBuffer = pMBWindow->buffers[dstBufferNum].pDrawable;
593
594     pGC = GetScratchGC (pDstBuffer->depth, pDstBuffer->pScreen);
595     if (!pGC)
596         return;
597
598     ValidateGC (pDstBuffer, pGC);
599     (* pGC->ops->CopyArea) (pSrcBuffer, pDstBuffer, pGC,
600                     0,0, pDstBuffer->width, pDstBuffer->height, 0,0);
601     FreeScratchGC (pGC);
602 }
603
604 /*
605  * Used if DrawSelectPlanFunc is not provided for when registering.
606  * However, it only works if selectPlane.ptr is a drawable. Also
607  * assumes that painting with color 0 selects the front buffer,
608  * while color 1 selects the back buffer.
609  */
610
611 static void
612 bufDrawSelectPlane(pScreen, selectPlane, prgn, bufferNum)
613     ScreenPtr   pScreen;
614     DevUnion    selectPlane;
615     RegionPtr   prgn;
616     long        bufferNum;
617 {
618     DrawablePtr pDrawable;
619     GCPtr pGC;
620     register int i;
621     register BoxPtr pbox;
622     register xRectangle *prect;
623     int numRects;
624     XID value;
625
626     if (REGION_NUM_RECTS(prgn) == 0)
627         return;
628
629     pDrawable = (DrawablePtr) selectPlane.ptr;
630     pGC = GetScratchGC (pDrawable->depth, pScreen);
631     if (!pGC)
632         return;
633
634     prect = (xRectangle *)ALLOCATE_LOCAL(REGION_NUM_RECTS(prgn) *
635                                          sizeof(xRectangle));
636     if (!prect)
637     {
638         FreeScratchGC(pGC);
639         return;
640     }
641
642     value = (XID) bufferNum;
643     DoChangeGC(pGC, GCForeground, &value, 0);
644     ValidateGC(pDrawable, pGC);
645
646     numRects = REGION_NUM_RECTS(prgn);
647     pbox = REGION_RECTS(prgn);
648     for (i= numRects; --i >= 0; pbox++, prect++)
649     {
650         prect->x = pbox->x1;
651         prect->y = pbox->y1;
652         prect->width = pbox->x2 - pbox->x1;
653         prect->height = pbox->y2 - pbox->y1;
654     }
655     prect -= numRects;
656     (* pGC->ops->PolyFillRect)(pDrawable, pGC, numRects, prect);
657
658     DEALLOCATE_LOCAL(prect);
659     FreeScratchGC (pGC);
660 }
661
662
663 static void
664 bufDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
665     ScreenPtr           pScreen;
666     mbufBufferPtr       *ppMBBuffer;
667     mbufWindowPtr       *ppMBWindow;
668     int                 nbuf;
669 {
670     WindowPtr       pWin;
671     BufferPtr       pPrevBuffer, pNewBuffer;
672     int             i, number;
673     mbufBufferPrivPtr pMBPriv;
674     mbufBufferPtr   pPrevMBBuffer;
675
676     pMBPriv   = MB_SCREEN_PRIV_BUFFER(pScreen);
677
678     for (i = 0; i < nbuf; i++)
679     {
680         number = ppMBBuffer[i]->number; /* 0=frontbuffer, 1=backbuffer */
681         pWin = ppMBWindow[i]->pWindow;
682         pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
683
684         pPrevBuffer = (BufferPtr) pPrevMBBuffer->pDrawable;
685         pNewBuffer  = (BufferPtr) ppMBBuffer[i]->pDrawable;
686
687         if (pPrevBuffer != pNewBuffer)
688         {
689             RegionPtr backBuffer = &pMBPriv->backBuffer;
690
691             /*
692              * Update the select plane and the backBuffer region.
693              */
694
695             (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
696                             &pWin->clipList, number);
697
698             if (number == BACK_BUFFER)
699                 REGION_UNION(pScreen, backBuffer, backBuffer,
700                                    &pWin->clipList);
701             else
702                 REGION_SUBTRACT(pScreen, backBuffer, backBuffer,
703                                    &pWin->clipList);
704
705             /* Switch which framebuffer the window draws into */
706             pWin->devPrivates[frameWindowPrivateIndex] =
707                 pMBPriv->frameBuffer[number];
708         }
709
710         switch (ppMBWindow[i]->updateAction)
711         {
712         case MultibufferUpdateActionUndefined:
713             break;
714         case MultibufferUpdateActionBackground:
715             (* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
716                 (pPrevMBBuffer, 0,0, 0,0, FALSE);
717             break;
718         case MultibufferUpdateActionUntouched:
719             break;
720         case MultibufferUpdateActionCopied:
721             if (pPrevBuffer != pNewBuffer)
722             {
723                 (* pMBPriv->CopyBufferBits) (ppMBWindow[i],
724                         ppMBBuffer[i]->number, pPrevMBBuffer->number);
725             }
726             break;
727         }
728     }
729 }
730
731 /* Updates the backBuffer region and paints the selectPlane. */
732
733 static void
734 bufPostValidateTree(pParent, pChild, kind)
735     WindowPtr   pParent, pChild;
736     VTKind      kind;
737 {
738     ScreenPtr pScreen;
739     mbufBufferPrivPtr pMBPriv;
740
741     if (pParent)
742         pScreen = pParent->drawable.pScreen;
743     else if (pChild)
744         pScreen = pChild->drawable.pScreen;
745     else
746         return; /* Hopeless */
747
748     pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
749
750     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
751     if (pScreen->PostValidateTree)
752         (* pScreen->PostValidateTree)(pParent, pChild, kind);
753     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
754
755     /* Does backBuffer need to change? */
756     if (pMBPriv->rgnChanged)
757     {
758         RegionRec exposed;
759         RegionPtr pSubtractRgn, pUnionRgn;
760         Bool overlap;
761
762         pMBPriv->rgnChanged = FALSE;
763
764         pSubtractRgn = &pMBPriv->subtractRgn;
765         pUnionRgn    = &pMBPriv->unionRgn;
766         REGION_VALIDATE(pScreen, pSubtractRgn, &overlap);
767 #ifdef DEBUG
768         if (overlap)
769             FatalError("bufPostValidateTree: subtractRgn overlaps");
770 #endif
771         REGION_VALIDATE(pScreen, pUnionRgn, &overlap);
772 #ifdef DEBUG
773         if (overlap)
774             FatalError("bufPostValidateTree: unionRgn overlaps");
775 #endif
776
777         /* Update backBuffer: subtract must come before union */
778         REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
779                               pSubtractRgn);
780         REGION_UNION(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
781                               pUnionRgn);
782
783         /* Paint gained and lost backbuffer areas in select plane */
784         REGION_INIT(pScreen, &exposed, NullBox, 0);
785         REGION_SUBTRACT(pScreen, &exposed, pSubtractRgn, pUnionRgn);
786         (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
787                                      &exposed, FRONT_BUFFER);
788
789         REGION_SUBTRACT(pScreen, &exposed, pUnionRgn, pSubtractRgn);
790         (* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
791                                     &exposed, BACK_BUFFER);
792         
793         REGION_UNINIT(pScreen, &exposed);
794         REGION_EMPTY(pScreen, pSubtractRgn);
795         REGION_EMPTY(pScreen, pUnionRgn);
796     }
797 }
798
799 /* XXX - Knows region internals. */
800
801 static Bool
802 RegionsEqual(reg1, reg2)
803     RegionPtr reg1;
804     RegionPtr reg2;
805 {
806     int i;
807     BoxPtr rects1, rects2;
808
809     if (reg1->extents.x1 != reg2->extents.x1) return FALSE;
810     if (reg1->extents.x2 != reg2->extents.x2) return FALSE;
811     if (reg1->extents.y1 != reg2->extents.y1) return FALSE;
812     if (reg1->extents.y2 != reg2->extents.y2) return FALSE;
813     if (REGION_NUM_RECTS(reg1) != REGION_NUM_RECTS(reg2)) return FALSE;
814     
815     rects1 = REGION_RECTS(reg1);
816     rects2 = REGION_RECTS(reg2);
817     for (i = 0; i != REGION_NUM_RECTS(reg1); i++) {
818         if (rects1[i].x1 != rects2[i].x1) return FALSE;
819         if (rects1[i].x2 != rects2[i].x2) return FALSE;
820         if (rects1[i].y1 != rects2[i].y1) return FALSE;
821         if (rects1[i].y2 != rects2[i].y2) return FALSE;
822     }
823     return TRUE;
824 }
825
826 /*
827  * If the window is multibuffered and displaying the backbuffer,
828  * add the old clipList to the subtractRgn and add the new clipList
829  * to the unionRgn. PostValidateTree will use subtractRgn and unionRgn
830  * to update the backBuffer region and the selectPlane.
831  *
832  * Copy changes to the window structure into the buffers.
833  * Send ClobberNotify events.
834  */
835
836 static void
837 bufClipNotify(pWin, dx,dy)
838     WindowPtr pWin;
839     int       dx,dy;
840 {
841     ScreenPtr pScreen = pWin->drawable.pScreen;
842     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
843     mbufWindowPtr       pMBWindow;
844     int i;
845
846     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
847     if (pScreen->ClipNotify)
848         (* pScreen->ClipNotify)(pWin, dx,dy);
849     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
850
851     if (pMBWindow = MB_WINDOW_PRIV(pWin))
852     {
853         RegionPtr pOldClipList = (RegionPtr) pMBWindow->devPrivate.ptr;
854
855         if (! RegionsEqual(pOldClipList, &pWin->clipList))
856         {
857             if (pMBWindow->displayedMultibuffer == BACK_BUFFER)
858             {
859                 pMBPriv->rgnChanged = TRUE;
860                 REGION_APPEND(pScreen, &pMBPriv->subtractRgn, pOldClipList);
861                 REGION_APPEND(pScreen, &pMBPriv->unionRgn, &pWin->clipList);
862             }
863
864             REGION_COPY(pScreen, pOldClipList,&pWin->clipList);
865         }
866
867         /* Update buffer x,y,w,h, and clipList */
868         for (i=0; i<pMBWindow->numMultibuffer; i++)
869         {
870             mbufBufferPtr pMBBuffer = pMBWindow->buffers + i;
871             if (pMBBuffer->clobber != pWin->visibility)
872             {
873                 pMBBuffer->clobber = pWin->visibility;
874                 MultibufferClobber(pMBBuffer);
875             }
876             UpdateBufferFromWindow(pMBBuffer->pDrawable, pWin);
877         }
878     }
879 }
880
881 /*
882  * Updates buffer's background fields when the window's changes.
883  * This is necessary because pScreen->PaintWindowBackground
884  * is used to paint the buffer.
885  *
886  * XXBS - Backingstore state will have be tracked too if it is supported.
887  */
888
889 static Bool
890 bufChangeWindowAttributes(pWin, mask)
891     WindowPtr pWin;
892     unsigned long mask;
893 {
894     ScreenPtr pScreen = pWin->drawable.pScreen;
895     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
896     mbufWindowPtr pMBWindow;
897     Bool ret;
898
899     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
900     ret = (* pScreen->ChangeWindowAttributes)(pWin, mask);
901     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
902
903     if (pMBWindow = MB_WINDOW_PRIV(pWin))
904     {
905         if (mask & (CWBackPixmap | CWBackPixel))
906         {
907             BufferPtr pBuffer;
908             int i;
909
910             for (i=0; i<pMBWindow->displayedMultibuffer; i++)
911             {
912                 pBuffer = (BufferPtr) pMBWindow->buffers[i].pDrawable;
913                 pBuffer->backgroundState = pWin->backgroundState;
914                 pBuffer->background = pWin->background;
915             }
916         }
917     }
918     return ret;
919 }
920
921 /*
922  * Send exposures and clear the background for a buffer whenever
923  * its corresponding window is exposed, except when called by
924  * ClearToBackground.
925  */
926
927 static void 
928 bufWindowExposures(pWin, prgn, other_exposed)
929     WindowPtr pWin;
930     register RegionPtr prgn, other_exposed;
931 {
932     ScreenPtr pScreen = pWin->drawable.pScreen;
933     mbufWindowPtr pMBWindow = MB_WINDOW_PRIV(pWin);
934     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
935     RegionRec tmp_rgn;
936     int i;
937     Bool handleBuffers;
938
939     handleBuffers = (!pMBPriv->inClearToBackground) &&
940         (pWin->drawable.type == DRAWABLE_WINDOW) &&
941         pMBWindow && (prgn && !REGION_NIL(prgn));
942
943     /* miWindowExposures munges prgn and other_exposed. */
944     if (handleBuffers)
945     {
946         REGION_INIT(pScreen, &tmp_rgn, NullBox, 0);
947         REGION_COPY(pScreen, &tmp_rgn,prgn);
948     }
949
950     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
951     (* pScreen->WindowExposures) (pWin, prgn, other_exposed);
952     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
953
954     if (!handleBuffers)
955         return;
956
957     /*
958      * Send expose events to all clients. Paint the exposed region for all
959      * buffers except the displayed buffer since it is handled when the
960      * window is painted.
961      *
962      * XXBS - Will have to be re-written to handle BackingStore on buffers.
963      */
964
965     for (i=0; i<pMBWindow->numMultibuffer; i++)
966     {
967         mbufBufferPtr pMBBuffer;
968         BufferPtr pBuffer;
969
970         pMBBuffer = pMBWindow->buffers + i;
971         pBuffer = (BufferPtr) pMBBuffer->pDrawable;
972
973         if (i != pMBWindow->displayedMultibuffer)
974             (* pScreen->PaintWindowBackground)(pBuffer,&tmp_rgn,PW_BACKGROUND);
975         if ((pMBBuffer->otherEventMask | pMBBuffer->eventMask) & ExposureMask)
976             MultibufferExpose(pMBBuffer, &tmp_rgn);
977     }
978
979     REGION_UNINIT(pScreen, &tmp_rgn);
980 }
981
982 /*
983  * Set ``inClearToBackground'' so that WindowExposures does not attempt
984  * to send expose events or clear the background on the buffers.
985  */
986
987 static void
988 bufClearToBackground(pWin, x,y,w,h, sendExpose)
989     WindowPtr pWin;
990     int x,y, w,h;
991     Bool sendExpose;
992 {
993     ScreenPtr pScreen = pWin->drawable.pScreen;
994     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
995
996     pMBPriv->inClearToBackground = TRUE;
997
998     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
999     (* pScreen->ClearToBackground)(pWin, x,y,w,h, sendExpose);
1000     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
1001
1002     pMBPriv->inClearToBackground = FALSE;
1003 }
1004
1005 /*
1006  * Move bits in both buffers. It does this by calling pScreen->CopyWindow
1007  * twice, once with the root window's devPrivate[frameWindowPrivateIndex]
1008  * pointing to the frontbuffer pixmap and once with it pointed to the
1009  * backbuffer pixmap. It does this if there are *any* existing multibuffered
1010  * window... a possible optimization is to copy the backbuffer only if this
1011  * window or its inferiors are multibuffered. May be faster, maybe not.
1012  *
1013  * XXX - Only works if your CopyWindow checks the root window's devPrivate
1014  *       to see which buffer to draw into. Works for cfbPaintWindow.
1015  */
1016
1017 /*ARGSUSED*/
1018 static void 
1019 bufCopyWindow(pWin, ptOldOrg, prgnSrc)
1020     WindowPtr pWin;
1021     DDXPointRec ptOldOrg;
1022     RegionPtr prgnSrc;
1023 {
1024     ScreenPtr pScreen = pWin->drawable.pScreen;
1025     mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
1026     WindowPtr pwinroot;
1027     DevUnion save;
1028
1029     UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
1030
1031     pwinroot = WindowTable[pScreen->myNum];
1032     save = pwinroot->devPrivates[frameWindowPrivateIndex];
1033
1034     /*
1035      * Copy front buffer
1036      */
1037
1038     pwinroot->devPrivates[frameWindowPrivateIndex] =
1039         pMBPriv->frameBuffer[FRONT_BUFFER];
1040     (* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
1041
1042     /*
1043      * Copy back buffer
1044      */
1045
1046     /* CopyWindow translates prgnSrc... translate it back for 2nd call. */
1047     REGION_TRANSLATE(pScreen, prgnSrc,
1048                                   ptOldOrg.x - pWin->drawable.x,
1049                                   ptOldOrg.y - pWin->drawable.y);
1050     pwinroot->devPrivates[frameWindowPrivateIndex] =
1051         pMBPriv->frameBuffer[BACK_BUFFER];
1052     (* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
1053
1054     pwinroot->devPrivates[frameWindowPrivateIndex] = save;
1055     REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
1056 }