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