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