/************************************************************ 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 "X.h" #include "Xproto.h" #include "misc.h" #include "os.h" #include "windowstr.h" #include "scrnintstr.h" #include "pixmapstr.h" #include "extnsionst.h" #include "dixstruct.h" #include "resource.h" #include "opaque.h" #define _MULTIBUF_SERVER_ /* don't want Xlib structures */ #include "multibufst.h" #include "regionstr.h" #include "gcstruct.h" #include "inputstr.h" #ifndef WIN32 #include #endif #ifdef PANORAMIX #include "panoramiX.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) #ifdef PANORAMIX extern int PanoramiXNumScreens; extern Bool noPanoramiXExtension; extern PanoramiXWindow *PanoramiXWinRoot; extern PanoramiXPmap *PanoramiXPmapRoot; extern PanoramiXData *panoramiXdataPtr; #endif /* The _Multibuffer and _Multibuffers structures below refer to each other, * so we need this forward declaration */ typedef struct _Multibuffers *MultibuffersPtr; /* * per-Multibuffer data */ typedef struct _Multibuffer { MultibuffersPtr pMultibuffers; /* associated window data */ Mask eventMask; /* MultibufferClobberNotifyMask|ExposureMask|MultibufferUpdateNotifyMask */ Mask otherEventMask; /* mask of all other clients event masks */ OtherClients *otherClients; /* other clients that want events */ int number; /* index of this buffer into array */ int side; /* always Mono */ int clobber; /* Unclobbered, PartiallyClobbered, FullClobbered */ PixmapPtr pPixmap; /* associated pixmap */ } MultibufferRec, *MultibufferPtr; /* * per-window data */ typedef struct _Multibuffers { WindowPtr pWindow; /* associated window */ int numMultibuffer; /* count of buffers */ int refcnt; /* ref count for delete */ int displayedMultibuffer; /* currently active buffer */ int updateAction; /* Undefined, Background, Untouched, Copied */ int updateHint; /* Frequent, Intermittent, Static */ int windowMode; /* always Mono */ TimeStamp lastUpdate; /* time of last update */ unsigned short width, height; /* last known window size */ short x, y; /* for static gravity */ MultibufferPtr buffers; /* array of numMultibuffer buffers */ } MultibuffersRec; /* * per-screen data */ typedef struct _MultibufferScreen { Bool (*PositionWindow)(); } MultibufferScreenRec, *MultibufferScreenPtr; /* * per display-image-buffers request data. */ typedef struct _DisplayRequest { struct _DisplayRequest *next; TimeStamp activateTime; ClientPtr pClient; XID id; } DisplayRequestRec, *DisplayRequestPtr; static unsigned char MultibufferReqCode; static int MultibufferEventBase; static int MultibufferErrorBase; int MultibufferScreenIndex = -1; int MultibufferWindowIndex = -1; static void PerformDisplayRequest (); static void DisposeDisplayRequest (); static Bool QueueDisplayRequest (); static void BumpTimeStamp (); void MultibufferExpose (); void MultibufferUpdate (); static void AliasMultibuffer (); int CreateImageBuffers (); void DestroyImageBuffers (); int DisplayImageBuffers (); static void RecalculateMultibufferOtherEvents (); static int EventSelectForMultibuffer(); /* * The Pixmap associated with a buffer can be found as a resource * with this type */ RESTYPE MultibufferDrawableResType; static int MultibufferDrawableDelete (); /* * 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 (); /* * The per-window data can be found as a resource with this type, * using the window resource id */ static RESTYPE MultibuffersResType; static int MultibuffersDelete (); /* * 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 (); /**************** * MultibufferExtensionInit * * Called from InitExtensions in main() * ****************/ static int ProcMultibufferDispatch(), SProcMultibufferDispatch(); static void MultibufferResetProc(); static void SClobberNotifyEvent(), SUpdateNotifyEvent(); static Bool MultibufferPositionWindow(); 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))) { MultibufferReqCode = (unsigned char)extEntry->base; MultibufferEventBase = extEntry->eventBase; MultibufferErrorBase = extEntry->errorBase; EventSwapVector[MultibufferEventBase + MultibufferClobberNotify] = SClobberNotifyEvent; EventSwapVector[MultibufferEventBase + MultibufferUpdateNotify] = 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; { REQUEST(xMbufGetBufferVersionReq); 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) ts_x_origin; gcvalues[3] = (pointer) 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; } #ifdef PANORAMIX static int ProcPanoramiXCreateImageBuffers (client) register ClientPtr client; { REQUEST(xMbufCreateImageBuffersReq); register int result; int i, j, k, len; PanoramiXWindow *pPanoramiXWin = PanoramiXWinRoot; PanoramiXWindow *next; PanoramiXWindow *pPanoramiXids; PanoramiXWindow *pPanoramiXPrev_ids; PanoramiXPmap *local; PanoramiXPmap *pPanoramiXPmap = PanoramiXPmapRoot; CARD32 *value, *orig_ids; XID *ids; XID ID; DrawablePtr pDrawable; REQUEST_AT_LEAST_SIZE (xMbufCreateImageBuffersReq); PANORAMIXFIND_ID(pPanoramiXWin,stuff->window); IF_RETURN(!pPanoramiXWin, BadRequest); len = stuff->length - (sizeof(xMbufCreateImageBuffersReq) >> 2); ids = (XID *)ALLOCATE_LOCAL(sizeof(XID)*len); orig_ids = (XID *)ALLOCATE_LOCAL(sizeof(XID)*len); if (!ids) return BadAlloc; memcpy((char *)orig_ids, (char *) &stuff[1], len * sizeof(XID)); value = (CARD32 *)&stuff[1]; /* New resources are pixmaps */ FOR_NSCREENS_OR_ONCE(pPanoramiXWin , j) { stuff->window = pPanoramiXWin->info[j].id; for (i = 0; i < len; i++) { ids[i] = (XID)orig_ids[i]; /* These will be MultibufferDrawableResType & MultibufferResType */ pPanoramiXPmap = PanoramiXPmapRoot; PANORAMIXFIND_ID(pPanoramiXPmap, ids[i]); if (!pPanoramiXPmap) { local = (PanoramiXWindow *)Xcalloc(sizeof(PanoramiXWindow)); for (k = 0; k <= PanoramiXNumScreens - 1; k++) { ID = k ? FakeClientID(client->index) : ids[i]; local->info[k].id = ID; } local->FreeMe = FALSE; PANORAMIXFIND_LAST(pPanoramiXPmap, PanoramiXPmapRoot); pPanoramiXPmap->next = local; value[i] = local->info[j].id; }else value[i] = pPanoramiXPmap->info[j].id; } if (!j) noPanoramiXExtension = TRUE; result = ProcCreateImageBuffers (client); noPanoramiXExtension = FALSE; BREAK_IF(result != Success); } if (result != Success) { if (ids) Xfree(ids); if (orig_ids) Xfree(orig_ids); if (local) Xfree(local); } return (result); } #endif #ifdef PANORAMIX int #else static int #endif 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); } #ifdef PANORAMIX if (noPanoramiXExtension) #endif 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; #ifdef PANORAMIX WindowPtr pWndw; PanoramiXPmap *pPanoramiXPmap = PanoramiXPmapRoot; MultibufferPtr *pScrn0Multibuffer; MultibuffersPtr *ppScrn0Multibuffers; int k; int panoramiX_buf = 0; Bool FoundScreen; #endif REQUEST_AT_LEAST_SIZE (xMbufDisplayImageBuffersReq); nbuf = stuff->length - (sizeof (xMbufDisplayImageBuffersReq) >> 2); if (!nbuf) return Success; minDelay = stuff->minDelay; ids = (XID *) &stuff[1]; #ifdef PANORAMIX if (!noPanoramiXExtension) { int maxbuf = 0; maxbuf = nbuf * PanoramiXNumScreens; ppScrn0Multibuffers = (MultibuffersPtr *) xalloc(maxbuf * sizeof (MultibuffersPtr)); pScrn0Multibuffer = (MultibufferPtr *) xalloc (maxbuf * sizeof(MultibufferPtr)); if (!ppScrn0Multibuffers || !pScrn0Multibuffer) { if ( sizeof (long) != sizeof(CARD32) ) DEALLOCATE_LOCAL(ids); xfree (ppScrn0Multibuffers); xfree (pScrn0Multibuffer); client->errorValue = 0; return BadAlloc; } } #endif 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++) { #ifdef PANORAMIX if (!noPanoramiXExtension) { pPanoramiXPmap = PanoramiXPmapRoot; PANORAMIXFIND_ID(pPanoramiXPmap, ids[i]); if (!pPanoramiXPmap){ if ( sizeof (long) != sizeof(CARD32) ) DEALLOCATE_LOCAL(ids); xfree (ppMultibuffers); xfree (pMultibuffer); client->errorValue = ids[i]; return MultibufferErrorBase + MultibufferBadBuffer; } FoundScreen = FALSE; pScrn0Multibuffer[panoramiX_buf] = (MultibufferPtr) LookupIDByType (ids[i], MultibufferResType); ppScrn0Multibuffers[i] = pScrn0Multibuffer[i]->pMultibuffers; pWndw = ppScrn0Multibuffers[i]->pWindow; for (k = 0; (k < PanoramiXNumScreens && !FoundScreen); k++) { pMultibuffer[panoramiX_buf] = (MultibufferPtr) LookupIDByType (pPanoramiXPmap->info[k].id, MultibufferResType); if (!pMultibuffer[i]) { if ( sizeof (long) != sizeof(CARD32) ) DEALLOCATE_LOCAL(ids); xfree (ppMultibuffers); xfree (pMultibuffer); client->errorValue = ids[i]; return MultibufferErrorBase + MultibufferBadBuffer; } ppMultibuffers[panoramiX_buf] = pMultibuffer[panoramiX_buf]->pMultibuffers; /* Figure out where the buffer resides, which screens */ if ( ((pWndw->drawable.x < 0) && (pWndw->drawable.x + pWndw->drawable.width < 0)) || ( (pWndw->drawable.x > panoramiXdataPtr[k].x + panoramiXdataPtr[k].width) && (pWndw->drawable.x + pWndw->drawable.width > panoramiXdataPtr[k].x + panoramiXdataPtr[k].width))) /* its not on screen - k -, try next screen */ continue; if ( ((pWndw->drawable.y < 0) && (pWndw->drawable.y + pWndw->drawable.height < 0)) || ( (pWndw->drawable.y > panoramiXdataPtr[k].y + panoramiXdataPtr[k].height) && (pWndw->drawable.y + pWndw->drawable.height > panoramiXdataPtr[k].y + panoramiXdataPtr[k].height))) /* its not on screen - k -, try next screen */ continue; /* The window resides on screen k, which means we need to keep the buffer information for this screen */ panoramiX_buf++; /* Is it only on this screen, or does it enter onto another screen */ if ( ((pWndw->drawable.x + pWndw->drawable.width) <= (panoramiXdataPtr[k].x + panoramiXdataPtr[k].width)) && ((pWndw->drawable.y + pWndw->drawable.height) <= (panoramiXdataPtr[k].y + panoramiXdataPtr[k].height )) ) FoundScreen = TRUE; } /* for each screen k */ for (j = 0; j < i; j++) { if (ppScrn0Multibuffers[i] == ppScrn0Multibuffers[j]) { if ( sizeof (long) != sizeof(CARD32) ) DEALLOCATE_LOCAL(ids); DEALLOCATE_LOCAL(ppScrn0Multibuffers); DEALLOCATE_LOCAL(pScrn0Multibuffer); DEALLOCATE_LOCAL(ppMultibuffers); DEALLOCATE_LOCAL(pMultibuffer); client->errorValue = ids[i]; return BadMatch; } } bufferTime = ppScrn0Multibuffers[i]->lastUpdate; }else { #endif 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; #ifdef PANORAMIX } #endif BumpTimeStamp (&bufferTime, minDelay); if (CompareTimeStamps (bufferTime, activateTime) == LATER) activateTime = bufferTime; } UpdateCurrentTime (); if (CompareTimeStamps (activateTime, currentTime) == LATER && QueueDisplayRequest (client, activateTime)) { ; } else #ifdef PANORAMIX if (!noPanoramiXExtension){ PerformDisplayRequest (ppMultibuffers, pMultibuffer, panoramiX_buf); }else #endif PerformDisplayRequest (ppMultibuffers, pMultibuffer, nbuf); #ifdef PANORAMIX if (!noPanoramiXExtension){ DEALLOCATE_LOCAL(ppScrn0Multibuffers); DEALLOCATE_LOCAL(pScrn0Multibuffer); } #endif DEALLOCATE_LOCAL(ppMultibuffers); DEALLOCATE_LOCAL(pMultibuffer); return Success; } #ifdef PANORAMIX static int ProcPanoramiXDestroyImageBuffers (client) ClientPtr client; { REQUEST (xMbufDestroyImageBuffersReq); WindowPtr pWin; register int result; int j; PanoramiXWindow *pPanoramiXWin = PanoramiXWinRoot; REQUEST_SIZE_MATCH (xMbufDestroyImageBuffersReq); PANORAMIXFIND_ID(pPanoramiXWin,stuff->window); IF_RETURN(!pPanoramiXWin, BadRequest); FOR_NSCREENS_OR_ONCE(pPanoramiXWin , j) { stuff->window = pPanoramiXWin->info[j].id; result = ProcDestroyImageBuffers (client); BREAK_IF(result != Success); } return (result); } #endif #ifdef PANORAMIX int #else static int #endif 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; } #ifdef PANORAMIX static int ProcPanoramiXSetMBufferAttributes (client) ClientPtr client; { REQUEST (xMbufSetMBufferAttributesReq); WindowPtr pWin; register int result; int j; PanoramiXWindow *pPanoramiXWin = PanoramiXWinRoot; REQUEST_SIZE_MATCH (xMbufSetMBufferAttributesReq); PANORAMIXFIND_ID(pPanoramiXWin,stuff->window); IF_RETURN(!pPanoramiXWin, BadRequest); FOR_NSCREENS_OR_ONCE(pPanoramiXWin , j) { stuff->window = pPanoramiXWin->info[j].id; result = ProcSetMBufferAttributes (client); BREAK_IF(result != Success); } return (result); } #endif #ifdef PANORAMIX int #else static int #endif ProcSetMBufferAttributes (client) register ClientPtr client; { REQUEST (xMbufSetMBufferAttributesReq); WindowPtr pWin; MultibuffersPtr pMultibuffers; int len; Mask vmask; Mask index; 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) { index = (Mask) lowbit (vmask); vmask &= ~index; switch (index) { 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, index; 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) { index = (Mask) lowbit (vmask); vmask &= ~index; switch (index) { 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; } 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: #ifdef PANORAMIX if ( !noPanoramiXExtension ) return ProcPanoramiXCreateImageBuffers (client); else return ProcCreateImageBuffers (client); #else return ProcCreateImageBuffers (client); #endif case X_MbufDisplayImageBuffers: return ProcDisplayImageBuffers (client); case X_MbufDestroyImageBuffers: #ifdef PANORAMIX if ( !noPanoramiXExtension ) return ProcPanoramiXDestroyImageBuffers (client); else return ProcDestroyImageBuffers (client); #else return ProcDestroyImageBuffers (client); #endif case X_MbufSetMBufferAttributes: #ifdef PANORAMIX if ( !noPanoramiXExtension ) return ProcPanoramiXSetMBufferAttributes (client); else return ProcSetMBufferAttributes (client); #else return ProcSetMBufferAttributes (client); #endif 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; ScreenPtr pScreen = pWin->drawable.pScreen; extern RegionPtr CreateUnclippedWinSize(); 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(pScreen, pWinSize, -pWin->drawable.x, -pWin->drawable.y); REGION_INTERSECT(pScreen, pExposed, pExposed, pWinSize); REGION_DESTROY(pScreen, pWinSize); MultibufferExpose (pPrevMultibuffer, pExposed); REGION_DESTROY(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)) { 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)) { 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, time) MultibufferPtr pMultibuffer; CARD32 time; { xMbufUpdateNotifyEvent event; event.type = MultibufferEventBase + MultibufferUpdateNotify; event.buffer = pMultibuffer->pPixmap->drawable.id; event.timeStamp = time; (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; }