Imported Upstream version 1.11.4
[ubuntu-omap:xserver.git] / hw / dmx / input / dmxcommon.c
1 /*
2  * Copyright 2001-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  *   David H. Dawes <dawes@xfree86.org>
31  *   Kevin E. Martin <kem@redhat.com>
32  *   Rickard E. (Rik) Faith <faith@redhat.com>
33  */
34
35 /** \file
36  *
37  * This file implements common routines used by the backend and console
38  * input devices.
39  */
40
41 #ifdef HAVE_DMX_CONFIG_H
42 #include <dmx-config.h>
43 #endif
44
45 #define DMX_STATE_DEBUG 0
46
47 #include "dmxinputinit.h"
48 #include "dmxcommon.h"
49 #include "dmxconsole.h"
50 #include "dmxprop.h"
51 #include "dmxsync.h"
52 #include "dmxmap.h"
53
54 #include "inputstr.h"
55 #include "input.h"
56 #include <X11/keysym.h>
57 #include "mipointer.h"
58 #include "scrnintstr.h"
59
60 #include <unistd.h>             /* For usleep() */
61
62 #if DMX_STATE_DEBUG
63 #define DMXDBG0(f)               dmxLog(dmxDebug,f)
64 #else
65 #define DMXDBG0(f)
66 #endif
67
68 /** Each device has a private area that is visible only from inside the
69  * driver code. */ 
70 typedef struct _myPrivate {
71     DMX_COMMON_PRIVATE;
72 } myPrivate;
73
74 static void dmxCommonKbdSetAR(Display *display,
75                               unsigned char *old, unsigned char *new)
76 {
77     XKeyboardControl kc;
78     XKeyboardState   ks;
79     unsigned long    mask = KBKey | KBAutoRepeatMode;
80     int              i, j;
81     int              minKeycode, maxKeycode;
82
83     if (!old) {
84         XGetKeyboardControl(display, &ks);
85         old = (unsigned char *)ks.auto_repeats;
86     }
87
88     XDisplayKeycodes(display, &minKeycode, &maxKeycode);
89     for (i = 1; i < 32; i++) {
90         if (!old || old[i] != new[i]) {
91             for (j = 0; j < 8; j++) {
92                 if ((new[i] & (1 << j)) != (old[i] & (1 << j))) {
93                     kc.key              = i * 8 + j;
94                     kc.auto_repeat_mode = ((new[i] & (1 << j))
95                                            ? AutoRepeatModeOn
96                                            : AutoRepeatModeOff);
97                     if (kc.key >= minKeycode && kc.key <= maxKeycode)
98                         XChangeKeyboardControl(display, mask, &kc);
99                 }
100             }
101         }
102     }
103 }
104
105 static void dmxCommonKbdSetLeds(Display *display, unsigned long new)
106 {
107     int              i;
108     XKeyboardControl kc;
109
110     for (i = 0; i < 32; i++) {
111         kc.led      = i + 1;
112         kc.led_mode = (new & (1 << i)) ? LedModeOn : LedModeOff;
113         XChangeKeyboardControl(display, KBLed | KBLedMode, &kc);
114     }
115 }
116
117 static void dmxCommonKbdSetCtrl(Display *display,
118                                 KeybdCtrl *old, KeybdCtrl *new)
119 {
120     XKeyboardControl kc;
121     unsigned long    mask = KBKeyClickPercent | KBAutoRepeatMode;
122
123     if (!old
124         || old->click         != new->click
125         || old->autoRepeat    != new->autoRepeat) {
126         
127         kc.key_click_percent = new->click;
128         kc.auto_repeat_mode  = new->autoRepeat;
129
130         XChangeKeyboardControl(display, mask, &kc);
131     }
132
133     dmxCommonKbdSetLeds(display, new->leds);
134     dmxCommonKbdSetAR(display, old ? old->autoRepeats : NULL,
135                       new->autoRepeats);
136 }
137
138 static void dmxCommonMouSetCtrl(Display *display, PtrCtrl *old, PtrCtrl *new)
139 {
140     Bool do_accel, do_threshold;
141     
142     if (!old
143         || old->num != new->num
144         || old->den != new->den
145         || old->threshold != new->threshold) {
146         do_accel     = (new->num > 0 && new->den > 0);
147         do_threshold = (new->threshold > 0);
148         if (do_accel || do_threshold) {
149             XChangePointerControl(display, do_accel, do_threshold,
150                                   new->num, new->den, new->threshold);
151         }
152     }
153 }
154
155 /** Update the keyboard control. */
156 void dmxCommonKbdCtrl(DevicePtr pDev, KeybdCtrl *ctrl)
157 {
158     GETPRIVFROMPDEV;
159
160     if (!priv->stateSaved && priv->be) dmxCommonSaveState(priv);
161     if (!priv->display || !priv->stateSaved) return;
162     dmxCommonKbdSetCtrl(priv->display,
163                         priv->kctrlset ? &priv->kctrl : NULL,
164                         ctrl);
165     priv->kctrl    = *ctrl;
166     priv->kctrlset = 1;
167 }
168
169 /** Update the mouse control. */
170 void dmxCommonMouCtrl(DevicePtr pDev, PtrCtrl *ctrl)
171 {
172     GETPRIVFROMPDEV;
173
174                                 /* Don't set the acceleration for the
175                                  * console, because that should be
176                                  * controlled by the X server that the
177                                  * console is running on.  Otherwise,
178                                  * the acceleration for the console
179                                  * window would be unexpected for the
180                                  * scale of the window. */
181     if (priv->be) {
182         dmxCommonMouSetCtrl(priv->display,
183                             priv->mctrlset ? &priv->mctrl : NULL,
184                             ctrl);
185         priv->mctrl    = *ctrl;
186         priv->mctrlset = 1;
187     }
188 }
189
190 /** Sound they keyboard bell. */
191 void dmxCommonKbdBell(DevicePtr pDev, int percent,
192                       int volume, int pitch, int duration)
193 {
194     GETPRIVFROMPDEV;
195     XKeyboardControl kc;
196     XKeyboardState   ks;
197     unsigned long    mask = KBBellPercent | KBBellPitch | KBBellDuration;
198     
199     if (!priv->be) XGetKeyboardControl(priv->display, &ks);
200     kc.bell_percent  = volume;
201     kc.bell_pitch    = pitch;
202     kc.bell_duration = duration;
203     XChangeKeyboardControl(priv->display, mask, &kc);
204     XBell(priv->display, percent);
205     if (!priv->be) {
206         kc.bell_percent  = ks.bell_percent;
207         kc.bell_pitch    = ks.bell_pitch;
208         kc.bell_duration = ks.bell_duration;
209         XChangeKeyboardControl(priv->display, mask, &kc);
210     }
211 }
212
213 /** Get the keyboard mapping. */
214 void dmxCommonKbdGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap)
215 {
216     GETPRIVFROMPDEV;
217     int             min_keycode;
218     int             max_keycode;
219     int             map_width;
220     KeySym          *keyboard_mapping;
221     XModifierKeymap *modifier_mapping;
222     int             i, j;
223
224                                 /* Compute pKeySyms.  Cast
225                                  * XGetKeyboardMapping because of
226                                  * compiler warning on 64-bit machines.
227                                  * We assume pointers to 32-bit and
228                                  * 64-bit ints are the same. */
229     XDisplayKeycodes(priv->display, &min_keycode, &max_keycode);
230     keyboard_mapping     = (KeySym *)XGetKeyboardMapping(priv->display,
231                                                          min_keycode,
232                                                          max_keycode
233                                                          - min_keycode + 1,
234                                                          &map_width);
235     pKeySyms->minKeyCode = min_keycode;
236     pKeySyms->maxKeyCode = max_keycode;
237     pKeySyms->mapWidth   = map_width;
238     pKeySyms->map        = keyboard_mapping;
239
240
241                                 /* Compute pModMap  */
242     modifier_mapping     = XGetModifierMapping(priv->display);
243     for (i = 0; i < MAP_LENGTH; i++)
244         pModMap[i] = 0;
245     for (j = 0; j < 8; j++) {
246         int max_keypermod = modifier_mapping->max_keypermod;
247         
248         for (i = 0; i < max_keypermod; i++) {
249             CARD8 keycode = modifier_mapping->modifiermap[j*max_keypermod + i];
250             if (keycode)
251                 pModMap[keycode] |= 1 << j;
252         }
253     }
254     XFreeModifiermap(modifier_mapping);
255 }
256
257 /** Fill in the XKEYBOARD parts of the \a info structure for the
258  * specified \a pDev. */
259 void dmxCommonKbdGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
260 {
261     GETPRIVFROMPDEV;
262     GETDMXINPUTFROMPRIV;
263     char *pt;
264
265     dmxCommonSaveState(priv);
266     if (priv->xkb) {
267 #define NAME(x) \
268  priv->xkb->names->x ? XGetAtomName(priv->display,priv->xkb->names->x) : NULL
269         info->names.keycodes = NAME(keycodes);
270         info->names.types    = NAME(types);
271         info->names.compat   = NAME(compat);
272         info->names.symbols  = NAME(symbols);
273         info->names.geometry = NAME(geometry);
274         info->freenames      = 1;
275 #undef NAME
276         dmxLogInput(dmxInput,
277                     "XKEYBOARD: keycodes = %s\n", info->names.keycodes);
278         dmxLogInput(dmxInput,
279                     "XKEYBOARD: symbols  = %s\n", info->names.symbols);
280         dmxLogInput(dmxInput,
281                     "XKEYBOARD: geometry = %s\n", info->names.geometry);
282         if ((pt = strchr(info->names.keycodes, '+'))) *pt = '\0';
283     }
284     dmxCommonRestoreState(priv);
285 }
286
287 /** Turn \a pDev on (i.e., take input from \a pDev). */
288 int dmxCommonKbdOn(DevicePtr pDev)
289 {
290     GETPRIVFROMPDEV;
291     if (priv->be) dmxCommonSaveState(priv);
292     priv->eventMask |= DMX_KEYBOARD_EVENT_MASK;
293     XSelectInput(priv->display, priv->window, priv->eventMask);
294     if (priv->be)
295         XSetInputFocus(priv->display, priv->window, RevertToPointerRoot,
296                        CurrentTime);
297     return -1;
298 }
299
300 /** Turn \a pDev off. */
301 void dmxCommonKbdOff(DevicePtr pDev)
302 {
303     GETPRIVFROMPDEV;
304     priv->eventMask &= ~DMX_KEYBOARD_EVENT_MASK;
305     XSelectInput(priv->display, priv->window, priv->eventMask);
306     dmxCommonRestoreState(priv);
307 }
308
309 /** Turn \a pDev on (i.e., take input from \a pDev). */
310 int dmxCommonOthOn(DevicePtr pDev)
311 {
312     GETPRIVFROMPDEV;
313     GETDMXINPUTFROMPRIV;
314     XEventClass event_list[DMX_MAX_XINPUT_EVENT_TYPES];
315     int         event_type[DMX_MAX_XINPUT_EVENT_TYPES];
316     int         count = 0;
317
318 #define ADD(type)                                                            \
319     if (count < DMX_MAX_XINPUT_EVENT_TYPES) {                                \
320         type(priv->xi, event_type[count], event_list[count]);                \
321         if (event_type[count]) {                                             \
322             dmxMapInsert(dmxLocal, event_type[count], XI_##type);            \
323             ++count;                                                         \
324         }                                                                    \
325     } else {                                                                 \
326         dmxLog(dmxWarning, "More than %d event types for %s\n",              \
327                DMX_MAX_XINPUT_EVENT_TYPES, dmxInput->name);                  \
328     }
329
330     if (!(priv->xi = XOpenDevice(priv->display, dmxLocal->deviceId))) {
331         dmxLog(dmxWarning, "Cannot open %s device (id=%d) on %s\n",
332                dmxLocal->deviceName ? dmxLocal->deviceName : "(unknown)",
333                dmxLocal->deviceId, dmxInput->name);
334         return -1;
335     }
336     ADD(DeviceKeyPress);
337     ADD(DeviceKeyRelease);
338     ADD(DeviceButtonPress);
339     ADD(DeviceButtonRelease);
340     ADD(DeviceMotionNotify);
341     ADD(DeviceFocusIn);
342     ADD(DeviceFocusOut);
343     ADD(ProximityIn);
344     ADD(ProximityOut);
345     ADD(DeviceStateNotify);
346     ADD(DeviceMappingNotify);
347     ADD(ChangeDeviceNotify);
348     XSelectExtensionEvent(priv->display, priv->window, event_list, count);
349     
350     return -1;
351 }
352
353 /** Turn \a pDev off. */
354 void dmxCommonOthOff(DevicePtr pDev)
355 {
356     GETPRIVFROMPDEV;
357     
358     if (priv->xi) XCloseDevice(priv->display, priv->xi);
359     priv->xi = NULL;
360 }
361
362 /** Fill the \a info structure with information needed to initialize \a
363  * pDev. */ 
364 void dmxCommonOthGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info)
365 {
366     GETPRIVFROMPDEV;
367     GETDMXINPUTFROMPRIV;
368     XExtensionVersion    *ext;
369     XDeviceInfo          *devices;
370     Display              *display = priv->display;
371     int                  num;
372     int                  i, j, k;
373     XextErrorHandler     handler;
374
375     if (!display && !(display = XOpenDisplay(dmxInput->name)))
376         return;
377     
378     /* Print out information about the XInput Extension. */
379     handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler);
380     ext     = XGetExtensionVersion(display, INAME);
381     XSetExtensionErrorHandler(handler);
382
383     if (ext && ext != (XExtensionVersion *)NoSuchExtension) {
384         XFree(ext);
385         devices = XListInputDevices(display, &num);
386         for (i = 0; i < num; i++) {
387             if (devices[i].id == (XID)dmxLocal->deviceId) {
388                 XAnyClassPtr     any;
389                 XKeyInfoPtr      ki;
390                 XButtonInfoPtr   bi;
391                 XValuatorInfoPtr vi;
392                 for (j = 0, any = devices[i].inputclassinfo;
393                      j < devices[i].num_classes;
394                      any = (XAnyClassPtr)((char *)any + any->length), j++) {
395                     switch (any->class) {
396                     case KeyClass:
397                         ki = (XKeyInfoPtr)any;
398                         info->keyboard           = 1;
399                         info->keyClass           = 1;
400                         info->keySyms.minKeyCode = ki->min_keycode;
401                         info->keySyms.maxKeyCode = ki->max_keycode;
402                         info->kbdFeedbackClass   = 1;
403                         break;
404                     case ButtonClass:
405                         bi = (XButtonInfoPtr)any;
406                         info->buttonClass        = 1;
407                         info->numButtons         = bi->num_buttons;
408                         info->ptrFeedbackClass   = 1;
409                         break;
410                     case ValuatorClass:
411                                 /* This assume all axes are either
412                                  * Absolute or Relative. */
413                         vi = (XValuatorInfoPtr)any;
414                         info->valuatorClass      = 1;
415                         if (vi->mode == Absolute)
416                             info->numAbsAxes     = vi->num_axes;
417                         else
418                             info->numRelAxes     = vi->num_axes;
419                         for (k = 0; k < vi->num_axes; k++) {
420                             info->res[k]         = vi->axes[k].resolution;
421                             info->minres[k]      = vi->axes[k].resolution;
422                             info->maxres[k]      = vi->axes[k].resolution;
423                             info->minval[k]      = vi->axes[k].min_value;
424                             info->maxval[k]      = vi->axes[k].max_value;
425                         }
426                         break;
427                     case FeedbackClass:
428                                 /* Only keyboard and pointer feedback
429                                  * are handled at this time. */
430                         break;
431                     case ProximityClass:
432                         info->proximityClass     = 1;
433                         break;
434                     case FocusClass:
435                         info->focusClass         = 1;
436                         break;
437                     case OtherClass:
438                         break;
439                     }
440                 }
441             }
442         }
443         XFreeDeviceList(devices);
444     }
445     if (display != priv->display) XCloseDisplay(display);
446 }
447
448 /** Obtain the mouse button mapping. */
449 void dmxCommonMouGetMap(DevicePtr pDev, unsigned char *map, int *nButtons)
450 {
451     GETPRIVFROMPDEV;
452     int i;
453     
454     *nButtons = XGetPointerMapping(priv->display, map, DMX_MAX_BUTTONS);
455     for (i = 0; i <= *nButtons; i++) map[i] = i;
456 }
457
458 static void *dmxCommonXSelect(DMXScreenInfo *dmxScreen, void *closure)
459 {
460     myPrivate *priv = closure;
461     XSelectInput(dmxScreen->beDisplay, dmxScreen->scrnWin, priv->eventMask);
462     return NULL;
463 }
464
465 static void *dmxCommonAddEnabledDevice(DMXScreenInfo *dmxScreen, void *closure)
466 {
467     AddEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
468     return NULL;
469 }
470
471 static void *dmxCommonRemoveEnabledDevice(DMXScreenInfo *dmxScreen,
472                                           void *closure)
473 {
474     RemoveEnabledDevice(XConnectionNumber(dmxScreen->beDisplay));
475     return NULL;
476 }
477
478 /** Turn \a pDev on (i.e., take input from \a pDev). */
479 int dmxCommonMouOn(DevicePtr pDev)
480 {
481     GETPRIVFROMPDEV;
482     GETDMXINPUTFROMPRIV;
483
484     priv->eventMask |= DMX_POINTER_EVENT_MASK;
485     if (dmxShadowFB) {
486         XWarpPointer(priv->display, priv->window, priv->window,
487                      0, 0, 0, 0,
488                      priv->initPointerX,
489                      priv->initPointerY);
490         dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
491     }
492     if (!priv->be) {
493         XSelectInput(priv->display, priv->window, priv->eventMask);
494         AddEnabledDevice(XConnectionNumber(priv->display));
495     } else {
496         dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
497         dmxPropertyIterate(priv->be, dmxCommonAddEnabledDevice, dmxInput);
498     }
499     
500     return -1;
501 }
502
503 /** Turn \a pDev off. */
504 void dmxCommonMouOff(DevicePtr pDev)
505 {
506     GETPRIVFROMPDEV;
507     GETDMXINPUTFROMPRIV;
508     
509     priv->eventMask &= ~DMX_POINTER_EVENT_MASK;
510     if (!priv->be) {
511         RemoveEnabledDevice(XConnectionNumber(priv->display));
512         XSelectInput(priv->display, priv->window, priv->eventMask);
513     } else {
514         dmxPropertyIterate(priv->be, dmxCommonRemoveEnabledDevice, dmxInput);
515         dmxPropertyIterate(priv->be, dmxCommonXSelect, priv);
516     }
517 }
518
519 /** Given the global coordinates \a x and \a y, determine the screen
520  * with the lowest number on which those coordinates lie.  If they are
521  * not on any screen, return -1.  The number returned is an index into
522  * \a dmxScreenInfo and is between -1 and \a dmxNumScreens - 1,
523  * inclusive. */
524 int dmxFindPointerScreen(int x, int y)
525 {
526     int i;
527
528     for (i = 0; i < dmxNumScreens; i++) {
529         ScreenPtr pScreen = screenInfo.screens[i];
530         if (x >= pScreen->x && x < pScreen->x + pScreen->width &&
531             y >= pScreen->y && y < pScreen->y + pScreen->height)
532             return i;
533     }
534     return -1;
535 }
536
537 /** Returns a pointer to the private area for the device that comes just
538  * prior to \a pDevice in the current \a dmxInput device list.  This is
539  * used as the private area for the current device in some situations
540  * (e.g., when a keyboard and mouse form a pair that should share the
541  * same private area).  If the requested private area cannot be located,
542  * then NULL is returned. */
543 pointer dmxCommonCopyPrivate(DeviceIntPtr pDevice)
544 {
545     GETDMXLOCALFROMPDEVICE;
546     DMXInputInfo *dmxInput = &dmxInputs[dmxLocal->inputIdx];
547     int          i;
548
549     for (i = 0; i < dmxInput->numDevs; i++)
550         if (dmxInput->devs[i] == dmxLocal && i)
551             return dmxInput->devs[i-1]->private;
552     return NULL;
553 }
554
555 /** This routine saves and resets some important state for the backend
556  * and console device drivers:
557  * - the modifier map is saved and set to 0 (so DMX controls the LEDs)
558  * - the key click, bell, led, and repeat masks are saved and set to the
559  * values that DMX claims to be using
560  *
561  * This routine and #dmxCommonRestoreState are used when the pointer
562  * enters and leaves the console window, or when the backend window is
563  * active or not active (for a full-screen window, this only happens at
564  * server startup and server shutdown).
565  */
566 void dmxCommonSaveState(pointer private)
567 {
568     GETPRIVFROMPRIVATE;
569     XKeyboardState   ks;
570     unsigned long    i;
571     XModifierKeymap  *modmap;
572
573     if (dmxInput->console) priv = dmxInput->devs[0]->private;
574     if (!priv->display || priv->stateSaved) return;
575     DMXDBG0("dmxCommonSaveState\n");
576     if (dmxUseXKB && (priv->xkb = XkbAllocKeyboard())) {
577         if (XkbGetIndicatorMap(priv->display, XkbAllIndicatorsMask, priv->xkb)
578             || XkbGetNames(priv->display, XkbAllNamesMask, priv->xkb)) {
579             dmxLogInput(dmxInput, "Could not get XKB information\n");
580             XkbFreeKeyboard(priv->xkb, 0, True);
581             priv->xkb = NULL;
582         } else {
583             if (priv->xkb->indicators) {
584                 priv->savedIndicators = *priv->xkb->indicators;
585                 for (i = 0; i < XkbNumIndicators; i++)
586                     if (priv->xkb->indicators->phys_indicators & (1 << i)) {
587                         priv->xkb->indicators->maps[i].flags
588                             = XkbIM_NoAutomatic;
589                     }
590                 XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
591             }
592         }
593     }
594
595     XGetKeyboardControl(priv->display, &ks);
596     priv->savedKctrl.click              = ks.key_click_percent;
597     priv->savedKctrl.bell               = ks.bell_percent;
598     priv->savedKctrl.bell_pitch         = ks.bell_pitch;
599     priv->savedKctrl.bell_duration      = ks.bell_duration;
600     priv->savedKctrl.leds               = ks.led_mask;
601     priv->savedKctrl.autoRepeat         = ks.global_auto_repeat;
602     for (i = 0; i < 32; i++)
603         priv->savedKctrl.autoRepeats[i] = ks.auto_repeats[i];
604     
605     dmxCommonKbdSetCtrl(priv->display, &priv->savedKctrl,
606                         &priv->dmxLocal->kctrl);
607
608     priv->savedModMap                   = XGetModifierMapping(priv->display);
609
610     modmap                              = XNewModifiermap(0);
611     XSetModifierMapping(priv->display, modmap);
612     if (dmxInput->scrnIdx != -1)
613         dmxSync(&dmxScreens[dmxInput->scrnIdx], TRUE);
614     XFreeModifiermap(modmap);
615
616     priv->stateSaved = 1;
617 }
618
619 /** This routine restores all the information saved by #dmxCommonSaveState. */
620 void dmxCommonRestoreState(pointer private)
621 {
622     GETPRIVFROMPRIVATE;
623     int retcode = -1;
624     CARD32 start;
625
626     if (dmxInput->console)
627         priv = dmxInput->devs[0]->private;
628     if (!priv->stateSaved)
629         return;
630     priv->stateSaved = 0;
631     
632     DMXDBG0("dmxCommonRestoreState\n");
633     if (priv->xkb) {
634         *priv->xkb->indicators = priv->savedIndicators;
635         XkbSetIndicatorMap(priv->display, ~0, priv->xkb);
636         XkbFreeKeyboard(priv->xkb, 0, True);
637         priv->xkb = 0;
638     }
639
640     for (start = GetTimeInMillis(); GetTimeInMillis() - start < 5000;) {
641         CARD32 tmp;
642         
643         retcode = XSetModifierMapping(priv->display, priv->savedModMap);
644         if (retcode == MappingSuccess)
645             break;
646         if (retcode == MappingBusy)
647             dmxLogInput(dmxInput, "Keyboard busy, waiting\n");
648         else
649             dmxLogInput(dmxInput, "Keyboard error, waiting\n");
650
651                                 /* Don't generate X11 protocol for a bit */
652         for (tmp = GetTimeInMillis(); GetTimeInMillis() - tmp < 250;) {
653             usleep(250);            /* This ends up sleeping only until
654                                      * the next key press generates an
655                                      * interruption.  We make the delay
656                                      * relatively short in case the user
657                                      * pressed they keys quickly. */
658         }
659
660     }
661     if (retcode != MappingSuccess)
662         dmxLog(dmxWarning, "Unable to restore keyboard modifier state!\n");
663     
664     XFreeModifiermap(priv->savedModMap);
665     priv->savedModMap = NULL;
666
667     dmxCommonKbdSetCtrl(priv->display, NULL, &priv->savedKctrl);
668     priv->kctrlset = 0;         /* Invalidate copy */
669 }