1012 lines
29 KiB
C
1012 lines
29 KiB
C
/*
|
|
|
|
Copyright 1989, 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
*/
|
|
|
|
|
|
#define NEED_REPLIES
|
|
#define NEED_EVENTS
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "misc.h"
|
|
#include "os.h"
|
|
#include "windowstr.h"
|
|
#include "scrnintstr.h"
|
|
#include "pixmapstr.h"
|
|
#include "extnsionst.h"
|
|
#include "dixstruct.h"
|
|
#include "resource.h"
|
|
#include "opaque.h"
|
|
#include "regionstr.h"
|
|
#include "gcstruct.h"
|
|
#include "inputstr.h"
|
|
#include "validate.h"
|
|
#include <sys/time.h>
|
|
|
|
#define _MULTIBUF_SERVER_ /* don't want Xlib structures */
|
|
#define _MULTIBUF_BUFFER_
|
|
#include <X11/extensions/multibufst.h>
|
|
|
|
/*
|
|
Support for doublebuffer hardare
|
|
|
|
This code is designed to support doublebuffer hardware where the
|
|
displayed buffer is selected on a per-pixel basis by an additional bit
|
|
plane, called the select plane. It could probably be easily modified
|
|
to work with systems that use window-id planes.
|
|
|
|
This is done by creating a new drawable type, DRAWABLE_BUFFER. The
|
|
type has the same exact layout as a window drawable. Your code should
|
|
treat a DRAWABLE_BUFFER the same as it would tread a DRAWABLE_WINDOW
|
|
when handling the gc drawing functions. In addition, PaintWindowBackground,
|
|
CopyWindow, and all of the gc drawing functions to be able to draw into both
|
|
framebuffers. Which framebuffer to draw into is selected by the contents of
|
|
pWin->devPrivates[frameWindowPrivateIndex].
|
|
The content of the devPrivate is either from frameBuffer[0] or
|
|
frameBuffer[1], depending on which buffer is being drawn into. When
|
|
pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[0],
|
|
the functions should draw into the front framebuffer. When
|
|
pWin->devPrivates[frameWindowPrivateIndex] == frameBuffer[1],
|
|
the functions should draw into the back framebuffer.
|
|
|
|
In addition, you need to provide a function that allows you to copy
|
|
bits between the buffers (optional since CopyArea can be used) and a
|
|
function that draws into the select plane. Then, you need to register
|
|
your functions and other information, by calling:
|
|
|
|
void
|
|
RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
|
|
CopyBufferBitsFunc, DrawSelectPlaneFunc)
|
|
int nInfo;
|
|
xMbufBufferInfo *pInfo;
|
|
DevUnion *frameBuffer;
|
|
DevUnion selectPlane;
|
|
|
|
"pInfo" is an array indicating which visuals and depths that double
|
|
buffering is supported on. "nInfo" is the length of the array.
|
|
|
|
"frameBuffer" is array of length 2. The contents of the array element
|
|
is ddx-specific. The content of frameBuffer[0] should, when placed in
|
|
the window private, indicate that framebuffer 0 should be drawn into.
|
|
The contents of frameBuffer[1], when placed into the window private,
|
|
should indicate that framebuffer 1 should be drawn into.
|
|
|
|
"selectPlane" is ddx-specific. It should contain information
|
|
neccessary for your displayProc to access the select plane.
|
|
It is passed to DrawSelectPlaneFunc.
|
|
|
|
"CopyBufferBitsFunc" is a ddx-specific function that copies from one
|
|
buffer of a multibuffered window to another buffer. If the CopyBufferBitsFunc
|
|
is NULL, a default function will be used that calls pScreen->CopyArea.
|
|
|
|
void CopyBufferBitsFunc(pMBWindow, srcBufferNum, dstBufferNum)
|
|
mbufWindowPtr pMBWindow;
|
|
int srcBufferNum, dstBufferNum;
|
|
|
|
"DrawSelectPlaneFunc" is a ddx-specific function that fills the
|
|
regions "prgn" of select plane with the value "bufferNum". If
|
|
selectPlane is a DrawablePtr (such as a PixmapPtr), you can pass
|
|
NULL for DrawSelectPlaneFunc, a default function will be used that
|
|
calls FillRectangle on the selectPlane.
|
|
|
|
void DrawSelectPlaneFunc(pScreen, selectPlane, prgn, bufferNum)
|
|
ScreenPtr pScreen;
|
|
DevUnion selectPlane;
|
|
RegionPtr prgn;
|
|
long bufferNum;
|
|
|
|
...
|
|
...
|
|
...
|
|
|
|
*/
|
|
|
|
#define MAX_BUFFERS 2 /* Only supports 2 buffers */
|
|
#define FRONT_BUFFER 0
|
|
#define BACK_BUFFER 1
|
|
|
|
|
|
/* Buffer drawables have the same structure as window drawables */
|
|
typedef WindowRec BufferRec;
|
|
typedef WindowPtr BufferPtr;
|
|
|
|
|
|
/*
|
|
* Call RegisterHdwrBuffer for every screen that has doublebuffer hardware.
|
|
*/
|
|
|
|
static int bufNumInfo[MAXSCREENS];
|
|
static xMbufBufferInfo *bufInfo[MAXSCREENS];
|
|
static DevUnion *bufFrameBuffer[MAXSCREENS];
|
|
static DevUnion bufselectPlane[MAXSCREENS];
|
|
static void (* bufCopyBufferBitsFunc[MAXSCREENS])();
|
|
static void (* bufDrawSelectPlaneFunc[MAXSCREENS])();
|
|
|
|
static Bool bufMultibufferInit();
|
|
|
|
|
|
void
|
|
RegisterDoubleBufferHardware(pScreen, nInfo, pInfo, frameBuffer, selectPlane,
|
|
CopyBufferBitsFunc, DrawSelectPlaneFunc)
|
|
ScreenPtr pScreen;
|
|
int nInfo;
|
|
xMbufBufferInfo *pInfo;
|
|
DevUnion *frameBuffer;
|
|
DevUnion selectPlane;
|
|
void (* CopyBufferBitsFunc)();
|
|
void (* DrawSelectPlaneFunc)();
|
|
{
|
|
bufNumInfo[pScreen->myNum] = nInfo;
|
|
bufInfo[pScreen->myNum] = pInfo;
|
|
bufFrameBuffer[pScreen->myNum] = frameBuffer;
|
|
bufselectPlane[pScreen->myNum] = selectPlane;
|
|
|
|
bufCopyBufferBitsFunc[pScreen->myNum] = CopyBufferBitsFunc;
|
|
bufDrawSelectPlaneFunc[pScreen->myNum] = DrawSelectPlaneFunc;
|
|
|
|
/* Register ourselves with device-independent multibuffers code */
|
|
RegisterMultibufferInit(pScreen, bufMultibufferInit);
|
|
}
|
|
|
|
|
|
/*
|
|
* Called by Multibuffer extension initialization.
|
|
* Initializes mbufScreenRec and its devPrivate.
|
|
*/
|
|
|
|
static Bool NoopDDA_True() { return TRUE; }
|
|
static Bool bufPositionWindow();
|
|
static int bufCreateImageBuffers();
|
|
static void bufDestroyImageBuffers();
|
|
static void bufDisplayImageBuffers();
|
|
static void bufClearImageBufferArea();
|
|
static void bufDestroyBuffer();
|
|
static void bufCopyBufferBits();
|
|
static void bufDrawSelectPlane();
|
|
static void bufWrapScreenFuncs();
|
|
static void bufResetProc();
|
|
|
|
static void bufPostValidateTree();
|
|
static void bufClipNotify();
|
|
static void bufWindowExposures();
|
|
static Bool bufChangeWindowAttributes();
|
|
static void bufClearToBackground();
|
|
static void bufCopyWindow();
|
|
|
|
extern WindowPtr *WindowTable;
|
|
|
|
static Bool
|
|
bufMultibufferInit(pScreen, pMBScreen)
|
|
ScreenPtr pScreen;
|
|
mbufScreenPtr pMBScreen;
|
|
{
|
|
mbufBufferPrivPtr pMBPriv;
|
|
BoxRec box;
|
|
|
|
/* Multibuffer info */
|
|
pMBScreen->nInfo = bufNumInfo[pScreen->myNum];
|
|
pMBScreen->pInfo = bufInfo[pScreen->myNum];
|
|
|
|
/* Hooks */
|
|
pMBScreen->CreateImageBuffers = bufCreateImageBuffers;
|
|
pMBScreen->DestroyImageBuffers = bufDestroyImageBuffers;
|
|
pMBScreen->DisplayImageBuffers = bufDisplayImageBuffers;
|
|
pMBScreen->ClearImageBufferArea = bufClearImageBufferArea;
|
|
pMBScreen->ChangeMBufferAttributes = NoopDDA_True;
|
|
pMBScreen->ChangeBufferAttributes = NoopDDA_True;
|
|
pMBScreen->DeleteBufferDrawable = bufDestroyBuffer;
|
|
pMBScreen->WrapScreenFuncs = bufWrapScreenFuncs;
|
|
pMBScreen->ResetProc = bufResetProc;
|
|
/* Create devPrivate part */
|
|
pMBPriv = (mbufBufferPrivPtr) xalloc(sizeof *pMBPriv);
|
|
if (!pMBPriv)
|
|
return (FALSE);
|
|
|
|
pMBScreen->devPrivate.ptr = (pointer) pMBPriv;
|
|
pMBPriv->frameBuffer = bufFrameBuffer[pScreen->myNum];
|
|
pMBPriv->selectPlane = bufselectPlane[pScreen->myNum];
|
|
|
|
/*
|
|
* Initializing the subtractRgn to the screen area will ensure that
|
|
* the selectPlane will get cleared on the first PostValidateTree.
|
|
*/
|
|
|
|
box.x1 = 0;
|
|
box.y1 = 0;
|
|
box.x2 = pScreen->width;
|
|
box.y2 = pScreen->height;
|
|
|
|
pMBPriv->rgnChanged = TRUE;
|
|
REGION_INIT(pScreen, &pMBPriv->backBuffer, &box, 1);
|
|
REGION_INIT(pScreen, &pMBPriv->subtractRgn, &box, 1);
|
|
REGION_NULL(pScreen, &pMBPriv->unionRgn);
|
|
|
|
/* Misc functions */
|
|
pMBPriv->CopyBufferBits = bufCopyBufferBitsFunc[pScreen->myNum];
|
|
pMBPriv->DrawSelectPlane = bufDrawSelectPlaneFunc[pScreen->myNum];
|
|
|
|
if (!pMBPriv->CopyBufferBits)
|
|
pMBPriv->CopyBufferBits = bufCopyBufferBits;
|
|
|
|
if (!pMBPriv->DrawSelectPlane)
|
|
pMBPriv->DrawSelectPlane = bufDrawSelectPlane;
|
|
|
|
/* screen functions */
|
|
pMBPriv->funcsWrapped = 0;
|
|
pMBPriv->inClearToBackground = FALSE;
|
|
pMBPriv->WindowExposures = NULL;
|
|
pMBPriv->CopyWindow = NULL;
|
|
pMBPriv->ClearToBackground = NULL;
|
|
pMBPriv->ClipNotify = NULL;
|
|
pMBPriv->ChangeWindowAttributes = NULL;
|
|
|
|
/* Start out wrapped to clear select plane */
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
UpdateBufferFromWindow(pBuffer, pWin)
|
|
BufferPtr pBuffer;
|
|
WindowPtr pWin;
|
|
{
|
|
pBuffer->drawable.x = pWin->drawable.x;
|
|
pBuffer->drawable.y = pWin->drawable.y;
|
|
pBuffer->drawable.width = pWin->drawable.width;
|
|
pBuffer->drawable.height = pWin->drawable.height;
|
|
|
|
pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
|
|
|
/* Update for PaintWindowBackground */
|
|
pBuffer->parent = pWin->parent;
|
|
|
|
/*
|
|
* Make the borderClip the same as the clipList so
|
|
* NotClippedByChildren comes out with just clipList.
|
|
*/
|
|
|
|
pBuffer->clipList = pWin->clipList;
|
|
pBuffer->borderClip = pWin->clipList;
|
|
pBuffer->winSize = pWin->winSize;
|
|
pBuffer->borderSize = pWin->borderSize;
|
|
|
|
pBuffer->origin = pWin->origin;
|
|
}
|
|
|
|
static BufferPtr
|
|
bufCreateBuffer(pScreen, pWin, bufferNum)
|
|
ScreenPtr pScreen;
|
|
WindowPtr pWin;
|
|
int bufferNum;
|
|
{
|
|
mbufBufferPrivPtr pMBPriv;
|
|
DevUnion *devPrivates;
|
|
BufferPtr pBuffer;
|
|
int i;
|
|
|
|
pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
pBuffer = AllocateWindow(pWin->drawable.pScreen);
|
|
if (!pBuffer)
|
|
return (NULL);
|
|
|
|
/* XXX- Until we know what is needed, copy everything. */
|
|
devPrivates = pBuffer->devPrivates;
|
|
*pBuffer = *pWin;
|
|
pBuffer->devPrivates = devPrivates;
|
|
|
|
pBuffer->drawable.type = DRAWABLE_BUFFER;
|
|
pBuffer->drawable.serialNumber = NEXT_SERIAL_NUMBER;
|
|
|
|
pBuffer->nextSib = NULL;
|
|
pBuffer->prevSib = NULL;
|
|
pBuffer->firstChild = NULL;
|
|
pBuffer->lastChild = NULL;
|
|
|
|
/* XXX - Need to call pScreen->CreateWindow for tile/stipples
|
|
* or should I just copy the devPrivates?
|
|
*/
|
|
|
|
for (i=0; i < pScreen->WindowPrivateLen; i++)
|
|
pBuffer->devPrivates[i] = pWin->devPrivates[i];
|
|
|
|
pBuffer->devPrivates[frameWindowPrivateIndex] =
|
|
pMBPriv->frameBuffer[bufferNum];
|
|
|
|
return pBuffer;
|
|
}
|
|
|
|
static void
|
|
bufDestroyBuffer(pDrawable)
|
|
DrawablePtr pDrawable;
|
|
{
|
|
xfree(pDrawable);
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
static int
|
|
bufCreateImageBuffers (pWin, nbuf, ids, action, hint)
|
|
WindowPtr pWin;
|
|
int nbuf;
|
|
XID *ids;
|
|
int action;
|
|
int hint;
|
|
{
|
|
ScreenPtr pScreen;
|
|
mbufScreenPtr pMBScreen;
|
|
mbufWindowPtr pMBWindow;
|
|
mbufBufferPtr pMBBuffer;
|
|
int i;
|
|
|
|
pScreen = pWin->drawable.pScreen;
|
|
pMBScreen = MB_SCREEN_PRIV(pScreen);
|
|
pMBWindow = MB_WINDOW_PRIV(pWin);
|
|
|
|
pMBWindow->devPrivate.ptr = (pointer) REGION_CREATE(pScreen, 0,0);
|
|
if (!pMBWindow->devPrivate.ptr)
|
|
return(0);
|
|
REGION_COPY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr,
|
|
&pWin->clipList);
|
|
|
|
for (i = 0; i < nbuf; i++)
|
|
{
|
|
pMBBuffer = pMBWindow->buffers + i;
|
|
pMBBuffer->pDrawable = (DrawablePtr) bufCreateBuffer(pScreen,pWin,i);
|
|
|
|
if (!pMBBuffer->pDrawable)
|
|
break;
|
|
|
|
if (!AddResource (ids[i], MultibufferDrawableResType,
|
|
(pointer) pMBBuffer->pDrawable))
|
|
{
|
|
bufDestroyBuffer((BufferPtr) pMBBuffer->pDrawable);
|
|
break;
|
|
}
|
|
pMBBuffer->pDrawable->id = ids[i];
|
|
|
|
/*
|
|
* If window is already mapped, generate exposures and
|
|
* clear the area of the newly buffers.
|
|
*/
|
|
|
|
if ((pWin->realized) && (i != pMBWindow->displayedMultibuffer))
|
|
(* pMBScreen->ClearImageBufferArea)(pMBBuffer, 0,0, 0,0, TRUE);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static void
|
|
bufDestroyImageBuffers(pWin)
|
|
WindowPtr pWin;
|
|
{
|
|
ScreenPtr pScreen;
|
|
mbufWindowPtr pMBWindow;
|
|
|
|
pScreen = pWin->drawable.pScreen;
|
|
|
|
if (pMBWindow = MB_WINDOW_PRIV(pWin))
|
|
{
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
/*
|
|
* if the backbuffer is currently being displayed, move the bits
|
|
* to the frontbuffer and display it instead.
|
|
*/
|
|
|
|
if (pWin->realized && (pMBWindow->displayedMultibuffer == BACK_BUFFER))
|
|
{
|
|
(* pMBPriv->CopyBufferBits)(pMBWindow, BACK_BUFFER, FRONT_BUFFER);
|
|
REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer,
|
|
&pMBPriv->backBuffer, &pWin->clipList);
|
|
(* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
|
|
&pWin->clipList, FRONT_BUFFER);
|
|
}
|
|
|
|
/* Switch window rendering to front buffer */
|
|
pWin->devPrivates[frameWindowPrivateIndex] =
|
|
pMBPriv->frameBuffer[FRONT_BUFFER];
|
|
|
|
REGION_DESTROY(pScreen, (RegionPtr) pMBWindow->devPrivate.ptr);
|
|
pMBWindow->devPrivate.ptr = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Can be replaced by pScreen->ClearToBackground if pBuffer->eventMask
|
|
* and wOtherEventsMasks(pBuffer) were setup.
|
|
*/
|
|
|
|
static void
|
|
bufClearImageBufferArea(pMBBuffer, x,y, w,h, generateExposures)
|
|
mbufBufferPtr pMBBuffer;
|
|
short x,y;
|
|
unsigned short w,h;
|
|
Bool generateExposures;
|
|
{
|
|
BoxRec box;
|
|
RegionRec reg;
|
|
RegionPtr pBSReg = NullRegion;
|
|
ScreenPtr pScreen;
|
|
BoxPtr extents;
|
|
int x1, y1, x2, y2;
|
|
BufferPtr pBuffer;
|
|
|
|
pBuffer = (BufferPtr) pMBBuffer->pDrawable;
|
|
/* compute everything using ints to avoid overflow */
|
|
|
|
x1 = pBuffer->drawable.x + x;
|
|
y1 = pBuffer->drawable.y + y;
|
|
if (w)
|
|
x2 = x1 + (int) w;
|
|
else
|
|
x2 = x1 + (int) pBuffer->drawable.width - (int) x;
|
|
if (h)
|
|
y2 = y1 + h;
|
|
else
|
|
y2 = y1 + (int) pBuffer->drawable.height - (int) y;
|
|
|
|
extents = &pBuffer->clipList.extents;
|
|
|
|
/* clip the resulting rectangle to the window clipList extents. This
|
|
* makes sure that the result will fit in a box, given that the
|
|
* screen is < 32768 on a side.
|
|
*/
|
|
|
|
if (x1 < extents->x1)
|
|
x1 = extents->x1;
|
|
if (x2 > extents->x2)
|
|
x2 = extents->x2;
|
|
if (y1 < extents->y1)
|
|
y1 = extents->y1;
|
|
if (y2 > extents->y2)
|
|
y2 = extents->y2;
|
|
|
|
if (x2 <= x1 || y2 <= y1)
|
|
{
|
|
x2 = x1 = 0;
|
|
y2 = y1 = 0;
|
|
}
|
|
|
|
box.x1 = x1;
|
|
box.x2 = x2;
|
|
box.y1 = y1;
|
|
box.y2 = y2;
|
|
|
|
pScreen = pBuffer->drawable.pScreen;
|
|
REGION_INIT(pScreen, ®, &box, 1);
|
|
|
|
REGION_INTERSECT(pScreen, ®, ®, &pBuffer->clipList);
|
|
if (pBuffer->backgroundState != None)
|
|
miPaintWindow(pBuffer, ®, PW_BACKGROUND);
|
|
if (generateExposures)
|
|
MultibufferExpose(pMBBuffer, ®);
|
|
#ifdef _notdef
|
|
/* XXBS - This is the original miClearToBackground code.
|
|
* WindowExposures needs to be called (or the functionality emulated)
|
|
* in order for backingStore to work, but first, pBuffer->eventMask
|
|
* and wOtherEventsMasks(pBuffer) need to be setup correctly.
|
|
*/
|
|
|
|
if (generateExposures)
|
|
(*pScreen->WindowExposures)(pBuffer, ®, pBSReg);
|
|
else if (pBuffer->backgroundState != None)
|
|
miPaintWindow(pBuffer, ®, PW_BACKGROUND);
|
|
#endif
|
|
REGION_UNINIT(pScreen, ®);
|
|
if (pBSReg)
|
|
REGION_DESTROY(pScreen, pBSReg);
|
|
}
|
|
|
|
static void
|
|
bufWrapScreenFuncs(pScreen)
|
|
ScreenPtr pScreen;
|
|
{
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,PostValidateTree, bufPostValidateTree);
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClipNotify, bufClipNotify);
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,WindowExposures,bufWindowExposures);
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,ChangeWindowAttributes, bufChangeWindowAttributes);
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,ClearToBackground,bufClearToBackground);
|
|
WRAP_SCREEN_FUNC(pScreen,pMBPriv,CopyWindow,bufCopyWindow);
|
|
}
|
|
|
|
static void
|
|
bufResetProc(pScreen)
|
|
ScreenPtr pScreen;
|
|
{
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
/*
|
|
* frameBuffer, selectPlane, and pInfo should be freed by
|
|
* whoever called RegisterDoubleBufferHardware
|
|
*/
|
|
|
|
REGION_UNINIT(pScreen, &pMBPriv->backBuffer);
|
|
REGION_UNINIT(pScreen, &pMBPriv->subtractRgn);
|
|
REGION_UNINIT(pScreen, &pMBPriv->unionRgn);
|
|
xfree(pMBPriv);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Used if CopyBufferBitsFunc is not provided when registering.
|
|
* This should work for everybody since CopyArea needs to support
|
|
* copying between buffers anyway.
|
|
*/
|
|
|
|
static void
|
|
bufCopyBufferBits(pMBWindow, srcBufferNum, dstBufferNum)
|
|
mbufWindowPtr pMBWindow;
|
|
int srcBufferNum, dstBufferNum;
|
|
{
|
|
DrawablePtr pSrcBuffer, pDstBuffer;
|
|
GCPtr pGC;
|
|
|
|
pSrcBuffer = pMBWindow->buffers[srcBufferNum].pDrawable;
|
|
pDstBuffer = pMBWindow->buffers[dstBufferNum].pDrawable;
|
|
|
|
pGC = GetScratchGC (pDstBuffer->depth, pDstBuffer->pScreen);
|
|
if (!pGC)
|
|
return;
|
|
|
|
ValidateGC (pDstBuffer, pGC);
|
|
(* pGC->ops->CopyArea) (pSrcBuffer, pDstBuffer, pGC,
|
|
0,0, pDstBuffer->width, pDstBuffer->height, 0,0);
|
|
FreeScratchGC (pGC);
|
|
}
|
|
|
|
/*
|
|
* Used if DrawSelectPlanFunc is not provided for when registering.
|
|
* However, it only works if selectPlane.ptr is a drawable. Also
|
|
* assumes that painting with color 0 selects the front buffer,
|
|
* while color 1 selects the back buffer.
|
|
*/
|
|
|
|
static void
|
|
bufDrawSelectPlane(pScreen, selectPlane, prgn, bufferNum)
|
|
ScreenPtr pScreen;
|
|
DevUnion selectPlane;
|
|
RegionPtr prgn;
|
|
long bufferNum;
|
|
{
|
|
DrawablePtr pDrawable;
|
|
GCPtr pGC;
|
|
register int i;
|
|
register BoxPtr pbox;
|
|
register xRectangle *prect;
|
|
int numRects;
|
|
XID value;
|
|
|
|
if (REGION_NUM_RECTS(prgn) == 0)
|
|
return;
|
|
|
|
pDrawable = (DrawablePtr) selectPlane.ptr;
|
|
pGC = GetScratchGC (pDrawable->depth, pScreen);
|
|
if (!pGC)
|
|
return;
|
|
|
|
prect = (xRectangle *)xalloc(REGION_NUM_RECTS(prgn) *
|
|
sizeof(xRectangle));
|
|
if (!prect)
|
|
{
|
|
FreeScratchGC(pGC);
|
|
return;
|
|
}
|
|
|
|
value = (XID) bufferNum;
|
|
DoChangeGC(pGC, GCForeground, &value, 0);
|
|
ValidateGC(pDrawable, pGC);
|
|
|
|
numRects = REGION_NUM_RECTS(prgn);
|
|
pbox = REGION_RECTS(prgn);
|
|
for (i= numRects; --i >= 0; pbox++, prect++)
|
|
{
|
|
prect->x = pbox->x1;
|
|
prect->y = pbox->y1;
|
|
prect->width = pbox->x2 - pbox->x1;
|
|
prect->height = pbox->y2 - pbox->y1;
|
|
}
|
|
prect -= numRects;
|
|
(* pGC->ops->PolyFillRect)(pDrawable, pGC, numRects, prect);
|
|
|
|
xfree(prect);
|
|
FreeScratchGC (pGC);
|
|
}
|
|
|
|
|
|
static void
|
|
bufDisplayImageBuffers(pScreen, ppMBWindow, ppMBBuffer, nbuf)
|
|
ScreenPtr pScreen;
|
|
mbufBufferPtr *ppMBBuffer;
|
|
mbufWindowPtr *ppMBWindow;
|
|
int nbuf;
|
|
{
|
|
WindowPtr pWin;
|
|
BufferPtr pPrevBuffer, pNewBuffer;
|
|
int i, number;
|
|
mbufBufferPrivPtr pMBPriv;
|
|
mbufBufferPtr pPrevMBBuffer;
|
|
|
|
pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
for (i = 0; i < nbuf; i++)
|
|
{
|
|
number = ppMBBuffer[i]->number; /* 0=frontbuffer, 1=backbuffer */
|
|
pWin = ppMBWindow[i]->pWindow;
|
|
pPrevMBBuffer = MB_DISPLAYED_BUFFER(ppMBWindow[i]);
|
|
|
|
pPrevBuffer = (BufferPtr) pPrevMBBuffer->pDrawable;
|
|
pNewBuffer = (BufferPtr) ppMBBuffer[i]->pDrawable;
|
|
|
|
if (pPrevBuffer != pNewBuffer)
|
|
{
|
|
RegionPtr backBuffer = &pMBPriv->backBuffer;
|
|
|
|
/*
|
|
* Update the select plane and the backBuffer region.
|
|
*/
|
|
|
|
(* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
|
|
&pWin->clipList, number);
|
|
|
|
if (number == BACK_BUFFER)
|
|
REGION_UNION(pScreen, backBuffer, backBuffer,
|
|
&pWin->clipList);
|
|
else
|
|
REGION_SUBTRACT(pScreen, backBuffer, backBuffer,
|
|
&pWin->clipList);
|
|
|
|
/* Switch which framebuffer the window draws into */
|
|
pWin->devPrivates[frameWindowPrivateIndex] =
|
|
pMBPriv->frameBuffer[number];
|
|
}
|
|
|
|
switch (ppMBWindow[i]->updateAction)
|
|
{
|
|
case MultibufferUpdateActionUndefined:
|
|
break;
|
|
case MultibufferUpdateActionBackground:
|
|
(* MB_SCREEN_PRIV(pScreen)->ClearImageBufferArea)
|
|
(pPrevMBBuffer, 0,0, 0,0, FALSE);
|
|
break;
|
|
case MultibufferUpdateActionUntouched:
|
|
break;
|
|
case MultibufferUpdateActionCopied:
|
|
if (pPrevBuffer != pNewBuffer)
|
|
{
|
|
(* pMBPriv->CopyBufferBits) (ppMBWindow[i],
|
|
ppMBBuffer[i]->number, pPrevMBBuffer->number);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Updates the backBuffer region and paints the selectPlane. */
|
|
|
|
static void
|
|
bufPostValidateTree(pParent, pChild, kind)
|
|
WindowPtr pParent, pChild;
|
|
VTKind kind;
|
|
{
|
|
ScreenPtr pScreen;
|
|
mbufBufferPrivPtr pMBPriv;
|
|
|
|
if (pParent)
|
|
pScreen = pParent->drawable.pScreen;
|
|
else if (pChild)
|
|
pScreen = pChild->drawable.pScreen;
|
|
else
|
|
return; /* Hopeless */
|
|
|
|
pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
|
|
if (pScreen->PostValidateTree)
|
|
(* pScreen->PostValidateTree)(pParent, pChild, kind);
|
|
REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, PostValidateTree);
|
|
|
|
/* Does backBuffer need to change? */
|
|
if (pMBPriv->rgnChanged)
|
|
{
|
|
RegionRec exposed;
|
|
RegionPtr pSubtractRgn, pUnionRgn;
|
|
Bool overlap;
|
|
|
|
pMBPriv->rgnChanged = FALSE;
|
|
|
|
pSubtractRgn = &pMBPriv->subtractRgn;
|
|
pUnionRgn = &pMBPriv->unionRgn;
|
|
REGION_VALIDATE(pScreen, pSubtractRgn, &overlap);
|
|
#ifdef DEBUG
|
|
if (overlap)
|
|
FatalError("bufPostValidateTree: subtractRgn overlaps");
|
|
#endif
|
|
REGION_VALIDATE(pScreen, pUnionRgn, &overlap);
|
|
#ifdef DEBUG
|
|
if (overlap)
|
|
FatalError("bufPostValidateTree: unionRgn overlaps");
|
|
#endif
|
|
|
|
/* Update backBuffer: subtract must come before union */
|
|
REGION_SUBTRACT(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
|
|
pSubtractRgn);
|
|
REGION_UNION(pScreen, &pMBPriv->backBuffer, &pMBPriv->backBuffer,
|
|
pUnionRgn);
|
|
|
|
/* Paint gained and lost backbuffer areas in select plane */
|
|
REGION_NULL(pScreen, &exposed);
|
|
REGION_SUBTRACT(pScreen, &exposed, pSubtractRgn, pUnionRgn);
|
|
(* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
|
|
&exposed, FRONT_BUFFER);
|
|
|
|
REGION_SUBTRACT(pScreen, &exposed, pUnionRgn, pSubtractRgn);
|
|
(* pMBPriv->DrawSelectPlane)(pScreen, pMBPriv->selectPlane,
|
|
&exposed, BACK_BUFFER);
|
|
|
|
REGION_UNINIT(pScreen, &exposed);
|
|
REGION_EMPTY(pScreen, pSubtractRgn);
|
|
REGION_EMPTY(pScreen, pUnionRgn);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If the window is multibuffered and displaying the backbuffer,
|
|
* add the old clipList to the subtractRgn and add the new clipList
|
|
* to the unionRgn. PostValidateTree will use subtractRgn and unionRgn
|
|
* to update the backBuffer region and the selectPlane.
|
|
*
|
|
* Copy changes to the window structure into the buffers.
|
|
* Send ClobberNotify events.
|
|
*/
|
|
|
|
static void
|
|
bufClipNotify(pWin, dx,dy)
|
|
WindowPtr pWin;
|
|
int dx,dy;
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
mbufWindowPtr pMBWindow;
|
|
int i;
|
|
|
|
UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
|
|
if (pScreen->ClipNotify)
|
|
(* pScreen->ClipNotify)(pWin, dx,dy);
|
|
REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClipNotify);
|
|
|
|
if (pMBWindow = MB_WINDOW_PRIV(pWin))
|
|
{
|
|
RegionPtr pOldClipList = (RegionPtr) pMBWindow->devPrivate.ptr;
|
|
|
|
if (! REGION_EQUAL(pScreen, pOldClipList, &pWin->clipList))
|
|
{
|
|
if (pMBWindow->displayedMultibuffer == BACK_BUFFER)
|
|
{
|
|
pMBPriv->rgnChanged = TRUE;
|
|
REGION_APPEND(pScreen, &pMBPriv->subtractRgn, pOldClipList);
|
|
REGION_APPEND(pScreen, &pMBPriv->unionRgn, &pWin->clipList);
|
|
}
|
|
|
|
REGION_COPY(pScreen, pOldClipList,&pWin->clipList);
|
|
}
|
|
|
|
/* Update buffer x,y,w,h, and clipList */
|
|
for (i=0; i<pMBWindow->numMultibuffer; i++)
|
|
{
|
|
mbufBufferPtr pMBBuffer = pMBWindow->buffers + i;
|
|
if (pMBBuffer->clobber != pWin->visibility)
|
|
{
|
|
pMBBuffer->clobber = pWin->visibility;
|
|
MultibufferClobber(pMBBuffer);
|
|
}
|
|
UpdateBufferFromWindow(pMBBuffer->pDrawable, pWin);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Updates buffer's background fields when the window's changes.
|
|
* This is necessary because miPaintWindow is used to paint the buffer.
|
|
*
|
|
* XXBS - Backingstore state will have be tracked too if it is supported.
|
|
*/
|
|
|
|
static Bool
|
|
bufChangeWindowAttributes(pWin, mask)
|
|
WindowPtr pWin;
|
|
unsigned long mask;
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
mbufWindowPtr pMBWindow;
|
|
Bool ret;
|
|
|
|
UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
|
|
ret = (* pScreen->ChangeWindowAttributes)(pWin, mask);
|
|
REWRAP_SCREEN_FUNC(pScreen, pMBPriv, Bool, ChangeWindowAttributes);
|
|
|
|
if (pMBWindow = MB_WINDOW_PRIV(pWin))
|
|
{
|
|
if (mask & (CWBackPixmap | CWBackPixel))
|
|
{
|
|
BufferPtr pBuffer;
|
|
int i;
|
|
|
|
for (i=0; i<pMBWindow->displayedMultibuffer; i++)
|
|
{
|
|
pBuffer = (BufferPtr) pMBWindow->buffers[i].pDrawable;
|
|
pBuffer->backgroundState = pWin->backgroundState;
|
|
pBuffer->background = pWin->background;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Send exposures and clear the background for a buffer whenever
|
|
* its corresponding window is exposed, except when called by
|
|
* ClearToBackground.
|
|
*/
|
|
|
|
static void
|
|
bufWindowExposures(pWin, prgn, other_exposed)
|
|
WindowPtr pWin;
|
|
register RegionPtr prgn, other_exposed;
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
mbufWindowPtr pMBWindow = MB_WINDOW_PRIV(pWin);
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
RegionRec tmp_rgn;
|
|
int i;
|
|
Bool handleBuffers;
|
|
|
|
handleBuffers = (!pMBPriv->inClearToBackground) &&
|
|
(pWin->drawable.type == DRAWABLE_WINDOW) &&
|
|
pMBWindow && (prgn && !REGION_NIL(prgn));
|
|
|
|
/* miWindowExposures munges prgn and other_exposed. */
|
|
if (handleBuffers)
|
|
{
|
|
REGION_NULL(pScreen, &tmp_rgn);
|
|
REGION_COPY(pScreen, &tmp_rgn, prgn);
|
|
}
|
|
|
|
UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
|
|
(* pScreen->WindowExposures) (pWin, prgn, other_exposed);
|
|
REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, WindowExposures);
|
|
|
|
if (!handleBuffers)
|
|
return;
|
|
|
|
/*
|
|
* Send expose events to all clients. Paint the exposed region for all
|
|
* buffers except the displayed buffer since it is handled when the
|
|
* window is painted.
|
|
*
|
|
* XXBS - Will have to be re-written to handle BackingStore on buffers.
|
|
*/
|
|
|
|
for (i=0; i<pMBWindow->numMultibuffer; i++)
|
|
{
|
|
mbufBufferPtr pMBBuffer;
|
|
BufferPtr pBuffer;
|
|
|
|
pMBBuffer = pMBWindow->buffers + i;
|
|
pBuffer = (BufferPtr) pMBBuffer->pDrawable;
|
|
|
|
if (i != pMBWindow->displayedMultibuffer)
|
|
miPaintWindow(pBuffer, &tmp_rgn, PW_BACKGROUND);
|
|
if ((pMBBuffer->otherEventMask | pMBBuffer->eventMask) & ExposureMask)
|
|
MultibufferExpose(pMBBuffer, &tmp_rgn);
|
|
}
|
|
|
|
REGION_UNINIT(pScreen, &tmp_rgn);
|
|
}
|
|
|
|
/*
|
|
* Set ``inClearToBackground'' so that WindowExposures does not attempt
|
|
* to send expose events or clear the background on the buffers.
|
|
*/
|
|
|
|
static void
|
|
bufClearToBackground(pWin, x,y,w,h, sendExpose)
|
|
WindowPtr pWin;
|
|
int x,y, w,h;
|
|
Bool sendExpose;
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
|
|
pMBPriv->inClearToBackground = TRUE;
|
|
|
|
UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
|
|
(* pScreen->ClearToBackground)(pWin, x,y,w,h, sendExpose);
|
|
REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, ClearToBackground);
|
|
|
|
pMBPriv->inClearToBackground = FALSE;
|
|
}
|
|
|
|
/*
|
|
* Move bits in both buffers. It does this by calling pScreen->CopyWindow
|
|
* twice, once with the root window's devPrivate[frameWindowPrivateIndex]
|
|
* pointing to the frontbuffer pixmap and once with it pointed to the
|
|
* backbuffer pixmap. It does this if there are *any* existing multibuffered
|
|
* window... a possible optimization is to copy the backbuffer only if this
|
|
* window or its inferiors are multibuffered. May be faster, maybe not.
|
|
*
|
|
* XXX - Only works if your CopyWindow checks the root window's devPrivate
|
|
* to see which buffer to draw into. Works for cfbPaintWindow.
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
static void
|
|
bufCopyWindow(pWin, ptOldOrg, prgnSrc)
|
|
WindowPtr pWin;
|
|
DDXPointRec ptOldOrg;
|
|
RegionPtr prgnSrc;
|
|
{
|
|
ScreenPtr pScreen = pWin->drawable.pScreen;
|
|
mbufBufferPrivPtr pMBPriv = MB_SCREEN_PRIV_BUFFER(pScreen);
|
|
WindowPtr pwinroot;
|
|
DevUnion save;
|
|
|
|
UNWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
|
|
|
|
pwinroot = WindowTable[pScreen->myNum];
|
|
save = pwinroot->devPrivates[frameWindowPrivateIndex];
|
|
|
|
/*
|
|
* Copy front buffer
|
|
*/
|
|
|
|
pwinroot->devPrivates[frameWindowPrivateIndex] =
|
|
pMBPriv->frameBuffer[FRONT_BUFFER];
|
|
(* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
|
|
|
|
/*
|
|
* Copy back buffer
|
|
*/
|
|
|
|
/* CopyWindow translates prgnSrc... translate it back for 2nd call. */
|
|
REGION_TRANSLATE(pScreen, prgnSrc,
|
|
ptOldOrg.x - pWin->drawable.x,
|
|
ptOldOrg.y - pWin->drawable.y);
|
|
pwinroot->devPrivates[frameWindowPrivateIndex] =
|
|
pMBPriv->frameBuffer[BACK_BUFFER];
|
|
(* pScreen->CopyWindow)(pWin, ptOldOrg, prgnSrc);
|
|
|
|
pwinroot->devPrivates[frameWindowPrivateIndex] = save;
|
|
REWRAP_SCREEN_FUNC(pScreen, pMBPriv, void, CopyWindow);
|
|
}
|