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