]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/xserver.git/blob - hw/dmx/input/dmxinputinit.c
Imported Upstream version 1.11.4
[glsdk/xserver.git] / hw / dmx / input / dmxinputinit.c
1 /*
2  * Copyright 2002-2003 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  */
28 /*
29  * Authors:
30  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *
32  */
34 /** \file
35  * This file provides generic input support.  Functions here set up
36  * input and lead to the calling of low-level device drivers for
37  * input. */
39 #ifdef HAVE_DMX_CONFIG_H
40 #include <dmx-config.h>
41 #endif
43 #define DMX_WINDOW_DEBUG 0
45 #include "dmxinputinit.h"
46 #include "dmxextension.h"       /* For dmxInputCount */
48 #include "dmxdummy.h"
49 #include "dmxbackend.h"
50 #include "dmxconsole.h"
51 #include "dmxcommon.h"
52 #include "dmxevents.h"
53 #include "dmxmotion.h"
54 #include "dmxprop.h"
55 #include "config/dmxconfig.h"
56 #include "dmxcursor.h"
58 #include "lnx-keyboard.h"
59 #include "lnx-ms.h"
60 #include "lnx-ps2.h"
61 #include "usb-keyboard.h"
62 #include "usb-mouse.h"
63 #include "usb-other.h"
64 #include "usb-common.h"
66 #include "dmxsigio.h"
67 #include "dmxarg.h"
69 #include "inputstr.h"
70 #include "input.h"
71 #include "mipointer.h"
72 #include "windowstr.h"
73 #include "mi.h"
74 #include "xkbsrv.h"
76 #include <X11/extensions/XI.h>
77 #include <X11/extensions/XIproto.h>
78 #include "exevents.h"
79 #include "extinit.h"
81 DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard;
83 static DMXLocalInputInfoRec DMXDummyMou = {
84     "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
85     NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
86 };
88 static DMXLocalInputInfoRec DMXDummyKbd = {
89     "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
90     NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
91 };
93 static DMXLocalInputInfoRec DMXBackendMou = {
94     "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2,
95     dmxBackendCreatePrivate, dmxBackendDestroyPrivate,
96     dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo,
97     dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition,
98     NULL, NULL, NULL,
99     dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL,
100     dmxCommonMouCtrl
101 };
103 static DMXLocalInputInfoRec DMXBackendKbd = {
104     "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND,
105     1, /* With backend-mou or console-mou */
106     dmxCommonCopyPrivate, NULL,
107     dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo,
108     dmxCommonKbdOn, dmxCommonKbdOff, NULL,
109     NULL, NULL, NULL,
110     NULL, NULL, NULL, NULL,
111     NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
112 };
114 static DMXLocalInputInfoRec DMXConsoleMou = {
115     "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2,
116     dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate,
117     dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo,
118     dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition,
119     NULL, NULL, NULL,
120     dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo,
121     dmxCommonMouCtrl
122 };
124 static DMXLocalInputInfoRec DMXConsoleKbd = {
125     "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE,
126     1, /* With backend-mou or console-mou */
127     dmxCommonCopyPrivate, NULL,
128     dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo,
129     dmxCommonKbdOn, dmxCommonKbdOff, NULL,
130     NULL, NULL, NULL,
131     NULL, NULL, NULL, NULL,
132     NULL, dmxCommonKbdCtrl, dmxCommonKbdBell
133 };
135 static DMXLocalInputInfoRec DMXLocalDevices[] = {
136                                 /* Dummy drivers that can compile on any OS */
137 #ifdef __linux__
138                                 /* Linux-specific drivers */
139     {
140         "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
141         kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate,
142         kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo,
143         kbdLinuxOn, kbdLinuxOff, NULL,
144         kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch,
145         kbdLinuxRead, NULL, NULL, NULL,
146         NULL, kbdLinuxCtrl, kbdLinuxBell
147     },
148     {
149         "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
150         msLinuxCreatePrivate, msLinuxDestroyPrivate,
151         msLinuxInit, NULL, NULL, msLinuxGetInfo,
152         msLinuxOn, msLinuxOff, NULL,
153         msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL,
154         msLinuxRead
155     },
156     {
157         "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
158         ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate,
159         ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo,
160         ps2LinuxOn, ps2LinuxOff, NULL,
161         ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL,
162         ps2LinuxRead
163     },
164 #endif
165 #ifdef __linux__
166                                 /* USB drivers, currently only for
167                                    Linux, but relatively easy to port to
168                                    other OSs */
169     {
170         "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
171         usbCreatePrivate, usbDestroyPrivate,
172         kbdUSBInit, NULL, NULL, kbdUSBGetInfo,
173         kbdUSBOn, usbOff, NULL,
174         NULL, NULL, NULL,
175         kbdUSBRead, NULL, NULL, NULL,
176         NULL, kbdUSBCtrl
177     },
178     {
179         "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
180         usbCreatePrivate, usbDestroyPrivate,
181         mouUSBInit, NULL, NULL, mouUSBGetInfo,
182         mouUSBOn, usbOff, NULL,
183         NULL, NULL, NULL,
184         mouUSBRead
185     },
186     {
187         "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1,
188         usbCreatePrivate, usbDestroyPrivate,
189         othUSBInit, NULL, NULL, othUSBGetInfo,
190         othUSBOn, usbOff, NULL,
191         NULL, NULL, NULL,
192         othUSBRead
193     },
194 #endif
195     {
196         "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1,
197         NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo
198     },
199     {
200         "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1,
201         NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo
202     },
203     { NULL }                    /* Must be last */
204 };
207 #if 11 /*BP*/
208 void
209 DDXRingBell(int volume, int pitch, int duration)
211    /* NO-OP */
214 /* taken from kdrive/src/kinput.c: */
215 static void
216 dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl)
218 #if 0
219     KdKeyboardInfo *ki;
221     for (ki = kdKeyboards; ki; ki = ki->next) {
222         if (ki->dixdev && ki->dixdev->id == pDevice->id)
223             break;
224     }
226     if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver)
227         return;
229     KdSetLeds(ki, ctrl->leds);
230     ki->bellPitch = ctrl->bell_pitch;
231     ki->bellDuration = ctrl->bell_duration; 
232 #endif
235 /* taken from kdrive/src/kinput.c: */
236 static void
237 dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something)
239 #if 0
240     KeybdCtrl *ctrl = arg;
241     KdKeyboardInfo *ki = NULL;
242     
243     for (ki = kdKeyboards; ki; ki = ki->next) {
244         if (ki->dixdev && ki->dixdev->id == pDev->id)
245             break;
246     }
248     if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver)
249         return;
250     
251     KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration);
252 #endif
255 #endif /*BP*/
257 static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal,
258                                      PtrCtrl *ctrl)
260     if (!dmxLocal) return;
261     dmxLocal->mctrl = *ctrl;
262     if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl);
265 /** Change the pointer control information for the \a pDevice.  If the
266  * device sends core events, then also change the control information
267  * for all of the pointer devices that send core events. */
268 void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl)
270     GETDMXLOCALFROMPDEVICE;
271     int i, j;
273     if (dmxLocal->sendsCore) {       /* Do for all core devices */
274         for (i = 0; i < dmxNumInputs; i++) {
275             DMXInputInfo *dmxInput = &dmxInputs[i];
276             if (dmxInput->detached) continue;
277             for (j = 0; j < dmxInput->numDevs; j++)
278                 if (dmxInput->devs[j]->sendsCore)
279                     _dmxChangePointerControl(dmxInput->devs[j], ctrl);
280         }
281     } else {                    /* Do for this device only */
282         _dmxChangePointerControl(dmxLocal, ctrl);
283     }
286 static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal,
287                                     KeybdCtrl *ctrl)
289     dmxLocal->kctrl = *ctrl;
290     if (dmxLocal->kCtrl) {
291         dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl);
292         if (dmxLocal->pDevice->kbdfeed) {
293             XkbEventCauseRec cause;
294             XkbSetCauseUnknown(&cause);
295             /* Generate XKB events, as necessary */
296             XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False,
297                                 NULL, &cause);
298         }
299     }
303 /** Change the keyboard control information for the \a pDevice.  If the
304  * device sends core events, then also change the control information
305  * for all of the keyboard devices that send core events. */
306 void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl)
308     GETDMXLOCALFROMPDEVICE;
309     int i, j;
311     if (dmxLocal->sendsCore) {       /* Do for all core devices */
312         for (i = 0; i < dmxNumInputs; i++) {
313             DMXInputInfo *dmxInput = &dmxInputs[i];
314             if (dmxInput->detached) continue;
315             for (j = 0; j < dmxInput->numDevs; j++)
316                 if (dmxInput->devs[j]->sendsCore)
317                     _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl);
318         }
319     } else {                    /* Do for this device only */
320         _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl);
321     }
324 static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent)
326     if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public,
327                                          percent,
328                                          dmxLocal->kctrl.bell,
329                                          dmxLocal->kctrl.bell_pitch,
330                                          dmxLocal->kctrl.bell_duration);
333 /** Sound the bell on the device.  If the device send core events, then
334  * sound the bell on all of the devices that send core events. */
335 void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice,
336                          pointer ctrl, int unknown)
338     GETDMXLOCALFROMPDEVICE;
339     int i, j;
341     if (dmxLocal->sendsCore) {       /* Do for all core devices */
342         for (i = 0; i < dmxNumInputs; i++) {
343             DMXInputInfo *dmxInput = &dmxInputs[i];
344             if (dmxInput->detached) continue;
345             for (j = 0; j < dmxInput->numDevs; j++)
346                 if (dmxInput->devs[j]->sendsCore)
347                     _dmxKeyboardBellProc(dmxInput->devs[j], percent);
348         }
349     } else {                    /* Do for this device only */
350         _dmxKeyboardBellProc(dmxLocal, percent);
351     }
354 static void dmxKeyboardFreeNames(XkbComponentNamesPtr names)
356     if (names->keycodes) XFree(names->keycodes);
357     if (names->types)    XFree(names->types);
358     if (names->compat)   XFree(names->compat);
359     if (names->symbols)  XFree(names->symbols);
360     if (names->geometry) XFree(names->geometry);
364 static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info)
366     GETDMXINPUTFROMPDEVICE;
367     XkbRMLVOSet rmlvo;
369     rmlvo.rules = dmxConfigGetXkbRules();
370     rmlvo.model = dmxConfigGetXkbModel();
371     rmlvo.layout = dmxConfigGetXkbLayout();
372     rmlvo.variant = dmxConfigGetXkbVariant();
373     rmlvo.options = dmxConfigGetXkbOptions();
375     XkbSetRulesDflts(&rmlvo);
376     if (!info->force && (dmxInput->keycodes
377                          || dmxInput->symbols
378                          || dmxInput->geometry)) {
379         if (info->freenames) dmxKeyboardFreeNames(&info->names);
380         info->freenames      = 0;
381         info->names.keycodes = dmxInput->keycodes;
382         info->names.types    = NULL;
383         info->names.compat   = NULL;
384         info->names.symbols  = dmxInput->symbols;
385         info->names.geometry = dmxInput->geometry;
387         dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s",
388                     info->names.keycodes);
389         if (info->names.symbols && *info->names.symbols)
390             dmxLogInputCont(dmxInput, " %s", info->names.symbols);
391         if (info->names.geometry && *info->names.geometry)
392             dmxLogInputCont(dmxInput, " %s", info->names.geometry);
393         dmxLogInputCont(dmxInput, "\n");
394     } else if (info->names.keycodes) {
395         dmxLogInput(dmxInput, "XKEYBOARD: From device: %s",
396                     info->names.keycodes);
397         if (info->names.symbols && *info->names.symbols)
398             dmxLogInputCont(dmxInput, " %s", info->names.symbols);
399         if (info->names.geometry && *info->names.geometry)
400             dmxLogInputCont(dmxInput, " %s", info->names.geometry);
401         dmxLogInputCont(dmxInput, "\n");
402     } else {
403         dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n",
404                     dmxConfigGetXkbRules(),
405                     dmxConfigGetXkbLayout(),
406                     dmxConfigGetXkbModel(),
407                     dmxConfigGetXkbVariant()
408                     ? dmxConfigGetXkbVariant() : "",
409                     dmxConfigGetXkbOptions()
410                     ? dmxConfigGetXkbOptions() : "");
411     }
412     InitKeyboardDeviceStruct(pDevice, &rmlvo,
413                                 dmxKeyboardBellProc,
414                                 dmxKeyboardKbdCtrlProc);
416     if (info->freenames) dmxKeyboardFreeNames(&info->names);
418     return Success;
421     
422 static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what)
424     GETDMXINPUTFROMPDEVICE;
425     int              fd;
426     DMXLocalInitInfo info;
427     int              i;
428     Atom             btn_labels[MAX_BUTTONS] = {0}; /* FIXME */
429     Atom             axis_labels[MAX_VALUATORS] = {0}; /* FIXME */
431     if (dmxInput->detached) return Success;
433     memset(&info, 0, sizeof(info));
434     switch (what) {
435     case DEVICE_INIT:
436         if (dmxLocal->init)
437             dmxLocal->init(pDev);
438         if (dmxLocal->get_info)
439             dmxLocal->get_info(pDev, &info);
440         if (info.keyboard) {    /* XKEYBOARD makes this a special case */
441             dmxKeyboardOn(pDevice, &info);
442             break;
443         }
444         if (info.keyClass) {
445             XkbRMLVOSet rmlvo;
447             rmlvo.rules = dmxConfigGetXkbRules();
448             rmlvo.model = dmxConfigGetXkbModel();
449             rmlvo.layout = dmxConfigGetXkbLayout();
450             rmlvo.variant = dmxConfigGetXkbVariant();
451             rmlvo.options = dmxConfigGetXkbOptions();
453             InitKeyboardDeviceStruct(pDevice,
454                                      &rmlvo,
455                                      dmxBell, dmxKbdCtrl);
456         }
457         if (info.buttonClass) {
458             InitButtonClassDeviceStruct(pDevice, info.numButtons,
459                                         btn_labels, info.map);
460         }
461         if (info.valuatorClass) {
462             if (info.numRelAxes && dmxLocal->sendsCore) {
463                 InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
464                                               axis_labels,
465                                               GetMaximumEventsNum(),
466                                               Relative);
467                 for (i = 0; i < info.numRelAxes; i++)
468                     InitValuatorAxisStruct(pDevice, i, axis_labels[i],
469                                            info.minval[i], info.maxval[i],
470                                            info.res[i],
471                                            info.minres[i], info.maxres[i],
472                                            Relative);
473             } else if (info.numRelAxes) {
474                 InitValuatorClassDeviceStruct(pDevice, info.numRelAxes,
475                                               axis_labels,
476                                               dmxPointerGetMotionBufferSize(),
477                                               Relative);
478                 for (i = 0; i < info.numRelAxes; i++)
479                     InitValuatorAxisStruct(pDevice, i, axis_labels[i],
480                                            info.minval[i],
481                                            info.maxval[i], info.res[i],
482                                            info.minres[i], info.maxres[i],
483                                            Relative);
484             } else if (info.numAbsAxes) {
485                 InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes,
486                                               axis_labels,
487                                               dmxPointerGetMotionBufferSize(),
488                                               Absolute);
489                 for (i = 0; i < info.numAbsAxes; i++)
490                     InitValuatorAxisStruct(pDevice, i,
491                                            axis_labels[i],
492                                            info.minval[i], info.maxval[i],
493                                            info.res[i], info.minres[i],
494                                            info.maxres[i], Absolute);
495             }
496         }
497         if (info.focusClass)       InitFocusClassDeviceStruct(pDevice);
498         if (info.proximityClass)   InitProximityClassDeviceStruct(pDevice);
499         if (info.ptrFeedbackClass)
500             InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl);
501         if (info.intFeedbackClass || info.strFeedbackClass)
502             dmxLog(dmxWarning,
503                    "Integer and string feedback not supported for %s\n",
504                    pDevice->name);
505         if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass))
506             dmxLog(dmxWarning,
507                    "Led and bel feedback not supported for non-keyboard %s\n",
508                    pDevice->name);
509         break;
510     case DEVICE_ON:
511         if (!pDev->on) {
512             if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0)
513                 dmxSigioRegister(dmxInput, fd);
514             pDev->on = TRUE;
515         }
516         break;
517     case DEVICE_OFF:
518     case DEVICE_CLOSE:
519             /* This can get called twice consecutively: once for a
520              * detached screen (DEVICE_OFF), and then again at server
521              * generation time (DEVICE_CLOSE). */
522         if (pDev->on) {
523             dmxSigioUnregister(dmxInput);
524             if (dmxLocal->off) dmxLocal->off(pDev);
525             pDev->on = FALSE;
526         }
527         break;
528     }
529     if (info.keySyms.map && info.freemap) {
530         XFree(info.keySyms.map);
531         info.keySyms.map = NULL;
532     }
533     if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True);
534     return Success;
537 static void dmxProcessInputEvents(DMXInputInfo *dmxInput)
539     int i;
541     mieqProcessInputEvents();
542 #if 00 /*BP*/
543     miPointerUpdate();
544 #endif
545     if (dmxInput->detached)
546         return;
547     for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
548         if (dmxInput->devs[i]->process_input) {
549             dmxInput->devs[i]->process_input(dmxInput->devs[i]->private);
550         }
552 #if 11 /*BP*/
553     mieqProcessInputEvents();
554 #endif
557 static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput,
558                                        DMXUpdateType type,
559                                        WindowPtr pWindow)
561     int i;
563 #ifdef PANORAMIX
564     if (!noPanoramiXExtension && pWindow && pWindow->parent != screenInfo.screens[0]->root)
565         return;
566 #endif
567 #if DMX_WINDOW_DEBUG
568     {
569         const char *name = "Unknown";
570         switch (type) {
571         case DMX_UPDATE_REALIZE:            name = "Realize";         break;
572         case DMX_UPDATE_UNREALIZE:          name = "Unrealize";       break;
573         case DMX_UPDATE_RESTACK:            name = "Restack";         break;
574         case DMX_UPDATE_COPY:               name = "Copy";            break;
575         case DMX_UPDATE_RESIZE:             name = "Resize";          break;
576         case DMX_UPDATE_REPARENT:           name = "Repaint";         break;
577         }
578         dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name);
579     }
580 #endif
582     if (dmxInput->detached)
583         return;
584     for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
585         if (dmxInput->devs[i]->update_info)
586             dmxInput->devs[i]->update_info(dmxInput->devs[i]->private,
587                                            type, pWindow);
590 static void dmxCollectAll(DMXInputInfo *dmxInput)
592     int i;
594     if (dmxInput->detached)
595         return;
596     for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding)
597         if (dmxInput->devs[i]->collect_events)
598             dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public,
599                                               dmxMotion,
600                                               dmxEnqueue,
601                                               dmxCheckSpecialKeys, DMX_BLOCK);
604 static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout,
605                             pointer pReadMask)
607     DMXInputInfo    *dmxInput = &dmxInputs[(uintptr_t)blockData];
608     static unsigned long generation = 0;
609     
610     if (generation != serverGeneration) {
611         generation = serverGeneration;
612         dmxCollectAll(dmxInput);
613     }
616 static void dmxSwitchReturn(pointer p)
618     DMXInputInfo *dmxInput = p;
619     int          i;
620     
621     dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched);
623     if (!dmxInput->vt_switched)
624         dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n");
625     dmxSigioEnableInput();
626     for (i = 0; i < dmxInput->numDevs; i++)
627         if (dmxInput->devs[i]->vt_post_switch)
628             dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private);
629     dmxInput->vt_switched = 0;
632 static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask)
634     DMXInputInfo *dmxInput = &dmxInputs[(uintptr_t)blockData];
635     int          i;
637     if (dmxInput->vt_switch_pending) {
638         dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending);
639         for (i = 0; i < dmxInput->numDevs; i++)
640             if (dmxInput->devs[i]->vt_pre_switch)
641                 dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private);
642         dmxInput->vt_switched       = dmxInput->vt_switch_pending;
643         dmxInput->vt_switch_pending = 0;
644         for (i = 0; i < dmxInput->numDevs; i++) {
645             if (dmxInput->devs[i]->vt_switch) {
646                 dmxSigioDisableInput();
647                 if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private,
648                                                   dmxInput->vt_switched,
649                                                   dmxSwitchReturn,
650                                                   dmxInput))
651                     dmxSwitchReturn(dmxInput);
652                 break;          /* Only call one vt_switch routine */
653             }
654         }
655     }
656     dmxCollectAll(dmxInput);
659 static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal)
661     static int           k = 0;
662     static int           m = 0;
663     static int           o = 0;
664     static unsigned long dmxGeneration = 0;
665 #define LEN  32
666     char *               buf = malloc(LEN);
668     if (dmxGeneration != serverGeneration) {
669         k = m = o     = 0;
670         dmxGeneration = serverGeneration;
671     }
673     switch (dmxLocal->type) {
674     case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break;
675     case DMX_LOCAL_MOUSE:    XmuSnprintf(buf, LEN, "Mouse%d", m++);    break;
676     default:                 XmuSnprintf(buf, LEN, "Other%d", o++);    break;
677     }
679     return buf;
682 static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal)
684     DeviceIntPtr pDevice;
685     Atom         atom;
686     const char   *name = NULL;
687     char         *devname;
688     DMXInputInfo *dmxInput;
690     if (!dmxLocal)
691         return NULL;
692     dmxInput = &dmxInputs[dmxLocal->inputIdx];
694     if (dmxLocal->sendsCore) {
695         if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) {
696             dmxLocal->isCore     = 1;
697             dmxLocalCoreKeyboard = dmxLocal;
698             name                 = "keyboard";
699         }
700         if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) {
701             dmxLocal->isCore     = 1;
702             dmxLocalCorePointer  = dmxLocal;
703             name                 = "pointer";
704         }
705     }
707     if (!name) {
708         name            = "extension";
709     }
711     if (!name)
712         dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name);
714     pDevice                       = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE);
715     if (!pDevice) {
716         dmxLog(dmxError, "Too many devices -- cannot add device %s\n",
717                dmxLocal->name);
718         return NULL;
719     }
720     pDevice->public.devicePrivate = dmxLocal;
721     dmxLocal->pDevice             = pDevice;
723     devname       = dmxMakeUniqueDeviceName(dmxLocal);
724     atom          = MakeAtom((char *)devname, strlen(devname), TRUE);
725     pDevice->type = atom;
726     pDevice->name = devname;
728     if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) {
729 #if 00 /*BP*/
730         miRegisterPointerDevice(screenInfo.screens[0], pDevice);
731 #else
732         /* Nothing? dmxDeviceOnOff() should get called to init, right? */
733 #endif
734     }
736     if (dmxLocal->create_private)
737         dmxLocal->private = dmxLocal->create_private(pDevice);
739     dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n",
740                 dmxLocal->name, name, devname,
741                 dmxLocal->isCore
742                 ? " [core]"
743                 : (dmxLocal->sendsCore
744                    ? " [sends core events]"
745                    : ""));
747     return pDevice;
750 static DMXLocalInputInfoPtr dmxLookupLocal(const char *name)
752     DMXLocalInputInfoPtr pt;
753     
754     for (pt = &DMXLocalDevices[0]; pt->name; ++pt)
755         if (!strcmp(pt->name, name)) return pt; /* search for device name */
756     return NULL;
759 /** Copy the local input information from \a s into a new \a devs slot
760  * in \a dmxInput. */
761 DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput,
762                                        DMXLocalInputInfoPtr s)
764     DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal));
765     
766     if (!dmxLocal)
767         dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n");
769     memcpy(dmxLocal, s, sizeof(*dmxLocal));
770     dmxLocal->inputIdx       = dmxInput->inputIdx;
771     dmxLocal->sendsCore      = dmxInput->core;
772     dmxLocal->savedSendsCore = dmxInput->core;
773     dmxLocal->deviceId       = -1;
775     ++dmxInput->numDevs;
776     dmxInput->devs = realloc(dmxInput->devs,
777                               dmxInput->numDevs * sizeof(*dmxInput->devs));
778     dmxInput->devs[dmxInput->numDevs-1] = dmxLocal;
779     
780     return dmxLocal;
783 static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a)
785     int                  i;
786     int                  help = 0;
787     DMXLocalInputInfoRec *pt;
789     for (i = 1; i < dmxArgC(a); i++) {
790         const char *name = dmxArgV(a, i);
791         if ((pt = dmxLookupLocal(name))) {
792             dmxInputCopyLocal(dmxInput, pt);
793         } else {
794             if (strlen(name))
795                 dmxLog(dmxWarning,
796                        "Could not find a driver called %s\n", name);
797             ++help;
798         }
799     }
800     if (help) {
801         dmxLog(dmxInfo, "Available local device drivers:\n");
802         for (pt = &DMXLocalDevices[0]; pt->name; ++pt) {
803             const char *type;
804             switch (pt->type) {
805             case DMX_LOCAL_KEYBOARD: type = "keyboard"; break;
806             case DMX_LOCAL_MOUSE:    type = "pointer";  break;
807             default:                 type = "unknown";  break;
808             }
809             dmxLog(dmxInfo, "   %s (%s)\n", pt->name, type);
810         }
811         dmxLog(dmxFatal, "Must have valid local device driver\n");
812     }
815 int dmxInputExtensionErrorHandler(Display *dsp, _Xconst char *name, _Xconst char *reason)
817     return 0;
820 static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI)
822     XExtensionVersion    *ext;
823     XDeviceInfo          *devices;
824     Display              *display;
825     int                  num;
826     int                  i, j;
827     XextErrorHandler     handler;
829     if (!(display = XOpenDisplay(dmxInput->name))) return;
830     
831     /* Print out information about the XInput Extension. */
832     handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
833     ext     = XGetExtensionVersion(display, INAME);
834     XSetExtensionErrorHandler(handler);
835     
836     if (!ext || ext == (XExtensionVersion *)NoSuchExtension) {
837         dmxLogInput(dmxInput, "%s is not available\n", INAME);
838     } else {
839         dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n",
840                     dmxInput->name, INAME,
841                     ext->major_version, ext->minor_version);
842         devices = XListInputDevices(display, &num);
844         XFree(ext);
845         ext = NULL;
847                                 /* Print a list of all devices */
848         for (i = 0; i < num; i++) {
849             const char *use = "Unknown";
850             switch (devices[i].use) {
851             case IsXPointer:           use = "XPointer";         break;
852             case IsXKeyboard:          use = "XKeyboard";        break;
853             case IsXExtensionDevice:   use = "XExtensionDevice"; break;
854             case IsXExtensionPointer:  use = "XExtensionPointer"; break;
855             case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break;
856             }
857             dmxLogInput(dmxInput, "  %2d %-10.10s %-16.16s\n",
858                         devices[i].id,
859                         devices[i].name ? devices[i].name : "",
860                         use);
861         }
863                                 /* Search for extensions */
864         for (i = 0; i < num; i++) {
865             switch (devices[i].use) {
866             case IsXKeyboard:
867                 for (j = 0; j < dmxInput->numDevs; j++) {
868                     DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
869                     if (dmxL->type == DMX_LOCAL_KEYBOARD
870                         && dmxL->deviceId < 0) {
871                         dmxL->deviceId   = devices[i].id;
872                         dmxL->deviceName = (devices[i].name
873                                             ? strdup(devices[i].name)
874                                             : NULL);
875                     }
876                 }
877                 break;
878             case IsXPointer:
879                 for (j = 0; j < dmxInput->numDevs; j++) {
880                     DMXLocalInputInfoPtr dmxL = dmxInput->devs[j];
881                     if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) {
882                         dmxL->deviceId   = devices[i].id;
883                         dmxL->deviceName = (devices[i].name
884                                             ? xstrdup(devices[i].name)
885                                             : NULL);
886                     }
887                 }
888                 break;
889             }
890         }
891         XFreeDeviceList(devices);
892     }
893     XCloseDisplay(display);
896 /** Re-initialize all the devices described in \a dmxInput.  Called from
897     #dmxAdjustCursorBoundaries before the cursor is redisplayed. */
898 void dmxInputReInit(DMXInputInfo *dmxInput)
900     int i;
902     for (i = 0; i < dmxInput->numDevs; i++) {
903         DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
904         if (dmxLocal->reinit)
905             dmxLocal->reinit(&dmxLocal->pDevice->public);
906     }
909 /** Re-initialize all the devices described in \a dmxInput.  Called from
910     #dmxAdjustCursorBoundaries after the cursor is redisplayed. */
911 void dmxInputLateReInit(DMXInputInfo *dmxInput)
913     int i;
915     for (i = 0; i < dmxInput->numDevs; i++) {
916         DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
917         if (dmxLocal->latereinit)
918             dmxLocal->latereinit(&dmxLocal->pDevice->public);
919     }
922 /** Initialize all of the devices described in \a dmxInput. */
923 void dmxInputInit(DMXInputInfo *dmxInput)
925     DeviceIntPtr         pPointer = NULL, pKeyboard = NULL;
926     dmxArg               a;
927     const char           *name;
928     int                  i;
929     int                  doXI               = 1; /* Include by default */
930     int                  forceConsole       = 0;
931     int                  doWindows          = 1; /* On by default */
932     int                  hasXkb             = 0;
934     a = dmxArgParse(dmxInput->name);
936     for (i = 1; i < dmxArgC(a); i++) {
937         switch (hasXkb) {
938         case 1:
939             dmxInput->keycodes = xstrdup(dmxArgV(a, i));
940             ++hasXkb;
941             break;
942         case 2:
943             dmxInput->symbols  = xstrdup(dmxArgV(a, i));
944             ++hasXkb;
945             break;
946         case 3:
947             dmxInput->geometry = xstrdup(dmxArgV(a, i));
948             hasXkb = 0;
949             break;
950         case 0:
951             if      (!strcmp(dmxArgV(a, i), "noxi"))      doXI         = 0;
952             else if (!strcmp(dmxArgV(a, i), "xi"))        doXI         = 1;
953             else if (!strcmp(dmxArgV(a, i), "console"))   forceConsole = 1;
954             else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0;
955             else if (!strcmp(dmxArgV(a, i), "windows"))   doWindows    = 1;
956             else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows    = 0;
957             else if (!strcmp(dmxArgV(a, i), "xkb"))       hasXkb       = 1;
958             else {
959                 dmxLog(dmxFatal,
960                        "Unknown input argument: %s\n", dmxArgV(a, i));
961             }
962         }
963     }
965     name = dmxArgV(a, 0);
967     if (!strcmp(name, "local")) {
968         dmxPopulateLocal(dmxInput, a);
969     } else if (!strcmp(name, "dummy")) {
970         dmxInputCopyLocal(dmxInput, &DMXDummyMou);
971         dmxInputCopyLocal(dmxInput, &DMXDummyKbd);
972         dmxLogInput(dmxInput, "Using dummy input\n");
973     } else {
974         int found;
976         for (found = 0, i = 0; i < dmxNumScreens; i++) {
977             if (dmxPropertySameDisplay(&dmxScreens[i], name)) {
978                 if (dmxScreens[i].shared)
979                     dmxLog(dmxFatal,
980                            "Cannot take input from shared backend (%s)\n",
981                            name);
982                 if (!dmxInput->core) {
983                     dmxLog(dmxWarning,
984                            "Cannot use core devices on a backend (%s)"
985                            " as XInput devices\n", name);
986                 } else {
987                     char *pt;
988                     for (pt = (char *)dmxInput->name; pt && *pt; pt++)
989                         if (*pt == ',') *pt = '\0';
990                     dmxInputCopyLocal(dmxInput, &DMXBackendMou);
991                     dmxInputCopyLocal(dmxInput, &DMXBackendKbd);
992                     dmxInput->scrnIdx = i;
993                     dmxLogInput(dmxInput,
994                                 "Using backend input from %s\n", name);
995                 }
996                 ++found;
997                 break;
998             }
999         }
1000         if (!found || forceConsole) {
1001             char *pt;
1002             if (found) dmxInput->console = TRUE;
1003             for (pt = (char *)dmxInput->name; pt && *pt; pt++)
1004                 if (*pt == ',') *pt = '\0';
1005             dmxInputCopyLocal(dmxInput, &DMXConsoleMou);
1006             dmxInputCopyLocal(dmxInput, &DMXConsoleKbd);
1007             if (doWindows) {
1008                 dmxInput->windows          = TRUE;
1009                 dmxInput->updateWindowInfo = dmxUpdateWindowInformation;
1010             }
1011             dmxLogInput(dmxInput,
1012                         "Using console input from %s (%s windows)\n",
1013                         name, doWindows ? "with" : "without");
1014         }
1015     }
1017     dmxArgFree(a);
1019                                 /* Locate extensions we may be interested in */
1020     dmxInputScanForExtensions(dmxInput, doXI);
1021     
1022     for (i = 0; i < dmxInput->numDevs; i++) {
1023         DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1024         dmxLocal->pDevice = dmxAddDevice(dmxLocal);
1025         if (dmxLocal->isCore) {
1026             if (dmxLocal->type == DMX_LOCAL_MOUSE)
1027                 pPointer  = dmxLocal->pDevice;
1028             if (dmxLocal->type == DMX_LOCAL_KEYBOARD)
1029                 pKeyboard = dmxLocal->pDevice;
1030         }
1031     }
1032     
1033     dmxInput->processInputEvents    = dmxProcessInputEvents;
1034     dmxInput->detached              = False;
1035     
1036     RegisterBlockAndWakeupHandlers(dmxBlockHandler, dmxWakeupHandler,
1037                                    (void *)(uintptr_t)dmxInput->inputIdx);
1040 static void dmxInputFreeLocal(DMXLocalInputInfoRec *local)
1042     if (!local) return;
1043     if (local->isCore && local->type == DMX_LOCAL_MOUSE)
1044         dmxLocalCorePointer  = NULL;
1045     if (local->isCore && local->type == DMX_LOCAL_KEYBOARD)
1046         dmxLocalCoreKeyboard = NULL;
1047     if (local->destroy_private) local->destroy_private(local->private);
1048     free(local->history);
1049     free(local->valuators);
1050     free(local->deviceName);
1051     local->private    = NULL;
1052     local->history    = NULL;
1053     local->deviceName = NULL;
1054     free(local);
1057 /** Free all of the memory associated with \a dmxInput */
1058 void dmxInputFree(DMXInputInfo *dmxInput)
1060     int i;
1061     
1062     if (!dmxInput) return;
1064     free(dmxInput->keycodes);
1065     free(dmxInput->symbols);
1066     free(dmxInput->geometry);
1068     for (i = 0; i < dmxInput->numDevs; i++) {
1069         dmxInputFreeLocal(dmxInput->devs[i]);
1070         dmxInput->devs[i] = NULL;
1071     }
1072     free(dmxInput->devs);
1073     dmxInput->devs    = NULL;
1074     dmxInput->numDevs = 0;
1075     if (dmxInput->freename) free(dmxInput->name);
1076     dmxInput->name    = NULL;
1079 /** Log information about all of the known devices using #dmxLog(). */
1080 void dmxInputLogDevices(void)
1082     int i, j;
1084     dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount());
1085     dmxLog(dmxInfo, "  Id  Name                 Classes\n");
1086     for (j = 0; j < dmxNumInputs; j++) {
1087         DMXInputInfo *dmxInput = &dmxInputs[j];
1088         const char   *pt = strchr(dmxInput->name, ',');
1089         int          len = (pt
1090                             ? (size_t)(pt-dmxInput->name)
1091                             : strlen(dmxInput->name));
1093         for (i = 0; i < dmxInput->numDevs; i++) {
1094             DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice;
1095             if (pDevice) {
1096                 dmxLog(dmxInfo, "  %2d%c %-20.20s",
1097                        pDevice->id,
1098                        dmxInput->detached ? 'D' : ' ',
1099                        pDevice->name);
1100                 if (pDevice->key)        dmxLogCont(dmxInfo, " key");
1101                 if (pDevice->valuator)   dmxLogCont(dmxInfo, " val");
1102                 if (pDevice->button)     dmxLogCont(dmxInfo, " btn");
1103                 if (pDevice->focus)      dmxLogCont(dmxInfo, " foc");
1104                 if (pDevice->kbdfeed)    dmxLogCont(dmxInfo, " fb/kbd");
1105                 if (pDevice->ptrfeed)    dmxLogCont(dmxInfo, " fb/ptr");
1106                 if (pDevice->intfeed)    dmxLogCont(dmxInfo, " fb/int");
1107                 if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str");
1108                 if (pDevice->bell)       dmxLogCont(dmxInfo, " fb/bel");
1109                 if (pDevice->leds)       dmxLogCont(dmxInfo, " fb/led");
1110                 if (!pDevice->key && !pDevice->valuator && !pDevice->button
1111                     && !pDevice->focus && !pDevice->kbdfeed
1112                     && !pDevice->ptrfeed && !pDevice->intfeed
1113                     && !pDevice->stringfeed && !pDevice->bell
1114                     && !pDevice->leds)   dmxLogCont(dmxInfo, " (none)");
1115                                                                  
1116                 dmxLogCont(dmxInfo, "\t[i%d/%*.*s",
1117                            dmxInput->inputIdx, len, len, dmxInput->name);
1118                 if (dmxInput->devs[i]->deviceId >= 0)
1119                     dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId);
1120                 if (dmxInput->devs[i]->deviceName)
1121                     dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName);
1122                 dmxLogCont(dmxInfo, "] %s\n",
1123                            dmxInput->devs[i]->isCore
1124                            ? "core"
1125                            : (dmxInput->devs[i]->sendsCore
1126                               ? "extension (sends core events)"
1127                               : "extension"));
1128             }
1129         }
1130     }
1133 /** Detach an input */
1134 int dmxInputDetach(DMXInputInfo *dmxInput)
1136     int i;
1138     if (dmxInput->detached) return BadAccess;
1139     
1140     for (i = 0; i < dmxInput->numDevs; i++) {
1141         DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1142         dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n",
1143                     dmxLocal->pDevice->id,
1144                     dmxLocal->pDevice->name,
1145                     dmxLocal->isCore
1146                     ? " [core]"
1147                     : (dmxLocal->sendsCore
1148                        ? " [sends core events]"
1149                        : ""));
1150         DisableDevice(dmxLocal->pDevice, TRUE);
1151     }
1152     dmxInput->detached = True;
1153     dmxInputLogDevices();
1154     return 0;
1157 /** Search for input associated with \a dmxScreen, and detach. */
1158 void dmxInputDetachAll(DMXScreenInfo *dmxScreen)
1160     int i;
1162     for (i = 0; i < dmxNumInputs; i++) {
1163         DMXInputInfo *dmxInput = &dmxInputs[i];
1164         if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput);
1165     }
1168 /** Search for input associated with \a deviceId, and detach. */
1169 int dmxInputDetachId(int id)
1171     DMXInputInfo *dmxInput = dmxInputLocateId(id);
1173     if (!dmxInput) return BadValue;
1174     
1175     return dmxInputDetach(dmxInput);
1178 DMXInputInfo *dmxInputLocateId(int id)
1180     int i, j;
1181     
1182     for (i = 0; i < dmxNumInputs; i++) {
1183         DMXInputInfo *dmxInput = &dmxInputs[i];
1184         for (j = 0; j < dmxInput->numDevs; j++) {
1185             DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j];
1186             if (dmxLocal->pDevice->id == id) return dmxInput;
1187         }
1188     }
1189     return NULL;
1192 static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id)
1194     dmxInputInit(dmxInput);
1195     InitAndStartDevices();
1196     if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id;
1197     dmxInputLogDevices();
1198     return 0;
1201 static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id)
1203     int i;
1204     
1205     dmxInput->detached = False;
1206     for (i = 0; i < dmxInput->numDevs; i++) {
1207         DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i];
1208         if (id) *id = dmxLocal->pDevice->id;
1209         dmxLogInput(dmxInput,
1210                     "Attaching device id %d: %s%s\n",
1211                     dmxLocal->pDevice->id,
1212                     dmxLocal->pDevice->name,
1213                     dmxLocal->isCore
1214                     ? " [core]"
1215                     : (dmxLocal->sendsCore
1216                        ? " [sends core events]"
1217                        : ""));
1218         EnableDevice(dmxLocal->pDevice, TRUE);
1219     }
1220     dmxInputLogDevices();
1221     return 0;
1224 int dmxInputAttachConsole(const char *name, int isCore, int *id)
1226     DMXInputInfo  *dmxInput;
1227     int           i;
1229     for (i = 0; i < dmxNumInputs; i++) {
1230         dmxInput = &dmxInputs[i];
1231         if (dmxInput->scrnIdx == -1
1232             && dmxInput->detached
1233             && !strcmp(dmxInput->name, name)) {
1234                                 /* Found match */
1235             dmxLogInput(dmxInput, "Reattaching detached console input\n");
1236             return dmxInputAttachOld(dmxInput, id);
1237         }
1238     }
1240                                 /* No match found */
1241     dmxInput = dmxConfigAddInput(xstrdup(name), isCore);
1242     dmxInput->freename = TRUE;
1243     dmxLogInput(dmxInput, "Attaching new console input\n");
1244     return dmxInputAttachNew(dmxInput, id);
1247 int dmxInputAttachBackend(int physicalScreen, int isCore, int *id)
1249     DMXInputInfo  *dmxInput;
1250     DMXScreenInfo *dmxScreen;
1251     int           i;
1252     
1253     if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue;
1254     for (i = 0; i < dmxNumInputs; i++) {
1255         dmxInput = &dmxInputs[i];
1256         if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) {
1257                                 /* Found match */
1258             if (!dmxInput->detached) return BadAccess; /* Already attached */
1259             dmxScreen = &dmxScreens[physicalScreen];
1260             if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */
1261             dmxLogInput(dmxInput, "Reattaching detached backend input\n");
1262             return dmxInputAttachOld(dmxInput, id);
1263         }
1264     }
1265                                 /* No match found */
1266     dmxScreen = &dmxScreens[physicalScreen];
1267     if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */
1268     dmxInput = dmxConfigAddInput(dmxScreen->name, isCore);
1269     dmxLogInput(dmxInput, "Attaching new backend input\n");
1270     return dmxInputAttachNew(dmxInput, id);