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