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