InitOutput.c revision 5a7dfde8
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        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
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
235#if INPUTTHREAD
236/** This function is called in Xserver/os/inputthread.c when starting
237    the input thread. */
238void
239ddxInputThreadInit(void)
240{
241}
242#endif
243
244void
245ddxUseMsg(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
265int
266ddxProcessArgument(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
393static void
394vfbInstallColormap(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
444static void
445vfbStoreColors(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
473static Bool
474vfbSaveScreen(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 */
482static void
483vfbBlockHandler(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
503static void
504vfbWakeupHandler(void *blockData, int result)
505{
506}
507
508static void
509vfbAllocateMmappedFramebuffer(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
559static void
560vfbAllocateSharedMemoryFramebuffer(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
586static char *
587vfbAllocateFramebufferMemory(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
653static void
654vfbWriteXWDFileHeader(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
717static Bool
718vfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
719{
720    return FALSE;
721}
722
723static void
724vfbCrossScreen(ScreenPtr pScreen, Bool entering)
725{
726}
727
728static miPointerScreenFuncRec vfbPointerCursorFuncs = {
729    vfbCursorOffScreen,
730    vfbCrossScreen,
731    miPointerWarpCursor
732};
733
734static Bool
735vfbCloseScreen(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
751static Bool
752vfbRROutputValidateMode(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
767static Bool
768vfbRRScreenSetSize(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
791static Bool
792vfbRRCrtcSet(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
804static Bool
805vfbRRGetInfo(ScreenPtr pScreen, Rotation *rotations)
806{
807    return TRUE;
808}
809
810static Bool
811vfbRandRInit(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
870static Bool
871vfbScreenInit(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
969void
970InitOutput(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