XKBUse.c revision 818534a1
1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30#include <stdio.h>
31#include <ctype.h>
32#include "Xlibint.h"
33#include <X11/extensions/XKBproto.h>
34#include "XKBlibint.h"
35
36static Bool _XkbIgnoreExtension = False;
37
38void
39XkbNoteMapChanges(XkbMapChangesPtr old,
40                  XkbMapNotifyEvent *new,
41                  unsigned wanted)
42{
43    int first, oldLast, newLast;
44
45    wanted &= new->changed;
46
47    if (wanted & XkbKeyTypesMask) {
48        if (old->changed & XkbKeyTypesMask) {
49            first = old->first_type;
50            oldLast = old->first_type + old->num_types - 1;
51            newLast = new->first_type + new->num_types - 1;
52
53            if (new->first_type < first)
54                first = new->first_type;
55            if (oldLast > newLast)
56                newLast = oldLast;
57            old->first_type = first;
58            old->num_types = newLast - first + 1;
59        }
60        else {
61            old->first_type = new->first_type;
62            old->num_types = new->num_types;
63        }
64    }
65    if (wanted & XkbKeySymsMask) {
66        if (old->changed & XkbKeySymsMask) {
67            first = old->first_key_sym;
68            oldLast = old->first_key_sym + old->num_key_syms - 1;
69            newLast = new->first_key_sym + new->num_key_syms - 1;
70
71            if (new->first_key_sym < first)
72                first = new->first_key_sym;
73            if (oldLast > newLast)
74                newLast = oldLast;
75            old->first_key_sym = first;
76            old->num_key_syms = newLast - first + 1;
77        }
78        else {
79            old->first_key_sym = new->first_key_sym;
80            old->num_key_syms = new->num_key_syms;
81        }
82    }
83    if (wanted & XkbKeyActionsMask) {
84        if (old->changed & XkbKeyActionsMask) {
85            first = old->first_key_act;
86            oldLast = old->first_key_act + old->num_key_acts - 1;
87            newLast = new->first_key_act + new->num_key_acts - 1;
88
89            if (new->first_key_act < first)
90                first = new->first_key_act;
91            if (oldLast > newLast)
92                newLast = oldLast;
93            old->first_key_act = first;
94            old->num_key_acts = newLast - first + 1;
95        }
96        else {
97            old->first_key_act = new->first_key_act;
98            old->num_key_acts = new->num_key_acts;
99        }
100    }
101    if (wanted & XkbKeyBehaviorsMask) {
102        if (old->changed & XkbKeyBehaviorsMask) {
103            first = old->first_key_behavior;
104            oldLast = old->first_key_behavior + old->num_key_behaviors - 1;
105            newLast = new->first_key_behavior + new->num_key_behaviors - 1;
106
107            if (new->first_key_behavior < first)
108                first = new->first_key_behavior;
109            if (oldLast > newLast)
110                newLast = oldLast;
111            old->first_key_behavior = first;
112            old->num_key_behaviors = newLast - first + 1;
113        }
114        else {
115            old->first_key_behavior = new->first_key_behavior;
116            old->num_key_behaviors = new->num_key_behaviors;
117        }
118    }
119    if (wanted & XkbVirtualModsMask) {
120        old->vmods |= new->vmods;
121    }
122    if (wanted & XkbExplicitComponentsMask) {
123        if (old->changed & XkbExplicitComponentsMask) {
124            first = old->first_key_explicit;
125            oldLast = old->first_key_explicit + old->num_key_explicit - 1;
126            newLast = new->first_key_explicit + new->num_key_explicit - 1;
127
128            if (new->first_key_explicit < first)
129                first = new->first_key_explicit;
130            if (oldLast > newLast)
131                newLast = oldLast;
132            old->first_key_explicit = first;
133            old->num_key_explicit = newLast - first + 1;
134        }
135        else {
136            old->first_key_explicit = new->first_key_explicit;
137            old->num_key_explicit = new->num_key_explicit;
138        }
139    }
140    if (wanted & XkbModifierMapMask) {
141        if (old->changed & XkbModifierMapMask) {
142            first = old->first_modmap_key;
143            oldLast = old->first_modmap_key + old->num_modmap_keys - 1;
144            newLast = new->first_modmap_key + new->num_modmap_keys - 1;
145
146            if (new->first_modmap_key < first)
147                first = new->first_modmap_key;
148            if (oldLast > newLast)
149                newLast = oldLast;
150            old->first_modmap_key = first;
151            old->num_modmap_keys = newLast - first + 1;
152        }
153        else {
154            old->first_modmap_key = new->first_modmap_key;
155            old->num_modmap_keys = new->num_modmap_keys;
156        }
157    }
158    if (wanted & XkbVirtualModMapMask) {
159        if (old->changed & XkbVirtualModMapMask) {
160            first = old->first_vmodmap_key;
161            oldLast = old->first_vmodmap_key + old->num_vmodmap_keys - 1;
162            newLast = new->first_vmodmap_key + new->num_vmodmap_keys - 1;
163
164            if (new->first_vmodmap_key < first)
165                first = new->first_vmodmap_key;
166            if (oldLast > newLast)
167                newLast = oldLast;
168            old->first_vmodmap_key = first;
169            old->num_vmodmap_keys = newLast - first + 1;
170        }
171        else {
172            old->first_vmodmap_key = new->first_vmodmap_key;
173            old->num_vmodmap_keys = new->num_vmodmap_keys;
174        }
175    }
176    old->changed |= wanted;
177    return;
178}
179
180void
181_XkbNoteCoreMapChanges(XkbMapChangesPtr old,
182                       XMappingEvent *new,
183                       unsigned int wanted)
184{
185    int first, oldLast, newLast;
186
187    if ((new->request == MappingKeyboard) && (wanted & XkbKeySymsMask)) {
188        if (old->changed & XkbKeySymsMask) {
189            first = old->first_key_sym;
190            oldLast = old->first_key_sym + old->num_key_syms - 1;
191            newLast = new->first_keycode + new->count - 1;
192
193            if (new->first_keycode < first)
194                first = new->first_keycode;
195            if (oldLast > newLast)
196                newLast = oldLast;
197            old->first_key_sym = first;
198            old->num_key_syms = newLast - first + 1;
199        }
200        else {
201            old->changed |= XkbKeySymsMask;
202            old->first_key_sym = new->first_keycode;
203            old->num_key_syms = new->count;
204        }
205    }
206    return;
207}
208
209static Bool
210wire_to_event(Display *dpy, XEvent *re, xEvent *event)
211{
212    xkbEvent *xkbevent = (xkbEvent *) event;
213    XkbInfoPtr xkbi;
214
215    if ((dpy->flags & XlibDisplayNoXkb) ||
216        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
217        return False;
218    xkbi = dpy->xkb_info;
219    if (((event->u.u.type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
220        return False;
221
222    switch (xkbevent->u.any.xkbType) {
223    case XkbStateNotify:
224    {
225        xkbStateNotify *sn = (xkbStateNotify *) event;
226
227        if (xkbi->selected_events & XkbStateNotifyMask) {
228            XkbStateNotifyEvent *sev = (XkbStateNotifyEvent *) re;
229
230            sev->type = XkbEventCode + xkbi->codes->first_event;
231            sev->xkb_type = XkbStateNotify;
232            sev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
233            sev->send_event = ((event->u.u.type & 0x80) != 0);
234            sev->display = dpy;
235            sev->time = sn->time;
236            sev->device = sn->deviceID;
237            sev->keycode = sn->keycode;
238            sev->event_type = sn->eventType;
239            sev->req_major = sn->requestMajor;
240            sev->req_minor = sn->requestMinor;
241            sev->changed = sn->changed;
242            sev->group = sn->group;
243            sev->base_group = sn->baseGroup;
244            sev->latched_group = sn->latchedGroup;
245            sev->locked_group = sn->lockedGroup;
246            sev->mods = sn->mods;
247            sev->base_mods = sn->baseMods;
248            sev->latched_mods = sn->latchedMods;
249            sev->locked_mods = sn->lockedMods;
250            sev->compat_state = sn->compatState;
251            sev->grab_mods = sn->grabMods;
252            sev->compat_grab_mods = sn->compatGrabMods;
253            sev->lookup_mods = sn->lookupMods;
254            sev->compat_lookup_mods = sn->compatLookupMods;
255            sev->ptr_buttons = sn->ptrBtnState;
256            return True;
257        }
258    }
259        break;
260    case XkbMapNotify:
261    {
262        xkbMapNotify *mn = (xkbMapNotify *) event;
263
264        if ((xkbi->selected_events & XkbMapNotifyMask) &&
265            (xkbi->selected_map_details & mn->changed)) {
266            XkbMapNotifyEvent *mev = (XkbMapNotifyEvent *) re;
267
268            mev->type = XkbEventCode + xkbi->codes->first_event;
269            mev->xkb_type = XkbMapNotify;
270            mev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
271            mev->send_event = ((event->u.u.type & 0x80) != 0);
272            mev->display = dpy;
273            mev->time = mn->time;
274            mev->device = mn->deviceID;
275            mev->changed = mn->changed;
276            mev->min_key_code = mn->minKeyCode;
277            mev->max_key_code = mn->maxKeyCode;
278            mev->first_type = mn->firstType;
279            mev->num_types = mn->nTypes;
280            mev->first_key_sym = mn->firstKeySym;
281            mev->num_key_syms = mn->nKeySyms;
282            mev->first_key_act = mn->firstKeyAct;
283            mev->num_key_acts = mn->nKeyActs;
284            mev->first_key_behavior = mn->firstKeyBehavior;
285            mev->num_key_behaviors = mn->nKeyBehaviors;
286            mev->vmods = mn->virtualMods;
287            mev->first_key_explicit = mn->firstKeyExplicit;
288            mev->num_key_explicit = mn->nKeyExplicit;
289            mev->first_modmap_key = mn->firstModMapKey;
290            mev->num_modmap_keys = mn->nModMapKeys;
291            mev->first_vmodmap_key = mn->firstVModMapKey;
292            mev->num_vmodmap_keys = mn->nVModMapKeys;
293            XkbNoteMapChanges(&xkbi->changes, mev, XKB_XLIB_MAP_MASK);
294            if (xkbi->changes.changed)
295                xkbi->flags |= XkbMapPending;
296            return True;
297        }
298        else if (mn->nKeySyms > 0) {
299            register XMappingEvent *ev = (XMappingEvent *) re;
300
301            ev->type = MappingNotify;
302            ev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
303            ev->send_event = ((event->u.u.type & 0x80) != 0);
304            ev->display = dpy;
305            ev->window = 0;
306            ev->first_keycode = mn->firstKeySym;
307            ev->request = MappingKeyboard;
308            ev->count = mn->nKeySyms;
309            _XkbNoteCoreMapChanges(&xkbi->changes, ev, XKB_XLIB_MAP_MASK);
310            if (xkbi->changes.changed)
311                xkbi->flags |= XkbMapPending;
312            return True;
313        }
314    }
315        break;
316    case XkbControlsNotify:
317    {
318        if (xkbi->selected_events & XkbControlsNotifyMask) {
319            xkbControlsNotify *cn = (xkbControlsNotify *) event;
320            XkbControlsNotifyEvent *cev = (XkbControlsNotifyEvent *) re;
321
322            cev->type = XkbEventCode + xkbi->codes->first_event;
323            cev->xkb_type = XkbControlsNotify;
324            cev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
325            cev->send_event = ((event->u.u.type & 0x80) != 0);
326            cev->display = dpy;
327            cev->time = cn->time;
328            cev->device = cn->deviceID;
329            cev->changed_ctrls = cn->changedControls;
330            cev->enabled_ctrls = cn->enabledControls;
331            cev->enabled_ctrl_changes = cn->enabledControlChanges;
332            cev->keycode = cn->keycode;
333            cev->num_groups = cn->numGroups;
334            cev->event_type = cn->eventType;
335            cev->req_major = cn->requestMajor;
336            cev->req_minor = cn->requestMinor;
337            return True;
338        }
339    }
340        break;
341    case XkbIndicatorMapNotify:
342    {
343        if (xkbi->selected_events & XkbIndicatorMapNotifyMask) {
344            xkbIndicatorNotify *in = (xkbIndicatorNotify *) event;
345            XkbIndicatorNotifyEvent *iev = (XkbIndicatorNotifyEvent *) re;
346
347            iev->type = XkbEventCode + xkbi->codes->first_event;
348            iev->xkb_type = XkbIndicatorMapNotify;
349            iev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
350            iev->send_event = ((event->u.u.type & 0x80) != 0);
351            iev->display = dpy;
352            iev->time = in->time;
353            iev->device = in->deviceID;
354            iev->changed = in->changed;
355            iev->state = in->state;
356            return True;
357        }
358    }
359        break;
360    case XkbIndicatorStateNotify:
361    {
362        if (xkbi->selected_events & XkbIndicatorStateNotifyMask) {
363            xkbIndicatorNotify *in = (xkbIndicatorNotify *) event;
364            XkbIndicatorNotifyEvent *iev = (XkbIndicatorNotifyEvent *) re;
365
366            iev->type = XkbEventCode + xkbi->codes->first_event;
367            iev->xkb_type = XkbIndicatorStateNotify;
368            iev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
369            iev->send_event = ((event->u.u.type & 0x80) != 0);
370            iev->display = dpy;
371            iev->time = in->time;
372            iev->device = in->deviceID;
373            iev->changed = in->changed;
374            iev->state = in->state;
375            return True;
376        }
377    }
378        break;
379    case XkbBellNotify:
380    {
381        if (xkbi->selected_events & XkbBellNotifyMask) {
382            xkbBellNotify *bn = (xkbBellNotify *) event;
383            XkbBellNotifyEvent *bev = (XkbBellNotifyEvent *) re;
384
385            bev->type = XkbEventCode + xkbi->codes->first_event;
386            bev->xkb_type = XkbBellNotify;
387            bev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
388            bev->send_event = ((event->u.u.type & 0x80) != 0);
389            bev->display = dpy;
390            bev->time = bn->time;
391            bev->device = bn->deviceID;
392            bev->percent = bn->percent;
393            bev->pitch = bn->pitch;
394            bev->duration = bn->duration;
395            bev->bell_class = bn->bellClass;
396            bev->bell_id = bn->bellID;
397            bev->name = bn->name;
398            bev->window = bn->window;
399            bev->event_only = bn->eventOnly;
400            return True;
401        }
402    }
403        break;
404    case XkbAccessXNotify:
405    {
406        if (xkbi->selected_events & XkbAccessXNotifyMask) {
407            xkbAccessXNotify *axn = (xkbAccessXNotify *) event;
408            XkbAccessXNotifyEvent *axev = (XkbAccessXNotifyEvent *) re;
409
410            axev->type = XkbEventCode + xkbi->codes->first_event;
411            axev->xkb_type = XkbAccessXNotify;
412            axev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
413            axev->send_event = ((event->u.u.type & 0x80) != 0);
414            axev->display = dpy;
415            axev->time = axn->time;
416            axev->device = axn->deviceID;
417            axev->detail = axn->detail;
418            axev->keycode = axn->keycode;
419            axev->sk_delay = axn->slowKeysDelay;
420            axev->debounce_delay = axn->debounceDelay;
421            return True;
422        }
423    }
424        break;
425    case XkbNamesNotify:
426    {
427        if (xkbi->selected_events & XkbNamesNotifyMask) {
428            xkbNamesNotify *nn = (xkbNamesNotify *) event;
429            XkbNamesNotifyEvent *nev = (XkbNamesNotifyEvent *) re;
430
431            nev->type = XkbEventCode + xkbi->codes->first_event;
432            nev->xkb_type = XkbNamesNotify;
433            nev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
434            nev->send_event = ((event->u.u.type & 0x80) != 0);
435            nev->display = dpy;
436            nev->time = nn->time;
437            nev->device = nn->deviceID;
438            nev->changed = nn->changed;
439            nev->first_type = nn->firstType;
440            nev->num_types = nn->nTypes;
441            nev->first_lvl = nn->firstLevelName;
442            nev->num_lvls = nn->nLevelNames;
443            nev->num_aliases = nn->nAliases;
444            nev->num_radio_groups = nn->nRadioGroups;
445            nev->changed_vmods = nn->changedVirtualMods;
446            nev->changed_groups = nn->changedGroupNames;
447            nev->changed_indicators = nn->changedIndicators;
448            nev->first_key = nn->firstKey;
449            nev->num_keys = nn->nKeys;
450            return True;
451        }
452    }
453        break;
454    case XkbCompatMapNotify:
455    {
456        if (xkbi->selected_events & XkbCompatMapNotifyMask) {
457            xkbCompatMapNotify *cmn = (xkbCompatMapNotify *) event;
458            XkbCompatMapNotifyEvent *cmev = (XkbCompatMapNotifyEvent *) re;
459
460            cmev->type = XkbEventCode + xkbi->codes->first_event;
461            cmev->xkb_type = XkbCompatMapNotify;
462            cmev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
463            cmev->send_event = ((event->u.u.type & 0x80) != 0);
464            cmev->display = dpy;
465            cmev->time = cmn->time;
466            cmev->device = cmn->deviceID;
467            cmev->changed_groups = cmn->changedGroups;
468            cmev->first_si = cmn->firstSI;
469            cmev->num_si = cmn->nSI;
470            cmev->num_total_si = cmn->nTotalSI;
471            return True;
472        }
473    }
474        break;
475    case XkbActionMessage:
476    {
477        if (xkbi->selected_events & XkbActionMessageMask) {
478            xkbActionMessage *am = (xkbActionMessage *) event;
479            XkbActionMessageEvent *amev = (XkbActionMessageEvent *) re;
480
481            amev->type = XkbEventCode + xkbi->codes->first_event;
482            amev->xkb_type = XkbActionMessage;
483            amev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
484            amev->send_event = ((event->u.u.type & 0x80) != 0);
485            amev->display = dpy;
486            amev->time = am->time;
487            amev->device = am->deviceID;
488            amev->keycode = am->keycode;
489            amev->press = am->press;
490            amev->key_event_follows = am->keyEventFollows;
491            amev->group = am->group;
492            amev->mods = am->mods;
493            memcpy(amev->message, am->message, XkbActionMessageLength);
494            amev->message[XkbActionMessageLength] = '\0';
495            return True;
496        }
497    }
498        break;
499    case XkbExtensionDeviceNotify:
500    {
501        if (xkbi->selected_events & XkbExtensionDeviceNotifyMask) {
502            xkbExtensionDeviceNotify *ed = (xkbExtensionDeviceNotify *) event;
503            XkbExtensionDeviceNotifyEvent *edev
504                = (XkbExtensionDeviceNotifyEvent *) re;
505
506            edev->type = XkbEventCode + xkbi->codes->first_event;
507            edev->xkb_type = XkbExtensionDeviceNotify;
508            edev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
509            edev->send_event = ((event->u.u.type & 0x80) != 0);
510            edev->display = dpy;
511            edev->time = ed->time;
512            edev->device = ed->deviceID;
513            edev->led_class = ed->ledClass;
514            edev->led_id = ed->ledID;
515            edev->reason = ed->reason;
516            edev->supported = ed->supported;
517            edev->leds_defined = ed->ledsDefined;
518            edev->led_state = ed->ledState;
519            edev->first_btn = ed->firstBtn;
520            edev->num_btns = ed->nBtns;
521            edev->unsupported = ed->unsupported;
522            return True;
523        }
524    }
525        break;
526    case XkbNewKeyboardNotify:
527    {
528        xkbNewKeyboardNotify *nkn = (xkbNewKeyboardNotify *) event;
529
530        if ((xkbi->selected_events & XkbNewKeyboardNotifyMask) &&
531            (xkbi->selected_nkn_details & nkn->changed)) {
532            XkbNewKeyboardNotifyEvent *nkev = (XkbNewKeyboardNotifyEvent *) re;
533
534            nkev->type = XkbEventCode + xkbi->codes->first_event;
535            nkev->xkb_type = XkbNewKeyboardNotify;
536            nkev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
537            nkev->send_event = ((event->u.u.type & 0x80) != 0);
538            nkev->display = dpy;
539            nkev->time = nkn->time;
540            nkev->device = nkn->deviceID;
541            nkev->old_device = nkn->oldDeviceID;
542            nkev->min_key_code = nkn->minKeyCode;
543            nkev->max_key_code = nkn->maxKeyCode;
544            nkev->old_min_key_code = nkn->oldMinKeyCode;
545            nkev->old_max_key_code = nkn->oldMaxKeyCode;
546            nkev->req_major = nkn->requestMajor;
547            nkev->req_minor = nkn->requestMinor;
548            nkev->changed = nkn->changed;
549            if ((xkbi->desc) && (nkev->send_event == 0) &&
550                ((xkbi->desc->device_spec == nkev->old_device) ||
551                 (nkev->device != nkev->old_device))) {
552                xkbi->flags = XkbMapPending | XkbXlibNewKeyboard;
553            }
554            return True;
555        }
556        else if (nkn->changed & (XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask)) {
557            register XMappingEvent *ev = (XMappingEvent *) re;
558
559            ev->type = MappingNotify;
560            ev->serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
561            ev->send_event = ((event->u.u.type & 0x80) != 0);
562            ev->display = dpy;
563            ev->window = 0;
564            ev->first_keycode = dpy->min_keycode;
565            ev->request = MappingKeyboard;
566            ev->count = (dpy->max_keycode - dpy->min_keycode) + 1;
567            if ((xkbi->desc) && (ev->send_event == 0) &&
568                ((xkbi->desc->device_spec == nkn->oldDeviceID) ||
569                 (nkn->deviceID != nkn->oldDeviceID))) {
570                xkbi->flags |= XkbMapPending | XkbXlibNewKeyboard;
571            }
572            return True;
573        }
574    }
575        break;
576    default:
577#ifdef DEBUG
578        fprintf(stderr, "Got unknown XKEYBOARD event (%d, base=%d)\n",
579                re->type, xkbi->codes->first_event);
580#endif
581        break;
582    }
583    return False;
584}
585
586Bool
587XkbIgnoreExtension(Bool ignore)
588{
589    if (getenv("XKB_FORCE") != NULL) {
590#ifdef DEBUG
591        fprintf(stderr,
592                "Forcing use of XKEYBOARD (overriding an IgnoreExtensions)\n");
593#endif
594        return False;
595    }
596#ifdef DEBUG
597    else if (getenv("XKB_DEBUG") != NULL) {
598        fprintf(stderr, "Explicitly %signoring XKEYBOARD\n",
599                ignore ? "" : "not ");
600    }
601#endif
602    _XkbIgnoreExtension = ignore;
603    return True;
604}
605
606static void
607_XkbFreeInfo(Display *dpy)
608{
609    XkbInfoPtr xkbi = dpy->xkb_info;
610
611    if (xkbi) {
612        if (xkbi->desc)
613            XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
614        Xfree(xkbi);
615    }
616}
617
618Bool
619XkbUseExtension(Display *dpy, int *major_rtrn, int *minor_rtrn)
620{
621    xkbUseExtensionReply rep;
622    register xkbUseExtensionReq *req;
623    XExtCodes *codes;
624    int ev_base, forceIgnore;
625    XkbInfoPtr xkbi;
626    char *str;
627    static int debugMsg;
628    static int been_here = 0;
629
630    if (dpy->xkb_info && !(dpy->flags & XlibDisplayNoXkb)) {
631        if (major_rtrn)
632            *major_rtrn = dpy->xkb_info->srv_major;
633        if (minor_rtrn)
634            *minor_rtrn = dpy->xkb_info->srv_minor;
635        return True;
636    }
637    if (!been_here) {
638        debugMsg = (getenv("XKB_DEBUG") != NULL);
639        been_here = 1;
640    }
641
642    if (major_rtrn)
643        *major_rtrn = 0;
644    if (minor_rtrn)
645        *minor_rtrn = 0;
646
647    if (!dpy->xkb_info) {
648        xkbi = _XkbTypedCalloc(1, XkbInfoRec);
649        if (!xkbi)
650            return False;
651        dpy->xkb_info = xkbi;
652        dpy->free_funcs->xkb = _XkbFreeInfo;
653
654        xkbi->xlib_ctrls |= (XkbLC_ControlFallback | XkbLC_ConsumeLookupMods);
655        if ((str = getenv("_XKB_OPTIONS_ENABLE")) != NULL) {
656            if ((str = getenv("_XKB_LATIN1_LOOKUP")) != NULL) {
657                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
658                    xkbi->xlib_ctrls &= ~XkbLC_ForceLatin1Lookup;
659                else
660                    xkbi->xlib_ctrls |= XkbLC_ForceLatin1Lookup;
661            }
662            if ((str = getenv("_XKB_CONSUME_LOOKUP_MODS")) != NULL) {
663                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
664                    xkbi->xlib_ctrls &= ~XkbLC_ConsumeLookupMods;
665                else
666                    xkbi->xlib_ctrls |= XkbLC_ConsumeLookupMods;
667            }
668            if ((str = getenv("_XKB_CONSUME_SHIFT_AND_LOCK")) != NULL) {
669                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
670                    xkbi->xlib_ctrls &= ~XkbLC_AlwaysConsumeShiftAndLock;
671                else
672                    xkbi->xlib_ctrls |= XkbLC_AlwaysConsumeShiftAndLock;
673            }
674            if ((str = getenv("_XKB_IGNORE_NEW_KEYBOARDS")) != NULL) {
675                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
676                    xkbi->xlib_ctrls &= ~XkbLC_IgnoreNewKeyboards;
677                else
678                    xkbi->xlib_ctrls |= XkbLC_IgnoreNewKeyboards;
679            }
680            if ((str = getenv("_XKB_CONTROL_FALLBACK")) != NULL) {
681                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
682                    xkbi->xlib_ctrls &= ~XkbLC_ControlFallback;
683                else
684                    xkbi->xlib_ctrls |= XkbLC_ControlFallback;
685            }
686            if ((str = getenv("_XKB_COMP_LED")) != NULL) {
687                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
688                    xkbi->xlib_ctrls &= ~XkbLC_ComposeLED;
689                else {
690                    xkbi->xlib_ctrls |= XkbLC_ComposeLED;
691                    if (strlen(str) > 0)
692                        xkbi->composeLED = XInternAtom(dpy, str, False);
693                }
694            }
695            if ((str = getenv("_XKB_COMP_FAIL_BEEP")) != NULL) {
696                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
697                    xkbi->xlib_ctrls &= ~XkbLC_BeepOnComposeFail;
698                else
699                    xkbi->xlib_ctrls |= XkbLC_BeepOnComposeFail;
700            }
701        }
702        if ((xkbi->composeLED == None) &&
703            ((xkbi->xlib_ctrls & XkbLC_ComposeLED) != 0))
704            xkbi->composeLED = XInternAtom(dpy, "Compose", False);
705#ifdef DEBUG
706        if (debugMsg) {
707            register unsigned c = xkbi->xlib_ctrls;
708
709            fprintf(stderr,
710                    "XKEYBOARD compose: beep on failure is %s, LED is %s\n",
711                    ((c & XkbLC_BeepOnComposeFail) ? "on" : "off"),
712                    ((c & XkbLC_ComposeLED) ? "on" : "off"));
713            fprintf(stderr,
714                    "XKEYBOARD XLookupString: %slatin-1, %s lookup modifiers\n",
715                    ((c & XkbLC_ForceLatin1Lookup) ? "allow non-" : "force "),
716                    ((c & XkbLC_ConsumeLookupMods) ? "consume" : "re-use"));
717            fprintf(stderr,
718                    "XKEYBOARD XLookupString: %sconsume shift and lock, %scontrol fallback\n",
719                    ((c & XkbLC_AlwaysConsumeShiftAndLock) ? "always " :
720                     "don't "), ((c & XkbLC_ControlFallback) ? "" : "no "));
721
722        }
723#endif
724    }
725    else
726        xkbi = dpy->xkb_info;
727
728    forceIgnore = (dpy->flags & XlibDisplayNoXkb) || dpy->keysyms;
729    forceIgnore = forceIgnore && (major_rtrn == NULL) && (minor_rtrn == NULL);
730    if (forceIgnore || _XkbIgnoreExtension || getenv("XKB_DISABLE")) {
731        LockDisplay(dpy);
732        dpy->flags |= XlibDisplayNoXkb;
733        UnlockDisplay(dpy);
734        if (debugMsg)
735            fprintf(stderr, "XKEYBOARD extension disabled or missing\n");
736        return False;
737    }
738
739    if ((codes = XInitExtension(dpy, XkbName)) == NULL) {
740        LockDisplay(dpy);
741        dpy->flags |= XlibDisplayNoXkb;
742        UnlockDisplay(dpy);
743        if (debugMsg)
744            fprintf(stderr, "XKEYBOARD extension not present\n");
745        return False;
746    }
747    xkbi->codes = codes;
748    LockDisplay(dpy);
749
750    GetReq(kbUseExtension, req);
751    req->reqType = xkbi->codes->major_opcode;
752    req->xkbReqType = X_kbUseExtension;
753    req->wantedMajor = XkbMajorVersion;
754    req->wantedMinor = XkbMinorVersion;
755    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse) || !rep.supported) {
756        Bool fail = True;
757
758        if (debugMsg)
759            fprintf(stderr,
760                    "XKEYBOARD version mismatch (want %d.%02d, got %d.%02d)\n",
761                    XkbMajorVersion, XkbMinorVersion,
762                    rep.serverMajor, rep.serverMinor);
763
764        /* pre-release 0.65 is very close to 1.00 */
765        if ((rep.serverMajor == 0) && (rep.serverMinor == 65)) {
766            if (debugMsg)
767                fprintf(stderr, "Trying to fall back to version 0.65...");
768            GetReq(kbUseExtension, req);
769            req->reqType = xkbi->codes->major_opcode;
770            req->xkbReqType = X_kbUseExtension;
771            req->wantedMajor = 0;
772            req->wantedMinor = 65;
773            if (_XReply(dpy, (xReply *) &rep, 0, xFalse) && rep.supported) {
774                if (debugMsg)
775                    fprintf(stderr, "succeeded\n");
776                fail = False;
777            }
778            else if (debugMsg)
779                fprintf(stderr, "failed\n");
780        }
781        if (fail) {
782            dpy->flags |= XlibDisplayNoXkb;
783            UnlockDisplay(dpy);
784            SyncHandle();
785            if (major_rtrn)
786                *major_rtrn = rep.serverMajor;
787            if (minor_rtrn)
788                *minor_rtrn = rep.serverMinor;
789            return False;
790        }
791    }
792#ifdef DEBUG
793    else if (forceIgnore) {
794        fprintf(stderr,
795                "Internal Error!  XkbUseExtension succeeded with forceIgnore set\n");
796    }
797#endif
798    UnlockDisplay(dpy);
799    xkbi->srv_major = rep.serverMajor;
800    xkbi->srv_minor = rep.serverMinor;
801    if (major_rtrn)
802        *major_rtrn = rep.serverMajor;
803    if (minor_rtrn)
804        *minor_rtrn = rep.serverMinor;
805    if (debugMsg)
806        fprintf(stderr, "XKEYBOARD (version %d.%02d/%d.%02d) OK!\n",
807                XkbMajorVersion, XkbMinorVersion,
808                rep.serverMajor, rep.serverMinor);
809
810    ev_base = codes->first_event;
811    XESetWireToEvent(dpy, ev_base + XkbEventCode, wire_to_event);
812    SyncHandle();
813    return True;
814}
815