/* $XFree86: xc/programs/Xserver/Xext/mbuf.c,v 3.15 2003/10/28 23:08:43 tsi Exp $ */ /************************************************************ 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. ********************************************************/ /* $Xorg: mbuf.c,v 1.4 2001/02/09 02:04:32 xorgcvs Exp $ */ #define NEED_REPLIES #define NEED_EVENTS #include #include #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 #ifdef EXTMODULE #include "xf86_ansic.h" #else #include #if !defined(WIN32) && !defined(Lynx) #include #endif #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) #if 0 static unsigned char MultibufferReqCode; #endif static int MultibufferEventBase; static int MultibufferErrorBase; int MultibufferScreenIndex = -1; int MultibufferWindowIndex = -1; 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; /* * allocate private pointers in windows and screens. Allocating * window privates may seem like an unnecessary expense, but every * PositionWindow call must check to see if the window is * multi-buffered; a resource lookup is too expensive. */ MultibufferScreenIndex = AllocateScreenPrivateIndex (); if (MultibufferScreenIndex < 0) return; MultibufferWindowIndex = AllocateWindowPrivateIndex (); for (i = 0; i < screenInfo.numScreens; i++) { pScreen = screenInfo.screens[i]; if (!AllocateWindowPrivate (pScreen, MultibufferWindowIndex, 0) || !(pMultibufferScreen = (MultibufferScreenPtr) xalloc (sizeof (MultibufferScreenRec)))) { for (j = 0; j < i; j++) xfree (screenInfo.screens[j]->devPrivates[MultibufferScreenIndex].ptr); return; } pScreen->devPrivates[MultibufferScreenIndex].ptr = (pointer) 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_CACHED|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))) { #if 0 MultibufferReqCode = (unsigned char)extEntry->base; #endif 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; if (MultibufferScreenIndex < 0) return; for (i = 0; i < screenInfo.numScreens; i++) { pScreen = screenInfo.screens[i]; if (pScreen->devPrivates[MultibufferScreenIndex].ptr) { pMultibufferScreen = (MultibufferScreenPtr) pScreen->devPrivates[MultibufferScreenIndex].ptr; 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); 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; pWin->devPrivates[MultibufferWindowIndex].ptr = (pointer) 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; int i; int err; REQUEST_AT_LEAST_SIZE (xMbufCreateImageBuffersReq); len = stuff->length - (sizeof(xMbufCreateImageBuffersReq) >> 2); if (len == 0) return BadLength; if (!(pWin = LookupWindow (stuff->window, client))) return BadWindow; 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) (pWin->devPrivates[MultibufferWindowIndex].ptr))->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 *) ALLOCATE_LOCAL(nbuf * sizeof (MultibuffersPtr)); pMultibuffer = (MultibufferPtr *) ALLOCATE_LOCAL(nbuf * sizeof (MultibufferPtr)); if (!ppMultibuffers || !pMultibuffer) { if (ppMultibuffers) DEALLOCATE_LOCAL(ppMultibuffers); if (pMultibuffer) DEALLOCATE_LOCAL(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]) { DEALLOCATE_LOCAL(ppMultibuffers); DEALLOCATE_LOCAL(pMultibuffer); client->errorValue = ids[i]; return MultibufferErrorBase + MultibufferBadBuffer; } ppMultibuffers[i] = pMultibuffer[i]->pMultibuffers; for (j = 0; j < i; j++) { if (ppMultibuffers[i] == ppMultibuffers[j]) { DEALLOCATE_LOCAL(ppMultibuffers); DEALLOCATE_LOCAL(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); DEALLOCATE_LOCAL(ppMultibuffers); DEALLOCATE_LOCAL(pMultibuffer); return Success; } static int ProcDestroyImageBuffers (client) register ClientPtr client; { REQUEST (xMbufDestroyImageBuffersReq); WindowPtr pWin; REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq); if (!(pWin = LookupWindow (stuff->window, client))) return BadWindow; DestroyImageBuffers (pWin); return Success; } static int ProcSetMBufferAttributes (client) register ClientPtr client; { REQUEST (xMbufSetMBufferAttributesReq); WindowPtr pWin; MultibuffersPtr pMultibuffers; int len; Mask vmask; Mask index2; CARD32 updateHint; XID *vlist; REQUEST_AT_LEAST_SIZE (xMbufSetMBufferAttributesReq); pWin = LookupWindow (stuff->window, client); if (!pWin) return BadWindow; 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; REQUEST_SIZE_MATCH (xMbufGetMBufferAttributesReq); pWin = LookupWindow (stuff->window, client); if (!pWin) return BadWindow; pMultibuffers = (MultibuffersPtr)LookupIDByType (pWin->drawable.id, MultibuffersResType); if (!pMultibuffers) return BadAccess; ids = (XID *) ALLOCATE_LOCAL (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); DEALLOCATE_LOCAL((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; int n; xMbufBufferInfo *pInfo; int nInfo; DepthPtr pDepth; pDrawable = (DrawablePtr) LookupDrawable (stuff->drawable, client); if (!pDrawable) return BadDrawable; pScreen = pDrawable->pScreen; nInfo = 0; for (i = 0; i < pScreen->numDepths; i++) { pDepth = &pScreen->allowedDepths[i]; nInfo += pDepth->numVids; } pInfo = (xMbufBufferInfo *) ALLOCATE_LOCAL (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); DEALLOCATE_LOCAL ((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) pWin->devPrivates[MultibufferWindowIndex].ptr)) 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 *) ALLOCATE_LOCAL (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]) { DEALLOCATE_LOCAL (pMultibuffer); return MultibufferErrorBase + MultibufferBadBuffer; } pMultibuffers[i] = pMultibuffer[i]->pMultibuffers; for (j = 0; j < i; j++) if (pMultibuffers[i] == pMultibuffers[j]) { DEALLOCATE_LOCAL (pMultibuffer); return BadMatch; } } PerformDisplayRequest (pMultibuffers, pMultibuffer, nbuf); DEALLOCATE_LOCAL (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 *) ALLOCATE_LOCAL(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); DEALLOCATE_LOCAL(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 */ pWin->devPrivates[MultibufferWindowIndex].ptr = 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) pScreen->devPrivates[MultibufferScreenIndex].ptr; (*pMultibufferScreen->PositionWindow) (pWin, x, y); /* if this window is not multibuffered, we're done */ if (!(pMultibuffers = (MultibuffersPtr) pWin->devPrivates[MultibufferWindowIndex].ptr)) 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); 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) pWin->devPrivates[MultibufferWindowIndex].ptr; 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; }