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