1764 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1764 lines
		
	
	
		
			48 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 <X11/X.h>
 | 
						|
#include <X11/Xproto.h>
 | 
						|
#include "window.h"
 | 
						|
#include "os.h"
 | 
						|
#include "windowstr.h"
 | 
						|
#include "scrnintstr.h"
 | 
						|
#include "pixmapstr.h"
 | 
						|
#include "gcstruct.h"
 | 
						|
#include "extnsionst.h"
 | 
						|
#include "dixstruct.h"
 | 
						|
#include "resource.h"
 | 
						|
#include "opaque.h"
 | 
						|
#include "sleepuntil.h"
 | 
						|
#define _MULTIBUF_SERVER_	/* don't want Xlib structures */
 | 
						|
#include <X11/extensions/multibufst.h>
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#if !defined(WIN32) && !defined(Lynx)
 | 
						|
#include <sys/time.h>
 | 
						|
#endif
 | 
						|
 | 
						|
/* given an OtherClientPtr obj, get the ClientPtr */
 | 
						|
#define rClient(obj) (clients[CLIENT_ID((obj)->resource)])
 | 
						|
 | 
						|
/* given a MultibufferPtr b, get the ClientPtr */
 | 
						|
#define bClient(b)   (clients[CLIENT_ID(b->pPixmap->drawable.id)])
 | 
						|
 | 
						|
#define ValidEventMasks (ExposureMask|MultibufferClobberNotifyMask|MultibufferUpdateNotifyMask)
 | 
						|
 | 
						|
static int		MultibufferEventBase;
 | 
						|
static int		MultibufferErrorBase;
 | 
						|
static DevPrivateKey MultibufferScreenPrivKey = &MultibufferScreenPrivKey;
 | 
						|
static DevPrivateKey MultibufferWindowPrivKey = &MultibufferWindowPrivKey;
 | 
						|
 | 
						|
static void		PerformDisplayRequest (
 | 
						|
				MultibuffersPtr * /* ppMultibuffers */,
 | 
						|
				MultibufferPtr * /* pMultibuffer */,
 | 
						|
				int /* nbuf */
 | 
						|
				);
 | 
						|
static Bool		QueueDisplayRequest (
 | 
						|
				ClientPtr /* client */,
 | 
						|
				TimeStamp /* activateTime */
 | 
						|
				);
 | 
						|
 | 
						|
static void		BumpTimeStamp (
 | 
						|
				TimeStamp * /* ts */,
 | 
						|
				CARD32 /* inc */
 | 
						|
				);
 | 
						|
 | 
						|
static void		AliasMultibuffer (
 | 
						|
				MultibuffersPtr /* pMultibuffers */,
 | 
						|
				int /* i */
 | 
						|
				);
 | 
						|
static void		RecalculateMultibufferOtherEvents (
 | 
						|
				MultibufferPtr /* pMultibuffer */
 | 
						|
				);
 | 
						|
static int		EventSelectForMultibuffer(
 | 
						|
				MultibufferPtr /* pMultibuffer */,
 | 
						|
				ClientPtr /* client */,
 | 
						|
				Mask /* mask */
 | 
						|
				);
 | 
						|
 | 
						|
/*
 | 
						|
 * The Pixmap associated with a buffer can be found as a resource
 | 
						|
 * with this type
 | 
						|
 */
 | 
						|
RESTYPE			MultibufferDrawableResType;
 | 
						|
static int		MultibufferDrawableDelete (
 | 
						|
				pointer /* value */,
 | 
						|
				XID /* id */
 | 
						|
				);
 | 
						|
/*
 | 
						|
 * The per-buffer data can be found as a resource with this type.
 | 
						|
 * the resource id of the per-buffer data is the same as the resource
 | 
						|
 * id of the pixmap
 | 
						|
 */
 | 
						|
static RESTYPE		MultibufferResType;
 | 
						|
static int		MultibufferDelete (
 | 
						|
				pointer /* value */,
 | 
						|
				XID /* id */
 | 
						|
				);
 | 
						|
 | 
						|
/*
 | 
						|
 * The per-window data can be found as a resource with this type,
 | 
						|
 * using the window resource id
 | 
						|
 */
 | 
						|
static RESTYPE		MultibuffersResType;
 | 
						|
static int		MultibuffersDelete (
 | 
						|
				pointer /* value */,
 | 
						|
				XID /* id */
 | 
						|
				);
 | 
						|
 | 
						|
/*
 | 
						|
 * Clients other than the buffer creator attach event masks in
 | 
						|
 * OtherClient structures; each has a resource of this type.
 | 
						|
 */
 | 
						|
static RESTYPE		OtherClientResType;
 | 
						|
static int		OtherClientDelete (
 | 
						|
				pointer /* value */,
 | 
						|
				XID /* id */
 | 
						|
				);
 | 
						|
 | 
						|
/****************
 | 
						|
 * MultibufferExtensionInit
 | 
						|
 *
 | 
						|
 * Called from InitExtensions in main()
 | 
						|
 *
 | 
						|
 ****************/
 | 
						|
 | 
						|
extern DISPATCH_PROC(ProcGetBufferAttributes);
 | 
						|
 | 
						|
static DISPATCH_PROC(ProcClearImageBufferArea);
 | 
						|
static DISPATCH_PROC(ProcCreateImageBuffers);
 | 
						|
static DISPATCH_PROC(ProcDestroyImageBuffers);
 | 
						|
static DISPATCH_PROC(ProcDisplayImageBuffers);
 | 
						|
static DISPATCH_PROC(ProcGetBufferInfo);
 | 
						|
static DISPATCH_PROC(ProcGetBufferVersion);
 | 
						|
static DISPATCH_PROC(ProcGetMBufferAttributes);
 | 
						|
static DISPATCH_PROC(ProcMultibufferDispatch);
 | 
						|
static DISPATCH_PROC(ProcSetBufferAttributes);
 | 
						|
static DISPATCH_PROC(ProcSetMBufferAttributes);
 | 
						|
static DISPATCH_PROC(SProcClearImageBufferArea);
 | 
						|
static DISPATCH_PROC(SProcCreateImageBuffers);
 | 
						|
static DISPATCH_PROC(SProcDestroyImageBuffers);
 | 
						|
static DISPATCH_PROC(SProcDisplayImageBuffers);
 | 
						|
static DISPATCH_PROC(SProcGetBufferAttributes);
 | 
						|
static DISPATCH_PROC(SProcGetBufferInfo);
 | 
						|
static DISPATCH_PROC(SProcGetBufferVersion);
 | 
						|
static DISPATCH_PROC(SProcGetMBufferAttributes);
 | 
						|
static DISPATCH_PROC(SProcMultibufferDispatch);
 | 
						|
static DISPATCH_PROC(SProcSetBufferAttributes);
 | 
						|
static DISPATCH_PROC(SProcSetMBufferAttributes);
 | 
						|
 | 
						|
static void		MultibufferResetProc(
 | 
						|
				ExtensionEntry * /* extEntry */
 | 
						|
				);
 | 
						|
static void		SClobberNotifyEvent(
 | 
						|
				xMbufClobberNotifyEvent * /* from */,
 | 
						|
				xMbufClobberNotifyEvent	* /* to */
 | 
						|
				);
 | 
						|
static void		SUpdateNotifyEvent(
 | 
						|
				xMbufUpdateNotifyEvent * /* from */,
 | 
						|
				xMbufUpdateNotifyEvent * /* to */
 | 
						|
				);
 | 
						|
static Bool		MultibufferPositionWindow(
 | 
						|
				WindowPtr /* pWin */,
 | 
						|
				int /* x */,
 | 
						|
				int /* y */
 | 
						|
				);
 | 
						|
 | 
						|
static void		SetupBackgroundPainter (
 | 
						|
				WindowPtr /* pWin */,
 | 
						|
				GCPtr /* pGC */
 | 
						|
				);
 | 
						|
 | 
						|
static int		DeliverEventsToMultibuffer (
 | 
						|
				MultibufferPtr /* pMultibuffer */,
 | 
						|
				xEvent * /* pEvents */,
 | 
						|
				int /* count */,
 | 
						|
				Mask /* filter */
 | 
						|
				);
 | 
						|
 | 
						|
void
 | 
						|
MultibufferExtensionInit()
 | 
						|
{
 | 
						|
    ExtensionEntry	    *extEntry;
 | 
						|
    int			    i, j;
 | 
						|
    ScreenPtr		    pScreen;
 | 
						|
    MultibufferScreenPtr    pMultibufferScreen;
 | 
						|
 | 
						|
    for (i = 0; i < screenInfo.numScreens; i++)
 | 
						|
    {
 | 
						|
	pScreen = screenInfo.screens[i];
 | 
						|
	if (!(pMultibufferScreen = (MultibufferScreenPtr) xalloc (sizeof (MultibufferScreenRec))))
 | 
						|
	{
 | 
						|
	    for (j = 0; j < i; j++)
 | 
						|
		xfree (dixLookupPrivate(&screenInfo.screens[j]->devPrivates, MultibufferScreenPrivKey));
 | 
						|
	    return;
 | 
						|
	}
 | 
						|
	dixSetPrivate(&pScreen->devPrivates, MultibufferScreenPrivKey, pMultibufferScreen);
 | 
						|
	/*
 | 
						|
 	 * wrap PositionWindow to resize the pixmap when the window
 | 
						|
	 * changes size
 | 
						|
 	 */
 | 
						|
	pMultibufferScreen->PositionWindow = pScreen->PositionWindow;
 | 
						|
	pScreen->PositionWindow = MultibufferPositionWindow;
 | 
						|
    }
 | 
						|
    /*
 | 
						|
     * create the resource types
 | 
						|
     */
 | 
						|
    MultibufferDrawableResType =
 | 
						|
	CreateNewResourceType(MultibufferDrawableDelete)|RC_DRAWABLE;
 | 
						|
    MultibufferResType = CreateNewResourceType(MultibufferDelete);
 | 
						|
    MultibuffersResType = CreateNewResourceType(MultibuffersDelete);
 | 
						|
    OtherClientResType = CreateNewResourceType(OtherClientDelete);
 | 
						|
    if (MultibufferDrawableResType && MultibufferResType &&
 | 
						|
	MultibuffersResType && 	OtherClientResType &&
 | 
						|
	(extEntry = AddExtension(MULTIBUFFER_PROTOCOL_NAME,
 | 
						|
				 MultibufferNumberEvents, 
 | 
						|
				 MultibufferNumberErrors,
 | 
						|
				 ProcMultibufferDispatch, SProcMultibufferDispatch,
 | 
						|
				 MultibufferResetProc, StandardMinorOpcode)))
 | 
						|
    {
 | 
						|
	MultibufferEventBase = extEntry->eventBase;
 | 
						|
	MultibufferErrorBase = extEntry->errorBase;
 | 
						|
	EventSwapVector[MultibufferEventBase + MultibufferClobberNotify] = (EventSwapPtr) SClobberNotifyEvent;
 | 
						|
	EventSwapVector[MultibufferEventBase + MultibufferUpdateNotify] = (EventSwapPtr) SUpdateNotifyEvent;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*ARGSUSED*/
 | 
						|
static void
 | 
						|
MultibufferResetProc (extEntry)
 | 
						|
ExtensionEntry	*extEntry;
 | 
						|
{
 | 
						|
    int			    i;
 | 
						|
    ScreenPtr		    pScreen;
 | 
						|
    MultibufferScreenPtr    pMultibufferScreen;
 | 
						|
    
 | 
						|
    for (i = 0; i < screenInfo.numScreens; i++)
 | 
						|
    {
 | 
						|
	pScreen = screenInfo.screens[i];
 | 
						|
	if ((pMultibufferScreen = (MultibufferScreenPtr)dixLookupPrivate(&pScreen->devPrivates, MultibufferScreenPrivKey)))
 | 
						|
	{
 | 
						|
	    pScreen->PositionWindow = pMultibufferScreen->PositionWindow;
 | 
						|
	    xfree (pMultibufferScreen);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcGetBufferVersion (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    xMbufGetBufferVersionReply	rep;
 | 
						|
    register int		n;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH (xMbufGetBufferVersionReq);
 | 
						|
    rep.type = X_Reply;
 | 
						|
    rep.length = 0;
 | 
						|
    rep.sequenceNumber = client->sequence;
 | 
						|
    rep.majorVersion = MULTIBUFFER_MAJOR_VERSION;
 | 
						|
    rep.minorVersion = MULTIBUFFER_MINOR_VERSION;
 | 
						|
    if (client->swapped) {
 | 
						|
    	swaps(&rep.sequenceNumber, n);
 | 
						|
    	swapl(&rep.length, n);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof (xMbufGetBufferVersionReply), (char *)&rep);
 | 
						|
    return (client->noClientException);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
SetupBackgroundPainter (pWin, pGC)
 | 
						|
    WindowPtr	pWin;
 | 
						|
    GCPtr	pGC;
 | 
						|
{
 | 
						|
    pointer	    gcvalues[4];
 | 
						|
    int		    ts_x_origin, ts_y_origin;
 | 
						|
    PixUnion	    background;
 | 
						|
    int		    backgroundState;
 | 
						|
    Mask	    gcmask;
 | 
						|
 | 
						|
    /*
 | 
						|
     * First take care of any ParentRelative stuff by altering the
 | 
						|
     * tile/stipple origin to match the coordinates of the upper-left
 | 
						|
     * corner of the first ancestor without a ParentRelative background.
 | 
						|
     * This coordinate is, of course, negative.
 | 
						|
     */
 | 
						|
 | 
						|
    ts_x_origin = ts_y_origin = 0;
 | 
						|
    while (pWin->backgroundState == ParentRelative) {
 | 
						|
	ts_x_origin -= pWin->origin.x;
 | 
						|
	ts_y_origin -= pWin->origin.y;
 | 
						|
	pWin = pWin->parent;
 | 
						|
    }
 | 
						|
    backgroundState = pWin->backgroundState;
 | 
						|
    background = pWin->background;
 | 
						|
 | 
						|
    switch (backgroundState)
 | 
						|
    {
 | 
						|
    case BackgroundPixel:
 | 
						|
	gcvalues[0] = (pointer) background.pixel;
 | 
						|
	gcvalues[1] = (pointer) FillSolid;
 | 
						|
	gcmask = GCForeground|GCFillStyle;
 | 
						|
	break;
 | 
						|
 | 
						|
    case BackgroundPixmap:
 | 
						|
	gcvalues[0] = (pointer) FillTiled;
 | 
						|
	gcvalues[1] = (pointer) background.pixmap;
 | 
						|
	gcvalues[2] = (pointer)(long) ts_x_origin;
 | 
						|
	gcvalues[3] = (pointer)(long) ts_y_origin;
 | 
						|
	gcmask = GCFillStyle|GCTile|GCTileStipXOrigin|GCTileStipYOrigin;
 | 
						|
	break;
 | 
						|
 | 
						|
    default:
 | 
						|
	gcvalues[0] = (pointer) GXnoop;
 | 
						|
	gcmask = GCFunction;
 | 
						|
    }
 | 
						|
    DoChangeGC(pGC, gcmask, (XID *)gcvalues, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
CreateImageBuffers (pWin, nbuf, ids, action, hint)
 | 
						|
    WindowPtr	pWin;
 | 
						|
    int		nbuf;
 | 
						|
    XID		*ids;
 | 
						|
    int		action;
 | 
						|
    int		hint;
 | 
						|
{
 | 
						|
    MultibuffersPtr	pMultibuffers;
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    ScreenPtr		pScreen;
 | 
						|
    int			width, height, depth;
 | 
						|
    int			i;
 | 
						|
    GCPtr		pClearGC = NULL;
 | 
						|
    xRectangle		clearRect;
 | 
						|
 | 
						|
    DestroyImageBuffers(pWin);
 | 
						|
    pMultibuffers = (MultibuffersPtr) xalloc (sizeof (MultibuffersRec) +
 | 
						|
					      nbuf * sizeof (MultibufferRec));
 | 
						|
    if (!pMultibuffers)
 | 
						|
	return BadAlloc;
 | 
						|
    pMultibuffers->pWindow = pWin;
 | 
						|
    pMultibuffers->buffers = (MultibufferPtr) (pMultibuffers + 1);
 | 
						|
    pMultibuffers->refcnt = pMultibuffers->numMultibuffer = 0;
 | 
						|
    if (!AddResource (pWin->drawable.id, MultibuffersResType, (pointer) pMultibuffers))
 | 
						|
	return BadAlloc;
 | 
						|
    width = pWin->drawable.width;
 | 
						|
    height = pWin->drawable.height;
 | 
						|
    depth = pWin->drawable.depth;
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
 | 
						|
    if (pWin->backgroundState != None)
 | 
						|
    {
 | 
						|
	pClearGC = GetScratchGC (pWin->drawable.depth, pScreen);
 | 
						|
	SetupBackgroundPainter (pWin, pClearGC);
 | 
						|
	clearRect.x = clearRect.y = 0;
 | 
						|
	clearRect.width = width;
 | 
						|
	clearRect.height = height;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < nbuf; i++)
 | 
						|
    {
 | 
						|
	pMultibuffer = &pMultibuffers->buffers[i];
 | 
						|
	pMultibuffer->eventMask = 0L;
 | 
						|
	pMultibuffer->otherEventMask = 0L;
 | 
						|
	pMultibuffer->otherClients = (OtherClientsPtr) NULL;
 | 
						|
	pMultibuffer->number = i;
 | 
						|
	pMultibuffer->side = MultibufferSideMono;
 | 
						|
	pMultibuffer->clobber = MultibufferUnclobbered;
 | 
						|
	pMultibuffer->pMultibuffers = pMultibuffers;
 | 
						|
	if (!AddResource (ids[i], MultibufferResType, (pointer) pMultibuffer))
 | 
						|
	    break;
 | 
						|
	pMultibuffer->pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, depth, 0);
 | 
						|
	if (!pMultibuffer->pPixmap)
 | 
						|
	    break;
 | 
						|
	if (!AddResource (ids[i], MultibufferDrawableResType, (pointer) pMultibuffer->pPixmap))
 | 
						|
	{
 | 
						|
	    FreeResource (ids[i], MultibufferResType);
 | 
						|
	    (*pScreen->DestroyPixmap) (pMultibuffer->pPixmap);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	pMultibuffer->pPixmap->drawable.id = ids[i];
 | 
						|
 | 
						|
	if (i > 0 && pClearGC)
 | 
						|
	{
 | 
						|
	    ValidateGC((DrawablePtr)pMultibuffer->pPixmap, pClearGC);
 | 
						|
	    (*pClearGC->ops->PolyFillRect)((DrawablePtr)pMultibuffer->pPixmap,
 | 
						|
					   pClearGC, 1, &clearRect);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    pMultibuffers->numMultibuffer = i;
 | 
						|
    pMultibuffers->refcnt = i;
 | 
						|
    pMultibuffers->displayedMultibuffer = -1;
 | 
						|
    if (i > 0)
 | 
						|
	AliasMultibuffer (pMultibuffers, 0);
 | 
						|
    pMultibuffers->updateAction = action;
 | 
						|
    pMultibuffers->updateHint = hint;
 | 
						|
    pMultibuffers->windowMode = MultibufferModeMono;
 | 
						|
    pMultibuffers->lastUpdate.months = 0;
 | 
						|
    pMultibuffers->lastUpdate.milliseconds = 0;
 | 
						|
    pMultibuffers->width = width;
 | 
						|
    pMultibuffers->height = height;
 | 
						|
    dixSetPrivate(&pWin->devPrivates, MultibufferWindowPrivKey, pMultibuffers);
 | 
						|
    if (pClearGC) FreeScratchGC(pClearGC);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
ProcCreateImageBuffers (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST(xMbufCreateImageBuffersReq);
 | 
						|
    xMbufCreateImageBuffersReply	rep;
 | 
						|
    register int		n;
 | 
						|
    WindowPtr			pWin;
 | 
						|
    XID				*ids;
 | 
						|
    int				len, nbuf, i, err, rc;
 | 
						|
 | 
						|
    REQUEST_AT_LEAST_SIZE (xMbufCreateImageBuffersReq);
 | 
						|
    len = stuff->length - (sizeof(xMbufCreateImageBuffersReq) >> 2);
 | 
						|
    if (len == 0)
 | 
						|
	return BadLength;
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
 | 
						|
    if (rc != Success)
 | 
						|
	return rc;
 | 
						|
    if (pWin->drawable.class == InputOnly)
 | 
						|
	return BadMatch;
 | 
						|
    switch (stuff->updateAction)
 | 
						|
    {
 | 
						|
    case MultibufferUpdateActionUndefined:
 | 
						|
    case MultibufferUpdateActionBackground:
 | 
						|
    case MultibufferUpdateActionUntouched:
 | 
						|
    case MultibufferUpdateActionCopied:
 | 
						|
	break;
 | 
						|
    default:
 | 
						|
	client->errorValue = stuff->updateAction;
 | 
						|
	return BadValue;
 | 
						|
    }
 | 
						|
    switch (stuff->updateHint)
 | 
						|
    {
 | 
						|
    case MultibufferUpdateHintFrequent:
 | 
						|
    case MultibufferUpdateHintIntermittent:
 | 
						|
    case MultibufferUpdateHintStatic:
 | 
						|
	break;
 | 
						|
    default:
 | 
						|
	client->errorValue = stuff->updateHint;
 | 
						|
	return BadValue;
 | 
						|
    }
 | 
						|
    nbuf = len;
 | 
						|
    ids = (XID *) &stuff[1];
 | 
						|
    for (i = 0; i < nbuf; i++)
 | 
						|
    {
 | 
						|
	LEGAL_NEW_RESOURCE(ids[i], client);
 | 
						|
    }
 | 
						|
    err = CreateImageBuffers (pWin, nbuf, ids,
 | 
						|
			      stuff->updateAction, stuff->updateHint);
 | 
						|
    if (err != Success)
 | 
						|
	return err;
 | 
						|
    rep.type = X_Reply;
 | 
						|
    rep.length = 0;
 | 
						|
    rep.sequenceNumber = client->sequence;
 | 
						|
    rep.numberBuffer = ((MultibuffersPtr) (dixLookupPrivate(&pWin->devPrivates, MultibufferWindowPrivKey)))->numMultibuffer;
 | 
						|
    if (client->swapped)
 | 
						|
    {
 | 
						|
    	swaps(&rep.sequenceNumber, n);
 | 
						|
    	swapl(&rep.length, n);
 | 
						|
	swaps(&rep.numberBuffer, n);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof (xMbufCreateImageBuffersReply), (char*)&rep);
 | 
						|
    return (client->noClientException);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcDisplayImageBuffers (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST(xMbufDisplayImageBuffersReq);
 | 
						|
    MultibufferPtr	    *pMultibuffer;
 | 
						|
    MultibuffersPtr	    *ppMultibuffers;
 | 
						|
    int		    nbuf;
 | 
						|
    XID		    *ids;
 | 
						|
    int		    i, j;
 | 
						|
    CARD32	    minDelay;
 | 
						|
    TimeStamp	    activateTime, bufferTime;
 | 
						|
    
 | 
						|
 | 
						|
    REQUEST_AT_LEAST_SIZE (xMbufDisplayImageBuffersReq);
 | 
						|
    nbuf = stuff->length - (sizeof (xMbufDisplayImageBuffersReq) >> 2);
 | 
						|
    if (!nbuf)
 | 
						|
	return Success;
 | 
						|
    minDelay = stuff->minDelay;
 | 
						|
    ids = (XID *) &stuff[1];
 | 
						|
    ppMultibuffers = (MultibuffersPtr *) xalloc(nbuf * sizeof (MultibuffersPtr));
 | 
						|
    pMultibuffer = (MultibufferPtr *) xalloc(nbuf * sizeof (MultibufferPtr));
 | 
						|
    if (!ppMultibuffers || !pMultibuffer)
 | 
						|
    {
 | 
						|
	if (ppMultibuffers) xfree(ppMultibuffers);
 | 
						|
	if (pMultibuffer)   xfree(pMultibuffer);
 | 
						|
	client->errorValue = 0;
 | 
						|
	return BadAlloc;
 | 
						|
    }
 | 
						|
    activateTime.months = 0;
 | 
						|
    activateTime.milliseconds = 0;
 | 
						|
    for (i = 0; i < nbuf; i++)
 | 
						|
    {
 | 
						|
	pMultibuffer[i] = (MultibufferPtr) LookupIDByType (ids[i], 
 | 
						|
MultibufferResType);
 | 
						|
	if (!pMultibuffer[i])
 | 
						|
	{
 | 
						|
	    xfree(ppMultibuffers);
 | 
						|
	    xfree(pMultibuffer);
 | 
						|
	    client->errorValue = ids[i];
 | 
						|
	    return MultibufferErrorBase + MultibufferBadBuffer;
 | 
						|
	}
 | 
						|
	ppMultibuffers[i] = pMultibuffer[i]->pMultibuffers;
 | 
						|
	for (j = 0; j < i; j++)
 | 
						|
	{
 | 
						|
	    if (ppMultibuffers[i] == ppMultibuffers[j])
 | 
						|
	    {
 | 
						|
	    	xfree(ppMultibuffers);
 | 
						|
	    	xfree(pMultibuffer);
 | 
						|
		client->errorValue = ids[i];
 | 
						|
	    	return BadMatch;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	bufferTime = ppMultibuffers[i]->lastUpdate;
 | 
						|
	BumpTimeStamp (&bufferTime, minDelay);
 | 
						|
	if (CompareTimeStamps (bufferTime, activateTime) == LATER)
 | 
						|
	    activateTime = bufferTime;
 | 
						|
    }
 | 
						|
    UpdateCurrentTime ();
 | 
						|
    if (CompareTimeStamps (activateTime, currentTime) == LATER &&
 | 
						|
	QueueDisplayRequest (client, activateTime))
 | 
						|
    {
 | 
						|
	;
 | 
						|
    }
 | 
						|
    else
 | 
						|
	PerformDisplayRequest (ppMultibuffers, pMultibuffer, nbuf);
 | 
						|
 | 
						|
    xfree(ppMultibuffers);
 | 
						|
    xfree(pMultibuffer);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
ProcDestroyImageBuffers (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST (xMbufDestroyImageBuffersReq);
 | 
						|
    WindowPtr	pWin;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
 | 
						|
    if (rc != Success)
 | 
						|
	return rc;
 | 
						|
    DestroyImageBuffers (pWin);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSetMBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST (xMbufSetMBufferAttributesReq);
 | 
						|
    WindowPtr	pWin;
 | 
						|
    MultibuffersPtr	pMultibuffers;
 | 
						|
    int		len, rc;
 | 
						|
    Mask	vmask;
 | 
						|
    Mask	index2;
 | 
						|
    CARD32	updateHint;
 | 
						|
    XID		*vlist;
 | 
						|
 | 
						|
    REQUEST_AT_LEAST_SIZE (xMbufSetMBufferAttributesReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
 | 
						|
    if (rc != Success)
 | 
						|
	return rc;
 | 
						|
    pMultibuffers = (MultibuffersPtr)LookupIDByType (pWin->drawable.id, MultibuffersResType);
 | 
						|
    if (!pMultibuffers)
 | 
						|
	return BadMatch;
 | 
						|
    len = stuff->length - (sizeof (xMbufSetMBufferAttributesReq) >> 2);
 | 
						|
    vmask = stuff->valueMask;
 | 
						|
    if (len != Ones (vmask))
 | 
						|
	return BadLength;
 | 
						|
    vlist = (XID *) &stuff[1];
 | 
						|
    while (vmask)
 | 
						|
    {
 | 
						|
	index2 = (Mask) lowbit (vmask);
 | 
						|
	vmask &= ~index2;
 | 
						|
	switch (index2)
 | 
						|
	{
 | 
						|
	case MultibufferWindowUpdateHint:
 | 
						|
	    updateHint = (CARD32) *vlist;
 | 
						|
	    switch (updateHint)
 | 
						|
	    {
 | 
						|
	    case MultibufferUpdateHintFrequent:
 | 
						|
	    case MultibufferUpdateHintIntermittent:
 | 
						|
	    case MultibufferUpdateHintStatic:
 | 
						|
		pMultibuffers->updateHint = updateHint;
 | 
						|
		break;
 | 
						|
	    default:
 | 
						|
		client->errorValue = updateHint;
 | 
						|
		return BadValue;
 | 
						|
	    }
 | 
						|
	    vlist++;
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    client->errorValue = stuff->valueMask;
 | 
						|
	    return BadValue;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcGetMBufferAttributes (client)
 | 
						|
    ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST (xMbufGetMBufferAttributesReq);
 | 
						|
    WindowPtr	pWin;
 | 
						|
    MultibuffersPtr	pMultibuffers;
 | 
						|
    XID		*ids;
 | 
						|
    xMbufGetMBufferAttributesReply  rep;
 | 
						|
    int		i, n, rc;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH (xMbufGetMBufferAttributesReq);
 | 
						|
    rc = dixLookupWindow(&pWin, stuff->window, client, DixUnknownAccess);
 | 
						|
    if (rc != Success)
 | 
						|
	return rc;
 | 
						|
    pMultibuffers = (MultibuffersPtr)LookupIDByType (pWin->drawable.id, MultibuffersResType);
 | 
						|
    if (!pMultibuffers)
 | 
						|
	return BadAccess;
 | 
						|
    ids = (XID *) xalloc (pMultibuffers->numMultibuffer * sizeof (XID));
 | 
						|
    if (!ids)
 | 
						|
	return BadAlloc;
 | 
						|
    for (i = 0; i < pMultibuffers->numMultibuffer; i++)
 | 
						|
	ids[i] = pMultibuffers->buffers[i].pPixmap->drawable.id;
 | 
						|
    rep.type = X_Reply;
 | 
						|
    rep.sequenceNumber = client->sequence;
 | 
						|
    rep.length = pMultibuffers->numMultibuffer;
 | 
						|
    rep.displayedBuffer = pMultibuffers->displayedMultibuffer;
 | 
						|
    rep.updateAction = pMultibuffers->updateAction;
 | 
						|
    rep.updateHint = pMultibuffers->updateHint;
 | 
						|
    rep.windowMode = pMultibuffers->windowMode;
 | 
						|
    if (client->swapped)
 | 
						|
    {
 | 
						|
    	swaps(&rep.sequenceNumber, n);
 | 
						|
    	swapl(&rep.length, n);
 | 
						|
	swaps(&rep.displayedBuffer, n);
 | 
						|
	SwapLongs (ids, pMultibuffers->numMultibuffer);
 | 
						|
    }
 | 
						|
    WriteToClient (client, sizeof(xMbufGetMBufferAttributesReply),
 | 
						|
		   (char *)&rep);
 | 
						|
    WriteToClient (client, (int)(pMultibuffers->numMultibuffer * sizeof (XID)),
 | 
						|
		   (char *)ids);
 | 
						|
    xfree((pointer) ids);
 | 
						|
    return client->noClientException;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcSetBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST(xMbufSetBufferAttributesReq);
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    int		len;
 | 
						|
    Mask	vmask, index2;
 | 
						|
    XID		*vlist;
 | 
						|
    Mask	eventMask;
 | 
						|
    int		result;
 | 
						|
 | 
						|
    REQUEST_AT_LEAST_SIZE (xMbufSetBufferAttributesReq);
 | 
						|
    pMultibuffer = (MultibufferPtr) LookupIDByType (stuff->buffer, MultibufferResType);
 | 
						|
    if (!pMultibuffer)
 | 
						|
	return MultibufferErrorBase + MultibufferBadBuffer;
 | 
						|
    len = stuff->length - (sizeof (xMbufSetBufferAttributesReq) >> 2);
 | 
						|
    vmask = stuff->valueMask;
 | 
						|
    if (len != Ones (vmask))
 | 
						|
	return BadLength;
 | 
						|
    vlist = (XID *) &stuff[1];
 | 
						|
    while (vmask)
 | 
						|
    {
 | 
						|
	index2 = (Mask) lowbit (vmask);
 | 
						|
	vmask &= ~index2;
 | 
						|
	switch (index2)
 | 
						|
	{
 | 
						|
	case MultibufferBufferEventMask:
 | 
						|
	    eventMask = (Mask) *vlist;
 | 
						|
	    vlist++;
 | 
						|
	    result = EventSelectForMultibuffer (pMultibuffer, client, eventMask);
 | 
						|
	    if (result != Success)
 | 
						|
		return result;
 | 
						|
	    break;
 | 
						|
	default:
 | 
						|
	    client->errorValue = stuff->valueMask;
 | 
						|
	    return BadValue;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
ProcGetBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST(xMbufGetBufferAttributesReq);
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    xMbufGetBufferAttributesReply	rep;
 | 
						|
    OtherClientsPtr		other;
 | 
						|
    int				n;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH (xMbufGetBufferAttributesReq);
 | 
						|
    pMultibuffer = (MultibufferPtr) LookupIDByType (stuff->buffer, MultibufferResType);
 | 
						|
    if (!pMultibuffer)
 | 
						|
	return MultibufferErrorBase + MultibufferBadBuffer;
 | 
						|
    rep.type = X_Reply;
 | 
						|
    rep.sequenceNumber = client->sequence;
 | 
						|
    rep.length = 0;
 | 
						|
    rep.window = pMultibuffer->pMultibuffers->pWindow->drawable.id;
 | 
						|
    if (bClient (pMultibuffer) == client)
 | 
						|
	rep.eventMask = pMultibuffer->eventMask;
 | 
						|
    else
 | 
						|
    {
 | 
						|
	rep.eventMask = (Mask) 0L;
 | 
						|
	for (other = pMultibuffer->otherClients; other; other = other->next)
 | 
						|
	    if (SameClient (other, client))
 | 
						|
	    {
 | 
						|
		rep.eventMask = other->mask;
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
    }
 | 
						|
    rep.bufferIndex = pMultibuffer->number;
 | 
						|
    rep.side = pMultibuffer->side;
 | 
						|
    if (client->swapped)
 | 
						|
    {
 | 
						|
    	swaps(&rep.sequenceNumber, n);
 | 
						|
    	swapl(&rep.length, n);
 | 
						|
	swapl(&rep.window, n);
 | 
						|
	swapl(&rep.eventMask, n);
 | 
						|
	swaps(&rep.bufferIndex, n);
 | 
						|
    }
 | 
						|
    WriteToClient(client, sizeof (xMbufGetBufferAttributesReply), (char *)&rep);
 | 
						|
    return (client->noClientException);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcGetBufferInfo (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST (xMbufGetBufferInfoReq);
 | 
						|
    DrawablePtr		    pDrawable;
 | 
						|
    xMbufGetBufferInfoReply rep;
 | 
						|
    ScreenPtr		    pScreen;
 | 
						|
    int			    i, j, k, n, rc;
 | 
						|
    xMbufBufferInfo	    *pInfo;
 | 
						|
    int			    nInfo;
 | 
						|
    DepthPtr		    pDepth;
 | 
						|
 | 
						|
    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
 | 
						|
			   DixUnknownAccess);
 | 
						|
    if (rc != Success)
 | 
						|
	return rc;
 | 
						|
    pScreen = pDrawable->pScreen;
 | 
						|
    nInfo = 0;
 | 
						|
    for (i = 0; i < pScreen->numDepths; i++)
 | 
						|
    {
 | 
						|
	pDepth = &pScreen->allowedDepths[i];
 | 
						|
	nInfo += pDepth->numVids;
 | 
						|
    }
 | 
						|
    pInfo = (xMbufBufferInfo *)
 | 
						|
		xalloc (nInfo * sizeof (xMbufBufferInfo));
 | 
						|
    if (!pInfo)
 | 
						|
	return BadAlloc;
 | 
						|
 | 
						|
    rep.type = X_Reply;
 | 
						|
    rep.sequenceNumber = client->sequence;
 | 
						|
    rep.length = nInfo * (sizeof (xMbufBufferInfo) >> 2);
 | 
						|
    rep.normalInfo = nInfo;
 | 
						|
    rep.stereoInfo = 0;
 | 
						|
    if (client->swapped)
 | 
						|
    {
 | 
						|
	swaps(&rep.sequenceNumber, n);
 | 
						|
	swapl(&rep.length, n);
 | 
						|
	swaps(&rep.normalInfo, n);
 | 
						|
	swaps(&rep.stereoInfo, n);
 | 
						|
    }
 | 
						|
 | 
						|
    k = 0;
 | 
						|
    for (i = 0; i < pScreen->numDepths; i++)
 | 
						|
    {
 | 
						|
	pDepth = &pScreen->allowedDepths[i];
 | 
						|
	for (j = 0; j < pDepth->numVids; j++)
 | 
						|
	{
 | 
						|
	    pInfo[k].visualID = pDepth->vids[j];
 | 
						|
	    pInfo[k].maxBuffers = 0;
 | 
						|
	    pInfo[k].depth = pDepth->depth;
 | 
						|
	    if (client->swapped)
 | 
						|
	    {
 | 
						|
		swapl (&pInfo[k].visualID, n);
 | 
						|
		swaps (&pInfo[k].maxBuffers, n);
 | 
						|
	    }
 | 
						|
	    k++;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    WriteToClient (client, sizeof (xMbufGetBufferInfoReply), (pointer) &rep);
 | 
						|
    WriteToClient (client, (int) nInfo * sizeof (xMbufBufferInfo), (pointer) pInfo);
 | 
						|
    xfree ((pointer) pInfo);
 | 
						|
    return client->noClientException;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcClearImageBufferArea (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST (xMbufClearImageBufferAreaReq);
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    WindowPtr pWin;
 | 
						|
    xRectangle clearRect;
 | 
						|
    int width, height;
 | 
						|
    DrawablePtr pDrawable;
 | 
						|
    ScreenPtr pScreen;
 | 
						|
 | 
						|
    REQUEST_SIZE_MATCH (xMbufClearImageBufferAreaReq);
 | 
						|
    pMultibuffer = (MultibufferPtr) LookupIDByType (stuff->buffer, MultibufferResType);
 | 
						|
    if (!pMultibuffer)
 | 
						|
	return MultibufferErrorBase + MultibufferBadBuffer;
 | 
						|
    if ((stuff->exposures != xTrue) && (stuff->exposures != xFalse))
 | 
						|
    {
 | 
						|
	client->errorValue = stuff->exposures;
 | 
						|
        return(BadValue);
 | 
						|
    }
 | 
						|
    pWin = pMultibuffer->pMultibuffers->pWindow;
 | 
						|
    width  = pWin->drawable.width;
 | 
						|
    height = pWin->drawable.height;
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
 | 
						|
    clearRect.x = stuff->x;
 | 
						|
    clearRect.y = stuff->y;
 | 
						|
    clearRect.width  = stuff->width  ? stuff->width  : width;
 | 
						|
    clearRect.height = stuff->height ? stuff->height : height;
 | 
						|
 | 
						|
    if (pWin->backgroundState != None)
 | 
						|
    {
 | 
						|
	GCPtr pClearGC;
 | 
						|
	pClearGC = GetScratchGC (pWin->drawable.depth, pScreen);
 | 
						|
	SetupBackgroundPainter (pWin, pClearGC);
 | 
						|
 | 
						|
	if (pMultibuffer->number == pMultibuffer->pMultibuffers->displayedMultibuffer)
 | 
						|
	    pDrawable = (DrawablePtr)pWin;
 | 
						|
	else
 | 
						|
	    pDrawable = (DrawablePtr)pMultibuffer->pPixmap;
 | 
						|
 | 
						|
	ValidateGC(pDrawable, pClearGC);
 | 
						|
	(*pClearGC->ops->PolyFillRect) (pDrawable, pClearGC, 1, &clearRect);
 | 
						|
	FreeScratchGC(pClearGC);
 | 
						|
    }
 | 
						|
 | 
						|
    if (stuff->exposures)
 | 
						|
    {
 | 
						|
	RegionRec region;
 | 
						|
	BoxRec box;
 | 
						|
	box.x1 = clearRect.x;
 | 
						|
	box.y1 = clearRect.y;
 | 
						|
	box.x2 = clearRect.x + clearRect.width;
 | 
						|
	box.y2 = clearRect.y + clearRect.height;
 | 
						|
	REGION_INIT(pScreen, ®ion, &box, 1);
 | 
						|
	MultibufferExpose(pMultibuffer, ®ion);
 | 
						|
	REGION_UNINIT(pScreen, ®ion);
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ProcMultibufferDispatch (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST(xReq);
 | 
						|
    switch (stuff->data) {
 | 
						|
    case X_MbufGetBufferVersion:
 | 
						|
	return ProcGetBufferVersion (client);
 | 
						|
    case X_MbufCreateImageBuffers:
 | 
						|
	return ProcCreateImageBuffers (client);
 | 
						|
    case X_MbufDisplayImageBuffers:
 | 
						|
	return ProcDisplayImageBuffers (client);
 | 
						|
    case X_MbufDestroyImageBuffers:
 | 
						|
	return ProcDestroyImageBuffers (client);
 | 
						|
    case X_MbufSetMBufferAttributes:
 | 
						|
	return ProcSetMBufferAttributes (client);
 | 
						|
    case X_MbufGetMBufferAttributes:
 | 
						|
	return ProcGetMBufferAttributes (client);
 | 
						|
    case X_MbufSetBufferAttributes:
 | 
						|
	return ProcSetBufferAttributes (client);
 | 
						|
    case X_MbufGetBufferAttributes:
 | 
						|
	return ProcGetBufferAttributes (client);
 | 
						|
    case X_MbufGetBufferInfo:
 | 
						|
	return ProcGetBufferInfo (client);
 | 
						|
    case X_MbufClearImageBufferArea:
 | 
						|
	return ProcClearImageBufferArea (client);
 | 
						|
    default:
 | 
						|
	return BadRequest;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcGetBufferVersion (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufGetBufferVersionReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    return ProcGetBufferVersion (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcCreateImageBuffers (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufCreateImageBuffersReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_AT_LEAST_SIZE (xMbufCreateImageBuffersReq);
 | 
						|
    swapl (&stuff->window, n);
 | 
						|
    SwapRestL(stuff);
 | 
						|
    return ProcCreateImageBuffers (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcDisplayImageBuffers (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufDisplayImageBuffersReq);
 | 
						|
    
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_AT_LEAST_SIZE (xMbufDisplayImageBuffersReq);
 | 
						|
    swaps (&stuff->minDelay, n);
 | 
						|
    swaps (&stuff->maxDelay, n);
 | 
						|
    SwapRestL(stuff);
 | 
						|
    return ProcDisplayImageBuffers (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcDestroyImageBuffers (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufDestroyImageBuffersReq);
 | 
						|
    
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq);
 | 
						|
    swapl (&stuff->window, n);
 | 
						|
    return ProcDestroyImageBuffers (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcSetMBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufSetMBufferAttributesReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xMbufSetMBufferAttributesReq);
 | 
						|
    swapl (&stuff->window, n);
 | 
						|
    swapl (&stuff->valueMask, n);
 | 
						|
    SwapRestL(stuff);
 | 
						|
    return ProcSetMBufferAttributes (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcGetMBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufGetMBufferAttributesReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xMbufGetMBufferAttributesReq);
 | 
						|
    swapl (&stuff->window, n);
 | 
						|
    return ProcGetMBufferAttributes (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcSetBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufSetBufferAttributesReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xMbufSetBufferAttributesReq);
 | 
						|
    swapl (&stuff->buffer, n);
 | 
						|
    swapl (&stuff->valueMask, n);
 | 
						|
    SwapRestL(stuff);
 | 
						|
    return ProcSetBufferAttributes (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcGetBufferAttributes (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufGetBufferAttributesReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_AT_LEAST_SIZE(xMbufGetBufferAttributesReq);
 | 
						|
    swapl (&stuff->buffer, n);
 | 
						|
    return ProcGetBufferAttributes (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcGetBufferInfo (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    register int    n;
 | 
						|
    REQUEST (xMbufGetBufferInfoReq);
 | 
						|
 | 
						|
    swaps (&stuff->length, n);
 | 
						|
    REQUEST_SIZE_MATCH (xMbufGetBufferInfoReq);
 | 
						|
    swapl (&stuff->drawable, n);
 | 
						|
    return ProcGetBufferInfo (client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcClearImageBufferArea(client)
 | 
						|
    register ClientPtr client;
 | 
						|
{
 | 
						|
    register char n;
 | 
						|
    REQUEST(xMbufClearImageBufferAreaReq);
 | 
						|
 | 
						|
    swaps(&stuff->length, n);
 | 
						|
    REQUEST_SIZE_MATCH (xMbufClearImageBufferAreaReq);
 | 
						|
    swapl(&stuff->buffer, n);
 | 
						|
    swaps(&stuff->x, n);
 | 
						|
    swaps(&stuff->y, n);
 | 
						|
    swaps(&stuff->width, n);
 | 
						|
    swaps(&stuff->height, n);
 | 
						|
    return ProcClearImageBufferArea(client);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
SProcMultibufferDispatch (client)
 | 
						|
    register ClientPtr	client;
 | 
						|
{
 | 
						|
    REQUEST(xReq);
 | 
						|
    switch (stuff->data) {
 | 
						|
    case X_MbufGetBufferVersion:
 | 
						|
	return SProcGetBufferVersion (client);
 | 
						|
    case X_MbufCreateImageBuffers:
 | 
						|
	return SProcCreateImageBuffers (client);
 | 
						|
    case X_MbufDisplayImageBuffers:
 | 
						|
	return SProcDisplayImageBuffers (client);
 | 
						|
    case X_MbufDestroyImageBuffers:
 | 
						|
	return SProcDestroyImageBuffers (client);
 | 
						|
    case X_MbufSetMBufferAttributes:
 | 
						|
	return SProcSetMBufferAttributes (client);
 | 
						|
    case X_MbufGetMBufferAttributes:
 | 
						|
	return SProcGetMBufferAttributes (client);
 | 
						|
    case X_MbufSetBufferAttributes:
 | 
						|
	return SProcSetBufferAttributes (client);
 | 
						|
    case X_MbufGetBufferAttributes:
 | 
						|
	return SProcGetBufferAttributes (client);
 | 
						|
    case X_MbufGetBufferInfo:
 | 
						|
	return SProcGetBufferInfo (client);
 | 
						|
    case X_MbufClearImageBufferArea:
 | 
						|
	return SProcClearImageBufferArea (client);
 | 
						|
    default:
 | 
						|
	return BadRequest;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
SUpdateNotifyEvent (from, to)
 | 
						|
    xMbufUpdateNotifyEvent	*from, *to;
 | 
						|
{
 | 
						|
    to->type = from->type;
 | 
						|
    cpswaps (from->sequenceNumber, to->sequenceNumber);
 | 
						|
    cpswapl (from->buffer, to->buffer);
 | 
						|
    cpswapl (from->timeStamp, to->timeStamp);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
SClobberNotifyEvent (from, to)
 | 
						|
    xMbufClobberNotifyEvent	*from, *to;
 | 
						|
{
 | 
						|
    to->type = from->type;
 | 
						|
    cpswaps (from->sequenceNumber, to->sequenceNumber);
 | 
						|
    cpswapl (from->buffer, to->buffer);
 | 
						|
    to->state = from->state;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
PerformDisplayRequest (ppMultibuffers, pMultibuffer, nbuf)
 | 
						|
    MultibufferPtr	    *pMultibuffer;
 | 
						|
    MultibuffersPtr	    *ppMultibuffers;
 | 
						|
    int		    nbuf;
 | 
						|
{
 | 
						|
    GCPtr	    pGC;
 | 
						|
    PixmapPtr	    pPrevPixmap, pNewPixmap;
 | 
						|
    xRectangle	    clearRect;
 | 
						|
    WindowPtr	    pWin;
 | 
						|
    RegionPtr	    pExposed;
 | 
						|
    int		    i;
 | 
						|
    MultibufferPtr  pPrevMultibuffer;
 | 
						|
    XID		    graphicsExpose;
 | 
						|
 | 
						|
    UpdateCurrentTime ();
 | 
						|
    for (i = 0; i < nbuf; i++)
 | 
						|
    {
 | 
						|
	pWin = ppMultibuffers[i]->pWindow;
 | 
						|
	pGC = GetScratchGC (pWin->drawable.depth, pWin->drawable.pScreen);
 | 
						|
	pPrevMultibuffer =
 | 
						|
	   &ppMultibuffers[i]->buffers[ppMultibuffers[i]->displayedMultibuffer];
 | 
						|
	pPrevPixmap = pPrevMultibuffer->pPixmap;
 | 
						|
	pNewPixmap = pMultibuffer[i]->pPixmap;
 | 
						|
	switch (ppMultibuffers[i]->updateAction)
 | 
						|
	{
 | 
						|
	case MultibufferUpdateActionUndefined:
 | 
						|
	    break;
 | 
						|
	case MultibufferUpdateActionBackground:
 | 
						|
	    SetupBackgroundPainter (pWin, pGC);
 | 
						|
	    ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
 | 
						|
	    clearRect.x = 0;
 | 
						|
	    clearRect.y = 0;
 | 
						|
	    clearRect.width = pPrevPixmap->drawable.width;
 | 
						|
	    clearRect.height = pPrevPixmap->drawable.height;
 | 
						|
	    (*pGC->ops->PolyFillRect) ((DrawablePtr)pPrevPixmap, pGC,
 | 
						|
				       1, &clearRect);
 | 
						|
	    break;
 | 
						|
	case MultibufferUpdateActionUntouched:
 | 
						|
	    /* copy the window to the pixmap that represents the
 | 
						|
	     * currently displayed buffer
 | 
						|
	     */
 | 
						|
	    if (pPrevMultibuffer->eventMask & ExposureMask)
 | 
						|
	    {
 | 
						|
	    	graphicsExpose = TRUE;
 | 
						|
	    	DoChangeGC (pGC, GCGraphicsExposures, &graphicsExpose, FALSE);
 | 
						|
	    }
 | 
						|
	    ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
 | 
						|
	    pExposed = (*pGC->ops->CopyArea)
 | 
						|
			    ((DrawablePtr) pWin,
 | 
						|
			     (DrawablePtr) pPrevPixmap,
 | 
						|
			     pGC,
 | 
						|
			     0, 0,
 | 
						|
			     pWin->drawable.width, pWin->drawable.height,
 | 
						|
			     0, 0);
 | 
						|
 | 
						|
	    /* if we couldn't copy the whole window to the buffer,
 | 
						|
	     * send expose events (if any client wants them)
 | 
						|
	     */
 | 
						|
	    if (pPrevMultibuffer->eventMask & ExposureMask)
 | 
						|
	    { /* some client wants expose events */
 | 
						|
	    	if (pExposed)
 | 
						|
	    	{
 | 
						|
		    RegionPtr	pWinSize;
 | 
						|
 | 
						|
		    pWinSize = CreateUnclippedWinSize (pWin);
 | 
						|
		    /* pExposed is window-relative, but at this point
 | 
						|
		     * pWinSize is screen-relative.  Make pWinSize be
 | 
						|
		     * window-relative so that region ops involving
 | 
						|
		     * pExposed and pWinSize behave sensibly.
 | 
						|
		     */
 | 
						|
		    REGION_TRANSLATE(pWin->drawable.pScreen, pWinSize,
 | 
						|
				     -pWin->drawable.x, -pWin->drawable.y);
 | 
						|
		    REGION_INTERSECT(pWin->drawable.pScreen, pExposed,
 | 
						|
				     pExposed, pWinSize);
 | 
						|
		    REGION_DESTROY(pWin->drawable.pScreen, pWinSize);
 | 
						|
	    	    MultibufferExpose (pPrevMultibuffer, pExposed);
 | 
						|
	    	    REGION_DESTROY(pWin->drawable.pScreen, pExposed);
 | 
						|
	    	}
 | 
						|
	    	graphicsExpose = FALSE;
 | 
						|
	    	DoChangeGC (pGC, GCGraphicsExposures, &graphicsExpose, FALSE);
 | 
						|
	    }
 | 
						|
	    break; /* end case MultibufferUpdateActionUntouched */
 | 
						|
 | 
						|
	case MultibufferUpdateActionCopied:
 | 
						|
	    ValidateGC ((DrawablePtr)pPrevPixmap, pGC);
 | 
						|
	    (*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap,
 | 
						|
				   (DrawablePtr)pPrevPixmap, pGC,
 | 
						|
				   0, 0,
 | 
						|
				   pWin->drawable.width, pWin->drawable.height,
 | 
						|
				   0, 0);
 | 
						|
	    break;
 | 
						|
	} /* end switch on update action */
 | 
						|
 | 
						|
	/* display the new buffer */
 | 
						|
	ValidateGC ((DrawablePtr)pWin, pGC);
 | 
						|
	(*pGC->ops->CopyArea) ((DrawablePtr)pNewPixmap, (DrawablePtr)pWin, pGC,
 | 
						|
			       0, 0,
 | 
						|
			       pWin->drawable.width, pWin->drawable.height,
 | 
						|
			       0, 0);
 | 
						|
	ppMultibuffers[i]->lastUpdate = currentTime;
 | 
						|
	MultibufferUpdate (pMultibuffer[i],
 | 
						|
			   ppMultibuffers[i]->lastUpdate.milliseconds);
 | 
						|
	AliasMultibuffer (ppMultibuffers[i],
 | 
						|
			  pMultibuffer[i] - ppMultibuffers[i]->buffers);
 | 
						|
	FreeScratchGC (pGC);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
DrawablePtr
 | 
						|
GetBufferPointer (pWin, i)
 | 
						|
    WindowPtr	pWin;
 | 
						|
    int		i;
 | 
						|
{
 | 
						|
    MultibuffersPtr pMultibuffers;
 | 
						|
 | 
						|
    if (!(pMultibuffers = (MultibuffersPtr) dixLookupPrivate(&pWin->devPrivates, MultibufferWindowPrivKey)))
 | 
						|
	return NULL;
 | 
						|
    return (DrawablePtr) pMultibuffers->buffers[i].pPixmap;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
DisplayImageBuffers (ids, nbuf)
 | 
						|
    XID	    *ids;
 | 
						|
    int	    nbuf;
 | 
						|
{
 | 
						|
    MultibufferPtr  *pMultibuffer;
 | 
						|
    MultibuffersPtr *pMultibuffers;
 | 
						|
    int		    i, j;
 | 
						|
 | 
						|
    pMultibuffer = (MultibufferPtr *) xalloc (nbuf * sizeof *pMultibuffer +
 | 
						|
				   nbuf * sizeof *pMultibuffers);
 | 
						|
    if (!pMultibuffer)
 | 
						|
	return BadAlloc;
 | 
						|
    pMultibuffers = (MultibuffersPtr *) (pMultibuffer + nbuf);
 | 
						|
    for (i = 0; i < nbuf; i++)
 | 
						|
    {
 | 
						|
	pMultibuffer[i] = (MultibufferPtr) LookupIDByType (ids[i], MultibufferResType);
 | 
						|
	if (!pMultibuffer[i])
 | 
						|
	{
 | 
						|
	    xfree (pMultibuffer);
 | 
						|
	    return MultibufferErrorBase + MultibufferBadBuffer;
 | 
						|
	}
 | 
						|
	pMultibuffers[i] = pMultibuffer[i]->pMultibuffers;
 | 
						|
	for (j = 0; j < i; j++)
 | 
						|
	    if (pMultibuffers[i] == pMultibuffers[j])
 | 
						|
	    {
 | 
						|
		xfree (pMultibuffer);
 | 
						|
		return BadMatch;
 | 
						|
	    }
 | 
						|
    }
 | 
						|
    PerformDisplayRequest (pMultibuffers, pMultibuffer, nbuf);
 | 
						|
    xfree (pMultibuffer);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static Bool
 | 
						|
QueueDisplayRequest (client, activateTime)
 | 
						|
    ClientPtr	    client;
 | 
						|
    TimeStamp	    activateTime;
 | 
						|
{
 | 
						|
    /* see xtest.c:ProcXTestFakeInput for code similar to this */
 | 
						|
 | 
						|
    if (!ClientSleepUntil(client, &activateTime, NULL, NULL))
 | 
						|
    {
 | 
						|
	return FALSE;
 | 
						|
    }
 | 
						|
    /* swap the request back so we can simply re-execute it */
 | 
						|
    if (client->swapped)
 | 
						|
    {
 | 
						|
    	register int    n;
 | 
						|
    	REQUEST (xMbufDisplayImageBuffersReq);
 | 
						|
    	
 | 
						|
    	SwapRestL(stuff);
 | 
						|
    	swaps (&stuff->length, n);
 | 
						|
    	swaps (&stuff->minDelay, n);
 | 
						|
    	swaps (&stuff->maxDelay, n);
 | 
						|
    }
 | 
						|
    ResetCurrentRequest (client);
 | 
						|
    client->sequence--;
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Deliver events to a buffer
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
DeliverEventsToMultibuffer (pMultibuffer, pEvents, count, filter)
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    xEvent	*pEvents;
 | 
						|
    int		count;
 | 
						|
    Mask	filter;
 | 
						|
{
 | 
						|
    int deliveries = 0, nondeliveries = 0;
 | 
						|
    int attempt;
 | 
						|
    OtherClients *other;
 | 
						|
 | 
						|
    /* if nobody wants the event, we're done */
 | 
						|
    if (!((pMultibuffer->otherEventMask|pMultibuffer->eventMask) & filter))
 | 
						|
	return 0;
 | 
						|
 | 
						|
    /* maybe send event to owner */
 | 
						|
    if ((attempt = TryClientEvents(
 | 
						|
	bClient(pMultibuffer), pEvents, count, pMultibuffer->eventMask, filter, (GrabPtr) 0)) != 0)
 | 
						|
    {
 | 
						|
	if (attempt > 0)
 | 
						|
	    deliveries++;
 | 
						|
	else
 | 
						|
	    nondeliveries--;
 | 
						|
    }
 | 
						|
 | 
						|
    /* maybe send event to other clients */
 | 
						|
    for (other = pMultibuffer->otherClients; other; other=other->next)
 | 
						|
    {
 | 
						|
	if ((attempt = TryClientEvents(
 | 
						|
	      rClient(other), pEvents, count, other->mask, filter, (GrabPtr) 0)) != 0)
 | 
						|
	{
 | 
						|
	    if (attempt > 0)
 | 
						|
		deliveries++;
 | 
						|
	    else
 | 
						|
		nondeliveries--;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (deliveries)
 | 
						|
	return deliveries;
 | 
						|
    return nondeliveries;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Send Expose events to interested clients
 | 
						|
 */
 | 
						|
 | 
						|
void
 | 
						|
MultibufferExpose (pMultibuffer, pRegion)
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    RegionPtr	pRegion;
 | 
						|
{
 | 
						|
    if (pRegion && !REGION_NIL(pRegion))
 | 
						|
    {
 | 
						|
	xEvent *pEvent;
 | 
						|
	PixmapPtr   pPixmap;
 | 
						|
	register xEvent *pe;
 | 
						|
	register BoxPtr pBox;
 | 
						|
	register int i;
 | 
						|
	int numRects;
 | 
						|
 | 
						|
	pPixmap = pMultibuffer->pPixmap;
 | 
						|
	REGION_TRANSLATE(pPixmap->drawable.pScreen, pRegion,
 | 
						|
		    -pPixmap->drawable.x, -pPixmap->drawable.y);
 | 
						|
	/* XXX MultibufferExpose "knows" the region representation */
 | 
						|
	numRects = REGION_NUM_RECTS(pRegion);
 | 
						|
	pBox = REGION_RECTS(pRegion);
 | 
						|
 | 
						|
	pEvent = (xEvent *) xalloc(numRects * sizeof(xEvent));
 | 
						|
	if (pEvent) {
 | 
						|
	    pe = pEvent;
 | 
						|
 | 
						|
	    for (i=1; i<=numRects; i++, pe++, pBox++)
 | 
						|
	    {
 | 
						|
		pe->u.u.type = Expose;
 | 
						|
		pe->u.expose.window = pPixmap->drawable.id;
 | 
						|
		pe->u.expose.x = pBox->x1;
 | 
						|
		pe->u.expose.y = pBox->y1;
 | 
						|
		pe->u.expose.width = pBox->x2 - pBox->x1;
 | 
						|
		pe->u.expose.height = pBox->y2 - pBox->y1;
 | 
						|
		pe->u.expose.count = (numRects - i);
 | 
						|
	    }
 | 
						|
	    (void) DeliverEventsToMultibuffer (pMultibuffer, pEvent, numRects,
 | 
						|
					       ExposureMask);
 | 
						|
	    xfree(pEvent);
 | 
						|
	}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* send UpdateNotify event */
 | 
						|
void
 | 
						|
MultibufferUpdate (pMultibuffer, time2)
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    CARD32	time2;
 | 
						|
{
 | 
						|
    xMbufUpdateNotifyEvent	event;
 | 
						|
 | 
						|
    event.type = MultibufferEventBase + MultibufferUpdateNotify;
 | 
						|
    event.buffer = pMultibuffer->pPixmap->drawable.id;
 | 
						|
    event.timeStamp = time2;
 | 
						|
    (void) DeliverEventsToMultibuffer (pMultibuffer, (xEvent *)&event,
 | 
						|
				1, (Mask)MultibufferUpdateNotifyMask);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * The sample implementation will never generate MultibufferClobberNotify
 | 
						|
 * events
 | 
						|
 */
 | 
						|
 | 
						|
void
 | 
						|
MultibufferClobber (pMultibuffer)
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
{
 | 
						|
    xMbufClobberNotifyEvent	event;
 | 
						|
 | 
						|
    event.type = MultibufferEventBase + MultibufferClobberNotify;
 | 
						|
    event.buffer = pMultibuffer->pPixmap->drawable.id;
 | 
						|
    event.state = pMultibuffer->clobber;
 | 
						|
    (void) DeliverEventsToMultibuffer (pMultibuffer, (xEvent *)&event,
 | 
						|
				1, (Mask)MultibufferClobberNotifyMask);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * make the resource id for buffer i refer to the window
 | 
						|
 * drawable instead of the pixmap;
 | 
						|
 */
 | 
						|
 | 
						|
static void
 | 
						|
AliasMultibuffer (pMultibuffers, i)
 | 
						|
    MultibuffersPtr	pMultibuffers;
 | 
						|
    int		i;
 | 
						|
{
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
 | 
						|
    if (i == pMultibuffers->displayedMultibuffer)
 | 
						|
	return;
 | 
						|
    /*
 | 
						|
     * remove the old association
 | 
						|
     */
 | 
						|
    if (pMultibuffers->displayedMultibuffer >= 0)
 | 
						|
    {
 | 
						|
	pMultibuffer = &pMultibuffers->buffers[pMultibuffers->displayedMultibuffer];
 | 
						|
	ChangeResourceValue (pMultibuffer->pPixmap->drawable.id,
 | 
						|
			     MultibufferDrawableResType,
 | 
						|
 			     (pointer) pMultibuffer->pPixmap);
 | 
						|
    }
 | 
						|
    /*
 | 
						|
     * make the new association
 | 
						|
     */
 | 
						|
    pMultibuffer = &pMultibuffers->buffers[i];
 | 
						|
    ChangeResourceValue (pMultibuffer->pPixmap->drawable.id,
 | 
						|
			 MultibufferDrawableResType,
 | 
						|
			 (pointer) pMultibuffers->pWindow);
 | 
						|
    pMultibuffers->displayedMultibuffer = i;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * free everything associated with multibuffering for this
 | 
						|
 * window
 | 
						|
 */
 | 
						|
 | 
						|
void
 | 
						|
DestroyImageBuffers (pWin)
 | 
						|
    WindowPtr	pWin;
 | 
						|
{
 | 
						|
    FreeResourceByType (pWin->drawable.id, MultibuffersResType, FALSE);
 | 
						|
    /* Zero out the window's pointer to the buffers so they won't be reused */
 | 
						|
    dixSetPrivate(&pWin->devPrivates, MultibufferWindowPrivKey, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * resize the buffers when the window is resized
 | 
						|
 */ 
 | 
						|
 | 
						|
static Bool
 | 
						|
MultibufferPositionWindow (pWin, x, y)
 | 
						|
    WindowPtr	pWin;
 | 
						|
    int		x, y;
 | 
						|
{
 | 
						|
    ScreenPtr	    pScreen;
 | 
						|
    MultibufferScreenPtr pMultibufferScreen;
 | 
						|
    MultibuffersPtr	    pMultibuffers;
 | 
						|
    MultibufferPtr	    pMultibuffer;
 | 
						|
    int		    width, height;
 | 
						|
    int		    i;
 | 
						|
    int		    dx, dy, dw, dh;
 | 
						|
    int		    sourcex, sourcey;
 | 
						|
    int		    destx, desty;
 | 
						|
    PixmapPtr	    pPixmap;
 | 
						|
    GCPtr	    pGC;
 | 
						|
    int		    savewidth, saveheight;
 | 
						|
    xRectangle	    clearRect;
 | 
						|
    Bool	    clear;
 | 
						|
 | 
						|
    pScreen = pWin->drawable.pScreen;
 | 
						|
    pMultibufferScreen = (MultibufferScreenPtr) dixLookupPrivate(&pScreen->devPrivates, MultibufferScreenPrivKey);
 | 
						|
    (*pMultibufferScreen->PositionWindow) (pWin, x, y);
 | 
						|
 | 
						|
    /* if this window is not multibuffered, we're done */
 | 
						|
    if (!(pMultibuffers = (MultibuffersPtr) dixLookupPrivate(&pWin->devPrivates, MultibufferWindowPrivKey)))
 | 
						|
	return TRUE;
 | 
						|
 | 
						|
    /* if new size is same as old, we're done */
 | 
						|
    if (pMultibuffers->width == pWin->drawable.width &&
 | 
						|
        pMultibuffers->height == pWin->drawable.height)
 | 
						|
	return TRUE;
 | 
						|
 | 
						|
    width = pWin->drawable.width;
 | 
						|
    height = pWin->drawable.height;
 | 
						|
    dx = pWin->drawable.x - pMultibuffers->x;
 | 
						|
    dy = pWin->drawable.x - pMultibuffers->y;
 | 
						|
    dw = width - pMultibuffers->width;
 | 
						|
    dh = height - pMultibuffers->height;
 | 
						|
    GravityTranslate (0, 0, -dx, -dy, dw, dh,
 | 
						|
		      pWin->bitGravity, &destx, &desty);
 | 
						|
 | 
						|
    /* if the window grew, remember to paint the window background,
 | 
						|
     * and maybe send expose events, for the new areas of the buffers
 | 
						|
     */
 | 
						|
    clear = pMultibuffers->width < width || pMultibuffers->height < height ||
 | 
						|
		pWin->bitGravity == ForgetGravity;
 | 
						|
 | 
						|
    sourcex = 0;
 | 
						|
    sourcey = 0;
 | 
						|
    savewidth = pMultibuffers->width;
 | 
						|
    saveheight = pMultibuffers->height;
 | 
						|
    /* clip rectangle to source and destination */
 | 
						|
    if (destx < 0)
 | 
						|
    {
 | 
						|
	savewidth += destx;
 | 
						|
	sourcex -= destx;
 | 
						|
	destx = 0;
 | 
						|
    }
 | 
						|
    if (destx + savewidth > width)
 | 
						|
	savewidth = width - destx;
 | 
						|
    if (desty < 0)
 | 
						|
    {
 | 
						|
	saveheight += desty;
 | 
						|
	sourcey -= desty;
 | 
						|
	desty = 0;
 | 
						|
    }
 | 
						|
    if (desty + saveheight > height)
 | 
						|
	saveheight = height - desty;
 | 
						|
 | 
						|
    pMultibuffers->width = width;
 | 
						|
    pMultibuffers->height = height;
 | 
						|
    pMultibuffers->x = pWin->drawable.x;
 | 
						|
    pMultibuffers->y = pWin->drawable.y;
 | 
						|
 | 
						|
    pGC = GetScratchGC (pWin->drawable.depth, pScreen);
 | 
						|
    if (clear)
 | 
						|
    {
 | 
						|
	SetupBackgroundPainter (pWin, pGC);
 | 
						|
	clearRect.x = 0;
 | 
						|
	clearRect.y = 0;
 | 
						|
	clearRect.width = width;
 | 
						|
	clearRect.height = height;
 | 
						|
    }
 | 
						|
    for (i = 0; i < pMultibuffers->numMultibuffer; i++)
 | 
						|
    {
 | 
						|
	pMultibuffer = &pMultibuffers->buffers[i];
 | 
						|
	pPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
 | 
						|
					    pWin->drawable.depth,
 | 
						|
					    CREATE_PIXMAP_USAGE_SCRATCH);
 | 
						|
	if (!pPixmap)
 | 
						|
	{
 | 
						|
	    DestroyImageBuffers (pWin);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	ValidateGC ((DrawablePtr)pPixmap, pGC);
 | 
						|
	/*
 | 
						|
	 * I suppose this could avoid quite a bit of work if
 | 
						|
	 * it computed the minimal area required.
 | 
						|
	 */
 | 
						|
	if (clear)
 | 
						|
	    (*pGC->ops->PolyFillRect) ((DrawablePtr)pPixmap, pGC, 1, &clearRect);
 | 
						|
	if (pWin->bitGravity != ForgetGravity)
 | 
						|
	{
 | 
						|
	    (*pGC->ops->CopyArea) ((DrawablePtr)pMultibuffer->pPixmap,
 | 
						|
				   (DrawablePtr)pPixmap, pGC,
 | 
						|
				    sourcex, sourcey, savewidth, saveheight,
 | 
						|
				    destx, desty);
 | 
						|
	}
 | 
						|
	pPixmap->drawable.id = pMultibuffer->pPixmap->drawable.id;
 | 
						|
	(*pScreen->DestroyPixmap) (pMultibuffer->pPixmap);
 | 
						|
	pMultibuffer->pPixmap = pPixmap;
 | 
						|
	if (i != pMultibuffers->displayedMultibuffer)
 | 
						|
	{
 | 
						|
	    ChangeResourceValue (pPixmap->drawable.id,
 | 
						|
				 MultibufferDrawableResType,
 | 
						|
				 (pointer) pPixmap);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    FreeScratchGC (pGC);
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* Resource delete func for MultibufferDrawableResType */
 | 
						|
/*ARGSUSED*/
 | 
						|
static int
 | 
						|
MultibufferDrawableDelete (value, id)
 | 
						|
    pointer	value;
 | 
						|
    XID		id;
 | 
						|
{
 | 
						|
    DrawablePtr	pDrawable = (DrawablePtr)value;
 | 
						|
    WindowPtr	pWin;
 | 
						|
    MultibuffersPtr	pMultibuffers;
 | 
						|
    PixmapPtr	pPixmap;
 | 
						|
 | 
						|
    if (pDrawable->type == DRAWABLE_WINDOW)
 | 
						|
    {
 | 
						|
	pWin = (WindowPtr) pDrawable;
 | 
						|
	pMultibuffers = (MultibuffersPtr) dixLookupPrivate(&pWin->devPrivates, MultibufferWindowPrivKey);
 | 
						|
	pPixmap = pMultibuffers->buffers[pMultibuffers->displayedMultibuffer].pPixmap;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
	pPixmap = (PixmapPtr) pDrawable;
 | 
						|
    }
 | 
						|
    (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/* Resource delete func for MultibufferResType */
 | 
						|
/*ARGSUSED*/
 | 
						|
static int
 | 
						|
MultibufferDelete (value, id)
 | 
						|
    pointer	value;
 | 
						|
    XID		id;
 | 
						|
{
 | 
						|
    MultibufferPtr	pMultibuffer = (MultibufferPtr)value;
 | 
						|
    MultibuffersPtr	pMultibuffers;
 | 
						|
 | 
						|
    pMultibuffers = pMultibuffer->pMultibuffers;
 | 
						|
    if (--pMultibuffers->refcnt == 0)
 | 
						|
    {
 | 
						|
	FreeResourceByType (pMultibuffers->pWindow->drawable.id,
 | 
						|
			    MultibuffersResType, TRUE);
 | 
						|
	xfree (pMultibuffers);
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/* Resource delete func for MultibuffersResType */
 | 
						|
/*ARGSUSED*/
 | 
						|
static int
 | 
						|
MultibuffersDelete (value, id)
 | 
						|
    pointer	value;
 | 
						|
    XID		id;
 | 
						|
{
 | 
						|
    MultibuffersPtr	pMultibuffers = (MultibuffersPtr)value;
 | 
						|
    int	i;
 | 
						|
 | 
						|
    if (pMultibuffers->refcnt == pMultibuffers->numMultibuffer)
 | 
						|
    {
 | 
						|
	for (i = pMultibuffers->numMultibuffer; --i >= 0; )
 | 
						|
	    FreeResource (pMultibuffers->buffers[i].pPixmap->drawable.id, 0);
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/* Resource delete func for OtherClientResType */
 | 
						|
static int
 | 
						|
OtherClientDelete (value, id)
 | 
						|
    pointer	value;
 | 
						|
    XID		id;
 | 
						|
{
 | 
						|
    MultibufferPtr	pMultibuffer = (MultibufferPtr)value;
 | 
						|
    register OtherClientsPtr	other, prev;
 | 
						|
 | 
						|
    prev = 0;
 | 
						|
    for (other = pMultibuffer->otherClients; other; other = other->next)
 | 
						|
    {
 | 
						|
	if (other->resource == id)
 | 
						|
	{
 | 
						|
	    if (prev)
 | 
						|
		prev->next = other->next;
 | 
						|
	    else
 | 
						|
		pMultibuffer->otherClients = other->next;
 | 
						|
	    xfree (other);
 | 
						|
	    RecalculateMultibufferOtherEvents (pMultibuffer);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	prev = other;
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
EventSelectForMultibuffer (pMultibuffer, client, mask)
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
    ClientPtr	client;
 | 
						|
    Mask	mask;
 | 
						|
{
 | 
						|
    OtherClientsPtr	other;
 | 
						|
 | 
						|
    if (mask & ~ValidEventMasks)
 | 
						|
    {
 | 
						|
	client->errorValue = mask;
 | 
						|
	return BadValue;
 | 
						|
    }
 | 
						|
    if (bClient (pMultibuffer) == client)
 | 
						|
    {
 | 
						|
	pMultibuffer->eventMask = mask;
 | 
						|
    }
 | 
						|
    else /* some other client besides the creator wants events */
 | 
						|
    {
 | 
						|
	for (other = pMultibuffer->otherClients; other; other = other->next)
 | 
						|
	{
 | 
						|
	    if (SameClient (other, client))
 | 
						|
	    {
 | 
						|
		if (mask == 0)
 | 
						|
		{
 | 
						|
		    FreeResource (other->resource, RT_NONE);
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
		other->mask = mask;
 | 
						|
		break;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
	if (!other)
 | 
						|
	{ /* new client that never selected events on this buffer before */
 | 
						|
	    other = (OtherClients *) xalloc (sizeof (OtherClients));
 | 
						|
	    if (!other)
 | 
						|
		return BadAlloc;
 | 
						|
	    other->mask = mask;
 | 
						|
	    other->resource = FakeClientID (client->index);
 | 
						|
	    if (!AddResource (other->resource, OtherClientResType, (pointer) pMultibuffer))
 | 
						|
	    {
 | 
						|
		xfree (other);
 | 
						|
		return BadAlloc;
 | 
						|
	    }
 | 
						|
	    other->next = pMultibuffer->otherClients;
 | 
						|
	    pMultibuffer->otherClients = other;
 | 
						|
	}
 | 
						|
	RecalculateMultibufferOtherEvents (pMultibuffer);
 | 
						|
    }
 | 
						|
    return (client->noClientException);
 | 
						|
}
 | 
						|
 | 
						|
/* or together all the otherClients event masks */
 | 
						|
static void
 | 
						|
RecalculateMultibufferOtherEvents (pMultibuffer)
 | 
						|
    MultibufferPtr	pMultibuffer;
 | 
						|
{
 | 
						|
    Mask	    otherEventMask;
 | 
						|
    OtherClients    *other;
 | 
						|
 | 
						|
    otherEventMask = 0L;
 | 
						|
    for (other = pMultibuffer->otherClients; other; other = other->next)
 | 
						|
	otherEventMask |= other->mask;
 | 
						|
    pMultibuffer->otherEventMask = otherEventMask;
 | 
						|
}
 | 
						|
 | 
						|
/* add milliseconds to a timestamp, handling overflow */
 | 
						|
static void
 | 
						|
BumpTimeStamp (ts, inc)
 | 
						|
TimeStamp   *ts;
 | 
						|
CARD32	    inc;
 | 
						|
{
 | 
						|
    CARD32  newms;
 | 
						|
 | 
						|
    newms = ts->milliseconds + inc;
 | 
						|
    if (newms < ts->milliseconds)
 | 
						|
	ts->months++;
 | 
						|
    ts->milliseconds = newms;
 | 
						|
}
 |