InitOutput.c revision 35c4bbdf
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 "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         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    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
106static int vfbNumScreens;
107static vfbScreenInfo *vfbScreens;
108
109static 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
118static Bool vfbPixmapDepths[33];
119
120#ifdef HAVE_MMAP
121static char *pfbdir = NULL;
122#endif
123typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType;
124static fbMemType fbmemtype = NORMAL_MEMORY_FB;
125static char needswap = 0;
126static 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
136static void
137vfbInitializePixmapDepths(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
146static int
147vfbBitsPerPixel(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
159void
160ddxGiveUp(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
204void
205AbortDDX(enum ExitCode error)
206{
207    ddxGiveUp(error);
208}
209
210#ifdef __APPLE__
211void
212DarwinHandleGUI(int argc, char *argv[])
213{
214}
215#endif
216
217void
218OsVendorInit(void)
219{
220}
221
222void
223OsVendorFatalError(const char *f, va_list args)
224{
225}
226
227#if defined(DDXBEFORERESET)
228void
229ddxBeforeReset(void)
230{
231    return;
232}
233#endif
234
235void
236ddxUseMsg(void)
237{
238    ErrorF("-screen scrn WxHxD     set screen's width, height, depth\n");
239    ErrorF("-pixdepths list-of-int support given pixmap depths\n");
240    ErrorF("+/-render		   turn on/off RENDER extension support"
241           "(default on)\n");
242    ErrorF("-linebias n            adjust thin line pixelization\n");
243    ErrorF("-blackpixel n          pixel value for black\n");
244    ErrorF("-whitepixel n          pixel value for white\n");
245
246#ifdef HAVE_MMAP
247    ErrorF
248        ("-fbdir directory       put framebuffers in mmap'ed files in directory\n");
249#endif
250
251#ifdef HAS_SHM
252    ErrorF("-shmem                 put framebuffers in shared memory\n");
253#endif
254}
255
256int
257ddxProcessArgument(int argc, char *argv[], int i)
258{
259    static Bool firstTime = TRUE;
260    static int lastScreen = -1;
261    vfbScreenInfo *currentScreen;
262
263    if (firstTime) {
264        vfbInitializePixmapDepths();
265        firstTime = FALSE;
266    }
267
268    if (lastScreen == -1)
269        currentScreen = &defaultScreenInfo;
270    else
271        currentScreen = &vfbScreens[lastScreen];
272
273#define CHECK_FOR_REQUIRED_ARGUMENTS(num) \
274    if (((i + num) >= argc) || (!argv[i + num])) {                      \
275      ErrorF("Required argument to %s not specified\n", argv[i]);       \
276      UseMsg();                                                         \
277      FatalError("Required argument to %s not specified\n", argv[i]);   \
278    }
279
280    if (strcmp(argv[i], "-screen") == 0) {      /* -screen n WxHxD */
281        int screenNum;
282
283        CHECK_FOR_REQUIRED_ARGUMENTS(2);
284        screenNum = atoi(argv[i + 1]);
285        /* The protocol only has a CARD8 for number of screens in the
286           connection setup block, so don't allow more than that. */
287        if ((screenNum < 0) || (screenNum >= 255)) {
288            ErrorF("Invalid screen number %d\n", screenNum);
289            UseMsg();
290            FatalError("Invalid screen number %d passed to -screen\n",
291                       screenNum);
292        }
293
294        if (vfbNumScreens <= screenNum) {
295            vfbScreens =
296                reallocarray(vfbScreens, screenNum + 1, sizeof(*vfbScreens));
297            if (!vfbScreens)
298                FatalError("Not enough memory for screen %d\n", screenNum);
299            for (; vfbNumScreens <= screenNum; ++vfbNumScreens)
300                vfbScreens[vfbNumScreens] = defaultScreenInfo;
301        }
302
303        if (3 != sscanf(argv[i + 2], "%dx%dx%d",
304                        &vfbScreens[screenNum].width,
305                        &vfbScreens[screenNum].height,
306                        &vfbScreens[screenNum].depth)) {
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        int depth, ret = 1;
319
320        CHECK_FOR_REQUIRED_ARGUMENTS(1);
321        while ((++i < argc) && (depth = atoi(argv[i])) != 0) {
322            if (depth < 0 || depth > 32) {
323                ErrorF("Invalid pixmap depth %d\n", depth);
324                UseMsg();
325                FatalError("Invalid pixmap depth %d passed to -pixdepths\n",
326                           depth);
327            }
328            vfbPixmapDepths[depth] = TRUE;
329            ret++;
330        }
331        return ret;
332    }
333
334    if (strcmp(argv[i], "+render") == 0) {      /* +render */
335        Render = TRUE;
336        return 1;
337    }
338
339    if (strcmp(argv[i], "-render") == 0) {      /* -render */
340        Render = FALSE;
341#ifdef COMPOSITE
342        noCompositeExtension = TRUE;
343#endif
344        return 1;
345    }
346
347    if (strcmp(argv[i], "-blackpixel") == 0) {  /* -blackpixel n */
348        CHECK_FOR_REQUIRED_ARGUMENTS(1);
349        currentScreen->blackPixel = atoi(argv[++i]);
350        return 2;
351    }
352
353    if (strcmp(argv[i], "-whitepixel") == 0) {  /* -whitepixel n */
354        CHECK_FOR_REQUIRED_ARGUMENTS(1);
355        currentScreen->whitePixel = atoi(argv[++i]);
356        return 2;
357    }
358
359    if (strcmp(argv[i], "-linebias") == 0) {    /* -linebias n */
360        CHECK_FOR_REQUIRED_ARGUMENTS(1);
361        currentScreen->lineBias = atoi(argv[++i]);
362        return 2;
363    }
364
365#ifdef HAVE_MMAP
366    if (strcmp(argv[i], "-fbdir") == 0) {       /* -fbdir directory */
367        CHECK_FOR_REQUIRED_ARGUMENTS(1);
368        pfbdir = argv[++i];
369        fbmemtype = MMAPPED_FILE_FB;
370        return 2;
371    }
372#endif                          /* HAVE_MMAP */
373
374#ifdef HAS_SHM
375    if (strcmp(argv[i], "-shmem") == 0) {       /* -shmem */
376        fbmemtype = SHARED_MEMORY_FB;
377        return 1;
378    }
379#endif
380
381    return 0;
382}
383
384static void
385vfbInstallColormap(ColormapPtr pmap)
386{
387    ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
388
389    if (pmap != oldpmap) {
390        int entries;
391        XWDFileHeader *pXWDHeader;
392        VisualPtr pVisual;
393        Pixel *ppix;
394        xrgb *prgb;
395        xColorItem *defs;
396        int i;
397
398        miInstallColormap(pmap);
399
400        entries = pmap->pVisual->ColormapEntries;
401        pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader;
402        pVisual = pmap->pVisual;
403
404        swapcopy32(pXWDHeader->visual_class, pVisual->class);
405        swapcopy32(pXWDHeader->red_mask, pVisual->redMask);
406        swapcopy32(pXWDHeader->green_mask, pVisual->greenMask);
407        swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask);
408        swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue);
409        swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries);
410
411        ppix = xallocarray(entries, sizeof(Pixel));
412        prgb = xallocarray(entries, sizeof(xrgb));
413        defs = xallocarray(entries, sizeof(xColorItem));
414
415        for (i = 0; i < entries; i++)
416            ppix[i] = i;
417        /* XXX truecolor */
418        QueryColors(pmap, entries, ppix, prgb, serverClient);
419
420        for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
421            defs[i].pixel = ppix[i] & 0xff;     /* change pixel to index */
422            defs[i].red = prgb[i].red;
423            defs[i].green = prgb[i].green;
424            defs[i].blue = prgb[i].blue;
425            defs[i].flags = DoRed | DoGreen | DoBlue;
426        }
427        (*pmap->pScreen->StoreColors) (pmap, entries, defs);
428
429        free(ppix);
430        free(prgb);
431        free(defs);
432    }
433}
434
435static void
436vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs)
437{
438    XWDColor *pXWDCmap;
439    int i;
440
441    if (pmap != GetInstalledmiColormap(pmap->pScreen)) {
442        return;
443    }
444
445    pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap;
446
447    if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
448        return;
449    }
450
451    for (i = 0; i < ndef; i++) {
452        if (pdefs[i].flags & DoRed) {
453            swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red);
454        }
455        if (pdefs[i].flags & DoGreen) {
456            swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green);
457        }
458        if (pdefs[i].flags & DoBlue) {
459            swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue);
460        }
461    }
462}
463
464static Bool
465vfbSaveScreen(ScreenPtr pScreen, int on)
466{
467    return TRUE;
468}
469
470#ifdef HAVE_MMAP
471
472/* this flushes any changes to the screens out to the mmapped file */
473static void
474vfbBlockHandler(void *blockData, OSTimePtr pTimeout, void *pReadmask)
475{
476    int i;
477
478    for (i = 0; i < vfbNumScreens; i++) {
479#ifdef MS_ASYNC
480        if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
481                        (size_t) vfbScreens[i].sizeInBytes, MS_ASYNC))
482#else
483        /* silly NetBSD and who else? */
484        if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
485                        (size_t) vfbScreens[i].sizeInBytes))
486#endif
487        {
488            perror("msync");
489            ErrorF("msync failed, %s", strerror(errno));
490        }
491    }
492}
493
494static void
495vfbWakeupHandler(void *blockData, int result, void *pReadmask)
496{
497}
498
499static void
500vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb)
501{
502#define DUMMY_BUFFER_SIZE 65536
503    char dummyBuffer[DUMMY_BUFFER_SIZE];
504    int currentFileSize, writeThisTime;
505
506    snprintf(pvfb->mmap_file, sizeof(pvfb->mmap_file), "%s/Xvfb_screen%d",
507             pfbdir, (int) (pvfb - vfbScreens));
508    if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT | O_RDWR, 0666))) {
509        perror("open");
510        ErrorF("open %s failed, %s", pvfb->mmap_file, strerror(errno));
511        return;
512    }
513
514    /* Extend the file to be the proper size */
515
516    memset(dummyBuffer, 0, DUMMY_BUFFER_SIZE);
517    for (currentFileSize = 0;
518         currentFileSize < pvfb->sizeInBytes;
519         currentFileSize += writeThisTime) {
520        writeThisTime = min(DUMMY_BUFFER_SIZE,
521                            pvfb->sizeInBytes - currentFileSize);
522        if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) {
523            perror("write");
524            ErrorF("write %s failed, %s", pvfb->mmap_file, strerror(errno));
525            return;
526        }
527    }
528
529    /* try to mmap the file */
530
531    pvfb->pXWDHeader = (XWDFileHeader *) mmap((caddr_t) NULL, pvfb->sizeInBytes,
532                                              PROT_READ | PROT_WRITE,
533                                              MAP_FILE | MAP_SHARED,
534                                              pvfb->mmap_fd, 0);
535    if (-1 == (long) pvfb->pXWDHeader) {
536        perror("mmap");
537        ErrorF("mmap %s failed, %s", pvfb->mmap_file, strerror(errno));
538        pvfb->pXWDHeader = NULL;
539        return;
540    }
541
542    if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler,
543                                        NULL)) {
544        pvfb->pXWDHeader = NULL;
545    }
546}
547#endif                          /* HAVE_MMAP */
548
549#ifdef HAS_SHM
550static void
551vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb)
552{
553    /* create the shared memory segment */
554
555    pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT | 0777);
556    if (pvfb->shmid < 0) {
557        perror("shmget");
558        ErrorF("shmget %d bytes failed, %s", pvfb->sizeInBytes,
559               strerror(errno));
560        return;
561    }
562
563    /* try to attach it */
564
565    pvfb->pXWDHeader = (XWDFileHeader *) shmat(pvfb->shmid, 0, 0);
566    if (-1 == (long) pvfb->pXWDHeader) {
567        perror("shmat");
568        ErrorF("shmat failed, %s", strerror(errno));
569        pvfb->pXWDHeader = NULL;
570        return;
571    }
572
573    ErrorF("screen %d shmid %d\n", (int) (pvfb - vfbScreens), pvfb->shmid);
574}
575#endif                          /* HAS_SHM */
576
577static char *
578vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb)
579{
580    if (pvfb->pfbMemory)
581        return pvfb->pfbMemory; /* already done */
582
583    pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height;
584
585    /* Calculate how many entries in colormap.  This is rather bogus, because
586     * the visuals haven't even been set up yet, but we need to know because we
587     * have to allocate space in the file for the colormap.  The number 10
588     * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c.
589     */
590
591    if (pvfb->depth <= 10) {    /* single index colormaps */
592        pvfb->ncolors = 1 << pvfb->depth;
593    }
594    else {                      /* decomposed colormaps */
595        int nplanes_per_color_component = pvfb->depth / 3;
596
597        if (pvfb->depth % 3)
598            nplanes_per_color_component++;
599        pvfb->ncolors = 1 << nplanes_per_color_component;
600    }
601
602    /* add extra bytes for XWDFileHeader, window name, and colormap */
603
604    pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN +
605        pvfb->ncolors * SIZEOF(XWDColor);
606
607    pvfb->pXWDHeader = NULL;
608    switch (fbmemtype) {
609#ifdef HAVE_MMAP
610    case MMAPPED_FILE_FB:
611        vfbAllocateMmappedFramebuffer(pvfb);
612        break;
613#else
614    case MMAPPED_FILE_FB:
615        break;
616#endif
617
618#ifdef HAS_SHM
619    case SHARED_MEMORY_FB:
620        vfbAllocateSharedMemoryFramebuffer(pvfb);
621        break;
622#else
623    case SHARED_MEMORY_FB:
624        break;
625#endif
626
627    case NORMAL_MEMORY_FB:
628        pvfb->pXWDHeader = (XWDFileHeader *) malloc(pvfb->sizeInBytes);
629        break;
630    }
631
632    if (pvfb->pXWDHeader) {
633        pvfb->pXWDCmap = (XWDColor *) ((char *) pvfb->pXWDHeader
634                                       + SIZEOF(XWDheader) +
635                                       XWD_WINDOW_NAME_LEN);
636        pvfb->pfbMemory = (char *) (pvfb->pXWDCmap + pvfb->ncolors);
637
638        return pvfb->pfbMemory;
639    }
640    else
641        return NULL;
642}
643
644static void
645vfbWriteXWDFileHeader(ScreenPtr pScreen)
646{
647    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
648    XWDFileHeader *pXWDHeader = pvfb->pXWDHeader;
649    char hostname[XWD_WINDOW_NAME_LEN];
650    unsigned long swaptest = 1;
651    int i;
652
653    needswap = *(char *) &swaptest;
654
655    pXWDHeader->header_size =
656        (char *) pvfb->pXWDCmap - (char *) pvfb->pXWDHeader;
657    pXWDHeader->file_version = XWD_FILE_VERSION;
658
659    pXWDHeader->pixmap_format = ZPixmap;
660    pXWDHeader->pixmap_depth = pvfb->depth;
661    pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height;
662    pXWDHeader->xoffset = 0;
663    pXWDHeader->byte_order = IMAGE_BYTE_ORDER;
664    pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER;
665#ifndef INTERNAL_VS_EXTERNAL_PADDING
666    pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width;
667    pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT;
668    pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD;
669#else
670    pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth;
671    pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO;
672    pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO;
673#endif
674    pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel;
675    pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth;
676    pXWDHeader->ncolors = pvfb->ncolors;
677
678    /* visual related fields are written when colormap is installed */
679
680    pXWDHeader->window_x = pXWDHeader->window_y = 0;
681    pXWDHeader->window_bdrwidth = 0;
682
683    /* write xwd "window" name: Xvfb hostname:server.screen */
684
685    if (-1 == gethostname(hostname, sizeof(hostname)))
686        hostname[0] = 0;
687    else
688        hostname[XWD_WINDOW_NAME_LEN - 1] = 0;
689    sprintf((char *) (pXWDHeader + 1), "Xvfb %s:%s.%d", hostname, display,
690            pScreen->myNum);
691
692    /* write colormap pixel slot values */
693
694    for (i = 0; i < pvfb->ncolors; i++) {
695        pvfb->pXWDCmap[i].pixel = i;
696    }
697
698    /* byte swap to most significant byte first */
699
700    if (needswap) {
701        SwapLongs((CARD32 *) pXWDHeader, SIZEOF(XWDheader) / 4);
702        for (i = 0; i < pvfb->ncolors; i++) {
703            swapl(&pvfb->pXWDCmap[i].pixel);
704        }
705    }
706}
707
708static Bool
709vfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
710{
711    return FALSE;
712}
713
714static void
715vfbCrossScreen(ScreenPtr pScreen, Bool entering)
716{
717}
718
719static miPointerScreenFuncRec vfbPointerCursorFuncs = {
720    vfbCursorOffScreen,
721    vfbCrossScreen,
722    miPointerWarpCursor
723};
724
725static Bool
726vfbCloseScreen(ScreenPtr pScreen)
727{
728    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
729
730    pScreen->CloseScreen = pvfb->closeScreen;
731
732    /*
733     * fb overwrites miCloseScreen, so do this here
734     */
735    if (pScreen->devPrivate)
736        (*pScreen->DestroyPixmap) (pScreen->devPrivate);
737    pScreen->devPrivate = NULL;
738
739    return pScreen->CloseScreen(pScreen);
740}
741
742static Bool
743vfbRROutputValidateMode(ScreenPtr           pScreen,
744                        RROutputPtr         output,
745                        RRModePtr           mode)
746{
747    rrScrPriv(pScreen);
748
749    if (pScrPriv->minWidth <= mode->mode.width &&
750        pScrPriv->maxWidth >= mode->mode.width &&
751        pScrPriv->minHeight <= mode->mode.height &&
752        pScrPriv->maxHeight >= mode->mode.height)
753        return TRUE;
754    else
755        return FALSE;
756}
757
758static Bool
759vfbRRScreenSetSize(ScreenPtr  pScreen,
760                   CARD16     width,
761                   CARD16     height,
762                   CARD32     mmWidth,
763                   CARD32     mmHeight)
764{
765    // Prevent screen updates while we change things around
766    SetRootClip(pScreen, ROOT_CLIP_NONE);
767
768    pScreen->width = width;
769    pScreen->height = height;
770    pScreen->mmWidth = mmWidth;
771    pScreen->mmHeight = mmHeight;
772
773    // Restore the ability to update screen, now with new dimensions
774    SetRootClip(pScreen, ROOT_CLIP_FULL);
775
776    RRScreenSizeNotify (pScreen);
777    RRTellChanged(pScreen);
778
779    return TRUE;
780}
781
782static Bool
783vfbRRCrtcSet(ScreenPtr pScreen,
784             RRCrtcPtr crtc,
785             RRModePtr mode,
786             int       x,
787             int       y,
788             Rotation  rotation,
789             int       numOutput,
790             RROutputPtr *outputs)
791{
792  return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs);
793}
794
795static Bool
796vfbRRGetInfo(ScreenPtr pScreen, Rotation *rotations)
797{
798    return TRUE;
799}
800
801static Bool
802vfbRandRInit(ScreenPtr pScreen)
803{
804    rrScrPrivPtr pScrPriv;
805#if RANDR_12_INTERFACE
806    RRModePtr  mode;
807    RRCrtcPtr  crtc;
808    RROutputPtr        output;
809    xRRModeInfo modeInfo;
810    char       name[64];
811#endif
812
813    if (!RRScreenInit (pScreen))
814       return FALSE;
815    pScrPriv = rrGetScrPriv(pScreen);
816    pScrPriv->rrGetInfo = vfbRRGetInfo;
817#if RANDR_12_INTERFACE
818    pScrPriv->rrCrtcSet = vfbRRCrtcSet;
819    pScrPriv->rrScreenSetSize = vfbRRScreenSetSize;
820    pScrPriv->rrOutputSetProperty = NULL;
821#if RANDR_13_INTERFACE
822    pScrPriv->rrOutputGetProperty = NULL;
823#endif
824    pScrPriv->rrOutputValidateMode = vfbRROutputValidateMode;
825    pScrPriv->rrModeDestroy = NULL;
826
827    RRScreenSetSizeRange (pScreen,
828                         1, 1,
829                         pScreen->width, pScreen->height);
830
831    sprintf (name, "%dx%d", pScreen->width, pScreen->height);
832    memset (&modeInfo, '\0', sizeof (modeInfo));
833    modeInfo.width = pScreen->width;
834    modeInfo.height = pScreen->height;
835    modeInfo.nameLength = strlen (name);
836
837    mode = RRModeGet (&modeInfo, name);
838    if (!mode)
839       return FALSE;
840
841    crtc = RRCrtcCreate (pScreen, NULL);
842    if (!crtc)
843       return FALSE;
844
845    output = RROutputCreate (pScreen, "screen", 6, NULL);
846    if (!output)
847       return FALSE;
848    if (!RROutputSetClones (output, NULL, 0))
849       return FALSE;
850    if (!RROutputSetModes (output, &mode, 1, 0))
851       return FALSE;
852    if (!RROutputSetCrtcs (output, &crtc, 1))
853       return FALSE;
854    if (!RROutputSetConnection (output, RR_Connected))
855       return FALSE;
856    RRCrtcNotify (crtc, mode, 0, 0, RR_Rotate_0, NULL, 1, &output);
857#endif
858    return TRUE;
859}
860
861static Bool
862vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
863{
864    vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
865    int dpix = monitorResolution, dpiy = monitorResolution;
866    int ret;
867    char *pbits;
868
869    if (dpix == 0)
870        dpix = 100;
871
872    if (dpiy == 0)
873        dpiy = 100;
874
875    pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth);
876    pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth);
877    if (pvfb->bitsPerPixel >= 8)
878        pvfb->paddedWidth = pvfb->paddedBytesWidth / (pvfb->bitsPerPixel / 8);
879    else
880        pvfb->paddedWidth = pvfb->paddedBytesWidth * 8;
881    pbits = vfbAllocateFramebufferMemory(pvfb);
882    if (!pbits)
883        return FALSE;
884
885    switch (pvfb->depth) {
886    case 8:
887        miSetVisualTypesAndMasks(8,
888                                 ((1 << StaticGray) |
889                                  (1 << GrayScale) |
890                                  (1 << StaticColor) |
891                                  (1 << PseudoColor) |
892                                  (1 << TrueColor) |
893                                  (1 << DirectColor)), 8, PseudoColor, 0, 0, 0);
894        break;
895    case 15:
896        miSetVisualTypesAndMasks(15,
897                                 ((1 << TrueColor) |
898                                  (1 << DirectColor)),
899                                 8, TrueColor, 0x7c00, 0x03e0, 0x001f);
900        break;
901    case 16:
902        miSetVisualTypesAndMasks(16,
903                                 ((1 << TrueColor) |
904                                  (1 << DirectColor)),
905                                 8, TrueColor, 0xf800, 0x07e0, 0x001f);
906        break;
907    case 24:
908        miSetVisualTypesAndMasks(24,
909                                 ((1 << TrueColor) |
910                                  (1 << DirectColor)),
911                                 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
912        break;
913    case 30:
914        miSetVisualTypesAndMasks(30,
915                                 ((1 << TrueColor) |
916                                  (1 << DirectColor)),
917                                 10, TrueColor, 0x3ff00000, 0x000ffc00,
918                                 0x000003ff);
919        break;
920    default:
921        return FALSE;
922    }
923
924    miSetPixmapDepths();
925
926    ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height,
927                       dpix, dpiy, pvfb->paddedWidth, pvfb->bitsPerPixel);
928    if (ret && Render)
929        fbPictureInit(pScreen, 0, 0);
930
931    if (!ret)
932        return FALSE;
933
934    if (!vfbRandRInit(pScreen))
935       return FALSE;
936
937    pScreen->InstallColormap = vfbInstallColormap;
938
939    pScreen->SaveScreen = vfbSaveScreen;
940    pScreen->StoreColors = vfbStoreColors;
941
942    miDCInitialize(pScreen, &vfbPointerCursorFuncs);
943
944    vfbWriteXWDFileHeader(pScreen);
945
946    pScreen->blackPixel = pvfb->blackPixel;
947    pScreen->whitePixel = pvfb->whitePixel;
948
949    ret = fbCreateDefColormap(pScreen);
950
951    miSetZeroLineBias(pScreen, pvfb->lineBias);
952
953    pvfb->closeScreen = pScreen->CloseScreen;
954    pScreen->CloseScreen = vfbCloseScreen;
955
956    return ret;
957
958}                               /* end vfbScreenInit */
959
960static const ExtensionModule vfbExtensions[] = {
961#ifdef GLXEXT
962    { GlxExtensionInit, "GLX", &noGlxExtension },
963#endif
964};
965
966static
967void vfbExtensionInit(void)
968{
969    LoadExtensionList(vfbExtensions, ARRAY_SIZE(vfbExtensions), TRUE);
970}
971
972void
973InitOutput(ScreenInfo * screen_info, int argc, char **argv)
974{
975    int i;
976    int NumFormats = 0;
977
978    if (serverGeneration == 1)
979        vfbExtensionInit();
980
981    /* initialize pixmap formats */
982
983    /* must have a pixmap depth to match every screen depth */
984    for (i = 0; i < vfbNumScreens; i++) {
985        vfbPixmapDepths[vfbScreens[i].depth] = TRUE;
986    }
987
988    /* RENDER needs a good set of pixmaps. */
989    if (Render) {
990        vfbPixmapDepths[1] = TRUE;
991        vfbPixmapDepths[4] = TRUE;
992        vfbPixmapDepths[8] = TRUE;
993#if 0
994        vfbPixmapDepths[12] = TRUE;
995#endif
996/*	vfbPixmapDepths[15] = TRUE; */
997        vfbPixmapDepths[16] = TRUE;
998        vfbPixmapDepths[24] = TRUE;
999#if 0
1000        vfbPixmapDepths[30] = TRUE;
1001#endif
1002        vfbPixmapDepths[32] = TRUE;
1003    }
1004
1005    for (i = 1; i <= 32; i++) {
1006        if (vfbPixmapDepths[i]) {
1007            if (NumFormats >= MAXFORMATS)
1008                FatalError("MAXFORMATS is too small for this server\n");
1009            screen_info->formats[NumFormats].depth = i;
1010            screen_info->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i);
1011            screen_info->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD;
1012            NumFormats++;
1013        }
1014    }
1015
1016    screen_info->imageByteOrder = IMAGE_BYTE_ORDER;
1017    screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
1018    screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
1019    screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
1020    screen_info->numPixmapFormats = NumFormats;
1021
1022    /* initialize screens */
1023
1024    if (vfbNumScreens < 1) {
1025        vfbScreens = &defaultScreenInfo;
1026        vfbNumScreens = 1;
1027    }
1028    for (i = 0; i < vfbNumScreens; i++) {
1029        if (-1 == AddScreen(vfbScreenInit, argc, argv)) {
1030            FatalError("Couldn't add screen %d", i);
1031        }
1032    }
1033
1034}                               /* end InitOutput */
1035