1 /*
2 * Copyright 2001-2004 Red Hat Inc., Durham, North Carolina.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation on the rights to use, copy, modify, merge,
10 * publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so,
12 * subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 */
27
28 /*
29 * Authors:
30 * Kevin E. Martin <kem@redhat.com>
31 * David H. Dawes <dawes@xfree86.org>
32 * Rickard E. (Rik) Faith <faith@redhat.com>
33 *
34 */
35
36 /** \file
37 * Provide expected functions for initialization from the ddx layer and
38 * global variables for the DMX server. */
39
40 #ifdef HAVE_DMX_CONFIG_H
41 #include <dmx-config.h>
42 #endif
43
44 #include "dmx.h"
45 #include "dmxinit.h"
46 #include "dmxsync.h"
47 #include "dmxlog.h"
48 #include "dmxinput.h"
49 #include "dmxscrinit.h"
50 #include "dmxcursor.h"
51 #include "dmxfont.h"
52 #include "config/dmxconfig.h"
53 #include "dmxcb.h"
54 #include "dmxprop.h"
55 #include "dmxstat.h"
56 #include "dmxpict.h"
57
58 #include <X11/Xos.h> /* For gettimeofday */
59 #include <X11/Xmu/SysUtil.h> /* For XmuGetHostname */
60 #include "dixstruct.h"
61 #ifdef PANORAMIX
62 #include "panoramiXsrv.h"
63 #endif
64
65 #include <signal.h> /* For SIGQUIT */
66
67 #ifdef GLXEXT
68 #include <GL/glx.h>
69 #include <GL/glxint.h>
70 #include "dmx_glxvisuals.h"
71 #include "glx_extinit.h"
72 #include <X11/extensions/Xext.h>
73 #include <X11/extensions/extutil.h>
74 #endif /* GLXEXT */
75
76 #include <X11/extensions/dmxproto.h>
77
78 /* Global variables available to all Xserver/hw/dmx routines. */
79 int dmxNumScreens;
80 DMXScreenInfo *dmxScreens;
81
82 int dmxNumInputs;
83 DMXInputInfo *dmxInputs;
84
85 XErrorEvent dmxLastErrorEvent;
86 Bool dmxErrorOccurred = FALSE;
87
88 char *dmxFontPath = NULL;
89
90 Bool dmxOffScreenOpt = TRUE;
91
92 Bool dmxSubdividePrimitives = TRUE;
93
94 Bool dmxLazyWindowCreation = TRUE;
95
96 Bool dmxUseXKB = TRUE;
97
98 int dmxDepth = 0;
99
100 #ifndef GLXEXT
101 static Bool dmxGLXProxy = FALSE;
102 #else
103 Bool dmxGLXProxy = TRUE;
104
105 Bool dmxGLXSwapGroupSupport = TRUE;
106
107 Bool dmxGLXSyncSwap = FALSE;
108
109 Bool dmxGLXFinishSwap = FALSE;
110 #endif
111
112 RESTYPE RRProviderType = 0;
113
114 Bool dmxIgnoreBadFontPaths = FALSE;
115
116 Bool dmxAddRemoveScreens = FALSE;
117
118 /* dmxErrorHandler catches errors that occur when calling one of the
119 * back-end servers. Some of this code is based on _XPrintDefaultError
120 * in xc/lib/X11/XlibInt.c */
121 static int
dmxErrorHandler(Display * dpy,XErrorEvent * ev)122 dmxErrorHandler(Display * dpy, XErrorEvent * ev)
123 {
124 #define DMX_ERROR_BUF_SIZE 256
125 /* RATS: these buffers are only used in
126 * length-limited calls. */
127 char buf[DMX_ERROR_BUF_SIZE];
128 char request[DMX_ERROR_BUF_SIZE];
129 _XExtension *ext = NULL;
130
131 dmxErrorOccurred = TRUE;
132 dmxLastErrorEvent = *ev;
133
134 XGetErrorText(dpy, ev->error_code, buf, sizeof(buf));
135 dmxLog(dmxWarning, "dmxErrorHandler: %s\n", buf);
136
137 /* Find major opcode name */
138 if (ev->request_code < 128) {
139 snprintf(request, sizeof(request), "%d", ev->request_code);
140 XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf));
141 }
142 else {
143 for (ext = dpy->ext_procs;
144 ext && ext->codes.major_opcode != ev->request_code;
145 ext = ext->next);
146 if (ext)
147 strlcpy(buf, ext->name, sizeof(buf));
148 else
149 buf[0] = '\0';
150 }
151 dmxLog(dmxWarning, " Major opcode: %d (%s)\n",
152 ev->request_code, buf);
153
154 /* Find minor opcode name */
155 if (ev->request_code >= 128 && ext) {
156 snprintf(request, sizeof(request), "%d", ev->request_code);
157 snprintf(request, sizeof(request), "%s.%d", ext->name, ev->minor_code);
158 XGetErrorDatabaseText(dpy, "XRequest", request, "", buf, sizeof(buf));
159 dmxLog(dmxWarning, " Minor opcode: %d (%s)\n",
160 ev->minor_code, buf);
161 }
162
163 /* Provide value information */
164 switch (ev->error_code) {
165 case BadValue:
166 dmxLog(dmxWarning, " Value: 0x%x\n",
167 (unsigned int) ev->resourceid);
168 break;
169 case BadAtom:
170 dmxLog(dmxWarning, " AtomID: 0x%x\n",
171 (unsigned int) ev->resourceid);
172 break;
173 default:
174 dmxLog(dmxWarning, " ResourceID: 0x%x\n",
175 (unsigned int) ev->resourceid);
176 break;
177 }
178
179 /* Provide serial number information */
180 dmxLog(dmxWarning, " Failed serial number: %d\n",
181 (unsigned int) ev->serial);
182 dmxLog(dmxWarning, " Current serial number: %d\n",
183 (unsigned int) dpy->request);
184 return 0;
185 }
186
187 #ifdef GLXEXT
188 static int
dmxNOPErrorHandler(Display * dpy,XErrorEvent * ev)189 dmxNOPErrorHandler(Display * dpy, XErrorEvent * ev)
190 {
191 return 0;
192 }
193 #endif
194
195 Bool
dmxOpenDisplay(DMXScreenInfo * dmxScreen)196 dmxOpenDisplay(DMXScreenInfo * dmxScreen)
197 {
198 if (!(dmxScreen->beDisplay = XOpenDisplay(dmxScreen->name)))
199 return FALSE;
200
201 dmxPropertyDisplay(dmxScreen);
202 return TRUE;
203 }
204
205 void
dmxSetErrorHandler(DMXScreenInfo * dmxScreen)206 dmxSetErrorHandler(DMXScreenInfo * dmxScreen)
207 {
208 XSetErrorHandler(dmxErrorHandler);
209 }
210
211 static void
dmxPrintScreenInfo(DMXScreenInfo * dmxScreen)212 dmxPrintScreenInfo(DMXScreenInfo * dmxScreen)
213 {
214 XWindowAttributes attribs;
215 int ndepths = 0, *depths = NULL;
216 int i;
217 Display *dpy = dmxScreen->beDisplay;
218 Screen *s = DefaultScreenOfDisplay(dpy);
219 int scr = DefaultScreen(dpy);
220
221 XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs);
222 if (!(depths = XListDepths(dpy, scr, &ndepths)))
223 ndepths = 0;
224
225 dmxLogOutput(dmxScreen, "Name of display: %s\n", DisplayString(dpy));
226 dmxLogOutput(dmxScreen, "Version number: %d.%d\n",
227 ProtocolVersion(dpy), ProtocolRevision(dpy));
228 dmxLogOutput(dmxScreen, "Vendor string: %s\n", ServerVendor(dpy));
229 if (!strstr(ServerVendor(dpy), "XFree86")) {
230 dmxLogOutput(dmxScreen, "Vendor release: %d\n", VendorRelease(dpy));
231 }
232 else {
233 /* This code based on xdpyinfo.c */
234 int v = VendorRelease(dpy);
235 int major = -1, minor = -1, patch = -1, subpatch = -1;
236
237 if (v < 336)
238 major = v / 100, minor = (v / 10) % 10, patch = v % 10;
239 else if (v < 3900) {
240 major = v / 1000;
241 minor = (v / 100) % 10;
242 if (((v / 10) % 10) || (v % 10)) {
243 patch = (v / 10) % 10;
244 if (v % 10)
245 subpatch = v % 10;
246 }
247 }
248 else if (v < 40000000) {
249 major = v / 1000;
250 minor = (v / 10) % 10;
251 if (v % 10)
252 patch = v % 10;
253 }
254 else {
255 major = v / 10000000;
256 minor = (v / 100000) % 100;
257 patch = (v / 1000) % 100;
258 if (v % 1000)
259 subpatch = v % 1000;
260 }
261 dmxLogOutput(dmxScreen, "Vendor release: %d (XFree86 version: %d.%d",
262 v, major, minor);
263 if (patch > 0)
264 dmxLogOutputCont(dmxScreen, ".%d", patch);
265 if (subpatch > 0)
266 dmxLogOutputCont(dmxScreen, ".%d", subpatch);
267 dmxLogOutputCont(dmxScreen, ")\n");
268 }
269
270 dmxLogOutput(dmxScreen, "Dimensions: %dx%d pixels\n",
271 attribs.width, attribs.height);
272 dmxLogOutput(dmxScreen, "%d depths on screen %d: ", ndepths, scr);
273 for (i = 0; i < ndepths; i++)
274 dmxLogOutputCont(dmxScreen, "%c%d", i ? ',' : ' ', depths[i]);
275 dmxLogOutputCont(dmxScreen, "\n");
276 dmxLogOutput(dmxScreen, "Depth of root window: %d plane%s (%d)\n",
277 attribs.depth, attribs.depth == 1 ? "" : "s",
278 DisplayPlanes(dpy, scr));
279 dmxLogOutput(dmxScreen, "Number of colormaps: %d min, %d max\n",
280 MinCmapsOfScreen(s), MaxCmapsOfScreen(s));
281 dmxLogOutput(dmxScreen, "Options: backing-store %s, save-unders %s\n",
282 (DoesBackingStore(s) == NotUseful) ? "no" :
283 ((DoesBackingStore(s) == Always) ? "yes" : "when mapped"),
284 DoesSaveUnders(s) ? "yes" : "no");
285 dmxLogOutput(dmxScreen, "Window Manager running: %s\n",
286 (dmxScreen->WMRunningOnBE) ? "yes" : "no");
287
288 if (dmxScreen->WMRunningOnBE) {
289 dmxLogOutputWarning(dmxScreen,
290 "Window manager running "
291 "-- colormaps not supported\n");
292 }
293 XFree(depths);
294 }
295
296 void
dmxGetScreenAttribs(DMXScreenInfo * dmxScreen)297 dmxGetScreenAttribs(DMXScreenInfo * dmxScreen)
298 {
299 XWindowAttributes attribs;
300 Display *dpy = dmxScreen->beDisplay;
301
302 #ifdef GLXEXT
303 int dummy;
304 #endif
305
306 XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &attribs);
307
308 dmxScreen->beWidth = attribs.width;
309 dmxScreen->beHeight = attribs.height;
310
311 /* Fill in missing geometry information */
312 if (dmxScreen->scrnXSign < 0) {
313 if (dmxScreen->scrnWidth) {
314 dmxScreen->scrnX = (attribs.width - dmxScreen->scrnWidth
315 - dmxScreen->scrnX);
316 }
317 else {
318 dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX;
319 dmxScreen->scrnX = 0;
320 }
321 }
322 if (dmxScreen->scrnYSign < 0) {
323 if (dmxScreen->scrnHeight) {
324 dmxScreen->scrnY = (attribs.height - dmxScreen->scrnHeight
325 - dmxScreen->scrnY);
326 }
327 else {
328 dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY;
329 dmxScreen->scrnY = 0;
330 }
331 }
332 if (!dmxScreen->scrnWidth)
333 dmxScreen->scrnWidth = attribs.width - dmxScreen->scrnX;
334 if (!dmxScreen->scrnHeight)
335 dmxScreen->scrnHeight = attribs.height - dmxScreen->scrnY;
336
337 if (!dmxScreen->rootWidth)
338 dmxScreen->rootWidth = dmxScreen->scrnWidth;
339 if (!dmxScreen->rootHeight)
340 dmxScreen->rootHeight = dmxScreen->scrnHeight;
341 if (dmxScreen->rootWidth + dmxScreen->rootX > dmxScreen->scrnWidth)
342 dmxScreen->rootWidth = dmxScreen->scrnWidth - dmxScreen->rootX;
343 if (dmxScreen->rootHeight + dmxScreen->rootY > dmxScreen->scrnHeight)
344 dmxScreen->rootHeight = dmxScreen->scrnHeight - dmxScreen->rootY;
345
346 /* FIXME: Get these from the back-end server */
347 dmxScreen->beXDPI = 75;
348 dmxScreen->beYDPI = 75;
349
350 dmxScreen->beDepth = attribs.depth; /* FIXME: verify that this
351 * works always. In
352 * particular, this will work
353 * well for depth=16, will fail
354 * because of colormap issues
355 * at depth 8. More work needs
356 * to be done here. */
357
358 if (dmxScreen->beDepth <= 8)
359 dmxScreen->beBPP = 8;
360 else if (dmxScreen->beDepth <= 16)
361 dmxScreen->beBPP = 16;
362 else
363 dmxScreen->beBPP = 32;
364
365 #ifdef GLXEXT
366 /* get the majorOpcode for the back-end GLX extension */
367 XQueryExtension(dpy, "GLX", &dmxScreen->glxMajorOpcode,
368 &dummy, &dmxScreen->glxErrorBase);
369 #endif
370
371 dmxPrintScreenInfo(dmxScreen);
372 dmxLogOutput(dmxScreen, "%dx%d+%d+%d on %dx%d at depth=%d, bpp=%d\n",
373 dmxScreen->scrnWidth, dmxScreen->scrnHeight,
374 dmxScreen->scrnX, dmxScreen->scrnY,
375 dmxScreen->beWidth, dmxScreen->beHeight,
376 dmxScreen->beDepth, dmxScreen->beBPP);
377 if (dmxScreen->beDepth == 8)
378 dmxLogOutputWarning(dmxScreen,
379 "Support for depth == 8 is not complete\n");
380 }
381
382 Bool
dmxGetVisualInfo(DMXScreenInfo * dmxScreen)383 dmxGetVisualInfo(DMXScreenInfo * dmxScreen)
384 {
385 int i;
386 XVisualInfo visinfo;
387
388 visinfo.screen = DefaultScreen(dmxScreen->beDisplay);
389 dmxScreen->beVisuals = XGetVisualInfo(dmxScreen->beDisplay,
390 VisualScreenMask,
391 &visinfo, &dmxScreen->beNumVisuals);
392
393 dmxScreen->beDefVisualIndex = -1;
394
395 if (defaultColorVisualClass >= 0 || dmxDepth > 0) {
396 for (i = 0; i < dmxScreen->beNumVisuals; i++)
397 if (defaultColorVisualClass >= 0) {
398 if (dmxScreen->beVisuals[i].class == defaultColorVisualClass) {
399 if (dmxDepth > 0) {
400 if (dmxScreen->beVisuals[i].depth == dmxDepth) {
401 dmxScreen->beDefVisualIndex = i;
402 break;
403 }
404 }
405 else {
406 dmxScreen->beDefVisualIndex = i;
407 break;
408 }
409 }
410 }
411 else if (dmxScreen->beVisuals[i].depth == dmxDepth) {
412 dmxScreen->beDefVisualIndex = i;
413 break;
414 }
415 }
416 else {
417 visinfo.visualid =
418 XVisualIDFromVisual(DefaultVisual(dmxScreen->beDisplay,
419 visinfo.screen));
420
421 for (i = 0; i < dmxScreen->beNumVisuals; i++)
422 if (visinfo.visualid == dmxScreen->beVisuals[i].visualid) {
423 dmxScreen->beDefVisualIndex = i;
424 break;
425 }
426 }
427
428 for (i = 0; i < dmxScreen->beNumVisuals; i++)
429 dmxLogVisual(dmxScreen, &dmxScreen->beVisuals[i],
430 (i == dmxScreen->beDefVisualIndex));
431
432 return dmxScreen->beDefVisualIndex >= 0;
433 }
434
435 void
dmxGetColormaps(DMXScreenInfo * dmxScreen)436 dmxGetColormaps(DMXScreenInfo * dmxScreen)
437 {
438 int i;
439
440 dmxScreen->beNumDefColormaps = dmxScreen->beNumVisuals;
441 dmxScreen->beDefColormaps = xallocarray(dmxScreen->beNumDefColormaps,
442 sizeof(*dmxScreen->beDefColormaps));
443
444 for (i = 0; i < dmxScreen->beNumDefColormaps; i++)
445 dmxScreen->beDefColormaps[i] =
446 XCreateColormap(dmxScreen->beDisplay,
447 DefaultRootWindow(dmxScreen->beDisplay),
448 dmxScreen->beVisuals[i].visual, AllocNone);
449
450 dmxScreen->beBlackPixel = BlackPixel(dmxScreen->beDisplay,
451 DefaultScreen(dmxScreen->beDisplay));
452 dmxScreen->beWhitePixel = WhitePixel(dmxScreen->beDisplay,
453 DefaultScreen(dmxScreen->beDisplay));
454 }
455
456 void
dmxGetPixmapFormats(DMXScreenInfo * dmxScreen)457 dmxGetPixmapFormats(DMXScreenInfo * dmxScreen)
458 {
459 dmxScreen->beDepths =
460 XListDepths(dmxScreen->beDisplay, DefaultScreen(dmxScreen->beDisplay),
461 &dmxScreen->beNumDepths);
462
463 dmxScreen->bePixmapFormats =
464 XListPixmapFormats(dmxScreen->beDisplay,
465 &dmxScreen->beNumPixmapFormats);
466 }
467
468 static Bool
dmxSetPixmapFormats(ScreenInfo * pScreenInfo,DMXScreenInfo * dmxScreen)469 dmxSetPixmapFormats(ScreenInfo * pScreenInfo, DMXScreenInfo * dmxScreen)
470 {
471 XPixmapFormatValues *bePixmapFormat;
472 PixmapFormatRec *format;
473 int i, j;
474
475 pScreenInfo->imageByteOrder = ImageByteOrder(dmxScreen->beDisplay);
476 pScreenInfo->bitmapScanlineUnit = BitmapUnit(dmxScreen->beDisplay);
477 pScreenInfo->bitmapScanlinePad = BitmapPad(dmxScreen->beDisplay);
478 pScreenInfo->bitmapBitOrder = BitmapBitOrder(dmxScreen->beDisplay);
479
480 pScreenInfo->numPixmapFormats = 0;
481 for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) {
482 bePixmapFormat = &dmxScreen->bePixmapFormats[i];
483 for (j = 0; j < dmxScreen->beNumDepths; j++)
484 if ((bePixmapFormat->depth == 1) ||
485 (bePixmapFormat->depth == dmxScreen->beDepths[j])) {
486 format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats];
487
488 format->depth = bePixmapFormat->depth;
489 format->bitsPerPixel = bePixmapFormat->bits_per_pixel;
490 format->scanlinePad = bePixmapFormat->scanline_pad;
491
492 pScreenInfo->numPixmapFormats++;
493 break;
494 }
495 }
496
497 return TRUE;
498 }
499
500 void
dmxCheckForWM(DMXScreenInfo * dmxScreen)501 dmxCheckForWM(DMXScreenInfo * dmxScreen)
502 {
503 Status status;
504 XWindowAttributes xwa;
505
506 status = XGetWindowAttributes(dmxScreen->beDisplay,
507 DefaultRootWindow(dmxScreen->beDisplay),
508 &xwa);
509 dmxScreen->WMRunningOnBE =
510 (status &&
511 ((xwa.all_event_masks & SubstructureRedirectMask) ||
512 (xwa.all_event_masks & SubstructureNotifyMask)));
513 }
514
515 /** Initialize the display and collect relevant information about the
516 * display properties */
517 static void
dmxDisplayInit(DMXScreenInfo * dmxScreen)518 dmxDisplayInit(DMXScreenInfo * dmxScreen)
519 {
520 if (!dmxOpenDisplay(dmxScreen))
521 dmxLog(dmxFatal,
522 "dmxOpenDisplay: Unable to open display %s\n", dmxScreen->name);
523
524 dmxSetErrorHandler(dmxScreen);
525 dmxCheckForWM(dmxScreen);
526 dmxGetScreenAttribs(dmxScreen);
527
528 if (!dmxGetVisualInfo(dmxScreen))
529 dmxLog(dmxFatal, "dmxGetVisualInfo: No matching visuals found\n");
530
531 dmxGetColormaps(dmxScreen);
532 dmxGetPixmapFormats(dmxScreen);
533 }
534
dmxAddExtensions(void)535 static void dmxAddExtensions(void)
536 {
537 const ExtensionModule dmxExtensions[] = {
538 { DMXExtensionInit, DMX_EXTENSION_NAME, NULL },
539 };
540
541 LoadExtensionList(dmxExtensions, ARRAY_SIZE(dmxExtensions), TRUE);
542 }
543
544 /** This routine is called in Xserver/dix/main.c from \a main(). */
545 void
InitOutput(ScreenInfo * pScreenInfo,int argc,char * argv[])546 InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[])
547 {
548 int i;
549 static unsigned long dmxGeneration = 0;
550
551 if (dmxGeneration != serverGeneration) {
552 int vendrel = VENDOR_RELEASE;
553 int major, minor, year, month, day;
554
555 dmxGeneration = serverGeneration;
556
557 major = vendrel / 100000000;
558 vendrel -= major * 100000000;
559 minor = vendrel / 1000000;
560 vendrel -= minor * 1000000;
561 year = vendrel / 10000;
562 vendrel -= year * 10000;
563 month = vendrel / 100;
564 vendrel -= month * 100;
565 day = vendrel;
566
567 /* Add other epoch tests here */
568 if (major > 0 && minor > 0)
569 year += 2000;
570
571 dmxLog(dmxInfo, "Generation: %lu\n", dmxGeneration);
572 dmxLog(dmxInfo, "DMX version: %d.%d.%02d%02d%02d (%s)\n",
573 major, minor, year, month, day, VENDOR_STRING);
574
575 SetVendorRelease(VENDOR_RELEASE);
576 SetVendorString(VENDOR_STRING);
577
578 dmxLog(dmxInfo, "MAXSCREENS: %d\n", MAXSCREENS);
579
580 for (i = 0; i < dmxNumScreens; i++) {
581 if (dmxScreens[i].beDisplay)
582 dmxLog(dmxWarning, "Display \"%s\" still open\n",
583 dmxScreens[i].name);
584 dmxStatFree(dmxScreens[i].stat);
585 dmxScreens[i].stat = NULL;
586 }
587 for (i = 0; i < dmxNumInputs; i++)
588 dmxInputFree(&dmxInputs[i]);
589 free(dmxScreens);
590 free(dmxInputs);
591 dmxScreens = NULL;
592 dmxInputs = NULL;
593 dmxNumScreens = 0;
594 dmxNumInputs = 0;
595 }
596
597 /* Make sure that the command-line arguments are sane. */
598 if (dmxAddRemoveScreens && dmxGLXProxy) {
599 /* Currently it is not possible to support GLX and Render
600 * extensions with dynamic screen addition/removal due to the
601 * state that each extension keeps, which cannot be restored. */
602 dmxLog(dmxWarning,
603 "GLX Proxy and Render extensions do not yet support dynamic\n");
604 dmxLog(dmxWarning,
605 "screen addition and removal. Please specify -noglxproxy\n");
606 dmxLog(dmxWarning,
607 "and -norender on the command line or in the configuration\n");
608 dmxLog(dmxWarning,
609 "file to disable these two extensions if you wish to use\n");
610 dmxLog(dmxWarning,
611 "the dynamic addition and removal of screens support.\n");
612 dmxLog(dmxFatal,
613 "Dynamic screen addition/removal error (see above).\n");
614 }
615
616 /* ddxProcessArgument has been called at this point, but any data
617 * from the configuration file has not been applied. Do so, and be
618 * sure we have at least one back-end display. */
619 dmxConfigConfigure();
620 if (!dmxNumScreens)
621 dmxLog(dmxFatal, "InitOutput: no back-end displays found\n");
622 if (!dmxNumInputs)
623 dmxLog(dmxInfo, "InitOutput: no inputs found\n");
624
625 /* Disable lazy window creation optimization if offscreen
626 * optimization is disabled */
627 if (!dmxOffScreenOpt && dmxLazyWindowCreation) {
628 dmxLog(dmxInfo,
629 "InitOutput: Disabling lazy window creation optimization\n");
630 dmxLog(dmxInfo,
631 " since it requires the offscreen optimization\n");
632 dmxLog(dmxInfo, " to function properly.\n");
633 dmxLazyWindowCreation = FALSE;
634 }
635
636 /* Open each display and gather information about it. */
637 for (i = 0; i < dmxNumScreens; i++)
638 dmxDisplayInit(&dmxScreens[i]);
639
640 #ifdef PANORAMIX
641 /* Register a Xinerama callback which will run from within
642 * PanoramiXCreateConnectionBlock. We can use the callback to
643 * determine if Xinerama is loaded and to check the visuals
644 * determined by PanoramiXConsolidate. */
645 XineramaRegisterConnectionBlockCallback(dmxConnectionBlockCallback);
646 #endif
647
648 /* Since we only have a single screen thus far, we only need to set
649 the pixmap formats to match that screen. FIXME: this isn't true. */
650 if (!dmxSetPixmapFormats(pScreenInfo, &dmxScreens[0]))
651 return;
652
653 /* Might want to install a signal handler to allow cleaning up after
654 * unexpected signals. The DIX/OS layer already handles SIGINT and
655 * SIGTERM, so everything is OK for expected signals. --DD
656 *
657 * SIGHUP, SIGINT, and SIGTERM are trapped in os/connection.c
658 * SIGQUIT is another common signal that is sent from the keyboard.
659 * Trap it here, to ensure that the keyboard modifier map and other
660 * state for the input devices are restored. (This makes the
661 * behavior of SIGQUIT somewhat unexpected, since it will be the
662 * same as the behavior of SIGINT. However, leaving the modifier
663 * map of the input devices empty is even more unexpected.) --RF
664 */
665 OsSignal(SIGQUIT, GiveUp);
666
667 #ifdef GLXEXT
668 /* Check if GLX extension exists on all back-end servers */
669 for (i = 0; i < dmxNumScreens; i++)
670 noGlxExtension |= (dmxScreens[i].glxMajorOpcode == 0);
671 #endif
672
673 if (serverGeneration == 1)
674 dmxAddExtensions();
675
676 /* Tell dix layer about the backend displays */
677 for (i = 0; i < dmxNumScreens; i++) {
678
679 #ifdef GLXEXT
680 if (!noGlxExtension) {
681 /*
682 * Builds GLX configurations from the list of visuals
683 * supported by the back-end server, and give that
684 * configuration list to the glx layer - so that he will
685 * build the visuals accordingly.
686 */
687
688 DMXScreenInfo *dmxScreen = &dmxScreens[i];
689 __GLXvisualConfig *configs = NULL;
690 dmxGlxVisualPrivate **configprivs = NULL;
691 int nconfigs = 0;
692 int (*oldErrorHandler) (Display *, XErrorEvent *);
693
694 /* Catch errors if when using an older GLX w/o FBconfigs */
695 oldErrorHandler = XSetErrorHandler(dmxNOPErrorHandler);
696
697 /* Get FBConfigs of the back-end server */
698 dmxScreen->fbconfigs = GetGLXFBConfigs(dmxScreen->beDisplay,
699 dmxScreen->glxMajorOpcode,
700 &dmxScreen->numFBConfigs);
701
702 XSetErrorHandler(oldErrorHandler);
703
704 dmxScreen->glxVisuals =
705 GetGLXVisualConfigs(dmxScreen->beDisplay,
706 DefaultScreen(dmxScreen->beDisplay),
707 &dmxScreen->numGlxVisuals);
708
709 if (dmxScreen->fbconfigs) {
710 configs =
711 GetGLXVisualConfigsFromFBConfigs(dmxScreen->fbconfigs,
712 dmxScreen->numFBConfigs,
713 dmxScreen->beVisuals,
714 dmxScreen->beNumVisuals,
715 dmxScreen->glxVisuals,
716 dmxScreen->numGlxVisuals,
717 &nconfigs);
718 }
719 else {
720 configs = dmxScreen->glxVisuals;
721 nconfigs = dmxScreen->numGlxVisuals;
722 }
723
724 configprivs = xallocarray(nconfigs, sizeof(dmxGlxVisualPrivate *));
725
726 if (configs != NULL && configprivs != NULL) {
727 int j;
728
729 /* Initialize our private info for each visual
730 * (currently only x_visual_depth and x_visual_class)
731 */
732 for (j = 0; j < nconfigs; j++) {
733
734 configprivs[j] = (dmxGlxVisualPrivate *)
735 malloc(sizeof(dmxGlxVisualPrivate));
736 configprivs[j]->x_visual_depth = 0;
737 configprivs[j]->x_visual_class = 0;
738
739 /* Find the visual depth */
740 if (configs[j].vid > 0) {
741 int k;
742
743 for (k = 0; k < dmxScreen->beNumVisuals; k++) {
744 if (dmxScreen->beVisuals[k].visualid ==
745 configs[j].vid) {
746 configprivs[j]->x_visual_depth =
747 dmxScreen->beVisuals[k].depth;
748 configprivs[j]->x_visual_class =
749 dmxScreen->beVisuals[k].class;
750 break;
751 }
752 }
753 }
754 }
755
756 XFlush(dmxScreen->beDisplay);
757 }
758 }
759 #endif /* GLXEXT */
760
761 AddScreen(dmxScreenInit, argc, argv);
762 }
763
764 /* Compute origin information. */
765 dmxInitOrigins();
766
767 /* Compute overlap information. */
768 dmxInitOverlap();
769
770 /* Make sure there is a global width/height available */
771 dmxComputeWidthHeight(DMX_NO_RECOMPUTE_BOUNDING_BOX);
772
773 /* FIXME: The following is temporarily placed here. When the DMX
774 * extension is available, it will be move there.
775 */
776 dmxInitFonts();
777
778 /* Initialize the render extension */
779 if (!noRenderExtension)
780 dmxInitRender();
781
782 /* Initialized things that need timer hooks */
783 dmxStatInit();
784 dmxSyncInit(); /* Calls RegisterBlockAndWakeupHandlers */
785 }
786
787 /* RATS: Assuming the fp string (which comes from the command-line argv
788 vector) is NULL-terminated, the buffer is large enough for the
789 strcpy. */
790 static void
dmxSetDefaultFontPath(const char * fp)791 dmxSetDefaultFontPath(const char *fp)
792 {
793 if (dmxFontPath) {
794 int fplen = strlen(fp) + 1;
795 int len = strlen(dmxFontPath);
796
797 dmxFontPath = realloc(dmxFontPath, len + fplen + 1);
798 dmxFontPath[len] = ',';
799 strncpy(&dmxFontPath[len + 1], fp, fplen);
800 }
801 else {
802 dmxFontPath = strdup(fp);
803 }
804
805 defaultFontPath = dmxFontPath;
806 }
807
808 /** This function is called in Xserver/os/utils.c from \a AbortServer().
809 * We must ensure that backend and console state is restored in the
810 * event the server shutdown wasn't clean. */
811 void
AbortDDX(enum ExitCode error)812 AbortDDX(enum ExitCode error)
813 {
814 int i;
815
816 for (i = 0; i < dmxNumScreens; i++) {
817 DMXScreenInfo *dmxScreen = &dmxScreens[i];
818
819 if (dmxScreen->beDisplay)
820 XCloseDisplay(dmxScreen->beDisplay);
821 dmxScreen->beDisplay = NULL;
822 }
823 }
824
825 #ifdef DDXBEFORERESET
826 void
ddxBeforeReset(void)827 ddxBeforeReset(void)
828 {
829 }
830 #endif
831
832 /** This function is called in Xserver/dix/main.c from \a main() when
833 * dispatchException & DE_TERMINATE (which is the only way to exit the
834 * main loop without an interruption. */
835 void
ddxGiveUp(enum ExitCode error)836 ddxGiveUp(enum ExitCode error)
837 {
838 AbortDDX(error);
839 }
840
841 #if INPUTTHREAD
842 /** This function is called in Xserver/os/inputthread.c when starting
843 the input thread. */
844 void
ddxInputThreadInit(void)845 ddxInputThreadInit(void)
846 {
847 }
848 #endif
849
850 /** This function is called in Xserver/os/osinit.c from \a OsInit(). */
851 void
OsVendorInit(void)852 OsVendorInit(void)
853 {
854 }
855
856 /** This function is called in Xserver/os/utils.c from \a FatalError()
857 * and \a VFatalError(). (Note that setting the function pointer \a
858 * OsVendorVErrorFProc will cause \a VErrorF() (which is called by the
859 * two routines mentioned here, as well as by others) to use the
860 * referenced routine instead of \a vfprintf().) */
861 void
OsVendorFatalError(const char * f,va_list args)862 OsVendorFatalError(const char *f, va_list args)
863 {
864 }
865
866 /** Process our command line arguments. */
867 int
ddxProcessArgument(int argc,char * argv[],int i)868 ddxProcessArgument(int argc, char *argv[], int i)
869 {
870 int retval = 0;
871
872 if (!strcmp(argv[i], "-display")) {
873 if (++i < argc)
874 dmxConfigStoreDisplay(argv[i]);
875 retval = 2;
876 }
877 else if (!strcmp(argv[i], "-inputfrom") || !strcmp(argv[i], "-input")) {
878 if (++i < argc)
879 dmxConfigStoreInput(argv[i]);
880 retval = 2;
881 }
882 else if (!strcmp(argv[i], "-xinputfrom") || !strcmp(argv[i], "-xinput")) {
883 if (++i < argc)
884 dmxConfigStoreXInput(argv[i]);
885 retval = 2;
886 }
887 else if (!strcmp(argv[i], "-noshadowfb")) {
888 retval = 1;
889 }
890 else if (!strcmp(argv[i], "-nomulticursor")) {
891 dmxCursorNoMulti();
892 retval = 1;
893 }
894 else if (!strcmp(argv[i], "-shadowfb")) {
895 retval = 1;
896 }
897 else if (!strcmp(argv[i], "-configfile")) {
898 if (++i < argc)
899 dmxConfigStoreFile(argv[i]);
900 retval = 2;
901 }
902 else if (!strcmp(argv[i], "-config")) {
903 if (++i < argc)
904 dmxConfigStoreConfig(argv[i]);
905 retval = 2;
906 }
907 else if (!strcmp(argv[i], "-fontpath")) {
908 if (++i < argc)
909 dmxSetDefaultFontPath(argv[i]);
910 retval = 2;
911 }
912 else if (!strcmp(argv[i], "-stat")) {
913 if ((i += 2) < argc)
914 dmxStatActivate(argv[i - 1], argv[i]);
915 retval = 3;
916 }
917 else if (!strcmp(argv[i], "-syncbatch")) {
918 if (++i < argc)
919 dmxSyncActivate(argv[i]);
920 retval = 2;
921 }
922 else if (!strcmp(argv[i], "-nooffscreenopt")) {
923 dmxOffScreenOpt = FALSE;
924 retval = 1;
925 }
926 else if (!strcmp(argv[i], "-nosubdivprims")) {
927 dmxSubdividePrimitives = FALSE;
928 retval = 1;
929 }
930 else if (!strcmp(argv[i], "-nowindowopt")) {
931 dmxLazyWindowCreation = FALSE;
932 retval = 1;
933 }
934 else if (!strcmp(argv[i], "-noxkb")) {
935 dmxUseXKB = FALSE;
936 retval = 1;
937 }
938 else if (!strcmp(argv[i], "-depth")) {
939 if (++i < argc)
940 dmxDepth = atoi(argv[i]);
941 retval = 2;
942 }
943 else if (!strcmp(argv[i], "-norender")) {
944 noRenderExtension = TRUE;
945 retval = 1;
946 #ifdef GLXEXT
947 }
948 else if (!strcmp(argv[i], "-noglxproxy")) {
949 dmxGLXProxy = FALSE;
950 retval = 1;
951 }
952 else if (!strcmp(argv[i], "-noglxswapgroup")) {
953 dmxGLXSwapGroupSupport = FALSE;
954 retval = 1;
955 }
956 else if (!strcmp(argv[i], "-glxsyncswap")) {
957 dmxGLXSyncSwap = TRUE;
958 retval = 1;
959 }
960 else if (!strcmp(argv[i], "-glxfinishswap")) {
961 dmxGLXFinishSwap = TRUE;
962 retval = 1;
963 #endif
964 }
965 else if (!strcmp(argv[i], "-ignorebadfontpaths")) {
966 dmxIgnoreBadFontPaths = TRUE;
967 retval = 1;
968 }
969 else if (!strcmp(argv[i], "-addremovescreens")) {
970 dmxAddRemoveScreens = TRUE;
971 retval = 1;
972 }
973 else if (!strcmp(argv[i], "-param")) {
974 if ((i += 2) < argc) {
975 if (!strcasecmp(argv[i - 1], "xkbrules"))
976 dmxConfigSetXkbRules(argv[i]);
977 else if (!strcasecmp(argv[i - 1], "xkbmodel"))
978 dmxConfigSetXkbModel(argv[i]);
979 else if (!strcasecmp(argv[i - 1], "xkblayout"))
980 dmxConfigSetXkbLayout(argv[i]);
981 else if (!strcasecmp(argv[i - 1], "xkbvariant"))
982 dmxConfigSetXkbVariant(argv[i]);
983 else if (!strcasecmp(argv[i - 1], "xkboptions"))
984 dmxConfigSetXkbOptions(argv[i]);
985 else
986 dmxLog(dmxWarning,
987 "-param requires: XkbRules, XkbModel, XkbLayout,"
988 " XkbVariant, or XkbOptions\n");
989 }
990 retval = 3;
991 }
992 if (!serverGeneration)
993 dmxConfigSetMaxScreens();
994 return retval;
995 }
996
997 /** Provide succinct usage information for the DMX server. */
998 void
ddxUseMsg(void)999 ddxUseMsg(void)
1000 {
1001 ErrorF("\n\nDevice Dependent Usage:\n");
1002 ErrorF("-display string Specify the back-end display(s)\n");
1003 ErrorF("-input string Specify input source for core device\n");
1004 ErrorF("-xinput string Specify input source for XInput device\n");
1005 ErrorF("-shadowfb Enable shadow frame buffer\n");
1006 ErrorF("-configfile file Read from a configuration file\n");
1007 ErrorF("-config config Select a specific configuration\n");
1008 ErrorF("-nomulticursor Turn of multiple cursor support\n");
1009 ErrorF("-fontpath Sets the default font path\n");
1010 ErrorF("-stat inter scrns Print out performance statistics\n");
1011 ErrorF("-syncbatch inter Set interval for XSync batching\n");
1012 ErrorF("-nooffscreenopt Disable offscreen optimization\n");
1013 ErrorF("-nosubdivprims Disable primitive subdivision\n");
1014 ErrorF(" optimization\n");
1015 ErrorF("-nowindowopt Disable lazy window creation optimization\n");
1016 ErrorF("-noxkb Disable use of the XKB extension with\n");
1017 ErrorF(" backend displays (cf. -kb).\n");
1018 ErrorF("-depth Specify the default root window depth\n");
1019 ErrorF("-norender Disable RENDER extension support\n");
1020 #ifdef GLXEXT
1021 ErrorF("-noglxproxy Disable GLX Proxy\n");
1022 ErrorF("-noglxswapgroup Disable swap group and swap barrier\n");
1023 ErrorF(" extensions in GLX proxy\n");
1024 ErrorF("-glxsyncswap Force XSync after swap buffers\n");
1025 ErrorF("-glxfinishswap Force glFinish after swap buffers\n");
1026 #endif
1027 ErrorF
1028 ("-ignorebadfontpaths Ignore bad font paths during initialization\n");
1029 ErrorF("-addremovescreens Enable dynamic screen addition/removal\n");
1030 ErrorF("-param ... Specify configuration parameters (e.g.,\n");
1031 ErrorF(" XkbRules, XkbModel, XkbLayout, etc.)\n");
1032 ErrorF("\n");
1033 ErrorF(" If the -input string matches a -display string, then input\n"
1034 " is taken from that backend display. (XInput cannot be taken\n"
1035 " from a backend display.) Placing \",console\" after the\n"
1036 " display name will force a console window to be opened on\n"
1037 " that display in addition to the backend input. This is\n"
1038 " useful if the backend window does not cover the whole\n"
1039 " physical display.\n\n");
1040
1041 ErrorF(" Otherwise, if the -input or -xinput string specifies another\n"
1042 " X display, then a console window will be created on that\n"
1043 " display. Placing \",windows\" or \",nowindows\" after the\n"
1044 " display name will control the display of window outlines in\n"
1045 " the console.\n\n");
1046
1047 ErrorF(" -input or -xinput dummy specifies no input.\n");
1048 ErrorF(" -input or -xinput local specifies the use of a raw keyboard,\n"
1049 " mouse, or other (extension) device:\n"
1050 " -input local,kbd,ps2 will use a ps2 mouse\n"
1051 " -input local,kbd,ms will use a serial mouse\n"
1052 " -input local,usb-kbd,usb-mou will use USB devices \n"
1053 " -xinput local,usb-oth will use a non-mouse and\n"
1054 " non-keyboard USB device with XInput\n\n");
1055
1056 ErrorF(" Special Keys:\n");
1057 ErrorF(" Ctrl-Alt-g Server grab/ungrab (console only)\n");
1058 ErrorF(" Ctrl-Alt-f Fine (1-pixel) mouse mode (console only)\n");
1059 ErrorF(" Ctrl-Alt-q Quit (core devices only)\n");
1060 ErrorF(" Ctrl-Alt-F* Switch to VC (local only)\n");
1061 }
1062