1/* 2 * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Thomas Roell not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Thomas Roell makes no representations 11 * about the suitability of this software for any purpose. It is provided 12 * "as is" without express or implied warranty. 13 * 14 * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 * 22 */ 23/* 24 * Copyright (c) 1994-2003 by The XFree86 Project, Inc. 25 * 26 * Permission is hereby granted, free of charge, to any person obtaining a 27 * copy of this software and associated documentation files (the "Software"), 28 * to deal in the Software without restriction, including without limitation 29 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 30 * and/or sell copies of the Software, and to permit persons to whom the 31 * Software is furnished to do so, subject to the following conditions: 32 * 33 * The above copyright notice and this permission notice shall be included in 34 * all copies or substantial portions of the Software. 35 * 36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 39 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 40 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 41 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 42 * OTHER DEALINGS IN THE SOFTWARE. 43 * 44 * Except as contained in this notice, the name of the copyright holder(s) 45 * and author(s) shall not be used in advertising or otherwise to promote 46 * the sale, use or other dealings in this Software without prior written 47 * authorization from the copyright holder(s) and author(s). 48 */ 49 50/* [JCH-96/01/21] Extended std reverse map to four buttons. */ 51 52#ifdef HAVE_XORG_CONFIG_H 53#include <xorg-config.h> 54#endif 55 56#include <X11/X.h> 57#include <X11/Xpoll.h> 58#include <X11/Xproto.h> 59#include "misc.h" 60#include "compiler.h" 61#include "xf86.h" 62#include "xf86Priv.h" 63#define XF86_OS_PRIVS 64#include "xf86_OSlib.h" 65#include <X11/keysym.h> 66 67#ifdef XFreeXDGA 68#include "dgaproc.h" 69#endif 70 71#include <X11/extensions/XI.h> 72#include <X11/extensions/XIproto.h> 73#include "inputstr.h" 74#include "xf86Xinput.h" 75 76#include "mi.h" 77#include "mipointer.h" 78 79#include "xkbsrv.h" 80#include "xkbstr.h" 81 82#ifdef DPMSExtension 83#include <X11/extensions/dpmsconst.h> 84#include "dpmsproc.h" 85#endif 86 87/* 88 * This is a toggling variable: 89 * FALSE = No VT switching keys have been pressed last time around 90 * TRUE = Possible VT switch Pending 91 * (DWH - 12/2/93) 92 * 93 * This has been generalised to work with Linux and *BSD+syscons (DHD) 94 */ 95 96Bool VTSwitchEnabled = TRUE; /* Allows run-time disabling for 97 *BSD and for avoiding VT 98 switches when using the DRI 99 automatic full screen mode.*/ 100 101extern fd_set EnabledDevices; 102 103#ifdef XF86PM 104extern void (*xf86OSPMClose)(void); 105#endif 106 107static void xf86VTSwitch(void); 108 109/* 110 * Allow arbitrary drivers or other XFree86 code to register with our main 111 * Wakeup handler. 112 */ 113typedef struct x_IHRec { 114 int fd; 115 InputHandlerProc ihproc; 116 pointer data; 117 Bool enabled; 118 struct x_IHRec * next; 119} IHRec, *IHPtr; 120 121static IHPtr InputHandlers = NULL; 122 123 124Bool 125LegalModifier(unsigned int key, DeviceIntPtr pDev) 126{ 127 return TRUE; 128} 129 130/* 131 * TimeSinceLastInputEvent -- 132 * Function used for screensaver purposes by the os module. Returns the 133 * time in milliseconds since there last was any input. 134 */ 135int 136TimeSinceLastInputEvent(void) 137{ 138 if (xf86Info.lastEventTime == 0) { 139 xf86Info.lastEventTime = GetTimeInMillis(); 140 } 141 return GetTimeInMillis() - xf86Info.lastEventTime; 142} 143 144/* 145 * SetTimeSinceLastInputEvent -- 146 * Set the lastEventTime to now. 147 */ 148void 149SetTimeSinceLastInputEvent(void) 150{ 151 xf86Info.lastEventTime = GetTimeInMillis(); 152} 153 154/* 155 * ProcessInputEvents -- 156 * Retrieve all waiting input events and pass them to DIX in their 157 * correct chronological order. Only reads from the system pointer 158 * and keyboard. 159 */ 160void 161ProcessInputEvents (void) 162{ 163 int x, y; 164 165 mieqProcessInputEvents(); 166 167 /* FIXME: This is a problem if we have multiple pointers */ 168 miPointerGetPosition(inputInfo.pointer, &x, &y); 169 xf86SetViewport(xf86Info.currentScreen, x, y); 170} 171 172/* 173 * Handle keyboard events that cause some kind of "action" 174 * (i.e., server termination, video mode changes, VT switches, etc.) 175 */ 176void 177xf86ProcessActionEvent(ActionEvent action, void *arg) 178{ 179 DebugF("ProcessActionEvent(%d,%x)\n", (int) action, arg); 180 switch (action) { 181 case ACTION_TERMINATE: 182 if (!xf86Info.dontZap) { 183#ifdef XFreeXDGA 184 DGAShutdown(); 185#endif 186 GiveUp(0); 187 } 188 break; 189 case ACTION_NEXT_MODE: 190 if (!xf86Info.dontZoom) 191 xf86ZoomViewport(xf86Info.currentScreen, 1); 192 break; 193 case ACTION_PREV_MODE: 194 if (!xf86Info.dontZoom) 195 xf86ZoomViewport(xf86Info.currentScreen, -1); 196 break; 197 case ACTION_SWITCHSCREEN: 198 if (VTSwitchEnabled && !xf86Info.dontVTSwitch && arg) { 199 int vtno = *((int *) arg); 200 201 if (vtno != xf86Info.vtno) { 202 if (!xf86VTActivate(vtno)) { 203 ErrorF("Failed to switch from vt%02d to vt%02d: %s\n", 204 xf86Info.vtno, vtno, strerror(errno)); 205 } 206 } 207 } 208 break; 209 case ACTION_SWITCHSCREEN_NEXT: 210 if (VTSwitchEnabled && !xf86Info.dontVTSwitch) { 211 if (!xf86VTActivate(xf86Info.vtno + 1)) { 212 /* If first try failed, assume this is the last VT and 213 * try wrapping around to the first vt. 214 */ 215 if (!xf86VTActivate(1)) { 216 ErrorF("Failed to switch from vt%02d to next vt: %s\n", 217 xf86Info.vtno, strerror(errno)); 218 } 219 } 220 } 221 break; 222 case ACTION_SWITCHSCREEN_PREV: 223 if (VTSwitchEnabled && !xf86Info.dontVTSwitch && xf86Info.vtno > 0) { 224 if (!xf86VTActivate(xf86Info.vtno - 1)) { 225 /* Don't know what the maximum VT is, so can't wrap around */ 226 ErrorF("Failed to switch from vt%02d to previous vt: %s\n", 227 xf86Info.vtno, strerror(errno)); 228 } 229 } 230 break; 231 default: 232 break; 233 } 234} 235 236/* 237 * xf86Wakeup -- 238 * Os wakeup handler. 239 */ 240 241/* ARGSUSED */ 242void 243xf86Wakeup(pointer blockData, int err, pointer pReadmask) 244{ 245 fd_set* LastSelectMask = (fd_set*)pReadmask; 246 fd_set devicesWithInput; 247 InputInfoPtr pInfo; 248 249 if (err >= 0) { 250 251 XFD_ANDSET(&devicesWithInput, LastSelectMask, &EnabledDevices); 252 if (XFD_ANYSET(&devicesWithInput)) { 253 pInfo = xf86InputDevs; 254 while (pInfo) { 255 if (pInfo->read_input && pInfo->fd >= 0 && 256 (FD_ISSET(pInfo->fd, &devicesWithInput) != 0)) { 257 int sigstate = xf86BlockSIGIO(); 258 259 /* 260 * Remove the descriptior from the set because more than one 261 * device may share the same file descriptor. 262 */ 263 FD_CLR(pInfo->fd, &devicesWithInput); 264 265 pInfo->read_input(pInfo); 266 xf86UnblockSIGIO(sigstate); 267 } 268 pInfo = pInfo->next; 269 } 270 } 271 } 272 273 if (err >= 0) { /* we don't want the handlers called if select() */ 274 IHPtr ih; /* returned with an error condition, do we? */ 275 276 for (ih = InputHandlers; ih; ih = ih->next) { 277 if (ih->enabled && ih->fd >= 0 && ih->ihproc && 278 (FD_ISSET(ih->fd, ((fd_set *)pReadmask)) != 0)) { 279 ih->ihproc(ih->fd, ih->data); 280 } 281 } 282 } 283 284 if (xf86VTSwitchPending()) xf86VTSwitch(); 285} 286 287 288/* 289 * xf86SigioReadInput -- 290 * signal handler for the SIGIO signal. 291 */ 292static void 293xf86SigioReadInput(int fd, void *closure) 294{ 295 int errno_save = errno; 296 InputInfoPtr pInfo = closure; 297 298 pInfo->read_input(pInfo); 299 300 errno = errno_save; 301} 302 303/* 304 * xf86AddEnabledDevice -- 305 * 306 */ 307void 308xf86AddEnabledDevice(InputInfoPtr pInfo) 309{ 310 if (!xf86InstallSIGIOHandler (pInfo->fd, xf86SigioReadInput, pInfo)) { 311 AddEnabledDevice(pInfo->fd); 312 } 313} 314 315/* 316 * xf86RemoveEnabledDevice -- 317 * 318 */ 319void 320xf86RemoveEnabledDevice(InputInfoPtr pInfo) 321{ 322 if (!xf86RemoveSIGIOHandler (pInfo->fd)) { 323 RemoveEnabledDevice(pInfo->fd); 324 } 325} 326 327static int *xf86SignalIntercept = NULL; 328 329void 330xf86InterceptSignals(int *signo) 331{ 332 if ((xf86SignalIntercept = signo)) 333 *signo = -1; 334} 335 336static void (*xf86SigIllHandler)(void) = NULL; 337 338void 339xf86InterceptSigIll(void (*sigillhandler)(void)) 340{ 341 xf86SigIllHandler = sigillhandler; 342} 343 344/* 345 * xf86SigWrapper -- 346 * Catch unexpected signals and exit or continue cleanly. 347 */ 348int 349xf86SigWrapper(int signo) 350{ 351 if ((signo == SIGILL) && xf86SigIllHandler) { 352 (*xf86SigIllHandler)(); 353 return 0; /* continue */ 354 } 355 356 if (xf86SignalIntercept && (*xf86SignalIntercept < 0)) { 357 *xf86SignalIntercept = signo; 358 return 0; /* continue */ 359 } 360 361 xf86Info.caughtSignal = TRUE; 362 return 1; /* abort */ 363} 364 365/* 366 * xf86PrintBacktrace -- 367 * Print a stack backtrace for debugging purposes. 368 */ 369void 370xf86PrintBacktrace(void) 371{ 372 xorg_backtrace(); 373} 374 375static void 376xf86ReleaseKeys(DeviceIntPtr pDev) 377{ 378 KeyClassPtr keyc; 379 int i, j, nevents, sigstate; 380 381 if (!pDev || !pDev->key) 382 return; 383 384 keyc = pDev->key; 385 386 /* 387 * Hmm... here is the biggest hack of every time ! 388 * It may be possible that a switch-vt procedure has finished BEFORE 389 * you released all keys neccessary to do this. That peculiar behavior 390 * can fool the X-server pretty much, cause it assumes that some keys 391 * were not released. TWM may stuck alsmost completly.... 392 * OK, what we are doing here is after returning from the vt-switch 393 * exeplicitely unrelease all keyboard keys before the input-devices 394 * are reenabled. 395 */ 396 397 for (i = keyc->xkbInfo->desc->min_key_code; 398 i < keyc->xkbInfo->desc->max_key_code; 399 i++) { 400 if (key_is_down(pDev, i, KEY_POSTED)) { 401 sigstate = xf86BlockSIGIO (); 402 nevents = GetKeyboardEvents(xf86Events, pDev, KeyRelease, i); 403 for (j = 0; j < nevents; j++) 404 mieqEnqueue(pDev, (InternalEvent*)(xf86Events + j)->event); 405 xf86UnblockSIGIO(sigstate); 406 } 407 } 408} 409 410/* 411 * xf86VTSwitch -- 412 * Handle requests for switching the vt. 413 */ 414static void 415xf86VTSwitch(void) 416{ 417 int i; 418 static int prevSIGIO; 419 InputInfoPtr pInfo; 420 IHPtr ih; 421 422 DebugF("xf86VTSwitch()\n"); 423 424#ifdef XFreeXDGA 425 if(!DGAVTSwitch()) 426 return; 427#endif 428 429 /* 430 * Since all screens are currently all in the same state it is sufficient 431 * check the first. This might change in future. 432 */ 433 if (xf86Screens[0]->vtSema) { 434 435 DebugF("xf86VTSwitch: Leaving, xf86Exiting is %s\n", 436 BOOLTOSTRING((dispatchException & DE_TERMINATE) ? TRUE : FALSE)); 437#ifdef DPMSExtension 438 if (DPMSPowerLevel != DPMSModeOn) 439 DPMSSet(serverClient, DPMSModeOn); 440#endif 441 for (i = 0; i < xf86NumScreens; i++) { 442 if (!(dispatchException & DE_TERMINATE)) 443 if (xf86Screens[i]->EnableDisableFBAccess) 444 (*xf86Screens[i]->EnableDisableFBAccess) (i, FALSE); 445 } 446 447 /* 448 * Keep the order: Disable Device > LeaveVT 449 * EnterVT > EnableDevice 450 */ 451 for (ih = InputHandlers; ih; ih = ih->next) 452 xf86DisableInputHandler(ih); 453 for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) { 454 if (pInfo->dev) { 455 xf86ReleaseKeys(pInfo->dev); 456 ProcessInputEvents(); 457 DisableDevice(pInfo->dev, TRUE); 458 } 459 } 460 461 prevSIGIO = xf86BlockSIGIO(); 462 for (i = 0; i < xf86NumScreens; i++) 463 xf86Screens[i]->LeaveVT(i, 0); 464 465 xf86AccessLeave(); /* We need this here, otherwise */ 466 467 if (!xf86VTSwitchAway()) { 468 /* 469 * switch failed 470 */ 471 472 DebugF("xf86VTSwitch: Leave failed\n"); 473 xf86AccessEnter(); 474 for (i = 0; i < xf86NumScreens; i++) { 475 if (!xf86Screens[i]->EnterVT(i, 0)) 476 FatalError("EnterVT failed for screen %d\n", i); 477 } 478 if (!(dispatchException & DE_TERMINATE)) { 479 for (i = 0; i < xf86NumScreens; i++) { 480 if (xf86Screens[i]->EnableDisableFBAccess) 481 (*xf86Screens[i]->EnableDisableFBAccess) (i, TRUE); 482 } 483 } 484 dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); 485 486 pInfo = xf86InputDevs; 487 while (pInfo) { 488 if (pInfo->dev) 489 EnableDevice(pInfo->dev, TRUE); 490 pInfo = pInfo->next; 491 } 492 for (ih = InputHandlers; ih; ih = ih->next) 493 xf86EnableInputHandler(ih); 494 495 xf86UnblockSIGIO(prevSIGIO); 496 497 } else { 498#ifdef XF86PM 499 if (xf86OSPMClose) 500 xf86OSPMClose(); 501 xf86OSPMClose = NULL; 502#endif 503 504 for (i = 0; i < xf86NumScreens; i++) { 505 /* 506 * zero all access functions to 507 * trap calls when switched away. 508 */ 509 xf86Screens[i]->vtSema = FALSE; 510 } 511 if (xorgHWAccess) 512 xf86DisableIO(); 513 } 514 } else { 515 DebugF("xf86VTSwitch: Entering\n"); 516 if (!xf86VTSwitchTo()) return; 517 518#ifdef XF86PM 519 xf86OSPMClose = xf86OSPMOpen(); 520#endif 521 522 if (xorgHWAccess) 523 xf86EnableIO(); 524 xf86AccessEnter(); 525 for (i = 0; i < xf86NumScreens; i++) { 526 xf86Screens[i]->vtSema = TRUE; 527 if (!xf86Screens[i]->EnterVT(i, 0)) 528 FatalError("EnterVT failed for screen %d\n", i); 529 } 530 for (i = 0; i < xf86NumScreens; i++) { 531 if (xf86Screens[i]->EnableDisableFBAccess) 532 (*xf86Screens[i]->EnableDisableFBAccess)(i, TRUE); 533 } 534 535 /* Turn screen saver off when switching back */ 536 dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); 537 538 pInfo = xf86InputDevs; 539 while (pInfo) { 540 if (pInfo->dev) 541 EnableDevice(pInfo->dev, TRUE); 542 pInfo = pInfo->next; 543 } 544 545 for (ih = InputHandlers; ih; ih = ih->next) 546 xf86EnableInputHandler(ih); 547 548 xf86UnblockSIGIO(prevSIGIO); 549 } 550} 551 552 553/* Input handler registration */ 554 555static pointer 556addInputHandler(int fd, InputHandlerProc proc, pointer data) 557{ 558 IHPtr ih; 559 560 if (fd < 0 || !proc) 561 return NULL; 562 563 ih = calloc(sizeof(*ih), 1); 564 if (!ih) 565 return NULL; 566 567 ih->fd = fd; 568 ih->ihproc = proc; 569 ih->data = data; 570 ih->enabled = TRUE; 571 572 ih->next = InputHandlers; 573 InputHandlers = ih; 574 575 return ih; 576} 577 578pointer 579xf86AddInputHandler(int fd, InputHandlerProc proc, pointer data) 580{ 581 IHPtr ih = addInputHandler(fd, proc, data); 582 583 if (ih) 584 AddEnabledDevice(fd); 585 return ih; 586} 587 588pointer 589xf86AddGeneralHandler(int fd, InputHandlerProc proc, pointer data) 590{ 591 IHPtr ih = addInputHandler(fd, proc, data); 592 593 if (ih) 594 AddGeneralSocket(fd); 595 return ih; 596} 597 598/** 599 * Set the handler for the console's fd. Replaces (and returns) the previous 600 * handler or NULL, whichever appropriate. 601 * proc may be NULL if the server should not handle events on the console. 602 */ 603InputHandlerProc 604xf86SetConsoleHandler(InputHandlerProc proc, pointer data) 605{ 606 static IHPtr handler = NULL; 607 IHPtr old_handler = handler; 608 609 if (old_handler) 610 xf86RemoveGeneralHandler(old_handler); 611 612 handler = xf86AddGeneralHandler(xf86Info.consoleFd, proc, data); 613 614 return (old_handler) ? old_handler->ihproc : NULL; 615} 616 617static void 618removeInputHandler(IHPtr ih) 619{ 620 IHPtr p; 621 622 if (ih == InputHandlers) 623 InputHandlers = ih->next; 624 else { 625 p = InputHandlers; 626 while (p && p->next != ih) 627 p = p->next; 628 if (ih) 629 p->next = ih->next; 630 } 631 free(ih); 632} 633 634int 635xf86RemoveInputHandler(pointer handler) 636{ 637 IHPtr ih; 638 int fd; 639 640 if (!handler) 641 return -1; 642 643 ih = handler; 644 fd = ih->fd; 645 646 if (ih->fd >= 0) 647 RemoveEnabledDevice(ih->fd); 648 removeInputHandler(ih); 649 650 return fd; 651} 652 653int 654xf86RemoveGeneralHandler(pointer handler) 655{ 656 IHPtr ih; 657 int fd; 658 659 if (!handler) 660 return -1; 661 662 ih = handler; 663 fd = ih->fd; 664 665 if (ih->fd >= 0) 666 RemoveGeneralSocket(ih->fd); 667 removeInputHandler(ih); 668 669 return fd; 670} 671 672void 673xf86DisableInputHandler(pointer handler) 674{ 675 IHPtr ih; 676 677 if (!handler) 678 return; 679 680 ih = handler; 681 ih->enabled = FALSE; 682 if (ih->fd >= 0) 683 RemoveEnabledDevice(ih->fd); 684} 685 686void 687xf86DisableGeneralHandler(pointer handler) 688{ 689 IHPtr ih; 690 691 if (!handler) 692 return; 693 694 ih = handler; 695 ih->enabled = FALSE; 696 if (ih->fd >= 0) 697 RemoveGeneralSocket(ih->fd); 698} 699 700void 701xf86EnableInputHandler(pointer handler) 702{ 703 IHPtr ih; 704 705 if (!handler) 706 return; 707 708 ih = handler; 709 ih->enabled = TRUE; 710 if (ih->fd >= 0) 711 AddEnabledDevice(ih->fd); 712} 713 714void 715xf86EnableGeneralHandler(pointer handler) 716{ 717 IHPtr ih; 718 719 if (!handler) 720 return; 721 722 ih = handler; 723 ih->enabled = TRUE; 724 if (ih->fd >= 0) 725 AddGeneralSocket(ih->fd); 726} 727 728/* 729 * As used currently by the DRI, the return value is ignored. 730 */ 731Bool 732xf86EnableVTSwitch(Bool new) 733{ 734 static Bool def = TRUE; 735 Bool old; 736 737 old = VTSwitchEnabled; 738 if (!new) { 739 /* Disable VT switching */ 740 def = VTSwitchEnabled; 741 VTSwitchEnabled = FALSE; 742 } else { 743 /* Restore VT switching to default */ 744 VTSwitchEnabled = def; 745 } 746 return old; 747} 748 749void 750DDXRingBell(int volume, int pitch, int duration) { 751 xf86OSRingBell(volume, pitch, duration); 752} 753