1766 lines
48 KiB
C
1766 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)
|
|
#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 int MultibufferScreenPrivKeyIndex;
|
|
static DevPrivateKey MultibufferScreenPrivKey = &MultibufferScreenPrivKeyIndex;
|
|
static int MultibufferWindowPrivKeyIndex;
|
|
static DevPrivateKey MultibufferWindowPrivKey = &MultibufferWindowPrivKeyIndex;
|
|
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
xMbufGetBufferVersionReply rep;
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
REQUEST(xMbufCreateImageBuffersReq);
|
|
xMbufCreateImageBuffersReply rep;
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
int n;
|
|
REQUEST (xMbufGetBufferVersionReq);
|
|
|
|
swaps (&stuff->length, n);
|
|
return ProcGetBufferVersion (client);
|
|
}
|
|
|
|
static int
|
|
SProcCreateImageBuffers (client)
|
|
ClientPtr client;
|
|
{
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
int n;
|
|
REQUEST (xMbufDestroyImageBuffersReq);
|
|
|
|
swaps (&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq);
|
|
swapl (&stuff->window, n);
|
|
return ProcDestroyImageBuffers (client);
|
|
}
|
|
|
|
static int
|
|
SProcSetMBufferAttributes (client)
|
|
ClientPtr client;
|
|
{
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
int n;
|
|
REQUEST (xMbufGetMBufferAttributesReq);
|
|
|
|
swaps (&stuff->length, n);
|
|
REQUEST_AT_LEAST_SIZE(xMbufGetMBufferAttributesReq);
|
|
swapl (&stuff->window, n);
|
|
return ProcGetMBufferAttributes (client);
|
|
}
|
|
|
|
static int
|
|
SProcSetBufferAttributes (client)
|
|
ClientPtr client;
|
|
{
|
|
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)
|
|
ClientPtr client;
|
|
{
|
|
int n;
|
|
REQUEST (xMbufGetBufferAttributesReq);
|
|
|
|
swaps (&stuff->length, n);
|
|
REQUEST_AT_LEAST_SIZE(xMbufGetBufferAttributesReq);
|
|
swapl (&stuff->buffer, n);
|
|
return ProcGetBufferAttributes (client);
|
|
}
|
|
|
|
static int
|
|
SProcGetBufferInfo (client)
|
|
ClientPtr client;
|
|
{
|
|
int n;
|
|
REQUEST (xMbufGetBufferInfoReq);
|
|
|
|
swaps (&stuff->length, n);
|
|
REQUEST_SIZE_MATCH (xMbufGetBufferInfoReq);
|
|
swapl (&stuff->drawable, n);
|
|
return ProcGetBufferInfo (client);
|
|
}
|
|
|
|
static int
|
|
SProcClearImageBufferArea(client)
|
|
ClientPtr client;
|
|
{
|
|
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)
|
|
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)
|
|
{
|
|
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), NULL, 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), NULL, 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;
|
|
xEvent *pe;
|
|
BoxPtr pBox;
|
|
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;
|
|
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;
|
|
}
|