xf86Events.c (18168B)
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/Xproto.h> 58 #include <X11/Xatom.h> 59 #include "misc.h" 60 #include "xf86.h" 61 #include "xf86Priv.h" 62 #define XF86_OS_PRIVS 63 #include "xf86_OSlib.h" 64 #include <X11/keysym.h> 65 66 #ifdef XFreeXDGA 67 #include "dgaproc.h" 68 #endif 69 70 #include <X11/extensions/XI.h> 71 #include <X11/extensions/XIproto.h> 72 #include "inputstr.h" 73 #include "xf86Xinput.h" 74 75 #include "mi.h" 76 #include "mipointer.h" 77 78 #include "xkbsrv.h" 79 #include "xkbstr.h" 80 81 #ifdef DPMSExtension 82 #include <X11/extensions/dpmsconst.h> 83 #include "dpmsproc.h" 84 #endif 85 86 #include "xf86platformBus.h" 87 #include "systemd-logind.h" 88 89 extern void (*xf86OSPMClose) (void); 90 91 static void xf86VTSwitch(void); 92 93 /* 94 * Allow arbitrary drivers or other XFree86 code to register with our main 95 * Wakeup handler. 96 */ 97 typedef struct x_IHRec { 98 int fd; 99 InputHandlerProc ihproc; 100 void *data; 101 Bool enabled; 102 Bool is_input; 103 struct x_IHRec *next; 104 } IHRec, *IHPtr; 105 106 static IHPtr InputHandlers = NULL; 107 108 /* 109 * TimeSinceLastInputEvent -- 110 * Function used for screensaver purposes by the os module. Returns the 111 * time in milliseconds since there last was any input. 112 */ 113 int 114 TimeSinceLastInputEvent(void) 115 { 116 if (xf86Info.lastEventTime == 0) { 117 xf86Info.lastEventTime = GetTimeInMillis(); 118 } 119 return GetTimeInMillis() - xf86Info.lastEventTime; 120 } 121 122 /* 123 * SetTimeSinceLastInputEvent -- 124 * Set the lastEventTime to now. 125 */ 126 void 127 SetTimeSinceLastInputEvent(void) 128 { 129 xf86Info.lastEventTime = GetTimeInMillis(); 130 } 131 132 /* 133 * ProcessInputEvents -- 134 * Retrieve all waiting input events and pass them to DIX in their 135 * correct chronological order. Only reads from the system pointer 136 * and keyboard. 137 */ 138 void 139 ProcessInputEvents(void) 140 { 141 int x, y; 142 143 mieqProcessInputEvents(); 144 145 /* FIXME: This is a problem if we have multiple pointers */ 146 miPointerGetPosition(inputInfo.pointer, &x, &y); 147 148 xf86SetViewport(xf86Info.currentScreen, x, y); 149 } 150 151 /* 152 * Handle keyboard events that cause some kind of "action" 153 * (i.e., server termination, video mode changes, VT switches, etc.) 154 */ 155 void 156 xf86ProcessActionEvent(ActionEvent action, void *arg) 157 { 158 DebugF("ProcessActionEvent(%d,%p)\n", (int) action, arg); 159 switch (action) { 160 case ACTION_TERMINATE: 161 if (!xf86Info.dontZap) { 162 xf86Msg(X_INFO, "Server zapped. Shutting down.\n"); 163 GiveUp(0); 164 } 165 break; 166 case ACTION_NEXT_MODE: 167 if (!xf86Info.dontZoom) 168 xf86ZoomViewport(xf86Info.currentScreen, 1); 169 break; 170 case ACTION_PREV_MODE: 171 if (!xf86Info.dontZoom) 172 xf86ZoomViewport(xf86Info.currentScreen, -1); 173 break; 174 case ACTION_SWITCHSCREEN: 175 if (!xf86Info.dontVTSwitch && arg) { 176 int vtno = *((int *) arg); 177 178 if (vtno != xf86Info.vtno) { 179 if (!xf86VTActivate(vtno)) { 180 ErrorF("Failed to switch from vt%02d to vt%02d: %s\n", 181 xf86Info.vtno, vtno, strerror(errno)); 182 } 183 } 184 } 185 break; 186 case ACTION_SWITCHSCREEN_NEXT: 187 if (!xf86Info.dontVTSwitch) { 188 if (!xf86VTActivate(xf86Info.vtno + 1)) { 189 /* If first try failed, assume this is the last VT and 190 * try wrapping around to the first vt. 191 */ 192 if (!xf86VTActivate(1)) { 193 ErrorF("Failed to switch from vt%02d to next vt: %s\n", 194 xf86Info.vtno, strerror(errno)); 195 } 196 } 197 } 198 break; 199 case ACTION_SWITCHSCREEN_PREV: 200 if (!xf86Info.dontVTSwitch && xf86Info.vtno > 0) { 201 if (!xf86VTActivate(xf86Info.vtno - 1)) { 202 /* Don't know what the maximum VT is, so can't wrap around */ 203 ErrorF("Failed to switch from vt%02d to previous vt: %s\n", 204 xf86Info.vtno, strerror(errno)); 205 } 206 } 207 break; 208 default: 209 break; 210 } 211 } 212 213 /* 214 * xf86Wakeup -- 215 * Os wakeup handler. 216 */ 217 218 /* ARGSUSED */ 219 void 220 xf86Wakeup(void *blockData, int err) 221 { 222 if (xf86VTSwitchPending()) 223 xf86VTSwitch(); 224 } 225 226 /* 227 * xf86ReadInput -- 228 * input thread handler 229 */ 230 231 static void 232 xf86ReadInput(int fd, int ready, void *closure) 233 { 234 InputInfoPtr pInfo = closure; 235 236 pInfo->read_input(pInfo); 237 } 238 239 /* 240 * xf86AddEnabledDevice -- 241 * 242 */ 243 void 244 xf86AddEnabledDevice(InputInfoPtr pInfo) 245 { 246 InputThreadRegisterDev(pInfo->fd, xf86ReadInput, pInfo); 247 } 248 249 /* 250 * xf86RemoveEnabledDevice -- 251 * 252 */ 253 void 254 xf86RemoveEnabledDevice(InputInfoPtr pInfo) 255 { 256 InputThreadUnregisterDev(pInfo->fd); 257 } 258 259 /* 260 * xf86PrintBacktrace -- 261 * Print a stack backtrace for debugging purposes. 262 */ 263 void 264 xf86PrintBacktrace(void) 265 { 266 xorg_backtrace(); 267 } 268 269 static void 270 xf86ReleaseKeys(DeviceIntPtr pDev) 271 { 272 KeyClassPtr keyc; 273 int i; 274 275 if (!pDev || !pDev->key) 276 return; 277 278 keyc = pDev->key; 279 280 /* 281 * Hmm... here is the biggest hack of every time ! 282 * It may be possible that a switch-vt procedure has finished BEFORE 283 * you released all keys necessary to do this. That peculiar behavior 284 * can fool the X-server pretty much, cause it assumes that some keys 285 * were not released. TWM may stuck almost completely.... 286 * OK, what we are doing here is after returning from the vt-switch 287 * explicitly unrelease all keyboard keys before the input-devices 288 * are re-enabled. 289 */ 290 291 for (i = keyc->xkbInfo->desc->min_key_code; 292 i < keyc->xkbInfo->desc->max_key_code; i++) { 293 if (key_is_down(pDev, i, KEY_POSTED)) { 294 input_lock(); 295 QueueKeyboardEvents(pDev, KeyRelease, i); 296 input_unlock(); 297 } 298 } 299 } 300 301 void 302 xf86DisableInputDeviceForVTSwitch(InputInfoPtr pInfo) 303 { 304 if (!pInfo->dev) 305 return; 306 307 if (!pInfo->dev->enabled) 308 pInfo->flags |= XI86_DEVICE_DISABLED; 309 310 xf86ReleaseKeys(pInfo->dev); 311 ProcessInputEvents(); 312 DisableDevice(pInfo->dev, TRUE); 313 } 314 315 void 316 xf86EnableInputDeviceForVTSwitch(InputInfoPtr pInfo) 317 { 318 if (pInfo->dev && (pInfo->flags & XI86_DEVICE_DISABLED) == 0) 319 EnableDevice(pInfo->dev, TRUE); 320 pInfo->flags &= ~XI86_DEVICE_DISABLED; 321 } 322 323 /* 324 * xf86UpdateHasVTProperty -- 325 * Update a flag property on the root window to say whether the server VT 326 * is currently the active one as some clients need to know this. 327 */ 328 static void 329 xf86UpdateHasVTProperty(Bool hasVT) 330 { 331 Atom property_name; 332 int32_t value = hasVT ? 1 : 0; 333 int i; 334 335 property_name = MakeAtom(HAS_VT_ATOM_NAME, sizeof(HAS_VT_ATOM_NAME) - 1, 336 FALSE); 337 if (property_name == BAD_RESOURCE) 338 FatalError("Failed to retrieve \"HAS_VT\" atom\n"); 339 for (i = 0; i < xf86NumScreens; i++) { 340 dixChangeWindowProperty(serverClient, 341 xf86ScrnToScreen(xf86Screens[i])->root, 342 property_name, XA_INTEGER, 32, 343 PropModeReplace, 1, &value, TRUE); 344 } 345 } 346 347 void 348 xf86VTLeave(void) 349 { 350 int i; 351 InputInfoPtr pInfo; 352 IHPtr ih; 353 354 DebugF("xf86VTSwitch: Leaving, xf86Exiting is %s\n", 355 BOOLTOSTRING((dispatchException & DE_TERMINATE) ? TRUE : FALSE)); 356 #ifdef DPMSExtension 357 if (DPMSPowerLevel != DPMSModeOn) 358 DPMSSet(serverClient, DPMSModeOn); 359 #endif 360 for (i = 0; i < xf86NumScreens; i++) { 361 if (!(dispatchException & DE_TERMINATE)) 362 if (xf86Screens[i]->EnableDisableFBAccess) 363 (*xf86Screens[i]->EnableDisableFBAccess) (xf86Screens[i], FALSE); 364 } 365 366 /* 367 * Keep the order: Disable Device > LeaveVT 368 * EnterVT > EnableDevice 369 */ 370 for (ih = InputHandlers; ih; ih = ih->next) { 371 if (ih->is_input) 372 xf86DisableInputHandler(ih); 373 else 374 xf86DisableGeneralHandler(ih); 375 } 376 for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) 377 xf86DisableInputDeviceForVTSwitch(pInfo); 378 379 input_lock(); 380 for (i = 0; i < xf86NumScreens; i++) 381 xf86Screens[i]->LeaveVT(xf86Screens[i]); 382 for (i = 0; i < xf86NumGPUScreens; i++) 383 xf86GPUScreens[i]->LeaveVT(xf86GPUScreens[i]); 384 385 if (systemd_logind_controls_session()) { 386 systemd_logind_drop_master(); 387 } 388 389 if (!xf86VTSwitchAway()) 390 goto switch_failed; 391 392 if (xf86OSPMClose) 393 xf86OSPMClose(); 394 xf86OSPMClose = NULL; 395 396 for (i = 0; i < xf86NumScreens; i++) { 397 /* 398 * zero all access functions to 399 * trap calls when switched away. 400 */ 401 xf86Screens[i]->vtSema = FALSE; 402 } 403 if (xorgHWAccess) 404 xf86DisableIO(); 405 406 xf86UpdateHasVTProperty(FALSE); 407 408 return; 409 410 switch_failed: 411 DebugF("xf86VTSwitch: Leave failed\n"); 412 for (i = 0; i < xf86NumScreens; i++) { 413 if (!xf86Screens[i]->EnterVT(xf86Screens[i])) 414 FatalError("EnterVT failed for screen %d\n", i); 415 } 416 for (i = 0; i < xf86NumGPUScreens; i++) { 417 if (!xf86GPUScreens[i]->EnterVT(xf86GPUScreens[i])) 418 FatalError("EnterVT failed for gpu screen %d\n", i); 419 } 420 if (!(dispatchException & DE_TERMINATE)) { 421 for (i = 0; i < xf86NumScreens; i++) { 422 if (xf86Screens[i]->EnableDisableFBAccess) 423 (*xf86Screens[i]->EnableDisableFBAccess) (xf86Screens[i], TRUE); 424 } 425 } 426 dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); 427 428 for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) 429 xf86EnableInputDeviceForVTSwitch(pInfo); 430 for (ih = InputHandlers; ih; ih = ih->next) { 431 if (ih->is_input) 432 xf86EnableInputHandler(ih); 433 else 434 xf86EnableGeneralHandler(ih); 435 } 436 input_unlock(); 437 } 438 439 void 440 xf86VTEnter(void) 441 { 442 int i; 443 InputInfoPtr pInfo; 444 IHPtr ih; 445 446 DebugF("xf86VTSwitch: Entering\n"); 447 if (!xf86VTSwitchTo()) 448 return; 449 450 xf86OSPMClose = xf86OSPMOpen(); 451 452 if (xorgHWAccess) 453 xf86EnableIO(); 454 for (i = 0; i < xf86NumScreens; i++) { 455 xf86Screens[i]->vtSema = TRUE; 456 if (!xf86Screens[i]->EnterVT(xf86Screens[i])) 457 FatalError("EnterVT failed for screen %d\n", i); 458 } 459 for (i = 0; i < xf86NumGPUScreens; i++) { 460 xf86GPUScreens[i]->vtSema = TRUE; 461 if (!xf86GPUScreens[i]->EnterVT(xf86GPUScreens[i])) 462 FatalError("EnterVT failed for gpu screen %d\n", i); 463 } 464 for (i = 0; i < xf86NumScreens; i++) { 465 if (xf86Screens[i]->EnableDisableFBAccess) 466 (*xf86Screens[i]->EnableDisableFBAccess) (xf86Screens[i], TRUE); 467 } 468 469 /* Turn screen saver off when switching back */ 470 dixSaveScreens(serverClient, SCREEN_SAVER_FORCER, ScreenSaverReset); 471 472 for (pInfo = xf86InputDevs; pInfo; pInfo = pInfo->next) { 473 /* Devices with server managed fds get enabled on logind resume */ 474 if (!(pInfo->flags & XI86_SERVER_FD)) 475 xf86EnableInputDeviceForVTSwitch(pInfo); 476 } 477 478 for (ih = InputHandlers; ih; ih = ih->next) { 479 if (ih->is_input) 480 xf86EnableInputHandler(ih); 481 else 482 xf86EnableGeneralHandler(ih); 483 } 484 #ifdef XSERVER_PLATFORM_BUS 485 /* check for any new output devices */ 486 xf86platformVTProbe(); 487 #endif 488 489 xf86UpdateHasVTProperty(TRUE); 490 491 input_unlock(); 492 } 493 494 /* 495 * xf86VTSwitch -- 496 * Handle requests for switching the vt. 497 */ 498 static void 499 xf86VTSwitch(void) 500 { 501 DebugF("xf86VTSwitch()\n"); 502 503 #ifdef XFreeXDGA 504 if (!DGAVTSwitch()) 505 return; 506 #endif 507 508 /* 509 * Since all screens are currently all in the same state it is sufficient 510 * check the first. This might change in future. 511 * 512 * VTLeave is always handled here (VT_PROCESS guarantees this is safe), 513 * if we use systemd_logind xf86VTEnter() gets called by systemd-logind.c 514 * once it has resumed all drm nodes. 515 */ 516 if (xf86VTOwner()) 517 xf86VTLeave(); 518 else if (!systemd_logind_controls_session()) 519 xf86VTEnter(); 520 } 521 522 /* Input handler registration */ 523 524 static void 525 xf86InputHandlerNotify(int fd, int ready, void *data) 526 { 527 IHPtr ih = data; 528 529 if (ih->enabled && ih->fd >= 0 && ih->ihproc) { 530 ih->ihproc(ih->fd, ih->data); 531 } 532 } 533 534 static void * 535 addInputHandler(int fd, InputHandlerProc proc, void *data) 536 { 537 IHPtr ih; 538 539 if (fd < 0 || !proc) 540 return NULL; 541 542 ih = calloc(sizeof(*ih), 1); 543 if (!ih) 544 return NULL; 545 546 ih->fd = fd; 547 ih->ihproc = proc; 548 ih->data = data; 549 ih->enabled = TRUE; 550 551 if (!SetNotifyFd(fd, xf86InputHandlerNotify, X_NOTIFY_READ, ih)) { 552 free(ih); 553 return NULL; 554 } 555 556 ih->next = InputHandlers; 557 InputHandlers = ih; 558 559 return ih; 560 } 561 562 void * 563 xf86AddInputHandler(int fd, InputHandlerProc proc, void *data) 564 { 565 IHPtr ih = addInputHandler(fd, proc, data); 566 567 if (ih) 568 ih->is_input = TRUE; 569 return ih; 570 } 571 572 void * 573 xf86AddGeneralHandler(int fd, InputHandlerProc proc, void *data) 574 { 575 IHPtr ih = addInputHandler(fd, proc, data); 576 577 return ih; 578 } 579 580 /** 581 * Set the handler for the console's fd. Replaces (and returns) the previous 582 * handler or NULL, whichever appropriate. 583 * proc may be NULL if the server should not handle events on the console. 584 */ 585 InputHandlerProc 586 xf86SetConsoleHandler(InputHandlerProc proc, void *data) 587 { 588 static IHPtr handler = NULL; 589 InputHandlerProc old_proc = NULL; 590 591 if (handler) { 592 old_proc = handler->ihproc; 593 xf86RemoveGeneralHandler(handler); 594 } 595 596 handler = xf86AddGeneralHandler(xf86Info.consoleFd, proc, data); 597 598 return old_proc; 599 } 600 601 static void 602 removeInputHandler(IHPtr ih) 603 { 604 IHPtr p; 605 606 if (ih->fd >= 0) 607 RemoveNotifyFd(ih->fd); 608 if (ih == InputHandlers) 609 InputHandlers = ih->next; 610 else { 611 p = InputHandlers; 612 while (p && p->next != ih) 613 p = p->next; 614 if (ih) 615 p->next = ih->next; 616 } 617 free(ih); 618 } 619 620 int 621 xf86RemoveInputHandler(void *handler) 622 { 623 IHPtr ih; 624 int fd; 625 626 if (!handler) 627 return -1; 628 629 ih = handler; 630 fd = ih->fd; 631 632 removeInputHandler(ih); 633 634 return fd; 635 } 636 637 int 638 xf86RemoveGeneralHandler(void *handler) 639 { 640 IHPtr ih; 641 int fd; 642 643 if (!handler) 644 return -1; 645 646 ih = handler; 647 fd = ih->fd; 648 649 removeInputHandler(ih); 650 651 return fd; 652 } 653 654 void 655 xf86DisableInputHandler(void *handler) 656 { 657 IHPtr ih; 658 659 if (!handler) 660 return; 661 662 ih = handler; 663 ih->enabled = FALSE; 664 if (ih->fd >= 0) 665 RemoveNotifyFd(ih->fd); 666 } 667 668 void 669 xf86DisableGeneralHandler(void *handler) 670 { 671 IHPtr ih; 672 673 if (!handler) 674 return; 675 676 ih = handler; 677 ih->enabled = FALSE; 678 if (ih->fd >= 0) 679 RemoveNotifyFd(ih->fd); 680 } 681 682 void 683 xf86EnableInputHandler(void *handler) 684 { 685 IHPtr ih; 686 687 if (!handler) 688 return; 689 690 ih = handler; 691 ih->enabled = TRUE; 692 if (ih->fd >= 0) 693 SetNotifyFd(ih->fd, xf86InputHandlerNotify, X_NOTIFY_READ, ih); 694 } 695 696 void 697 xf86EnableGeneralHandler(void *handler) 698 { 699 IHPtr ih; 700 701 if (!handler) 702 return; 703 704 ih = handler; 705 ih->enabled = TRUE; 706 if (ih->fd >= 0) 707 SetNotifyFd(ih->fd, xf86InputHandlerNotify, X_NOTIFY_READ, ih); 708 } 709 710 void 711 DDXRingBell(int volume, int pitch, int duration) 712 { 713 xf86OSRingBell(volume, pitch, duration); 714 } 715 716 Bool 717 xf86VTOwner(void) 718 { 719 /* at system startup xf86Screens[0] won't be set - but we will own the VT */ 720 if (xf86NumScreens == 0) 721 return TRUE; 722 return xf86Screens[0]->vtSema; 723 }