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        dpy->xkb_info = NULL;
616    }
617}
618
619Bool
620XkbUseExtension(Display *dpy, int *major_rtrn, int *minor_rtrn)
621{
622    xkbUseExtensionReply rep;
623    register xkbUseExtensionReq *req;
624    XExtCodes *codes;
625    int ev_base, forceIgnore;
626    XkbInfoPtr xkbi;
627    char *str;
628    static int debugMsg;
629    static int been_here = 0;
630
631    if (dpy->xkb_info && !(dpy->flags & XlibDisplayNoXkb)) {
632        if (major_rtrn)
633            *major_rtrn = dpy->xkb_info->srv_major;
634        if (minor_rtrn)
635            *minor_rtrn = dpy->xkb_info->srv_minor;
636        return True;
637    }
638    if (!been_here) {
639        debugMsg = (getenv("XKB_DEBUG") != NULL);
640        been_here = 1;
641    }
642
643    if (major_rtrn)
644        *major_rtrn = 0;
645    if (minor_rtrn)
646        *minor_rtrn = 0;
647
648    if (!dpy->xkb_info) {
649        xkbi = _XkbTypedCalloc(1, XkbInfoRec);
650        if (!xkbi)
651            return False;
652        dpy->xkb_info = xkbi;
653        dpy->free_funcs->xkb = _XkbFreeInfo;
654
655        xkbi->xlib_ctrls |= (XkbLC_ControlFallback | XkbLC_ConsumeLookupMods);
656        if ((str = getenv("_XKB_OPTIONS_ENABLE")) != NULL) {
657            if ((str = getenv("_XKB_LATIN1_LOOKUP")) != NULL) {
658                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
659                    xkbi->xlib_ctrls &= ~XkbLC_ForceLatin1Lookup;
660                else
661                    xkbi->xlib_ctrls |= XkbLC_ForceLatin1Lookup;
662            }
663            if ((str = getenv("_XKB_CONSUME_LOOKUP_MODS")) != NULL) {
664                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
665                    xkbi->xlib_ctrls &= ~XkbLC_ConsumeLookupMods;
666                else
667                    xkbi->xlib_ctrls |= XkbLC_ConsumeLookupMods;
668            }
669            if ((str = getenv("_XKB_CONSUME_SHIFT_AND_LOCK")) != NULL) {
670                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
671                    xkbi->xlib_ctrls &= ~XkbLC_AlwaysConsumeShiftAndLock;
672                else
673                    xkbi->xlib_ctrls |= XkbLC_AlwaysConsumeShiftAndLock;
674            }
675            if ((str = getenv("_XKB_IGNORE_NEW_KEYBOARDS")) != NULL) {
676                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
677                    xkbi->xlib_ctrls &= ~XkbLC_IgnoreNewKeyboards;
678                else
679                    xkbi->xlib_ctrls |= XkbLC_IgnoreNewKeyboards;
680            }
681            if ((str = getenv("_XKB_CONTROL_FALLBACK")) != NULL) {
682                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
683                    xkbi->xlib_ctrls &= ~XkbLC_ControlFallback;
684                else
685                    xkbi->xlib_ctrls |= XkbLC_ControlFallback;
686            }
687            if ((str = getenv("_XKB_COMP_LED")) != NULL) {
688                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
689                    xkbi->xlib_ctrls &= ~XkbLC_ComposeLED;
690                else {
691                    xkbi->xlib_ctrls |= XkbLC_ComposeLED;
692                    if (strlen(str) > 0)
693                        xkbi->composeLED = XInternAtom(dpy, str, False);
694                }
695            }
696            if ((str = getenv("_XKB_COMP_FAIL_BEEP")) != NULL) {
697                if ((strcmp(str, "off") == 0) || (strcmp(str, "0") == 0))
698                    xkbi->xlib_ctrls &= ~XkbLC_BeepOnComposeFail;
699                else
700                    xkbi->xlib_ctrls |= XkbLC_BeepOnComposeFail;
701            }
702        }
703        if ((xkbi->composeLED == None) &&
704            ((xkbi->xlib_ctrls & XkbLC_ComposeLED) != 0))
705            xkbi->composeLED = XInternAtom(dpy, "Compose", False);
706#ifdef DEBUG
707        if (debugMsg) {
708            register unsigned c = xkbi->xlib_ctrls;
709
710            fprintf(stderr,
711                    "XKEYBOARD compose: beep on failure is %s, LED is %s\n",
712                    ((c & XkbLC_BeepOnComposeFail) ? "on" : "off"),
713                    ((c & XkbLC_ComposeLED) ? "on" : "off"));
714            fprintf(stderr,
715                    "XKEYBOARD XLookupString: %slatin-1, %s lookup modifiers\n",
716                    ((c & XkbLC_ForceLatin1Lookup) ? "allow non-" : "force "),
717                    ((c & XkbLC_ConsumeLookupMods) ? "consume" : "re-use"));
718            fprintf(stderr,
719                    "XKEYBOARD XLookupString: %sconsume shift and lock, %scontrol fallback\n",
720                    ((c & XkbLC_AlwaysConsumeShiftAndLock) ? "always " :
721                     "don't "), ((c & XkbLC_ControlFallback) ? "" : "no "));
722
723        }
724#endif
725    }
726    else
727        xkbi = dpy->xkb_info;
728
729    forceIgnore = (dpy->flags & XlibDisplayNoXkb) || dpy->keysyms;
730    forceIgnore = forceIgnore && (major_rtrn == NULL) && (minor_rtrn == NULL);
731    if (forceIgnore || _XkbIgnoreExtension || getenv("XKB_DISABLE")) {
732        LockDisplay(dpy);
733        dpy->flags |= XlibDisplayNoXkb;
734        UnlockDisplay(dpy);
735        if (debugMsg)
736            fprintf(stderr, "XKEYBOARD extension disabled or missing\n");
737        return False;
738    }
739
740    if ((codes = XInitExtension(dpy, XkbName)) == NULL) {
741        LockDisplay(dpy);
742        dpy->flags |= XlibDisplayNoXkb;
743        UnlockDisplay(dpy);
744        if (debugMsg)
745            fprintf(stderr, "XKEYBOARD extension not present\n");
746        return False;
747    }
748    xkbi->codes = codes;
749    LockDisplay(dpy);
750
751    GetReq(kbUseExtension, req);
752    req->reqType = xkbi->codes->major_opcode;
753    req->xkbReqType = X_kbUseExtension;
754    req->wantedMajor = XkbMajorVersion;
755    req->wantedMinor = XkbMinorVersion;
756    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse) || !rep.supported) {
757        Bool fail = True;
758
759        if (debugMsg)
760            fprintf(stderr,
761                    "XKEYBOARD version mismatch (want %d.%02d, got %d.%02d)\n",
762                    XkbMajorVersion, XkbMinorVersion,
763                    rep.serverMajor, rep.serverMinor);
764
765        /* pre-release 0.65 is very close to 1.00 */
766        if ((rep.serverMajor == 0) && (rep.serverMinor == 65)) {
767            if (debugMsg)
768                fprintf(stderr, "Trying to fall back to version 0.65...");
769            GetReq(kbUseExtension, req);
770            req->reqType = xkbi->codes->major_opcode;
771            req->xkbReqType = X_kbUseExtension;
772            req->wantedMajor = 0;
773            req->wantedMinor = 65;
774            if (_XReply(dpy, (xReply *) &rep, 0, xFalse) && rep.supported) {
775                if (debugMsg)
776                    fprintf(stderr, "succeeded\n");
777                fail = False;
778            }
779            else if (debugMsg)
780                fprintf(stderr, "failed\n");
781        }
782        if (fail) {
783            dpy->flags |= XlibDisplayNoXkb;
784            UnlockDisplay(dpy);
785            SyncHandle();
786            if (major_rtrn)
787                *major_rtrn = rep.serverMajor;
788            if (minor_rtrn)
789                *minor_rtrn = rep.serverMinor;
790            return False;
791        }
792    }
793#ifdef DEBUG
794    else if (forceIgnore) {
795        fprintf(stderr,
796                "Internal Error!  XkbUseExtension succeeded with forceIgnore set\n");
797    }
798#endif
799    UnlockDisplay(dpy);
800    xkbi->srv_major = rep.serverMajor;
801    xkbi->srv_minor = rep.serverMinor;
802    if (major_rtrn)
803        *major_rtrn = rep.serverMajor;
804    if (minor_rtrn)
805        *minor_rtrn = rep.serverMinor;
806    if (debugMsg)
807        fprintf(stderr, "XKEYBOARD (version %d.%02d/%d.%02d) OK!\n",
808                XkbMajorVersion, XkbMinorVersion,
809                rep.serverMajor, rep.serverMinor);
810
811    ev_base = codes->first_event;
812    XESetWireToEvent(dpy, ev_base + XkbEventCode, wire_to_event);
813    SyncHandle();
814    return True;
815}
816