X-Git-Url: https://git.sesse.net/?p=rdpsrv;a=blobdiff_plain;f=Xserver%2Fprograms%2FXserver%2FXext%2Fshm.c;fp=Xserver%2Fprograms%2FXserver%2FXext%2Fshm.c;h=5501f94f41d0c2f3941737b8c7052641d82e308a;hp=0000000000000000000000000000000000000000;hb=b6e6afccf37f4ad0515ef2a698f714fdf1bf23b3;hpb=e3340a110a3b01756b8e67531395a33b40a17d37 diff --git a/Xserver/programs/Xserver/Xext/shm.c b/Xserver/programs/Xserver/Xext/shm.c new file mode 100644 index 0000000..5501f94 --- /dev/null +++ b/Xserver/programs/Xserver/Xext/shm.c @@ -0,0 +1,1089 @@ +/************************************************************ + +Copyright (c) 1989 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +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 +X CONSORTIUM 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 X Consortium 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 X Consortium. + +********************************************************/ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +/* $XConsortium: shm.c,v 1.25 95/04/06 16:00:55 dpw Exp $ */ +/* $XFree86: xc/programs/Xserver/Xext/shm.c,v 3.8 1997/01/18 06:52:59 dawes Exp $ */ + +#include +#ifndef Lynx +#include +#include +#else +#include +#include +#endif +#define NEED_REPLIES +#define NEED_EVENTS +#include "X.h" +#include "Xproto.h" +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "resource.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "gcstruct.h" +#include "extnsionst.h" +#include "servermd.h" +#define _XSHM_SERVER_ +#include "shmstr.h" +#include "Xfuncproto.h" + +typedef struct _ShmDesc { + struct _ShmDesc *next; + int shmid; + int refcnt; + char *addr; + Bool writable; + unsigned long size; +} ShmDescRec, *ShmDescPtr; + +static void miShmPutImage(XSHM_PUT_IMAGE_ARGS); +static void fbShmPutImage(XSHM_PUT_IMAGE_ARGS); +static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); +static int ShmDetachSegment( +#if NeedFunctionPrototypes + pointer /* value */, + XID /* shmseg */ +#endif + ); +static void ShmResetProc( +#if NeedFunctionPrototypes + ExtensionEntry * /* extEntry */ +#endif + ); +static void SShmCompletionEvent( +#if NeedFunctionPrototypes + xShmCompletionEvent * /* from */, + xShmCompletionEvent * /* to */ +#endif + ); + +static DISPATCH_PROC(ProcShmAttach); +static DISPATCH_PROC(ProcShmCreatePixmap); +static DISPATCH_PROC(ProcShmDetach); +static DISPATCH_PROC(ProcShmDispatch); +static DISPATCH_PROC(ProcShmGetImage); +static DISPATCH_PROC(ProcShmGetImage); +static DISPATCH_PROC(ProcShmGetImage); +static DISPATCH_PROC(ProcShmPutImage); +static DISPATCH_PROC(ProcShmQueryVersion); +static DISPATCH_PROC(SProcShmAttach); +static DISPATCH_PROC(SProcShmCreatePixmap); +static DISPATCH_PROC(SProcShmDetach); +static DISPATCH_PROC(SProcShmDispatch); +static DISPATCH_PROC(SProcShmGetImage); +static DISPATCH_PROC(SProcShmPutImage); +static DISPATCH_PROC(SProcShmQueryVersion); + +static unsigned char ShmReqCode; +static int ShmCompletionCode; +static int BadShmSegCode; +static RESTYPE ShmSegType, ShmPixType; +static ShmDescPtr Shmsegs; +static Bool sharedPixmaps; +static int pixmapFormat; +static int shmPixFormat[MAXSCREENS]; +static ShmFuncsPtr shmFuncs[MAXSCREENS]; +static ShmFuncs miFuncs = {NULL, miShmPutImage}; +static ShmFuncs fbFuncs = {fbShmCreatePixmap, fbShmPutImage}; + +#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ +{ \ + shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \ + if (!shmdesc) \ + { \ + client->errorValue = shmseg; \ + return BadShmSegCode; \ + } \ +} + +#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ +{ \ + VERIFY_SHMSEG(shmseg, shmdesc, client); \ + if ((offset & 3) || (offset > shmdesc->size)) \ + { \ + client->errorValue = offset; \ + return BadValue; \ + } \ + if (needwrite && !shmdesc->writable) \ + return BadAccess; \ +} + +#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ +{ \ + if ((offset + len) > shmdesc->size) \ + { \ + return BadAccess; \ + } \ +} + + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#include + +static Bool badSysCall = FALSE; + +static void +SigSysHandler(signo) +int signo; +{ + badSysCall = TRUE; +} + +static Bool CheckForShmSyscall() +{ + void (*oldHandler)(); + int shmid = -1; + + /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ + oldHandler = signal(SIGSYS, SigSysHandler); + + badSysCall = FALSE; + shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); + /* Clean up */ + if (shmid != -1) + { + shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL); + } + signal(SIGSYS, oldHandler); + return(!badSysCall); +} +#endif + +void +ShmExtensionInit() +{ + ExtensionEntry *extEntry; + int i; + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + if (!CheckForShmSyscall()) + { + ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); + return; + } +#endif + +#ifdef INTERNAL_VS_EXTERNAL_PADDING + sharedPixmaps = xFalse; + pixmapFormat = 0; +#else + sharedPixmaps = xTrue; + pixmapFormat = shmPixFormat[0]; + for (i = 0; i < screenInfo.numScreens; i++) + { + if (!shmFuncs[i]) + shmFuncs[i] = &miFuncs; + if (!shmFuncs[i]->CreatePixmap) + sharedPixmaps = xFalse; + if (shmPixFormat[i] && (shmPixFormat[i] != pixmapFormat)) + { + sharedPixmaps = xFalse; + pixmapFormat = 0; + } + } + if (!pixmapFormat) + pixmapFormat = ZPixmap; +#endif + ShmSegType = CreateNewResourceType(ShmDetachSegment); + ShmPixType = CreateNewResourceType(ShmDetachSegment); + if (ShmSegType && ShmPixType && + (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, + ProcShmDispatch, SProcShmDispatch, + ShmResetProc, StandardMinorOpcode))) + { + ShmReqCode = (unsigned char)extEntry->base; + ShmCompletionCode = extEntry->eventBase; + BadShmSegCode = extEntry->errorBase; + EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; + } +} + +/*ARGSUSED*/ +static void +ShmResetProc (extEntry) +ExtensionEntry *extEntry; +{ + int i; + + for (i = 0; i < MAXSCREENS; i++) + { + shmFuncs[i] = (ShmFuncsPtr)NULL; + shmPixFormat[i] = 0; + } +} + +void +ShmRegisterFuncs(pScreen, funcs) + ScreenPtr pScreen; + ShmFuncsPtr funcs; +{ + shmFuncs[pScreen->myNum] = funcs; +} + +void +ShmSetPixmapFormat(pScreen, format) + ScreenPtr pScreen; + int format; +{ + shmPixFormat[pScreen->myNum] = format; +} + +void +ShmRegisterFbFuncs(pScreen) + ScreenPtr pScreen; +{ + shmFuncs[pScreen->myNum] = &fbFuncs; +} + +static int +ProcShmQueryVersion(client) + register ClientPtr client; +{ + xShmQueryVersionReply rep; + register int n; + + REQUEST_SIZE_MATCH(xShmQueryVersionReq); + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.sharedPixmaps = sharedPixmaps; + rep.pixmapFormat = pixmapFormat; + rep.majorVersion = SHM_MAJOR_VERSION; + rep.minorVersion = SHM_MINOR_VERSION; + rep.uid = geteuid(); + rep.gid = getegid(); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + swaps(&rep.uid, n); + swaps(&rep.gid, n); + } + WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep); + return (client->noClientException); +} + +static int +ProcShmAttach(client) + register ClientPtr client; +{ + struct shmid_ds buf; + ShmDescPtr shmdesc; + REQUEST(xShmAttachReq); + + REQUEST_SIZE_MATCH(xShmAttachReq); + LEGAL_NEW_RESOURCE(stuff->shmseg, client); + if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) + { + client->errorValue = stuff->readOnly; + return(BadValue); + } + for (shmdesc = Shmsegs; + shmdesc && (shmdesc->shmid != stuff->shmid); + shmdesc = shmdesc->next) + ; + if (shmdesc) + { + if (!stuff->readOnly && !shmdesc->writable) + return BadAccess; + shmdesc->refcnt++; + } + else + { + shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec)); + if (!shmdesc) + return BadAlloc; + shmdesc->addr = shmat(stuff->shmid, 0, + stuff->readOnly ? SHM_RDONLY : 0); + if ((shmdesc->addr == ((char *)-1)) || + shmctl(stuff->shmid, IPC_STAT, &buf)) + { + xfree(shmdesc); + return BadAccess; + } + shmdesc->shmid = stuff->shmid; + shmdesc->refcnt = 1; + shmdesc->writable = !stuff->readOnly; + shmdesc->size = buf.shm_segsz; + shmdesc->next = Shmsegs; + Shmsegs = shmdesc; + } + if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc)) + return BadAlloc; + return(client->noClientException); +} + +/*ARGSUSED*/ +static int +ShmDetachSegment(value, shmseg) + pointer value; /* must conform to DeleteType */ + XID shmseg; +{ + ShmDescPtr shmdesc = (ShmDescPtr)value; + ShmDescPtr *prev; + + if (--shmdesc->refcnt) + return TRUE; + shmdt(shmdesc->addr); + for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next) + ; + *prev = shmdesc->next; + xfree(shmdesc); + return Success; +} + +static int +ProcShmDetach(client) + register ClientPtr client; +{ + ShmDescPtr shmdesc; + REQUEST(xShmDetachReq); + + REQUEST_SIZE_MATCH(xShmDetachReq); + VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); + FreeResource(stuff->shmseg, RT_NONE); + return(client->noClientException); +} + +static void +miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) + DrawablePtr dst; + GCPtr pGC; + int depth, w, h, sx, sy, sw, sh, dx, dy; + unsigned int format; + char *data; +{ + PixmapPtr pmap; + GCPtr putGC; + + putGC = GetScratchGC(depth, dst->pScreen); + if (!putGC) + return; + pmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth); + if (!pmap) + { + FreeScratchGC(putGC); + return; + } + ValidateGC((DrawablePtr)pmap, putGC); + (*putGC->ops->PutImage)((DrawablePtr)pmap, putGC, depth, -sx, -sy, w, h, 0, + (format == XYPixmap) ? XYPixmap : ZPixmap, data); + FreeScratchGC(putGC); + if (format == XYBitmap) + (void)(*pGC->ops->CopyPlane)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh, + dx, dy, 1L); + else + (void)(*pGC->ops->CopyArea)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh, + dx, dy); + (*pmap->drawable.pScreen->DestroyPixmap)(pmap); +} + +static void +fbShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data) + DrawablePtr dst; + GCPtr pGC; + int depth, w, h, sx, sy, sw, sh, dx, dy; + unsigned int format; + char *data; +{ + if ((format == ZPixmap) || (depth == 1)) + { + PixmapPtr pPixmap; + + pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, + /*XXX*/depth, PixmapBytePad(w, depth), (pointer)data); + if (!pPixmap) + return; + if (format == XYBitmap) + (void)(*pGC->ops->CopyPlane)((DrawablePtr)pPixmap, dst, pGC, + sx, sy, sw, sh, dx, dy, 1L); + else + (void)(*pGC->ops->CopyArea)((DrawablePtr)pPixmap, dst, pGC, + sx, sy, sw, sh, dx, dy); + FreeScratchPixmapHeader(pPixmap); + } + else + miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, + data); +} + +static int +ProcShmPutImage(client) + register ClientPtr client; +{ + register GCPtr pGC; + register DrawablePtr pDraw; + long length; +#ifdef INTERNAL_VS_EXTERNAL_PADDING + long lengthProto; + char *tmpImage; + int tmpAlloced = 0; +#endif + ShmDescPtr shmdesc; + REQUEST(xShmPutImageReq); + + REQUEST_SIZE_MATCH(xShmPutImageReq); + VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); + if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) + return BadValue; + if (stuff->format == XYBitmap) + { + if (stuff->depth != 1) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); +#ifdef INTERNAL_VS_EXTERNAL_PADDING + lengthProto = PixmapBytePadProto(stuff->totalWidth, 1); +#endif + } + else if (stuff->format == XYPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, 1); + length *= stuff->depth; +#ifdef INTERNAL_VS_EXTERNAL_PADDING + lengthProto = PixmapBytePadProto(stuff->totalWidth, 1); + lengthProto *= stuff->depth; +#endif + } + else if (stuff->format == ZPixmap) + { + if (pDraw->depth != stuff->depth) + return BadMatch; + length = PixmapBytePad(stuff->totalWidth, stuff->depth); +#ifdef INTERNAL_VS_EXTERNAL_PADDING + lengthProto = PixmapBytePadProto(stuff->totalWidth, stuff->depth); +#endif + } + else + { + client->errorValue = stuff->format; + return BadValue; + } + +#ifdef INTERNAL_VS_EXTERNAL_PADDING + VERIFY_SHMSIZE(shmdesc, stuff->offset, lengthProto * stuff->totalHeight, + client); +#else + VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, + client); +#endif + if (stuff->srcX > stuff->totalWidth) + { + client->errorValue = stuff->srcX; + return BadValue; + } + if (stuff->srcY > stuff->totalHeight) + { + client->errorValue = stuff->srcY; + return BadValue; + } + if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) + { + client->errorValue = stuff->srcWidth; + return BadValue; + } + if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) + { + client->errorValue = stuff->srcHeight; + return BadValue; + } + +#ifdef INTERNAL_VS_EXTERNAL_PADDING + /* handle 64 bit case where protocol may pad to 32 and we want 64 + * In this case, length is what the server wants and lengthProto is + * what the protocol thinks it is. If the the two are different, + * copy the protocol version (i.e. the memory shared between the + * server and the client) to a version with a scanline pad of 64. + */ + if (length != lengthProto) + { + register int i; + char * stuffptr, /* pointer into protocol data */ + * tmpptr; /* new location to copy to */ + + if(!(tmpImage = (char *) ALLOCATE_LOCAL(length*stuff->totalHeight))) + return (BadAlloc); + tmpAlloced = 1; + + bzero(tmpImage,length*stuff->totalHeight); + + if (stuff->format == XYPixmap) + { + int lineBytes = PixmapBytePad(stuff->totalWidth, 1); + int lineBytesProto = PixmapBytePadProto(stuff->totalWidth, 1); + int depth = stuff->depth; + + stuffptr = shmdesc->addr + stuff->offset ; + tmpptr = tmpImage; + for (i = 0; i < stuff->totalHeight*stuff->depth; + stuffptr += lineBytesProto,tmpptr += lineBytes, i++) + bcopy(stuffptr,tmpptr,lineBytesProto); + } + else + { + for (i = 0, + stuffptr = shmdesc->addr + stuff->offset, + tmpptr=tmpImage; + i < stuff->totalHeight; + stuffptr += lengthProto,tmpptr += length, i++) + bcopy(stuffptr,tmpptr,lengthProto); + } + } + /* handle 64-bit case where stuff is not 64-bit aligned + */ + else if ((unsigned long)(shmdesc->addr+stuff->offset) & + (sizeof(long)-1)) + { + if(!(tmpImage = (char *) ALLOCATE_LOCAL(length*stuff->totalHeight))) + return (BadAlloc); + tmpAlloced = 1; + bcopy((char *)(shmdesc->addr+stuff->offset), + tmpImage, + length*stuff->totalHeight); + } + else + tmpImage = (char *)(shmdesc->addr+stuff->offset); +#endif + + if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) || + ((stuff->format != ZPixmap) && + (stuff->srcX < screenInfo.bitmapScanlinePad) && + ((stuff->format == XYBitmap) || + ((stuff->srcY == 0) && + (stuff->srcHeight == stuff->totalHeight))))) && + ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth)) + (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, + stuff->dstX, stuff->dstY, + stuff->totalWidth, stuff->srcHeight, + stuff->srcX, stuff->format, +#ifdef INTERNAL_VS_EXTERNAL_PADDING + tmpImage + +#else + shmdesc->addr + stuff->offset + +#endif + (stuff->srcY * length)); + else + (*shmFuncs[pDraw->pScreen->myNum]->PutImage)( + pDraw, pGC, stuff->depth, stuff->format, + stuff->totalWidth, stuff->totalHeight, + stuff->srcX, stuff->srcY, + stuff->srcWidth, stuff->srcHeight, + stuff->dstX, stuff->dstY, +#ifdef INTERNAL_VS_EXTERNAL_PADDING + tmpImage); + +#else + shmdesc->addr + stuff->offset); +#endif + + if (stuff->sendEvent) + { + xShmCompletionEvent ev; + + ev.type = ShmCompletionCode; + ev.drawable = stuff->drawable; + ev.sequenceNumber = client->sequence; + ev.minorEvent = X_ShmPutImage; + ev.majorEvent = ShmReqCode; + ev.shmseg = stuff->shmseg; + ev.offset = stuff->offset; + WriteEventsToClient(client, 1, (xEvent *) &ev); + } + +#ifdef INTERNAL_VS_EXTERNAL_PADDING + if (tmpAlloced) + DEALLOCATE_LOCAL(tmpImage); +#endif + + return (client->noClientException); +} + + + +static int +ProcShmGetImage(client) + register ClientPtr client; +{ + register DrawablePtr pDraw; + long lenPer, length; + Mask plane; + xShmGetImageReply xgi; + ShmDescPtr shmdesc; + int n; +#ifdef INTERNAL_VS_EXTERNAL_PADDING + long widthBytesLine,widthBytesLineProto; + long lenPerProto,lengthProto; + char *tmpImage; + int tmpAlloced = 0; +#endif + + REQUEST(xShmGetImageReq); + + REQUEST_SIZE_MATCH(xShmGetImageReq); + if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) + { + client->errorValue = stuff->format; + return(BadValue); + } + VERIFY_DRAWABLE(pDraw, stuff->drawable, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + if (pDraw->type == DRAWABLE_WINDOW) + { + if( /* check for being viewable */ + !((WindowPtr) pDraw)->realized || + /* check for being on screen */ + pDraw->x + stuff->x < 0 || + pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width || + pDraw->y + stuff->y < 0 || + pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height || + /* check for being inside of border */ + stuff->x < - wBorderWidth((WindowPtr)pDraw) || + stuff->x + (int)stuff->width > + wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || + stuff->y < -wBorderWidth((WindowPtr)pDraw) || + stuff->y + (int)stuff->height > + wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height + ) + return(BadMatch); + xgi.visual = wVisual(((WindowPtr)pDraw)); + } + else + { + if (stuff->x < 0 || + stuff->x+(int)stuff->width > pDraw->width || + stuff->y < 0 || + stuff->y+(int)stuff->height > pDraw->height + ) + return(BadMatch); + xgi.visual = None; + } + xgi.type = X_Reply; + xgi.length = 0; + xgi.sequenceNumber = client->sequence; + xgi.depth = pDraw->depth; + if(stuff->format == ZPixmap) + { +#ifdef INTERNAL_VS_EXTERNAL_PADDING + widthBytesLine = PixmapBytePad(stuff->width, pDraw->depth); + length = widthBytesLine * stuff->height; + widthBytesLineProto = PixmapBytePadProto(stuff->width, pDraw->depth); + lengthProto = widthBytesLineProto * stuff->height; +#else + length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; +#endif + } + else + { +#ifdef INTERNAL_VS_EXTERNAL_PADDING + widthBytesLine = PixmapBytePad(stuff->width, 1); + lenPer = widthBytesLine * stuff->height; + plane = ((Mask)1) << (pDraw->depth - 1); + /* only planes asked for */ + length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); + + widthBytesLineProto = PixmapBytePadProto(stuff->width, 1); + lenPerProto = widthBytesLineProto * stuff->height; + lengthProto = lenPerProto * Ones(stuff->planeMask & + (plane | (plane - 1))); +#else + lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; + plane = ((Mask)1) << (pDraw->depth - 1); + /* only planes asked for */ + length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); +#endif + } + +#ifdef INTERNAL_VS_EXTERNAL_PADDING + VERIFY_SHMSIZE(shmdesc, stuff->offset, lengthProto, client); + xgi.size = lengthProto; +#else + VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); + xgi.size = length; +#endif + + if (length == 0) + { + /* nothing to do */ + } + else if (stuff->format == ZPixmap) + { +#ifdef INTERNAL_VS_EXTERNAL_PADDING + /* check for protocol/server padding differences. + */ + if ((widthBytesLine != widthBytesLineProto) || + ((unsigned long)shmdesc->addr + stuff->offset & (sizeof(long)-1))) + { + /* temp stuff for 64 bit alignment stuff */ + register char * bufPtr, * protoPtr; + register int i; + + if(!(tmpImage = (char *) ALLOCATE_LOCAL(length))) + return (BadAlloc); + tmpAlloced = 1; + + (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, stuff->planeMask, + tmpImage); + + /* for 64-bit server, convert image to pad to 32 bits + */ + bzero(shmdesc->addr + stuff->offset,lengthProto); + + for (i=0,bufPtr=tmpImage,protoPtr=shmdesc->addr + stuff->offset; + i < stuff->height; + bufPtr += widthBytesLine,protoPtr += widthBytesLineProto, + i++) + bcopy(bufPtr,protoPtr,widthBytesLineProto); + } + else + { + (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, stuff->planeMask, + shmdesc->addr + stuff->offset); + } +#else + (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, stuff->planeMask, + shmdesc->addr + stuff->offset); +#endif + } + else + { +#ifdef INTERNAL_VS_EXTERNAL_PADDING + /* check for protocol/server padding differences. + */ + if ((widthBytesLine != widthBytesLineProto) || + ((unsigned long)shmdesc->addr + stuff->offset & + (sizeof(long)-1))) + { + if(!(tmpImage = (char *) ALLOCATE_LOCAL(length))) + return (BadAlloc); + tmpAlloced = 1; + } +#endif + + length = stuff->offset; + for (; plane; plane >>= 1) + { + if (stuff->planeMask & plane) + { +#ifdef INTERNAL_VS_EXTERNAL_PADDING + if ((widthBytesLine != widthBytesLineProto) || + ((unsigned long)shmdesc->addr + stuff->offset & + (sizeof(long)-1))) + { + /* get image for each plane. + */ + (*pDraw->pScreen->GetImage)(pDraw, + stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, plane, + tmpImage); + + /* for 64-bit server, convert image to pad to 32 bits */ + bzero(shmdesc->addr+length, widthBytesLine); + bcopy(tmpImage, shmdesc->addr+length, widthBytesLineProto); + /* increment length */ + length += lenPerProto; + } + else /* no diff between protocol and server */ + { + (*pDraw->pScreen->GetImage)(pDraw, + stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, plane, + shmdesc->addr + length); + length += lenPer; + } +#else + (*pDraw->pScreen->GetImage)(pDraw, + stuff->x, stuff->y, + stuff->width, stuff->height, + stuff->format, plane, + shmdesc->addr + length); + length += lenPer; +#endif + } + } + } + + if (client->swapped) { + swaps(&xgi.sequenceNumber, n); + swapl(&xgi.length, n); + swapl(&xgi.visual, n); + swapl(&xgi.size, n); + } + WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); + +#ifdef INTERNAL_VS_EXTERNAL_PADDING + if (tmpAlloced) + DEALLOCATE_LOCAL(tmpImage); +#endif + + return(client->noClientException); +} + +static PixmapPtr +fbShmCreatePixmap (pScreen, width, height, depth, addr) + ScreenPtr pScreen; + int width; + int height; + int depth; + char *addr; +{ + register PixmapPtr pPixmap; + + pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth); + if (!pPixmap) + return NullPixmap; + + if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, + /*XXX*/depth, PixmapBytePad(width, depth), (pointer)addr)) + return NullPixmap; + return pPixmap; +} + +static int +ProcShmCreatePixmap(client) + register ClientPtr client; +{ + PixmapPtr pMap; + register DrawablePtr pDraw; + DepthPtr pDepth; + register int i; + ShmDescPtr shmdesc; + REQUEST(xShmCreatePixmapReq); + + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + client->errorValue = stuff->pid; + if (!sharedPixmaps) + return BadImplementation; + LEGAL_NEW_RESOURCE(stuff->pid, client); + VERIFY_GEOMETRABLE(pDraw, stuff->drawable, client); + VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); + if (!stuff->width || !stuff->height) + { + client->errorValue = 0; + return BadValue; + } + if (stuff->depth != 1) + { + pDepth = pDraw->pScreen->allowedDepths; + for (i=0; ipScreen->numDepths; i++, pDepth++) + if (pDepth->depth == stuff->depth) + goto CreatePmap; + client->errorValue = stuff->depth; + return BadValue; + } +CreatePmap: + VERIFY_SHMSIZE(shmdesc, stuff->offset, + PixmapBytePad(stuff->width, stuff->depth) * stuff->height, + client); + pMap = (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap)( + pDraw->pScreen, stuff->width, + stuff->height, stuff->depth, + shmdesc->addr + stuff->offset); + if (pMap) + { + pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pMap->drawable.id = stuff->pid; + if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) + { + shmdesc->refcnt++; + if (AddResource(stuff->pid, ShmPixType, (pointer)shmdesc)) + return(client->noClientException); + FreeResource(stuff->pid, RT_NONE); + } + } + return (BadAlloc); +} + +static int +ProcShmDispatch (client) + register ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_ShmQueryVersion: + return ProcShmQueryVersion(client); + case X_ShmAttach: + return ProcShmAttach(client); + case X_ShmDetach: + return ProcShmDetach(client); + case X_ShmPutImage: + return ProcShmPutImage(client); + case X_ShmGetImage: + return ProcShmGetImage(client); + case X_ShmCreatePixmap: + return ProcShmCreatePixmap(client); + default: + return BadRequest; + } +} + +static void +SShmCompletionEvent(from, to) + xShmCompletionEvent *from, *to; +{ + to->type = from->type; + cpswaps(from->sequenceNumber, to->sequenceNumber); + cpswapl(from->drawable, to->drawable); + cpswaps(from->minorEvent, to->minorEvent); + to->majorEvent = from->majorEvent; + cpswapl(from->shmseg, to->shmseg); + cpswapl(from->offset, to->offset); +} + +static int +SProcShmQueryVersion(client) + register ClientPtr client; +{ + register int n; + REQUEST(xShmQueryVersionReq); + + swaps(&stuff->length, n); + return ProcShmQueryVersion(client); +} + +static int +SProcShmAttach(client) + ClientPtr client; +{ + register int n; + REQUEST(xShmAttachReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmAttachReq); + swapl(&stuff->shmseg, n); + swapl(&stuff->shmid, n); + return ProcShmAttach(client); +} + +static int +SProcShmDetach(client) + ClientPtr client; +{ + register int n; + REQUEST(xShmDetachReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmDetachReq); + swapl(&stuff->shmseg, n); + return ProcShmDetach(client); +} + +static int +SProcShmPutImage(client) + ClientPtr client; +{ + register int n; + REQUEST(xShmPutImageReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmPutImageReq); + swapl(&stuff->drawable, n); + swapl(&stuff->gc, n); + swaps(&stuff->totalWidth, n); + swaps(&stuff->totalHeight, n); + swaps(&stuff->srcX, n); + swaps(&stuff->srcY, n); + swaps(&stuff->srcWidth, n); + swaps(&stuff->srcHeight, n); + swaps(&stuff->dstX, n); + swaps(&stuff->dstY, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->offset, n); + return ProcShmPutImage(client); +} + +static int +SProcShmGetImage(client) + ClientPtr client; +{ + register int n; + REQUEST(xShmGetImageReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmGetImageReq); + swapl(&stuff->drawable, n); + swaps(&stuff->x, n); + swaps(&stuff->y, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + swapl(&stuff->planeMask, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->offset, n); + return ProcShmGetImage(client); +} + +static int +SProcShmCreatePixmap(client) + ClientPtr client; +{ + register int n; + REQUEST(xShmCreatePixmapReq); + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xShmCreatePixmapReq); + swapl(&stuff->drawable, n); + swaps(&stuff->width, n); + swaps(&stuff->height, n); + swapl(&stuff->shmseg, n); + swapl(&stuff->offset, n); + return ProcShmCreatePixmap(client); +} + +static int +SProcShmDispatch (client) + register ClientPtr client; +{ + REQUEST(xReq); + switch (stuff->data) + { + case X_ShmQueryVersion: + return SProcShmQueryVersion(client); + case X_ShmAttach: + return SProcShmAttach(client); + case X_ShmDetach: + return SProcShmDetach(client); + case X_ShmPutImage: + return SProcShmPutImage(client); + case X_ShmGetImage: + return SProcShmGetImage(client); + case X_ShmCreatePixmap: + return SProcShmCreatePixmap(client); + default: + return BadRequest; + } +}