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