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