1 /*
2 
3 Copyright 1993, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26 
27 */
28 
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
31 #endif
32 
33 #if defined(WIN32)
34 #include <X11/Xwinsock.h>
35 #endif
36 #include <stdio.h>
37 #include <X11/X.h>
38 #include <X11/Xproto.h>
39 #include <X11/Xos.h>
40 #include "scrnintstr.h"
41 #include "servermd.h"
42 #define PSZ 8
43 #include "fb.h"
44 #include "colormapst.h"
45 #include "gcstruct.h"
46 #include "input.h"
47 #include "mipointer.h"
48 #include "micmap.h"
49 #include <sys/types.h>
50 #ifdef HAVE_MMAP
51 #include <sys/mman.h>
52 #ifndef MAP_FILE
53 #define MAP_FILE 0
54 #endif
55 #endif                          /* HAVE_MMAP */
56 #include <sys/stat.h>
57 #include <errno.h>
58 #ifndef WIN32
59 #include <sys/param.h>
60 #endif
61 #include <X11/XWDFile.h>
62 #ifdef HAS_SHM
63 #include <sys/ipc.h>
64 #include <sys/shm.h>
65 #endif                          /* HAS_SHM */
66 #include "dix.h"
67 #include "miline.h"
68 #include "glx_extinit.h"
69 #include "randrstr.h"
70 
71 #define VFB_DEFAULT_WIDTH      1280
72 #define VFB_DEFAULT_HEIGHT     1024
73 #define VFB_DEFAULT_DEPTH        24
74 #define VFB_DEFAULT_WHITEPIXEL    1
75 #define VFB_DEFAULT_BLACKPIXEL    0
76 #define VFB_DEFAULT_LINEBIAS      0
77 #define XWD_WINDOW_NAME_LEN      60
78 
79 typedef struct {
80     int width;
81     int paddedBytesWidth;
82     int paddedWidth;
83     int height;
84     int depth;
85     int bitsPerPixel;
86     int sizeInBytes;
87     int ncolors;
88     char *pfbMemory;
89     XWDColor *pXWDCmap;
90     XWDFileHeader *pXWDHeader;
91     Pixel blackPixel;
92     Pixel whitePixel;
93     unsigned int lineBias;
94     CloseScreenProcPtr closeScreen;
95 
96 #ifdef HAVE_MMAP
97     int mmap_fd;
98     char mmap_file[MAXPATHLEN];
99 #endif
100 
101 #ifdef HAS_SHM
102     int shmid;
103 #endif
104 } vfbScreenInfo, *vfbScreenInfoPtr;
105 
106 static int vfbNumScreens;
107 static vfbScreenInfo *vfbScreens;
108 
109 static vfbScreenInfo defaultScreenInfo = {
110     .width = VFB_DEFAULT_WIDTH,
111     .height = VFB_DEFAULT_HEIGHT,
112     .depth = VFB_DEFAULT_DEPTH,
113     .blackPixel = VFB_DEFAULT_BLACKPIXEL,
114     .whitePixel = VFB_DEFAULT_WHITEPIXEL,
115     .lineBias = VFB_DEFAULT_LINEBIAS,
116 };
117 
118 static Bool vfbPixmapDepths[33];
119 
120 #ifdef HAVE_MMAP
121 static char *pfbdir = NULL;
122 #endif
123 typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType;
124 static fbMemType fbmemtype = NORMAL_MEMORY_FB;
125 static char needswap = 0;
126 static Bool Render = TRUE;
127 
128 #define swapcopy16(_dst, _src) \
129     if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \
130     else _dst = _src;
131 
132 #define swapcopy32(_dst, _src) \
133     if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \
134     else _dst = _src;
135 
136 static void
vfbInitializePixmapDepths(void)137 vfbInitializePixmapDepths(void)
138 {
139     int i;
140 
141     vfbPixmapDepths[1] = TRUE;  /* always need bitmaps */
142     for (i = 2; i <= 32; i++)
143         vfbPixmapDepths[i] = FALSE;
144 }
145 
146 static int
vfbBitsPerPixel(int depth)147 vfbBitsPerPixel(int depth)
148 {
149     if (depth == 1)
150         return 1;
151     else if (depth <= 8)
152         return 8;
153     else if (depth <= 16)
154         return 16;
155     else
156         return 32;
157 }
158 
159 void
ddxGiveUp(enum ExitCode error)160 ddxGiveUp(enum ExitCode error)
161 {
162     int i;
163 
164     /* clean up the framebuffers */
165 
166     switch (fbmemtype) {
167 #ifdef HAVE_MMAP
168     case MMAPPED_FILE_FB:
169         for (i = 0; i < vfbNumScreens; i++) {
170             if (-1 == unlink(vfbScreens[i].mmap_file)) {
171                 perror("unlink");
172                 ErrorF("unlink %s failed, %s",
173                        vfbScreens[i].mmap_file, strerror(errno));
174             }
175         }
176         break;
177 #else                           /* HAVE_MMAP */
178     case MMAPPED_FILE_FB:
179         break;
180 #endif                          /* HAVE_MMAP */
181 
182 #ifdef HAS_SHM
183     case SHARED_MEMORY_FB:
184         for (i = 0; i < vfbNumScreens; i++) {
185             if (-1 == shmdt((char *) vfbScreens[i].pXWDHeader)) {
186                 perror("shmdt");
187                 ErrorF("shmdt failed, %s", strerror(errno));
188             }
189         }
190         break;
191 #else                           /* HAS_SHM */
192     case SHARED_MEMORY_FB:
193         break;
194 #endif                          /* HAS_SHM */
195 
196     case NORMAL_MEMORY_FB:
197         for (i = 0; i < vfbNumScreens; i++) {
198             free(vfbScreens[i].pXWDHeader);
199         }
200         break;
201     }
202 }
203 
204 void
AbortDDX(enum ExitCode error)205 AbortDDX(enum ExitCode error)
206 {
207     ddxGiveUp(error);
208 }
209 
210 #ifdef __APPLE__
211 void
DarwinHandleGUI(int argc,char * argv[])212 DarwinHandleGUI(int argc, char *argv[])
213 {
214 }
215 #endif
216 
217 void
OsVendorInit(void)218 OsVendorInit(void)
219 {
220 }
221 
222 void
OsVendorFatalError(const char * f,va_list args)223 OsVendorFatalError(const char *f, va_list args)
224 {
225 }
226 
227 #if defined(DDXBEFORERESET)
228 void
ddxBeforeReset(void)229 ddxBeforeReset(void)
230 {
231     return;
232 }
233 #endif
234 
235 #if INPUTTHREAD
236 /** This function is called in Xserver/os/inputthread.c when starting
237     the input thread. */
238 void
ddxInputThreadInit(void)239 ddxInputThreadInit(void)
240 {
241 }
242 #endif
243 
244 void
ddxUseMsg(void)245 ddxUseMsg(void)
246 {
247     ErrorF("-screen scrn WxHxD     set screen's width, height, depth\n");
248     ErrorF("-pixdepths list-of-int support given pixmap depths\n");
249     ErrorF("+/-render		   turn on/off RENDER extension support"
250            "(default on)\n");
251     ErrorF("-linebias n            adjust thin line pixelization\n");
252     ErrorF("-blackpixel n          pixel value for black\n");
253     ErrorF("-whitepixel n          pixel value for white\n");
254 
255 #ifdef HAVE_MMAP
256     ErrorF
257         ("-fbdir directory       put framebuffers in mmap'ed files in directory\n");
258 #endif
259 
260 #ifdef HAS_SHM
261     ErrorF("-shmem                 put framebuffers in shared memory\n");
262 #endif
263 }
264 
265 int
ddxProcessArgument(int argc,char * argv[],int i)266 ddxProcessArgument(int argc, char *argv[], int i)
267 {
268     static Bool firstTime = TRUE;
269     static int lastScreen = -1;
270     vfbScreenInfo *currentScreen;
271 
272     if (firstTime) {
273         vfbInitializePixmapDepths();
274         firstTime = FALSE;
275     }
276 
277     if (lastScreen == -1)
278         currentScreen = &defaultScreenInfo;
279     else
280         currentScreen = &vfbScreens[lastScreen];
281 
282 #define CHECK_FOR_REQUIRED_ARGUMENTS(num) \
283     if (((i + num) >= argc) || (!argv[i + num])) {                      \
284       ErrorF("Required argument to %s not specified\n", argv[i]);       \
285       UseMsg();                                                         \
286       FatalError("Required argument to %s not specified\n", argv[i]);   \
287     }
288 
289     if (strcmp(argv[i], "-screen") == 0) {      /* -screen n WxHxD */
290         int screenNum;
291 
292         CHECK_FOR_REQUIRED_ARGUMENTS(2);
293         screenNum = atoi(argv[i + 1]);
294         /* The protocol only has a CARD8 for number of screens in the
295            connection setup block, so don't allow more than that. */
296         if ((screenNum < 0) || (screenNum >= 255)) {
297             ErrorF("Invalid screen number %d\n", screenNum);
298             UseMsg();
299             FatalError("Invalid screen number %d passed to -screen\n",
300                        screenNum);
301         }
302 
303         if (vfbNumScreens <= screenNum) {
304             vfbScreens =
305                 reallocarray(vfbScreens, screenNum + 1, sizeof(*vfbScreens));
306             if (!vfbScreens)
307                 FatalError("Not enough memory for screen %d\n", screenNum);
308             for (; vfbNumScreens <= screenNum; ++vfbNumScreens)
309                 vfbScreens[vfbNumScreens] = defaultScreenInfo;
310         }
311 
312         if (3 != sscanf(argv[i + 2], "%dx%dx%d",
313                         &vfbScreens[screenNum].width,
314                         &vfbScreens[screenNum].height,
315                         &vfbScreens[screenNum].depth)) {
316             ErrorF("Invalid screen configuration %s\n", argv[i + 2]);
317             UseMsg();
318             FatalError("Invalid screen configuration %s for -screen %d\n",
319                        argv[i + 2], screenNum);
320         }
321 
322         lastScreen = screenNum;
323         return 3;
324     }
325 
326     if (strcmp(argv[i], "-pixdepths") == 0) {   /* -pixdepths list-of-depth */
327         int depth, ret = 1;
328 
329         CHECK_FOR_REQUIRED_ARGUMENTS(1);
330         while ((++i < argc) && (depth = atoi(argv[i])) != 0) {
331             if (depth < 0 || depth > 32) {
332                 ErrorF("Invalid pixmap depth %d\n", depth);
333                 UseMsg();
334                 FatalError("Invalid pixmap depth %d passed to -pixdepths\n",
335                            depth);
336             }
337             vfbPixmapDepths[depth] = TRUE;
338             ret++;
339         }
340         return ret;
341     }
342 
343     if (strcmp(argv[i], "+render") == 0) {      /* +render */
344         Render = TRUE;
345         return 1;
346     }
347 
348     if (strcmp(argv[i], "-render") == 0) {      /* -render */
349         Render = FALSE;
350 #ifdef COMPOSITE
351         noCompositeExtension = TRUE;
352 #endif
353         return 1;
354     }
355 
356     if (strcmp(argv[i], "-blackpixel") == 0) {  /* -blackpixel n */
357         CHECK_FOR_REQUIRED_ARGUMENTS(1);
358         currentScreen->blackPixel = atoi(argv[++i]);
359         return 2;
360     }
361 
362     if (strcmp(argv[i], "-whitepixel") == 0) {  /* -whitepixel n */
363         CHECK_FOR_REQUIRED_ARGUMENTS(1);
364         currentScreen->whitePixel = atoi(argv[++i]);
365         return 2;
366     }
367 
368     if (strcmp(argv[i], "-linebias") == 0) {    /* -linebias n */
369         CHECK_FOR_REQUIRED_ARGUMENTS(1);
370         currentScreen->lineBias = atoi(argv[++i]);
371         return 2;
372     }
373 
374 #ifdef HAVE_MMAP
375     if (strcmp(argv[i], "-fbdir") == 0) {       /* -fbdir directory */
376         CHECK_FOR_REQUIRED_ARGUMENTS(1);
377         pfbdir = argv[++i];
378         fbmemtype = MMAPPED_FILE_FB;
379         return 2;
380     }
381 #endif                          /* HAVE_MMAP */
382 
383 #ifdef HAS_SHM
384     if (strcmp(argv[i], "-shmem") == 0) {       /* -shmem */
385         fbmemtype = SHARED_MEMORY_FB;
386         return 1;
387     }
388 #endif
389 
390     return 0;
391 }
392 
393 static void
vfbInstallColormap(ColormapPtr pmap)394 vfbInstallColormap(ColormapPtr pmap)
395 {
396     ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
397 
398     if (pmap != oldpmap) {
399         int entries;
400         XWDFileHeader *pXWDHeader;
401         VisualPtr pVisual;
402         Pixel *ppix;
403         xrgb *prgb;
404         xColorItem *defs;
405         int i;
406 
407         miInstallColormap(pmap);
408 
409         entries = pmap->pVisual->ColormapEntries;
410         pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader;
411         pVisual = pmap->pVisual;
412 
413         swapcopy32(pXWDHeader->visual_class, pVisual->class);
414         swapcopy32(pXWDHeader->red_mask, pVisual->redMask);
415         swapcopy32(pXWDHeader->green_mask, pVisual->greenMask);
416         swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask);
417         swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue);
418         swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries);
419 
420         ppix = xallocarray(entries, sizeof(Pixel));
421         prgb = xallocarray(entries, sizeof(xrgb));
422         defs = xallocarray(entries, sizeof(xColorItem));
423 
424         for (i = 0; i < entries; i++)
425             ppix[i] = i;
426         /* XXX truecolor */
427         QueryColors(pmap, entries, ppix, prgb, serverClient);
428 
429         for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
430             defs[i].pixel = ppix[i] & 0xff;     /* change pixel to index */
431             defs[i].red = prgb[i].red;
432             defs[i].green = prgb[i].green;
433             defs[i].blue = prgb[i].blue;
434             defs[i].flags = DoRed | DoGreen | DoBlue;
435         }
436         (*pmap->pScreen->StoreColors) (pmap, entries, defs);
437 
438         free(ppix);
439         free(prgb);
440         free(defs);
441     }
442 }
443 
444 static void
vfbStoreColors(ColormapPtr pmap,int ndef,xColorItem * pdefs)445 vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs)
446 {
447     XWDColor *pXWDCmap;
448     int i;
449 
450     if (pmap != GetInstalledmiColormap(pmap->pScreen)) {
451         return;
452     }
453 
454     pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap;
455 
456     if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
457         return;
458     }
459 
460     for (i = 0; i < ndef; i++) {
461         if (pdefs[i].flags & DoRed) {
462             swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red);
463         }
464         if (pdefs[i].flags & DoGreen) {
465             swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green);
466         }
467         if (pdefs[i].flags & DoBlue) {
468             swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue);
469         }
470     }
471 }
472 
473 static Bool
vfbSaveScreen(ScreenPtr pScreen,int on)474 vfbSaveScreen(ScreenPtr pScreen, int on)
475 {
476     return TRUE;
477 }
478 
479 #ifdef HAVE_MMAP
480 
481 /* this flushes any changes to the screens out to the mmapped file */
482 static void
vfbBlockHandler(void * blockData,void * timeout)483 vfbBlockHandler(void *blockData, void *timeout)
484 {
485     int i;
486 
487     for (i = 0; i < vfbNumScreens; i++) {
488 #ifdef MS_ASYNC
489         if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
490                         (size_t) vfbScreens[i].sizeInBytes, MS_ASYNC))
491 #else
492         /* silly NetBSD and who else? */
493         if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
494                         (size_t) vfbScreens[i].sizeInBytes))
495 #endif
496         {
497             perror("msync");
498             ErrorF("msync failed, %s", strerror(errno));
499         }
500     }
501 }
502 
503 static void
vfbWakeupHandler(void * blockData,int result)504 vfbWakeupHandler(void *blockData, int result)
505 {
506 }
507 
508 static void
vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb)509 vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb)
510 {
511 #define DUMMY_BUFFER_SIZE 65536
512     char dummyBuffer[DUMMY_BUFFER_SIZE];
513     int currentFileSize, writeThisTime;
514 
515     snprintf(pvfb->mmap_file, sizeof(pvfb->mmap_file), "%s/Xvfb_screen%d",
516              pfbdir, (int) (pvfb - vfbScreens));
517     if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT | O_RDWR, 0666))) {
518         perror("open");
519         ErrorF("open %s failed, %s", pvfb->mmap_file, strerror(errno));
520         return;
521     }
522 
523     /* Extend the file to be the proper size */
524 
525     memset(dummyBuffer, 0, DUMMY_BUFFER_SIZE);
526     for (currentFileSize = 0;
527          currentFileSize < pvfb->sizeInBytes;
528          currentFileSize += writeThisTime) {
529         writeThisTime = min(DUMMY_BUFFER_SIZE,
530                             pvfb->sizeInBytes - currentFileSize);
531         if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) {
532             perror("write");
533             ErrorF("write %s failed, %s", pvfb->mmap_file, strerror(errno));
534             return;
535         }
536     }
537 
538     /* try to mmap the file */
539 
540     pvfb->pXWDHeader = (XWDFileHeader *) mmap((caddr_t) NULL, pvfb->sizeInBytes,
541                                               PROT_READ | PROT_WRITE,
542                                               MAP_FILE | MAP_SHARED,
543                                               pvfb->mmap_fd, 0);
544     if (-1 == (long) pvfb->pXWDHeader) {
545         perror("mmap");
546         ErrorF("mmap %s failed, %s", pvfb->mmap_file, strerror(errno));
547         pvfb->pXWDHeader = NULL;
548         return;
549     }
550 
551     if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler,
552                                         NULL)) {
553         pvfb->pXWDHeader = NULL;
554     }
555 }
556 #endif                          /* HAVE_MMAP */
557 
558 #ifdef HAS_SHM
559 static void
vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb)560 vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb)
561 {
562     /* create the shared memory segment */
563 
564     pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT | 0777);
565     if (pvfb->shmid < 0) {
566         perror("shmget");
567         ErrorF("shmget %d bytes failed, %s", pvfb->sizeInBytes,
568                strerror(errno));
569         return;
570     }
571 
572     /* try to attach it */
573 
574     pvfb->pXWDHeader = (XWDFileHeader *) shmat(pvfb->shmid, 0, 0);
575     if (-1 == (long) pvfb->pXWDHeader) {
576         perror("shmat");
577         ErrorF("shmat failed, %s", strerror(errno));
578         pvfb->pXWDHeader = NULL;
579         return;
580     }
581 
582     ErrorF("screen %d shmid %d\n", (int) (pvfb - vfbScreens), pvfb->shmid);
583 }
584 #endif                          /* HAS_SHM */
585 
586 static char *
vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb)587 vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb)
588 {
589     if (pvfb->pfbMemory)
590         return pvfb->pfbMemory; /* already done */
591 
592     pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height;
593 
594     /* Calculate how many entries in colormap.  This is rather bogus, because
595      * the visuals haven't even been set up yet, but we need to know because we
596      * have to allocate space in the file for the colormap.  The number 10
597      * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c.
598      */
599 
600     if (pvfb->depth <= 10) {    /* single index colormaps */
601         pvfb->ncolors = 1 << pvfb->depth;
602     }
603     else {                      /* decomposed colormaps */
604         int nplanes_per_color_component = pvfb->depth / 3;
605 
606         if (pvfb->depth % 3)
607             nplanes_per_color_component++;
608         pvfb->ncolors = 1 << nplanes_per_color_component;
609     }
610 
611     /* add extra bytes for XWDFileHeader, window name, and colormap */
612 
613     pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN +
614         pvfb->ncolors * SIZEOF(XWDColor);
615 
616     pvfb->pXWDHeader = NULL;
617     switch (fbmemtype) {
618 #ifdef HAVE_MMAP
619     case MMAPPED_FILE_FB:
620         vfbAllocateMmappedFramebuffer(pvfb);
621         break;
622 #else
623     case MMAPPED_FILE_FB:
624         break;
625 #endif
626 
627 #ifdef HAS_SHM
628     case SHARED_MEMORY_FB:
629         vfbAllocateSharedMemoryFramebuffer(pvfb);
630         break;
631 #else
632     case SHARED_MEMORY_FB:
633         break;
634 #endif
635 
636     case NORMAL_MEMORY_FB:
637         pvfb->pXWDHeader = (XWDFileHeader *) malloc(pvfb->sizeInBytes);
638         break;
639     }
640 
641     if (pvfb->pXWDHeader) {
642         pvfb->pXWDCmap = (XWDColor *) ((char *) pvfb->pXWDHeader
643                                        + SIZEOF(XWDheader) +
644                                        XWD_WINDOW_NAME_LEN);
645         pvfb->pfbMemory = (char *) (pvfb->pXWDCmap + pvfb->ncolors);
646 
647         return pvfb->pfbMemory;
648     }
649     else
650         return NULL;
651 }
652 
653 static void
vfbWriteXWDFileHeader(ScreenPtr pScreen)654 vfbWriteXWDFileHeader(ScreenPtr pScreen)
655 {
656     vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
657     XWDFileHeader *pXWDHeader = pvfb->pXWDHeader;
658     char hostname[XWD_WINDOW_NAME_LEN];
659     unsigned long swaptest = 1;
660     int i;
661 
662     needswap = *(char *) &swaptest;
663 
664     pXWDHeader->header_size =
665         (char *) pvfb->pXWDCmap - (char *) pvfb->pXWDHeader;
666     pXWDHeader->file_version = XWD_FILE_VERSION;
667 
668     pXWDHeader->pixmap_format = ZPixmap;
669     pXWDHeader->pixmap_depth = pvfb->depth;
670     pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height;
671     pXWDHeader->xoffset = 0;
672     pXWDHeader->byte_order = IMAGE_BYTE_ORDER;
673     pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER;
674 #ifndef INTERNAL_VS_EXTERNAL_PADDING
675     pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width;
676     pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT;
677     pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD;
678 #else
679     pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth;
680     pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO;
681     pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO;
682 #endif
683     pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel;
684     pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth;
685     pXWDHeader->ncolors = pvfb->ncolors;
686 
687     /* visual related fields are written when colormap is installed */
688 
689     pXWDHeader->window_x = pXWDHeader->window_y = 0;
690     pXWDHeader->window_bdrwidth = 0;
691 
692     /* write xwd "window" name: Xvfb hostname:server.screen */
693 
694     if (-1 == gethostname(hostname, sizeof(hostname)))
695         hostname[0] = 0;
696     else
697         hostname[XWD_WINDOW_NAME_LEN - 1] = 0;
698     sprintf((char *) (pXWDHeader + 1), "Xvfb %s:%s.%d", hostname, display,
699             pScreen->myNum);
700 
701     /* write colormap pixel slot values */
702 
703     for (i = 0; i < pvfb->ncolors; i++) {
704         pvfb->pXWDCmap[i].pixel = i;
705     }
706 
707     /* byte swap to most significant byte first */
708 
709     if (needswap) {
710         SwapLongs((CARD32 *) pXWDHeader, SIZEOF(XWDheader) / 4);
711         for (i = 0; i < pvfb->ncolors; i++) {
712             swapl(&pvfb->pXWDCmap[i].pixel);
713         }
714     }
715 }
716 
717 static Bool
vfbCursorOffScreen(ScreenPtr * ppScreen,int * x,int * y)718 vfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
719 {
720     return FALSE;
721 }
722 
723 static void
vfbCrossScreen(ScreenPtr pScreen,Bool entering)724 vfbCrossScreen(ScreenPtr pScreen, Bool entering)
725 {
726 }
727 
728 static miPointerScreenFuncRec vfbPointerCursorFuncs = {
729     vfbCursorOffScreen,
730     vfbCrossScreen,
731     miPointerWarpCursor
732 };
733 
734 static Bool
vfbCloseScreen(ScreenPtr pScreen)735 vfbCloseScreen(ScreenPtr pScreen)
736 {
737     vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
738 
739     pScreen->CloseScreen = pvfb->closeScreen;
740 
741     /*
742      * fb overwrites miCloseScreen, so do this here
743      */
744     if (pScreen->devPrivate)
745         (*pScreen->DestroyPixmap) (pScreen->devPrivate);
746     pScreen->devPrivate = NULL;
747 
748     return pScreen->CloseScreen(pScreen);
749 }
750 
751 static Bool
vfbRROutputValidateMode(ScreenPtr pScreen,RROutputPtr output,RRModePtr mode)752 vfbRROutputValidateMode(ScreenPtr           pScreen,
753                         RROutputPtr         output,
754                         RRModePtr           mode)
755 {
756     rrScrPriv(pScreen);
757 
758     if (pScrPriv->minWidth <= mode->mode.width &&
759         pScrPriv->maxWidth >= mode->mode.width &&
760         pScrPriv->minHeight <= mode->mode.height &&
761         pScrPriv->maxHeight >= mode->mode.height)
762         return TRUE;
763     else
764         return FALSE;
765 }
766 
767 static Bool
vfbRRScreenSetSize(ScreenPtr pScreen,CARD16 width,CARD16 height,CARD32 mmWidth,CARD32 mmHeight)768 vfbRRScreenSetSize(ScreenPtr  pScreen,
769                    CARD16     width,
770                    CARD16     height,
771                    CARD32     mmWidth,
772                    CARD32     mmHeight)
773 {
774     // Prevent screen updates while we change things around
775     SetRootClip(pScreen, ROOT_CLIP_NONE);
776 
777     pScreen->width = width;
778     pScreen->height = height;
779     pScreen->mmWidth = mmWidth;
780     pScreen->mmHeight = mmHeight;
781 
782     // Restore the ability to update screen, now with new dimensions
783     SetRootClip(pScreen, ROOT_CLIP_FULL);
784 
785     RRScreenSizeNotify (pScreen);
786     RRTellChanged(pScreen);
787 
788     return TRUE;
789 }
790 
791 static Bool
vfbRRCrtcSet(ScreenPtr pScreen,RRCrtcPtr crtc,RRModePtr mode,int x,int y,Rotation rotation,int numOutput,RROutputPtr * outputs)792 vfbRRCrtcSet(ScreenPtr pScreen,
793              RRCrtcPtr crtc,
794              RRModePtr mode,
795              int       x,
796              int       y,
797              Rotation  rotation,
798              int       numOutput,
799              RROutputPtr *outputs)
800 {
801   return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs);
802 }
803 
804 static Bool
vfbRRGetInfo(ScreenPtr pScreen,Rotation * rotations)805 vfbRRGetInfo(ScreenPtr pScreen, Rotation *rotations)
806 {
807     return TRUE;
808 }
809 
810 static Bool
vfbRandRInit(ScreenPtr pScreen)811 vfbRandRInit(ScreenPtr pScreen)
812 {
813     rrScrPrivPtr pScrPriv;
814 #if RANDR_12_INTERFACE
815     RRModePtr  mode;
816     RRCrtcPtr  crtc;
817     RROutputPtr        output;
818     xRRModeInfo modeInfo;
819     char       name[64];
820 #endif
821 
822     if (!RRScreenInit (pScreen))
823        return FALSE;
824     pScrPriv = rrGetScrPriv(pScreen);
825     pScrPriv->rrGetInfo = vfbRRGetInfo;
826 #if RANDR_12_INTERFACE
827     pScrPriv->rrCrtcSet = vfbRRCrtcSet;
828     pScrPriv->rrScreenSetSize = vfbRRScreenSetSize;
829     pScrPriv->rrOutputSetProperty = NULL;
830 #if RANDR_13_INTERFACE
831     pScrPriv->rrOutputGetProperty = NULL;
832 #endif
833     pScrPriv->rrOutputValidateMode = vfbRROutputValidateMode;
834     pScrPriv->rrModeDestroy = NULL;
835 
836     RRScreenSetSizeRange (pScreen,
837                          1, 1,
838                          pScreen->width, pScreen->height);
839 
840     sprintf (name, "%dx%d", pScreen->width, pScreen->height);
841     memset (&modeInfo, '\0', sizeof (modeInfo));
842     modeInfo.width = pScreen->width;
843     modeInfo.height = pScreen->height;
844     modeInfo.nameLength = strlen (name);
845 
846     mode = RRModeGet (&modeInfo, name);
847     if (!mode)
848        return FALSE;
849 
850     crtc = RRCrtcCreate (pScreen, NULL);
851     if (!crtc)
852        return FALSE;
853 
854     output = RROutputCreate (pScreen, "screen", 6, NULL);
855     if (!output)
856        return FALSE;
857     if (!RROutputSetClones (output, NULL, 0))
858        return FALSE;
859     if (!RROutputSetModes (output, &mode, 1, 0))
860        return FALSE;
861     if (!RROutputSetCrtcs (output, &crtc, 1))
862        return FALSE;
863     if (!RROutputSetConnection (output, RR_Connected))
864        return FALSE;
865     RRCrtcNotify (crtc, mode, 0, 0, RR_Rotate_0, NULL, 1, &output);
866 #endif
867     return TRUE;
868 }
869 
870 static Bool
vfbScreenInit(ScreenPtr pScreen,int argc,char ** argv)871 vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
872 {
873     vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
874     int dpix = monitorResolution, dpiy = monitorResolution;
875     int ret;
876     char *pbits;
877 
878     if (dpix == 0)
879         dpix = 100;
880 
881     if (dpiy == 0)
882         dpiy = 100;
883 
884     pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth);
885     pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth);
886     if (pvfb->bitsPerPixel >= 8)
887         pvfb->paddedWidth = pvfb->paddedBytesWidth / (pvfb->bitsPerPixel / 8);
888     else
889         pvfb->paddedWidth = pvfb->paddedBytesWidth * 8;
890     pbits = vfbAllocateFramebufferMemory(pvfb);
891     if (!pbits)
892         return FALSE;
893 
894     switch (pvfb->depth) {
895     case 8:
896         miSetVisualTypesAndMasks(8,
897                                  ((1 << StaticGray) |
898                                   (1 << GrayScale) |
899                                   (1 << StaticColor) |
900                                   (1 << PseudoColor) |
901                                   (1 << TrueColor) |
902                                   (1 << DirectColor)), 8, PseudoColor, 0, 0, 0);
903         break;
904     case 15:
905         miSetVisualTypesAndMasks(15,
906                                  ((1 << TrueColor) |
907                                   (1 << DirectColor)),
908                                  8, TrueColor, 0x7c00, 0x03e0, 0x001f);
909         break;
910     case 16:
911         miSetVisualTypesAndMasks(16,
912                                  ((1 << TrueColor) |
913                                   (1 << DirectColor)),
914                                  8, TrueColor, 0xf800, 0x07e0, 0x001f);
915         break;
916     case 24:
917         miSetVisualTypesAndMasks(24,
918                                  ((1 << TrueColor) |
919                                   (1 << DirectColor)),
920                                  8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
921         break;
922     case 30:
923         miSetVisualTypesAndMasks(30,
924                                  ((1 << TrueColor) |
925                                   (1 << DirectColor)),
926                                  10, TrueColor, 0x3ff00000, 0x000ffc00,
927                                  0x000003ff);
928         break;
929     default:
930         return FALSE;
931     }
932 
933     miSetPixmapDepths();
934 
935     ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height,
936                        dpix, dpiy, pvfb->paddedWidth, pvfb->bitsPerPixel);
937     if (ret && Render)
938         fbPictureInit(pScreen, 0, 0);
939 
940     if (!ret)
941         return FALSE;
942 
943     if (!vfbRandRInit(pScreen))
944        return FALSE;
945 
946     pScreen->InstallColormap = vfbInstallColormap;
947 
948     pScreen->SaveScreen = vfbSaveScreen;
949     pScreen->StoreColors = vfbStoreColors;
950 
951     miDCInitialize(pScreen, &vfbPointerCursorFuncs);
952 
953     vfbWriteXWDFileHeader(pScreen);
954 
955     pScreen->blackPixel = pvfb->blackPixel;
956     pScreen->whitePixel = pvfb->whitePixel;
957 
958     ret = fbCreateDefColormap(pScreen);
959 
960     miSetZeroLineBias(pScreen, pvfb->lineBias);
961 
962     pvfb->closeScreen = pScreen->CloseScreen;
963     pScreen->CloseScreen = vfbCloseScreen;
964 
965     return ret;
966 
967 }                               /* end vfbScreenInit */
968 
969 void
InitOutput(ScreenInfo * screen_info,int argc,char ** argv)970 InitOutput(ScreenInfo * screen_info, int argc, char **argv)
971 {
972     int i;
973     int NumFormats = 0;
974 
975     /* initialize pixmap formats */
976 
977     /* must have a pixmap depth to match every screen depth */
978     for (i = 0; i < vfbNumScreens; i++) {
979         vfbPixmapDepths[vfbScreens[i].depth] = TRUE;
980     }
981 
982     /* RENDER needs a good set of pixmaps. */
983     if (Render) {
984         vfbPixmapDepths[1] = TRUE;
985         vfbPixmapDepths[4] = TRUE;
986         vfbPixmapDepths[8] = TRUE;
987 #if 0
988         vfbPixmapDepths[12] = TRUE;
989 #endif
990 /*	vfbPixmapDepths[15] = TRUE; */
991         vfbPixmapDepths[16] = TRUE;
992         vfbPixmapDepths[24] = TRUE;
993 #if 0
994         vfbPixmapDepths[30] = TRUE;
995 #endif
996         vfbPixmapDepths[32] = TRUE;
997     }
998 
999     xorgGlxCreateVendor();
1000 
1001     for (i = 1; i <= 32; i++) {
1002         if (vfbPixmapDepths[i]) {
1003             if (NumFormats >= MAXFORMATS)
1004                 FatalError("MAXFORMATS is too small for this server\n");
1005             screen_info->formats[NumFormats].depth = i;
1006             screen_info->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i);
1007             screen_info->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD;
1008             NumFormats++;
1009         }
1010     }
1011 
1012     screen_info->imageByteOrder = IMAGE_BYTE_ORDER;
1013     screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
1014     screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
1015     screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
1016     screen_info->numPixmapFormats = NumFormats;
1017 
1018     /* initialize screens */
1019 
1020     if (vfbNumScreens < 1) {
1021         vfbScreens = &defaultScreenInfo;
1022         vfbNumScreens = 1;
1023     }
1024     for (i = 0; i < vfbNumScreens; i++) {
1025         if (-1 == AddScreen(vfbScreenInit, argc, argv)) {
1026             FatalError("Couldn't add screen %d", i);
1027         }
1028     }
1029 
1030 }                               /* end InitOutput */
1031