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