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