]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/Xext/shm.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / programs / Xserver / Xext / shm.c
1 /************************************************************
2
3 Copyright (c) 1989  X Consortium
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
25
26 ********************************************************/
27
28 /* THIS IS NOT AN X CONSORTIUM STANDARD */
29
30 /* $XConsortium: shm.c,v 1.25 95/04/06 16:00:55 dpw Exp $ */
31 /* $XFree86: xc/programs/Xserver/Xext/shm.c,v 3.8 1997/01/18 06:52:59 dawes Exp $ */
32
33 #include <sys/types.h>
34 #ifndef Lynx
35 #include <sys/ipc.h>
36 #include <sys/shm.h>
37 #else
38 #include <ipc.h>
39 #include <shm.h>
40 #endif
41 #define NEED_REPLIES
42 #define NEED_EVENTS
43 #include "X.h"
44 #include "Xproto.h"
45 #include "misc.h"
46 #include "os.h"
47 #include "dixstruct.h"
48 #include "resource.h"
49 #include "scrnintstr.h"
50 #include "windowstr.h"
51 #include "pixmapstr.h"
52 #include "gcstruct.h"
53 #include "extnsionst.h"
54 #include "servermd.h"
55 #define _XSHM_SERVER_
56 #include "shmstr.h"
57 #include "Xfuncproto.h"
58
59 typedef struct _ShmDesc {
60     struct _ShmDesc *next;
61     int shmid;
62     int refcnt;
63     char *addr;
64     Bool writable;
65     unsigned long size;
66 } ShmDescRec, *ShmDescPtr;
67
68 static void miShmPutImage(XSHM_PUT_IMAGE_ARGS);
69 static void fbShmPutImage(XSHM_PUT_IMAGE_ARGS);
70 static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
71 static int ShmDetachSegment(
72 #if NeedFunctionPrototypes
73     pointer             /* value */,
74     XID                 /* shmseg */
75 #endif
76     );
77 static void ShmResetProc(
78 #if NeedFunctionPrototypes
79     ExtensionEntry *    /* extEntry */
80 #endif
81     );
82 static void SShmCompletionEvent(
83 #if NeedFunctionPrototypes
84     xShmCompletionEvent * /* from */,
85     xShmCompletionEvent * /* to */
86 #endif
87     );
88
89 static DISPATCH_PROC(ProcShmAttach);
90 static DISPATCH_PROC(ProcShmCreatePixmap);
91 static DISPATCH_PROC(ProcShmDetach);
92 static DISPATCH_PROC(ProcShmDispatch);
93 static DISPATCH_PROC(ProcShmGetImage);
94 static DISPATCH_PROC(ProcShmGetImage);
95 static DISPATCH_PROC(ProcShmGetImage);
96 static DISPATCH_PROC(ProcShmPutImage);
97 static DISPATCH_PROC(ProcShmQueryVersion);
98 static DISPATCH_PROC(SProcShmAttach);
99 static DISPATCH_PROC(SProcShmCreatePixmap);
100 static DISPATCH_PROC(SProcShmDetach);
101 static DISPATCH_PROC(SProcShmDispatch);
102 static DISPATCH_PROC(SProcShmGetImage);
103 static DISPATCH_PROC(SProcShmPutImage);
104 static DISPATCH_PROC(SProcShmQueryVersion);
105
106 static unsigned char ShmReqCode;
107 static int ShmCompletionCode;
108 static int BadShmSegCode;
109 static RESTYPE ShmSegType, ShmPixType;
110 static ShmDescPtr Shmsegs;
111 static Bool sharedPixmaps;
112 static int pixmapFormat;
113 static int shmPixFormat[MAXSCREENS];
114 static ShmFuncsPtr shmFuncs[MAXSCREENS];
115 static ShmFuncs miFuncs = {NULL, miShmPutImage};
116 static ShmFuncs fbFuncs = {fbShmCreatePixmap, fbShmPutImage};
117
118 #define VERIFY_SHMSEG(shmseg,shmdesc,client) \
119 { \
120     shmdesc = (ShmDescPtr)LookupIDByType(shmseg, ShmSegType); \
121     if (!shmdesc) \
122     { \
123         client->errorValue = shmseg; \
124         return BadShmSegCode; \
125     } \
126 }
127
128 #define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
129 { \
130     VERIFY_SHMSEG(shmseg, shmdesc, client); \
131     if ((offset & 3) || (offset > shmdesc->size)) \
132     { \
133         client->errorValue = offset; \
134         return BadValue; \
135     } \
136     if (needwrite && !shmdesc->writable) \
137         return BadAccess; \
138 }
139
140 #define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
141 { \
142     if ((offset + len) > shmdesc->size) \
143     { \
144         return BadAccess; \
145     } \
146 }
147
148
149 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
150 #include <sys/signal.h>
151
152 static Bool badSysCall = FALSE;
153
154 static void
155 SigSysHandler(signo)
156 int signo;
157 {
158     badSysCall = TRUE;
159 }
160
161 static Bool CheckForShmSyscall()
162 {
163     void (*oldHandler)();
164     int shmid = -1;
165
166     /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
167     oldHandler = signal(SIGSYS, SigSysHandler);
168
169     badSysCall = FALSE;
170     shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
171     /* Clean up */
172     if (shmid != -1)
173     {
174         shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
175     }
176     signal(SIGSYS, oldHandler);
177     return(!badSysCall);
178 }
179 #endif
180     
181 void
182 ShmExtensionInit()
183 {
184     ExtensionEntry *extEntry;
185     int i;
186
187 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
188     if (!CheckForShmSyscall())
189     {
190         ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
191         return;
192     }
193 #endif
194
195 #ifdef INTERNAL_VS_EXTERNAL_PADDING
196     sharedPixmaps = xFalse;
197     pixmapFormat = 0;
198 #else
199     sharedPixmaps = xTrue;
200     pixmapFormat = shmPixFormat[0];
201     for (i = 0; i < screenInfo.numScreens; i++)
202     {
203         if (!shmFuncs[i])
204             shmFuncs[i] = &miFuncs;
205         if (!shmFuncs[i]->CreatePixmap)
206             sharedPixmaps = xFalse;
207         if (shmPixFormat[i] && (shmPixFormat[i] != pixmapFormat))
208         {
209             sharedPixmaps = xFalse;
210             pixmapFormat = 0;
211         }
212     }
213     if (!pixmapFormat)
214         pixmapFormat = ZPixmap;
215 #endif
216     ShmSegType = CreateNewResourceType(ShmDetachSegment);
217     ShmPixType = CreateNewResourceType(ShmDetachSegment);
218     if (ShmSegType && ShmPixType &&
219         (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
220                                  ProcShmDispatch, SProcShmDispatch,
221                                  ShmResetProc, StandardMinorOpcode)))
222     {
223         ShmReqCode = (unsigned char)extEntry->base;
224         ShmCompletionCode = extEntry->eventBase;
225         BadShmSegCode = extEntry->errorBase;
226         EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
227     }
228 }
229
230 /*ARGSUSED*/
231 static void
232 ShmResetProc (extEntry)
233 ExtensionEntry  *extEntry;
234 {
235     int i;
236
237     for (i = 0; i < MAXSCREENS; i++)
238     {
239         shmFuncs[i] = (ShmFuncsPtr)NULL;
240         shmPixFormat[i] = 0;
241     }
242 }
243
244 void
245 ShmRegisterFuncs(pScreen, funcs)
246     ScreenPtr pScreen;
247     ShmFuncsPtr funcs;
248 {
249     shmFuncs[pScreen->myNum] = funcs;
250 }
251
252 void
253 ShmSetPixmapFormat(pScreen, format)
254     ScreenPtr pScreen;
255     int format;
256 {
257     shmPixFormat[pScreen->myNum] = format;
258 }
259
260 void
261 ShmRegisterFbFuncs(pScreen)
262     ScreenPtr pScreen;
263 {
264     shmFuncs[pScreen->myNum] = &fbFuncs;
265 }
266
267 static int
268 ProcShmQueryVersion(client)
269     register ClientPtr client;
270 {
271     xShmQueryVersionReply rep;
272     register int n;
273
274     REQUEST_SIZE_MATCH(xShmQueryVersionReq);
275     rep.type = X_Reply;
276     rep.length = 0;
277     rep.sequenceNumber = client->sequence;
278     rep.sharedPixmaps = sharedPixmaps;
279     rep.pixmapFormat = pixmapFormat;
280     rep.majorVersion = SHM_MAJOR_VERSION;
281     rep.minorVersion = SHM_MINOR_VERSION;
282     rep.uid = geteuid();
283     rep.gid = getegid();
284     if (client->swapped) {
285         swaps(&rep.sequenceNumber, n);
286         swapl(&rep.length, n);
287         swaps(&rep.majorVersion, n);
288         swaps(&rep.minorVersion, n);
289         swaps(&rep.uid, n);
290         swaps(&rep.gid, n);
291     }
292     WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep);
293     return (client->noClientException);
294 }
295
296 static int
297 ProcShmAttach(client)
298     register ClientPtr client;
299 {
300     struct shmid_ds buf;
301     ShmDescPtr shmdesc;
302     REQUEST(xShmAttachReq);
303
304     REQUEST_SIZE_MATCH(xShmAttachReq);
305     LEGAL_NEW_RESOURCE(stuff->shmseg, client);
306     if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse))
307     {
308         client->errorValue = stuff->readOnly;
309         return(BadValue);
310     }
311     for (shmdesc = Shmsegs;
312          shmdesc && (shmdesc->shmid != stuff->shmid);
313          shmdesc = shmdesc->next)
314         ;
315     if (shmdesc)
316     {
317         if (!stuff->readOnly && !shmdesc->writable)
318             return BadAccess;
319         shmdesc->refcnt++;
320     }
321     else
322     {
323         shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec));
324         if (!shmdesc)
325             return BadAlloc;
326         shmdesc->addr = shmat(stuff->shmid, 0,
327                               stuff->readOnly ? SHM_RDONLY : 0);
328         if ((shmdesc->addr == ((char *)-1)) ||
329             shmctl(stuff->shmid, IPC_STAT, &buf))
330         {
331             xfree(shmdesc);
332             return BadAccess;
333         }
334         shmdesc->shmid = stuff->shmid;
335         shmdesc->refcnt = 1;
336         shmdesc->writable = !stuff->readOnly;
337         shmdesc->size = buf.shm_segsz;
338         shmdesc->next = Shmsegs;
339         Shmsegs = shmdesc;
340     }
341     if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc))
342         return BadAlloc;
343     return(client->noClientException);
344 }
345
346 /*ARGSUSED*/
347 static int
348 ShmDetachSegment(value, shmseg)
349     pointer value; /* must conform to DeleteType */
350     XID shmseg;
351 {
352     ShmDescPtr shmdesc = (ShmDescPtr)value;
353     ShmDescPtr *prev;
354
355     if (--shmdesc->refcnt)
356         return TRUE;
357     shmdt(shmdesc->addr);
358     for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next)
359         ;
360     *prev = shmdesc->next;
361     xfree(shmdesc);
362     return Success;
363 }
364
365 static int
366 ProcShmDetach(client)
367     register ClientPtr client;
368 {
369     ShmDescPtr shmdesc;
370     REQUEST(xShmDetachReq);
371
372     REQUEST_SIZE_MATCH(xShmDetachReq);
373     VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
374     FreeResource(stuff->shmseg, RT_NONE);
375     return(client->noClientException);
376 }
377
378 static void
379 miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data)
380     DrawablePtr dst;
381     GCPtr       pGC;
382     int         depth, w, h, sx, sy, sw, sh, dx, dy;
383     unsigned int format;
384     char        *data;
385 {
386     PixmapPtr pmap;
387     GCPtr putGC;
388
389     putGC = GetScratchGC(depth, dst->pScreen);
390     if (!putGC)
391         return;
392     pmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth);
393     if (!pmap)
394     {
395         FreeScratchGC(putGC);
396         return;
397     }
398     ValidateGC((DrawablePtr)pmap, putGC);
399     (*putGC->ops->PutImage)((DrawablePtr)pmap, putGC, depth, -sx, -sy, w, h, 0,
400                             (format == XYPixmap) ? XYPixmap : ZPixmap, data);
401     FreeScratchGC(putGC);
402     if (format == XYBitmap)
403         (void)(*pGC->ops->CopyPlane)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh,
404                                      dx, dy, 1L);
405     else
406         (void)(*pGC->ops->CopyArea)((DrawablePtr)pmap, dst, pGC, 0, 0, sw, sh,
407                                     dx, dy);
408     (*pmap->drawable.pScreen->DestroyPixmap)(pmap);
409 }
410
411 static void
412 fbShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy, data)
413     DrawablePtr dst;
414     GCPtr       pGC;
415     int         depth, w, h, sx, sy, sw, sh, dx, dy;
416     unsigned int format;
417     char        *data;
418 {
419     if ((format == ZPixmap) || (depth == 1))
420     {
421         PixmapPtr pPixmap;
422
423         pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
424                         /*XXX*/depth, PixmapBytePad(w, depth), (pointer)data);
425         if (!pPixmap)
426             return;
427         if (format == XYBitmap)
428             (void)(*pGC->ops->CopyPlane)((DrawablePtr)pPixmap, dst, pGC,
429                                          sx, sy, sw, sh, dx, dy, 1L);
430         else
431             (void)(*pGC->ops->CopyArea)((DrawablePtr)pPixmap, dst, pGC,
432                                         sx, sy, sw, sh, dx, dy);
433         FreeScratchPixmapHeader(pPixmap);
434     }
435     else
436         miShmPutImage(dst, pGC, depth, format, w, h, sx, sy, sw, sh, dx, dy,
437                       data);
438 }
439
440 static int
441 ProcShmPutImage(client)
442     register ClientPtr client;
443 {
444     register GCPtr pGC;
445     register DrawablePtr pDraw;
446     long length;
447 #ifdef INTERNAL_VS_EXTERNAL_PADDING
448     long lengthProto;
449     char *tmpImage;
450     int  tmpAlloced = 0;
451 #endif
452     ShmDescPtr shmdesc;
453     REQUEST(xShmPutImageReq);
454
455     REQUEST_SIZE_MATCH(xShmPutImageReq);
456     VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, pGC, client);
457     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
458     if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
459         return BadValue;
460     if (stuff->format == XYBitmap)
461     {
462         if (stuff->depth != 1)
463             return BadMatch;
464         length = PixmapBytePad(stuff->totalWidth, 1);
465 #ifdef INTERNAL_VS_EXTERNAL_PADDING
466         lengthProto = PixmapBytePadProto(stuff->totalWidth, 1);
467 #endif
468     }
469     else if (stuff->format == XYPixmap)
470     {
471         if (pDraw->depth != stuff->depth)
472             return BadMatch;
473         length = PixmapBytePad(stuff->totalWidth, 1);
474         length *= stuff->depth;
475 #ifdef INTERNAL_VS_EXTERNAL_PADDING
476         lengthProto = PixmapBytePadProto(stuff->totalWidth, 1);
477         lengthProto *= stuff->depth;
478 #endif
479     }
480     else if (stuff->format == ZPixmap)
481     {
482         if (pDraw->depth != stuff->depth)
483             return BadMatch;
484         length = PixmapBytePad(stuff->totalWidth, stuff->depth);
485 #ifdef INTERNAL_VS_EXTERNAL_PADDING
486         lengthProto = PixmapBytePadProto(stuff->totalWidth, stuff->depth);
487 #endif
488     }
489     else
490     {
491         client->errorValue = stuff->format;
492         return BadValue;
493     }
494
495 #ifdef INTERNAL_VS_EXTERNAL_PADDING
496     VERIFY_SHMSIZE(shmdesc, stuff->offset, lengthProto * stuff->totalHeight,
497                    client);
498 #else
499     VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
500                    client);
501 #endif
502     if (stuff->srcX > stuff->totalWidth)
503     {
504         client->errorValue = stuff->srcX;
505         return BadValue;
506     }
507     if (stuff->srcY > stuff->totalHeight)
508     {
509         client->errorValue = stuff->srcY;
510         return BadValue;
511     }
512     if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth)
513     {
514         client->errorValue = stuff->srcWidth;
515         return BadValue;
516     }
517     if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight)
518     {
519         client->errorValue = stuff->srcHeight;
520         return BadValue;
521     }
522
523 #ifdef INTERNAL_VS_EXTERNAL_PADDING
524     /* handle 64 bit case where protocol may pad to 32 and we want 64 
525      * In this case, length is what the server wants and lengthProto is
526      * what the protocol thinks it is.  If the the two are different,
527      * copy the protocol version (i.e. the memory shared between the 
528      * server and the client) to a version with a scanline pad of 64.
529      */
530     if (length != lengthProto) 
531     {
532         register int    i;
533         char            * stuffptr, /* pointer into protocol data */
534                         * tmpptr;   /* new location to copy to */
535
536         if(!(tmpImage = (char *) ALLOCATE_LOCAL(length*stuff->totalHeight)))
537             return (BadAlloc);
538         tmpAlloced = 1;
539     
540         bzero(tmpImage,length*stuff->totalHeight);
541     
542         if (stuff->format == XYPixmap) 
543         {
544             int lineBytes =  PixmapBytePad(stuff->totalWidth, 1);
545             int lineBytesProto = PixmapBytePadProto(stuff->totalWidth, 1);
546             int depth = stuff->depth;
547
548             stuffptr = shmdesc->addr + stuff->offset ;
549             tmpptr = tmpImage;
550             for (i = 0; i < stuff->totalHeight*stuff->depth;
551                  stuffptr += lineBytesProto,tmpptr += lineBytes, i++) 
552                 bcopy(stuffptr,tmpptr,lineBytesProto);
553         }
554         else 
555         {
556             for (i = 0,
557                  stuffptr = shmdesc->addr + stuff->offset,
558                  tmpptr=tmpImage;
559                  i < stuff->totalHeight;
560                  stuffptr += lengthProto,tmpptr += length, i++) 
561                 bcopy(stuffptr,tmpptr,lengthProto);
562         }
563     }
564     /* handle 64-bit case where stuff is not 64-bit aligned 
565      */
566     else if ((unsigned long)(shmdesc->addr+stuff->offset) & 
567              (sizeof(long)-1)) 
568     {
569         if(!(tmpImage = (char *) ALLOCATE_LOCAL(length*stuff->totalHeight)))
570             return (BadAlloc);
571         tmpAlloced = 1;
572         bcopy((char *)(shmdesc->addr+stuff->offset),
573               tmpImage,
574               length*stuff->totalHeight);
575     }
576     else
577         tmpImage = (char *)(shmdesc->addr+stuff->offset);
578 #endif
579
580     if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
581          ((stuff->format != ZPixmap) &&
582           (stuff->srcX < screenInfo.bitmapScanlinePad) &&
583           ((stuff->format == XYBitmap) ||
584            ((stuff->srcY == 0) &&
585             (stuff->srcHeight == stuff->totalHeight))))) &&
586         ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
587         (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
588                                stuff->dstX, stuff->dstY,
589                                stuff->totalWidth, stuff->srcHeight, 
590                                stuff->srcX, stuff->format, 
591 #ifdef INTERNAL_VS_EXTERNAL_PADDING
592                                tmpImage +
593 #else
594                                shmdesc->addr + stuff->offset +
595 #endif
596                                (stuff->srcY * length));
597     else
598         (*shmFuncs[pDraw->pScreen->myNum]->PutImage)(
599                                pDraw, pGC, stuff->depth, stuff->format,
600                                stuff->totalWidth, stuff->totalHeight,
601                                stuff->srcX, stuff->srcY,
602                                stuff->srcWidth, stuff->srcHeight,
603                                stuff->dstX, stuff->dstY,
604 #ifdef INTERNAL_VS_EXTERNAL_PADDING
605                                tmpImage);
606     
607 #else
608                                shmdesc->addr + stuff->offset);
609 #endif
610
611     if (stuff->sendEvent)
612     {
613         xShmCompletionEvent ev;
614
615         ev.type = ShmCompletionCode;
616         ev.drawable = stuff->drawable;
617         ev.sequenceNumber = client->sequence;
618         ev.minorEvent = X_ShmPutImage;
619         ev.majorEvent = ShmReqCode;
620         ev.shmseg = stuff->shmseg;
621         ev.offset = stuff->offset;
622         WriteEventsToClient(client, 1, (xEvent *) &ev);
623     }
624
625 #ifdef INTERNAL_VS_EXTERNAL_PADDING
626     if (tmpAlloced)
627         DEALLOCATE_LOCAL(tmpImage);
628 #endif
629
630      return (client->noClientException);
631 }
632
633
634
635 static int
636 ProcShmGetImage(client)
637     register ClientPtr client;
638 {
639     register DrawablePtr pDraw;
640     long                lenPer, length;
641     Mask                plane;
642     xShmGetImageReply   xgi;
643     ShmDescPtr          shmdesc;
644     int                 n;
645 #ifdef INTERNAL_VS_EXTERNAL_PADDING
646     long                widthBytesLine,widthBytesLineProto;
647     long                lenPerProto,lengthProto;
648     char                *tmpImage;
649     int                 tmpAlloced = 0;
650 #endif
651
652     REQUEST(xShmGetImageReq);
653
654     REQUEST_SIZE_MATCH(xShmGetImageReq);
655     if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap))
656     {
657         client->errorValue = stuff->format;
658         return(BadValue);
659     }
660     VERIFY_DRAWABLE(pDraw, stuff->drawable, client);
661     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
662     if (pDraw->type == DRAWABLE_WINDOW)
663     {
664       if( /* check for being viewable */
665          !((WindowPtr) pDraw)->realized ||
666           /* check for being on screen */
667          pDraw->x + stuff->x < 0 ||
668          pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width ||
669          pDraw->y + stuff->y < 0 ||
670          pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height ||
671           /* check for being inside of border */
672          stuff->x < - wBorderWidth((WindowPtr)pDraw) ||
673          stuff->x + (int)stuff->width >
674                 wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width ||
675          stuff->y < -wBorderWidth((WindowPtr)pDraw) ||
676          stuff->y + (int)stuff->height >
677                 wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height
678         )
679             return(BadMatch);
680         xgi.visual = wVisual(((WindowPtr)pDraw));
681     }
682     else
683     {
684         if (stuff->x < 0 ||
685             stuff->x+(int)stuff->width > pDraw->width ||
686             stuff->y < 0 ||
687             stuff->y+(int)stuff->height > pDraw->height
688             )
689             return(BadMatch);
690         xgi.visual = None;
691     }
692     xgi.type = X_Reply;
693     xgi.length = 0;
694     xgi.sequenceNumber = client->sequence;
695     xgi.depth = pDraw->depth;
696     if(stuff->format == ZPixmap)
697     {
698 #ifdef INTERNAL_VS_EXTERNAL_PADDING
699         widthBytesLine = PixmapBytePad(stuff->width, pDraw->depth);
700         length = widthBytesLine * stuff->height;
701         widthBytesLineProto =  PixmapBytePadProto(stuff->width, pDraw->depth);
702         lengthProto = widthBytesLineProto * stuff->height;
703 #else
704         length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
705 #endif
706     }
707     else 
708     {
709 #ifdef INTERNAL_VS_EXTERNAL_PADDING
710         widthBytesLine = PixmapBytePad(stuff->width, 1);
711         lenPer = widthBytesLine * stuff->height;
712         plane = ((Mask)1) << (pDraw->depth - 1);
713         /* only planes asked for */
714         length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
715
716         widthBytesLineProto = PixmapBytePadProto(stuff->width, 1);
717         lenPerProto = widthBytesLineProto * stuff->height;
718         lengthProto = lenPerProto * Ones(stuff->planeMask & 
719                                          (plane | (plane - 1)));
720 #else
721         lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
722         plane = ((Mask)1) << (pDraw->depth - 1);
723         /* only planes asked for */
724         length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
725 #endif
726     }
727
728 #ifdef INTERNAL_VS_EXTERNAL_PADDING
729     VERIFY_SHMSIZE(shmdesc, stuff->offset, lengthProto, client);
730     xgi.size = lengthProto;
731 #else
732     VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
733     xgi.size = length;
734 #endif
735
736     if (length == 0)
737     {
738         /* nothing to do */
739     }
740     else if (stuff->format == ZPixmap)
741     {
742 #ifdef INTERNAL_VS_EXTERNAL_PADDING
743         /* check for protocol/server padding differences.
744          */
745         if ((widthBytesLine != widthBytesLineProto) ||
746             ((unsigned long)shmdesc->addr + stuff->offset & (sizeof(long)-1))) 
747         {
748             /* temp stuff for 64 bit alignment stuff */
749             register char * bufPtr, * protoPtr;
750             register int i;
751
752             if(!(tmpImage = (char *) ALLOCATE_LOCAL(length))) 
753               return (BadAlloc);
754             tmpAlloced = 1;
755             
756             (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y,
757                                         stuff->width, stuff->height,
758                                         stuff->format, stuff->planeMask,
759                                         tmpImage);
760             
761             /* for 64-bit server, convert image to pad to 32 bits 
762              */
763             bzero(shmdesc->addr + stuff->offset,lengthProto);
764             
765             for (i=0,bufPtr=tmpImage,protoPtr=shmdesc->addr + stuff->offset; 
766                  i < stuff->height;
767                  bufPtr += widthBytesLine,protoPtr += widthBytesLineProto, 
768                  i++)
769                 bcopy(bufPtr,protoPtr,widthBytesLineProto);
770         }
771         else 
772         {
773             (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y,
774                                         stuff->width, stuff->height,
775                                         stuff->format, stuff->planeMask,
776                                         shmdesc->addr + stuff->offset);
777         }
778 #else
779         (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y,
780                                     stuff->width, stuff->height,
781                                     stuff->format, stuff->planeMask,
782                                     shmdesc->addr + stuff->offset);
783 #endif
784     }
785     else
786     {
787 #ifdef INTERNAL_VS_EXTERNAL_PADDING
788         /* check for protocol/server padding differences.
789          */
790         if ((widthBytesLine != widthBytesLineProto) ||
791             ((unsigned long)shmdesc->addr + stuff->offset & 
792              (sizeof(long)-1))) 
793         {
794             if(!(tmpImage = (char *) ALLOCATE_LOCAL(length)))
795               return (BadAlloc);
796             tmpAlloced = 1;
797         }
798 #endif
799
800         length = stuff->offset;
801         for (; plane; plane >>= 1)
802         {
803             if (stuff->planeMask & plane)
804             {
805 #ifdef INTERNAL_VS_EXTERNAL_PADDING
806                 if ((widthBytesLine != widthBytesLineProto) ||
807                     ((unsigned long)shmdesc->addr + stuff->offset & 
808                      (sizeof(long)-1))) 
809                 {
810                     /* get image for each plane. 
811                      */
812                     (*pDraw->pScreen->GetImage)(pDraw,
813                                                 stuff->x, stuff->y,
814                                                 stuff->width, stuff->height,
815                                                 stuff->format, plane,
816                                                 tmpImage);
817                     
818                     /* for 64-bit server, convert image to pad to 32 bits */
819                     bzero(shmdesc->addr+length, widthBytesLine);
820                     bcopy(tmpImage, shmdesc->addr+length, widthBytesLineProto);
821                     /* increment length */
822                     length += lenPerProto;
823                 }
824                 else /* no diff between protocol and server */
825                 {
826                     (*pDraw->pScreen->GetImage)(pDraw,
827                                                 stuff->x, stuff->y,
828                                                 stuff->width, stuff->height,
829                                                 stuff->format, plane,
830                                                 shmdesc->addr + length);
831                     length += lenPer;
832                 }
833 #else
834                 (*pDraw->pScreen->GetImage)(pDraw,
835                                             stuff->x, stuff->y,
836                                             stuff->width, stuff->height,
837                                             stuff->format, plane,
838                                             shmdesc->addr + length);
839                 length += lenPer;
840 #endif
841             }
842         }
843     }
844     
845     if (client->swapped) {
846         swaps(&xgi.sequenceNumber, n);
847         swapl(&xgi.length, n);
848         swapl(&xgi.visual, n);
849         swapl(&xgi.size, n);
850     }
851     WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi);
852
853 #ifdef INTERNAL_VS_EXTERNAL_PADDING
854     if (tmpAlloced)
855         DEALLOCATE_LOCAL(tmpImage);
856 #endif
857
858     return(client->noClientException);
859 }
860
861 static PixmapPtr
862 fbShmCreatePixmap (pScreen, width, height, depth, addr)
863     ScreenPtr   pScreen;
864     int         width;
865     int         height;
866     int         depth;
867     char        *addr;
868 {
869     register PixmapPtr pPixmap;
870
871     pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth);
872     if (!pPixmap)
873         return NullPixmap;
874
875     if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth,
876                   /*XXX*/depth, PixmapBytePad(width, depth), (pointer)addr))
877         return NullPixmap;
878     return pPixmap;
879 }
880
881 static int
882 ProcShmCreatePixmap(client)
883     register ClientPtr client;
884 {
885     PixmapPtr pMap;
886     register DrawablePtr pDraw;
887     DepthPtr pDepth;
888     register int i;
889     ShmDescPtr shmdesc;
890     REQUEST(xShmCreatePixmapReq);
891
892     REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
893     client->errorValue = stuff->pid;
894     if (!sharedPixmaps)
895         return BadImplementation;
896     LEGAL_NEW_RESOURCE(stuff->pid, client);
897     VERIFY_GEOMETRABLE(pDraw, stuff->drawable, client);
898     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
899     if (!stuff->width || !stuff->height)
900     {
901         client->errorValue = 0;
902         return BadValue;
903     }
904     if (stuff->depth != 1)
905     {
906         pDepth = pDraw->pScreen->allowedDepths;
907         for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++)
908            if (pDepth->depth == stuff->depth)
909                goto CreatePmap;
910         client->errorValue = stuff->depth;
911         return BadValue;
912     }
913 CreatePmap:
914     VERIFY_SHMSIZE(shmdesc, stuff->offset,
915                    PixmapBytePad(stuff->width, stuff->depth) * stuff->height,
916                    client);
917     pMap = (*shmFuncs[pDraw->pScreen->myNum]->CreatePixmap)(
918                             pDraw->pScreen, stuff->width,
919                             stuff->height, stuff->depth,
920                             shmdesc->addr + stuff->offset);
921     if (pMap)
922     {
923         pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
924         pMap->drawable.id = stuff->pid;
925         if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap))
926         {
927             shmdesc->refcnt++;
928             if (AddResource(stuff->pid, ShmPixType, (pointer)shmdesc))
929                 return(client->noClientException);
930             FreeResource(stuff->pid, RT_NONE);
931         }
932     }
933     return (BadAlloc);
934 }
935
936 static int
937 ProcShmDispatch (client)
938     register ClientPtr  client;
939 {
940     REQUEST(xReq);
941     switch (stuff->data)
942     {
943     case X_ShmQueryVersion:
944         return ProcShmQueryVersion(client);
945     case X_ShmAttach:
946         return ProcShmAttach(client);
947     case X_ShmDetach:
948         return ProcShmDetach(client);
949     case X_ShmPutImage:
950         return ProcShmPutImage(client);
951     case X_ShmGetImage:
952         return ProcShmGetImage(client);
953     case X_ShmCreatePixmap:
954         return ProcShmCreatePixmap(client);
955     default:
956         return BadRequest;
957     }
958 }
959
960 static void
961 SShmCompletionEvent(from, to)
962     xShmCompletionEvent *from, *to;
963 {
964     to->type = from->type;
965     cpswaps(from->sequenceNumber, to->sequenceNumber);
966     cpswapl(from->drawable, to->drawable);
967     cpswaps(from->minorEvent, to->minorEvent);
968     to->majorEvent = from->majorEvent;
969     cpswapl(from->shmseg, to->shmseg);
970     cpswapl(from->offset, to->offset);
971 }
972
973 static int
974 SProcShmQueryVersion(client)
975     register ClientPtr  client;
976 {
977     register int n;
978     REQUEST(xShmQueryVersionReq);
979
980     swaps(&stuff->length, n);
981     return ProcShmQueryVersion(client);
982 }
983
984 static int
985 SProcShmAttach(client)
986     ClientPtr client;
987 {
988     register int n;
989     REQUEST(xShmAttachReq);
990     swaps(&stuff->length, n);
991     REQUEST_SIZE_MATCH(xShmAttachReq);
992     swapl(&stuff->shmseg, n);
993     swapl(&stuff->shmid, n);
994     return ProcShmAttach(client);
995 }
996
997 static int
998 SProcShmDetach(client)
999     ClientPtr client;
1000 {
1001     register int n;
1002     REQUEST(xShmDetachReq);
1003     swaps(&stuff->length, n);
1004     REQUEST_SIZE_MATCH(xShmDetachReq);
1005     swapl(&stuff->shmseg, n);
1006     return ProcShmDetach(client);
1007 }
1008
1009 static int
1010 SProcShmPutImage(client)
1011     ClientPtr client;
1012 {
1013     register int n;
1014     REQUEST(xShmPutImageReq);
1015     swaps(&stuff->length, n);
1016     REQUEST_SIZE_MATCH(xShmPutImageReq);
1017     swapl(&stuff->drawable, n);
1018     swapl(&stuff->gc, n);
1019     swaps(&stuff->totalWidth, n);
1020     swaps(&stuff->totalHeight, n);
1021     swaps(&stuff->srcX, n);
1022     swaps(&stuff->srcY, n);
1023     swaps(&stuff->srcWidth, n);
1024     swaps(&stuff->srcHeight, n);
1025     swaps(&stuff->dstX, n);
1026     swaps(&stuff->dstY, n);
1027     swapl(&stuff->shmseg, n);
1028     swapl(&stuff->offset, n);
1029     return ProcShmPutImage(client);
1030 }
1031
1032 static int
1033 SProcShmGetImage(client)
1034     ClientPtr client;
1035 {
1036     register int n;
1037     REQUEST(xShmGetImageReq);
1038     swaps(&stuff->length, n);
1039     REQUEST_SIZE_MATCH(xShmGetImageReq);
1040     swapl(&stuff->drawable, n);
1041     swaps(&stuff->x, n);
1042     swaps(&stuff->y, n);
1043     swaps(&stuff->width, n);
1044     swaps(&stuff->height, n);
1045     swapl(&stuff->planeMask, n);
1046     swapl(&stuff->shmseg, n);
1047     swapl(&stuff->offset, n);
1048     return ProcShmGetImage(client);
1049 }
1050
1051 static int
1052 SProcShmCreatePixmap(client)
1053     ClientPtr client;
1054 {
1055     register int n;
1056     REQUEST(xShmCreatePixmapReq);
1057     swaps(&stuff->length, n);
1058     REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
1059     swapl(&stuff->drawable, n);
1060     swaps(&stuff->width, n);
1061     swaps(&stuff->height, n);
1062     swapl(&stuff->shmseg, n);
1063     swapl(&stuff->offset, n);
1064     return ProcShmCreatePixmap(client);
1065 }
1066
1067 static int
1068 SProcShmDispatch (client)
1069     register ClientPtr  client;
1070 {
1071     REQUEST(xReq);
1072     switch (stuff->data)
1073     {
1074     case X_ShmQueryVersion:
1075         return SProcShmQueryVersion(client);
1076     case X_ShmAttach:
1077         return SProcShmAttach(client);
1078     case X_ShmDetach:
1079         return SProcShmDetach(client);
1080     case X_ShmPutImage:
1081         return SProcShmPutImage(client);
1082     case X_ShmGetImage:
1083         return SProcShmGetImage(client);
1084     case X_ShmCreatePixmap:
1085         return SProcShmCreatePixmap(client);
1086     default:
1087         return BadRequest;
1088     }
1089 }