XKB.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 "Xlibint.h"
32#include <X11/extensions/XKBproto.h>
33#include "XKBlibint.h"
34
35XkbInternAtomFunc       _XkbInternAtomFunc  = XInternAtom;
36XkbGetAtomNameFunc      _XkbGetAtomNameFunc = XGetAtomName;
37
38Bool
39XkbQueryExtension(Display *dpy,
40                  int *opcodeReturn,
41                  int *eventBaseReturn,
42                  int *errorBaseReturn,
43                  int *majorReturn,
44                  int *minorReturn)
45{
46    if (!XkbUseExtension(dpy, majorReturn, minorReturn))
47        return False;
48    if (opcodeReturn)
49        *opcodeReturn = dpy->xkb_info->codes->major_opcode;
50    if (eventBaseReturn)
51        *eventBaseReturn = dpy->xkb_info->codes->first_event;
52    if (errorBaseReturn)
53        *errorBaseReturn = dpy->xkb_info->codes->first_error;
54    if (majorReturn)
55        *majorReturn = dpy->xkb_info->srv_major;
56    if (minorReturn)
57        *minorReturn = dpy->xkb_info->srv_minor;
58    return True;
59}
60
61Bool
62XkbLibraryVersion(int *libMajorRtrn, int *libMinorRtrn)
63{
64    int supported;
65
66    if (*libMajorRtrn != XkbMajorVersion) {
67        /* version 0.65 is (almost) compatible with 1.00 */
68        if ((XkbMajorVersion == 1) &&
69            (((*libMajorRtrn) == 0) && ((*libMinorRtrn) == 65)))
70            supported = True;
71        else
72            supported = False;
73    }
74    else {
75        supported = True;
76    }
77
78    *libMajorRtrn = XkbMajorVersion;
79    *libMinorRtrn = XkbMinorVersion;
80    return supported;
81}
82
83Bool
84XkbSelectEvents(Display *dpy,
85                unsigned int deviceSpec,
86                unsigned int affect,
87                unsigned int selectAll)
88{
89    register xkbSelectEventsReq *req;
90    XkbInfoPtr xkbi;
91
92    if ((dpy->flags & XlibDisplayNoXkb) ||
93        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
94        return False;
95    LockDisplay(dpy);
96    xkbi = dpy->xkb_info;
97    xkbi->selected_events &= ~affect;
98    xkbi->selected_events |= (affect & selectAll);
99    GetReq(kbSelectEvents, req);
100    req->reqType = xkbi->codes->major_opcode;
101    req->xkbReqType = X_kbSelectEvents;
102    req->deviceSpec = deviceSpec;
103    req->affectWhich = (CARD16) affect;
104    req->clear = affect & (~selectAll);
105    req->selectAll = affect & selectAll;
106    if (affect & XkbMapNotifyMask) {
107        req->affectMap = XkbAllMapComponentsMask;
108        /* the implicit support needs the client info */
109        /* even if the client itself doesn't want it */
110        if (selectAll & XkbMapNotifyMask)
111            req->map = XkbAllMapEventsMask;
112        else
113            req->map = XkbAllClientInfoMask;
114        if (selectAll & XkbMapNotifyMask)
115            xkbi->selected_map_details = XkbAllMapEventsMask;
116        else
117            xkbi->selected_map_details = 0;
118    }
119    if (affect & XkbNewKeyboardNotifyMask) {
120        if (selectAll & XkbNewKeyboardNotifyMask)
121            xkbi->selected_nkn_details = XkbAllNewKeyboardEventsMask;
122        else
123            xkbi->selected_nkn_details = 0;
124        if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
125            /* we want it, even if the client doesn't.  Don't mess */
126            /* around with details -- ask for all of them and throw */
127            /* away the ones we don't need */
128            req->selectAll |= XkbNewKeyboardNotifyMask;
129        }
130    }
131    UnlockDisplay(dpy);
132    SyncHandle();
133    return True;
134}
135
136Bool
137XkbSelectEventDetails(Display *dpy,
138                      unsigned deviceSpec,
139                      unsigned eventType,
140                      unsigned long int affect,
141                      unsigned long int details)
142{
143    register xkbSelectEventsReq *req;
144    XkbInfoPtr  xkbi;
145    int         size = 0;
146    char        *out;
147    union {
148        CARD8   *c8;
149        CARD16  *c16;
150        CARD32  *c32;
151    } u;
152
153    if ((dpy->flags & XlibDisplayNoXkb) ||
154        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
155        return False;
156    LockDisplay(dpy);
157    xkbi = dpy->xkb_info;
158    if (affect & details)
159        xkbi->selected_events |= (1 << eventType);
160    else
161        xkbi->selected_events &= ~(1 << eventType);
162    GetReq(kbSelectEvents, req);
163    req->reqType = xkbi->codes->major_opcode;
164    req->xkbReqType = X_kbSelectEvents;
165    req->deviceSpec = deviceSpec;
166    req->clear = req->selectAll = 0;
167    if (eventType == XkbMapNotify) {
168        /* we need all of the client info, even if the application */
169        /* doesn't.   Make sure that we always request the stuff */
170        /* that the implicit support needs, and just filter out anything */
171        /* the client doesn't want later */
172        req->affectWhich = 0;
173        req->selectAll = 0;
174        req->clear = 0;
175        req->affectMap = (CARD16) affect;
176        req->map = (CARD16) details | (XkbAllClientInfoMask & affect);
177        req->affectWhich = XkbMapNotifyMask;
178        xkbi->selected_map_details &= ~affect;
179        xkbi->selected_map_details |= (details & affect);
180    }
181    else {
182        req->affectMap = req->map = 0;
183        req->affectWhich = (1 << eventType);
184        switch (eventType) {
185        case XkbNewKeyboardNotify:
186            xkbi->selected_nkn_details &= ~affect;
187            xkbi->selected_nkn_details |= (details & affect);
188            if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards))
189                details = (affect & XkbAllNewKeyboardEventsMask);
190        case XkbStateNotify:
191        case XkbNamesNotify:
192        case XkbAccessXNotify:
193        case XkbExtensionDeviceNotify:
194            size = 2;
195            req->length += 1;
196            break;
197        case XkbControlsNotify:
198        case XkbIndicatorStateNotify:
199        case XkbIndicatorMapNotify:
200            size = 4;
201            req->length += 2;
202            break;
203        case XkbBellNotify:
204        case XkbActionMessage:
205        case XkbCompatMapNotify:
206            size = 1;
207            req->length += 1;
208            break;
209        }
210        BufAlloc(char *, out, (((size * 2) + (unsigned) 3) / 4) * 4);
211
212        u.c8 = (CARD8 *) out;
213        if (size == 2) {
214            u.c16[0] = (CARD16) affect;
215            u.c16[1] = (CARD16) details;
216        }
217        else if (size == 4) {
218            u.c32[0] = (CARD32) affect;
219            u.c32[1] = (CARD32) details;
220        }
221        else {
222            u.c8[0] = (CARD8) affect;
223            u.c8[1] = (CARD8) details;
224        }
225    }
226    UnlockDisplay(dpy);
227    SyncHandle();
228    return True;
229}
230
231Bool
232XkbLockModifiers(Display *dpy,
233                 unsigned int deviceSpec,
234                 unsigned int affect,
235                 unsigned int values)
236{
237    register xkbLatchLockStateReq *req;
238    XkbInfoPtr xkbi;
239
240    if ((dpy->flags & XlibDisplayNoXkb) ||
241        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
242        return False;
243    LockDisplay(dpy);
244    xkbi = dpy->xkb_info;
245    GetReq(kbLatchLockState, req);
246    req->reqType = xkbi->codes->major_opcode;
247    req->xkbReqType = X_kbLatchLockState;
248    req->deviceSpec = deviceSpec;
249    req->affectModLocks = affect;
250    req->modLocks = values;
251    req->lockGroup = False;
252    req->groupLock = 0;
253
254    req->affectModLatches = req->modLatches = 0;
255    req->latchGroup = False;
256    req->groupLatch = 0;
257    UnlockDisplay(dpy);
258    SyncHandle();
259    return True;
260}
261
262Bool
263XkbLatchModifiers(Display *dpy,
264                  unsigned int deviceSpec,
265                  unsigned int affect,
266                  unsigned int values)
267{
268    register xkbLatchLockStateReq *req;
269    XkbInfoPtr xkbi;
270
271    if ((dpy->flags & XlibDisplayNoXkb) ||
272        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
273        return False;
274    LockDisplay(dpy);
275    xkbi = dpy->xkb_info;
276    GetReq(kbLatchLockState, req);
277    req->reqType = xkbi->codes->major_opcode;
278    req->xkbReqType = X_kbLatchLockState;
279    req->deviceSpec = deviceSpec;
280
281    req->affectModLatches = affect;
282    req->modLatches = values;
283    req->latchGroup = False;
284    req->groupLatch = 0;
285
286    req->affectModLocks = req->modLocks = 0;
287    req->lockGroup = False;
288    req->groupLock = 0;
289
290    UnlockDisplay(dpy);
291    SyncHandle();
292    return True;
293}
294
295Bool
296XkbLockGroup(Display *dpy, unsigned int deviceSpec, unsigned int group)
297{
298    register xkbLatchLockStateReq *req;
299    XkbInfoPtr xkbi;
300
301    if ((dpy->flags & XlibDisplayNoXkb) ||
302        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
303        return False;
304    LockDisplay(dpy);
305    xkbi = dpy->xkb_info;
306    GetReq(kbLatchLockState, req);
307    req->reqType = xkbi->codes->major_opcode;
308    req->xkbReqType = X_kbLatchLockState;
309    req->deviceSpec = deviceSpec;
310    req->affectModLocks = 0;
311    req->modLocks = 0;
312    req->lockGroup = True;
313    req->groupLock = group;
314
315    req->affectModLatches = req->modLatches = 0;
316    req->latchGroup = False;
317    req->groupLatch = 0;
318    UnlockDisplay(dpy);
319    SyncHandle();
320    return True;
321}
322
323Bool
324XkbLatchGroup(Display *dpy, unsigned int deviceSpec, unsigned int group)
325{
326    register xkbLatchLockStateReq *req;
327    XkbInfoPtr xkbi;
328
329    if ((dpy->flags & XlibDisplayNoXkb) ||
330        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
331        return False;
332    LockDisplay(dpy);
333    xkbi = dpy->xkb_info;
334    GetReq(kbLatchLockState, req);
335    req->reqType = xkbi->codes->major_opcode;
336    req->xkbReqType = X_kbLatchLockState;
337    req->deviceSpec = deviceSpec;
338
339    req->affectModLatches = 0;
340    req->modLatches = 0;
341    req->latchGroup = True;
342    req->groupLatch = group;
343
344    req->affectModLocks = req->modLocks = 0;
345    req->lockGroup = False;
346    req->groupLock = 0;
347
348    UnlockDisplay(dpy);
349    SyncHandle();
350    return True;
351}
352
353unsigned
354XkbSetXlibControls(Display *dpy, unsigned affect, unsigned values)
355{
356    if (!dpy->xkb_info)
357        XkbUseExtension(dpy, NULL, NULL);
358    if (!dpy->xkb_info)
359        return 0;
360    affect &= XkbLC_AllControls;
361    dpy->xkb_info->xlib_ctrls &= ~affect;
362    dpy->xkb_info->xlib_ctrls |= (affect & values);
363    return dpy->xkb_info->xlib_ctrls;
364}
365
366unsigned
367XkbGetXlibControls(Display *dpy)
368{
369    if (!dpy->xkb_info)
370        XkbUseExtension(dpy, NULL, NULL);
371    if (!dpy->xkb_info)
372        return 0;
373    return dpy->xkb_info->xlib_ctrls;
374}
375
376unsigned int
377XkbXlibControlsImplemented(void)
378{
379#ifdef __sgi
380    return XkbLC_AllControls;
381#else
382    return XkbLC_AllControls & ~XkbLC_AllComposeControls;
383#endif
384}
385
386Bool
387XkbSetDebuggingFlags(Display *dpy,
388                     unsigned int mask,
389                     unsigned int flags,
390                     char *msg,
391                     unsigned int ctrls_mask,
392                     unsigned int ctrls,
393                     unsigned int *rtrn_flags,
394                     unsigned int *rtrn_ctrls)
395{
396    register xkbSetDebuggingFlagsReq *req;
397    xkbSetDebuggingFlagsReply rep;
398    XkbInfoPtr xkbi;
399
400    if ((dpy->flags & XlibDisplayNoXkb) ||
401        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
402        return False;
403    LockDisplay(dpy);
404    xkbi = dpy->xkb_info;
405    GetReq(kbSetDebuggingFlags, req);
406    req->reqType        = xkbi->codes->major_opcode;
407    req->xkbReqType     = X_kbSetDebuggingFlags;
408    req->affectFlags    = mask;
409    req->flags          = flags;
410    req->affectCtrls    = ctrls_mask;
411    req->ctrls          = ctrls;
412
413    if (msg) {
414        char *out;
415
416        req->msgLength = (unsigned short) strlen(msg) + 1;
417        req->length += (req->msgLength + (unsigned) 3) >> 2;
418        BufAlloc(char *, out, ((req->msgLength + (unsigned) 3) / 4) * 4);
419        memcpy(out, msg, req->msgLength);
420    }
421    else
422        req->msgLength = 0;
423    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
424        UnlockDisplay(dpy);
425        SyncHandle();
426        return False;
427    }
428    if (rtrn_flags)
429        *rtrn_flags = rep.currentFlags;
430    if (rtrn_ctrls)
431        *rtrn_ctrls = rep.currentCtrls;
432    UnlockDisplay(dpy);
433    SyncHandle();
434    return True;
435}
436
437Bool
438XkbComputeEffectiveMap(XkbDescPtr xkb,
439                       XkbKeyTypePtr type,
440                       unsigned char *map_rtrn)
441{
442    register int i;
443    unsigned tmp;
444    XkbKTMapEntryPtr entry = NULL;
445
446    if ((!xkb) || (!type) || (!xkb->server))
447        return False;
448
449    if (type->mods.vmods != 0) {
450        if (!XkbVirtualModsToReal(xkb, type->mods.vmods, &tmp))
451            return False;
452
453        type->mods.mask = tmp | type->mods.real_mods;
454        entry = type->map;
455        for (i = 0; i < type->map_count; i++, entry++) {
456            tmp = 0;
457            if (entry->mods.vmods != 0) {
458                if (!XkbVirtualModsToReal(xkb, entry->mods.vmods, &tmp))
459                    return False;
460                if (tmp == 0) {
461                    entry->active = False;
462                    continue;
463                }
464            }
465            entry->active = True;
466            entry->mods.mask = (entry->mods.real_mods | tmp) & type->mods.mask;
467        }
468    }
469    else {
470        type->mods.mask = type->mods.real_mods;
471    }
472    if (map_rtrn != NULL) {
473        bzero(map_rtrn, type->mods.mask + 1);
474        for (i = 0; i < type->map_count; i++) {
475            if (entry && entry->active) {
476                map_rtrn[type->map[i].mods.mask] = type->map[i].level;
477            }
478        }
479    }
480    return True;
481}
482
483Status
484XkbGetState(Display *dpy, unsigned deviceSpec, XkbStatePtr rtrn)
485{
486    register xkbGetStateReq *req;
487    xkbGetStateReply rep;
488    XkbInfoPtr xkbi;
489
490    if ((dpy->flags & XlibDisplayNoXkb) ||
491        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
492        return BadAccess;
493    LockDisplay(dpy);
494    xkbi = dpy->xkb_info;
495    GetReq(kbGetState, req);
496    req->reqType = xkbi->codes->major_opcode;
497    req->xkbReqType = X_kbGetState;
498    req->deviceSpec = deviceSpec;
499    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
500        UnlockDisplay(dpy);
501        SyncHandle();
502        return BadImplementation;
503    }
504    rtrn->mods                  = rep.mods;
505    rtrn->base_mods             = rep.baseMods;
506    rtrn->latched_mods          = rep.latchedMods;
507    rtrn->locked_mods           = rep.lockedMods;
508    rtrn->group                 = rep.group;
509    rtrn->base_group            = rep.baseGroup;
510    rtrn->latched_group         = rep.latchedGroup;
511    rtrn->locked_group          = rep.lockedGroup;
512    rtrn->compat_state          = rep.compatState;
513    rtrn->grab_mods             = rep.grabMods;
514    rtrn->compat_grab_mods      = rep.compatGrabMods;
515    rtrn->lookup_mods           = rep.lookupMods;
516    rtrn->compat_lookup_mods    = rep.compatLookupMods;
517    rtrn->ptr_buttons           = rep.ptrBtnState;
518    UnlockDisplay(dpy);
519    SyncHandle();
520    return Success;
521}
522
523Bool
524XkbSetDetectableAutoRepeat(Display *dpy, Bool detectable, Bool *supported)
525{
526    register xkbPerClientFlagsReq *req;
527    xkbPerClientFlagsReply rep;
528    XkbInfoPtr xkbi;
529
530    if ((dpy->flags & XlibDisplayNoXkb) ||
531        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
532        return False;
533    LockDisplay(dpy);
534    xkbi = dpy->xkb_info;
535    GetReq(kbPerClientFlags, req);
536    req->reqType = xkbi->codes->major_opcode;
537    req->xkbReqType = X_kbPerClientFlags;
538    req->deviceSpec = XkbUseCoreKbd;
539    req->change = XkbPCF_DetectableAutoRepeatMask;
540    if (detectable)
541        req->value = XkbPCF_DetectableAutoRepeatMask;
542    else
543        req->value = 0;
544    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
545    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
546        UnlockDisplay(dpy);
547        SyncHandle();
548        return False;
549    }
550    UnlockDisplay(dpy);
551    SyncHandle();
552    if (supported != NULL)
553        *supported = ((rep.supported & XkbPCF_DetectableAutoRepeatMask) != 0);
554    return ((rep.value & XkbPCF_DetectableAutoRepeatMask) != 0);
555}
556
557Bool
558XkbGetDetectableAutoRepeat(Display *dpy, Bool *supported)
559{
560    register xkbPerClientFlagsReq *req;
561    xkbPerClientFlagsReply rep;
562    XkbInfoPtr xkbi;
563
564    if ((dpy->flags & XlibDisplayNoXkb) ||
565        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
566        return False;
567    LockDisplay(dpy);
568    xkbi = dpy->xkb_info;
569    GetReq(kbPerClientFlags, req);
570    req->reqType = xkbi->codes->major_opcode;
571    req->xkbReqType = X_kbPerClientFlags;
572    req->deviceSpec = XkbUseCoreKbd;
573    req->change = 0;
574    req->value = 0;
575    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
576    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
577        UnlockDisplay(dpy);
578        SyncHandle();
579        return False;
580    }
581    UnlockDisplay(dpy);
582    SyncHandle();
583    if (supported != NULL)
584        *supported = ((rep.supported & XkbPCF_DetectableAutoRepeatMask) != 0);
585    return ((rep.value & XkbPCF_DetectableAutoRepeatMask) != 0);
586}
587
588Bool
589XkbSetAutoResetControls(Display *dpy,
590                        unsigned changes,
591                        unsigned *auto_ctrls,
592                        unsigned *auto_values)
593{
594    register xkbPerClientFlagsReq *req;
595    xkbPerClientFlagsReply rep;
596    XkbInfoPtr xkbi;
597
598    if ((dpy->flags & XlibDisplayNoXkb) ||
599        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
600        return False;
601    LockDisplay(dpy);
602    xkbi = dpy->xkb_info;
603    GetReq(kbPerClientFlags, req);
604    req->reqType = xkbi->codes->major_opcode;
605    req->xkbReqType = X_kbPerClientFlags;
606    req->change = XkbPCF_AutoResetControlsMask;
607    req->deviceSpec = XkbUseCoreKbd;
608    req->value = XkbPCF_AutoResetControlsMask;
609    req->ctrlsToChange = changes;
610    req->autoCtrls = *auto_ctrls;
611    req->autoCtrlValues = *auto_values;
612    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
613        UnlockDisplay(dpy);
614        SyncHandle();
615        return False;
616    }
617    UnlockDisplay(dpy);
618    SyncHandle();
619    *auto_ctrls = rep.autoCtrls;
620    *auto_values = rep.autoCtrlValues;
621    return ((rep.value & XkbPCF_AutoResetControlsMask) != 0);
622}
623
624Bool
625XkbGetAutoResetControls(Display *dpy,
626                        unsigned *auto_ctrls,
627                        unsigned *auto_ctrl_values)
628{
629    register xkbPerClientFlagsReq *req;
630    xkbPerClientFlagsReply rep;
631    XkbInfoPtr xkbi;
632
633    if ((dpy->flags & XlibDisplayNoXkb) ||
634        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
635        return False;
636    LockDisplay(dpy);
637    xkbi = dpy->xkb_info;
638    GetReq(kbPerClientFlags, req);
639    req->reqType = xkbi->codes->major_opcode;
640    req->xkbReqType = X_kbPerClientFlags;
641    req->deviceSpec = XkbUseCoreKbd;
642    req->change = 0;
643    req->value = 0;
644    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
645    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
646        UnlockDisplay(dpy);
647        SyncHandle();
648        return False;
649    }
650    UnlockDisplay(dpy);
651    SyncHandle();
652    if (auto_ctrls)
653        *auto_ctrls = rep.autoCtrls;
654    if (auto_ctrl_values)
655        *auto_ctrl_values = rep.autoCtrlValues;
656    return ((rep.value & XkbPCF_AutoResetControlsMask) != 0);
657}
658
659Bool
660XkbSetPerClientControls(Display *dpy, unsigned change, unsigned *values)
661{
662    register xkbPerClientFlagsReq *req;
663    xkbPerClientFlagsReply rep;
664    XkbInfoPtr xkbi;
665    unsigned value_hold = *values;
666
667    if ((dpy->flags & XlibDisplayNoXkb) ||
668        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
669        (change & ~(XkbPCF_GrabsUseXKBStateMask |
670                    XkbPCF_LookupStateWhenGrabbed |
671                    XkbPCF_SendEventUsesXKBState)))
672        return False;
673    LockDisplay(dpy);
674    xkbi = dpy->xkb_info;
675    GetReq(kbPerClientFlags, req);
676    req->reqType = xkbi->codes->major_opcode;
677    req->xkbReqType = X_kbPerClientFlags;
678    req->change = change;
679    req->deviceSpec = XkbUseCoreKbd;
680    req->value = *values;
681    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
682    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
683        UnlockDisplay(dpy);
684        SyncHandle();
685        return False;
686    }
687    UnlockDisplay(dpy);
688    SyncHandle();
689    *values = rep.value;
690    return ((rep.value & value_hold) != 0);
691}
692
693Bool
694XkbGetPerClientControls(Display *dpy, unsigned *ctrls)
695{
696    register xkbPerClientFlagsReq *req;
697    xkbPerClientFlagsReply rep;
698    XkbInfoPtr xkbi;
699
700    if ((dpy->flags & XlibDisplayNoXkb) ||
701        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
702        (*ctrls & ~(XkbPCF_GrabsUseXKBStateMask |
703                    XkbPCF_LookupStateWhenGrabbed |
704                    XkbPCF_SendEventUsesXKBState)))
705        return False;
706    LockDisplay(dpy);
707    xkbi = dpy->xkb_info;
708    GetReq(kbPerClientFlags, req);
709    req->reqType = xkbi->codes->major_opcode;
710    req->xkbReqType = X_kbPerClientFlags;
711    req->deviceSpec = XkbUseCoreKbd;
712    req->change = 0;
713    req->value = 0;
714    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
715    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
716        UnlockDisplay(dpy);
717        SyncHandle();
718        return False;
719    }
720    UnlockDisplay(dpy);
721    SyncHandle();
722    if (ctrls)
723        *ctrls = (rep.value & (XkbPCF_GrabsUseXKBStateMask |
724                               XkbPCF_LookupStateWhenGrabbed |
725                               XkbPCF_SendEventUsesXKBState));
726    return (True);
727}
728
729Display *
730XkbOpenDisplay(char *name,
731               int *ev_rtrn,
732               int *err_rtrn,
733               int *major_rtrn,
734               int *minor_rtrn,
735               int *reason)
736{
737    Display *dpy;
738    int major_num, minor_num;
739
740    if ((major_rtrn != NULL) && (minor_rtrn != NULL)) {
741        if (!XkbLibraryVersion(major_rtrn, minor_rtrn)) {
742            if (reason != NULL)
743                *reason = XkbOD_BadLibraryVersion;
744            return NULL;
745        }
746    }
747    else {
748        major_num = XkbMajorVersion;
749        minor_num = XkbMinorVersion;
750        major_rtrn = &major_num;
751        minor_rtrn = &minor_num;
752    }
753    dpy = XOpenDisplay(name);
754    if (dpy == NULL) {
755        if (reason != NULL)
756            *reason = XkbOD_ConnectionRefused;
757        return NULL;
758    }
759    if (!XkbQueryExtension(dpy, NULL, ev_rtrn, err_rtrn,
760                           major_rtrn, minor_rtrn)) {
761        if (reason != NULL) {
762            if ((*major_rtrn != 0) || (*minor_rtrn != 0))
763                *reason = XkbOD_BadServerVersion;
764            else
765                *reason = XkbOD_NonXkbServer;
766        }
767        XCloseDisplay(dpy);
768        return NULL;
769    }
770    if (reason != NULL)
771        *reason = XkbOD_Success;
772    return dpy;
773}
774
775void
776XkbSetAtomFuncs(XkbInternAtomFunc getAtom, XkbGetAtomNameFunc getName)
777{
778    _XkbInternAtomFunc = (getAtom ? getAtom : XInternAtom);
779    _XkbGetAtomNameFunc = (getName ? getName : XGetAtomName);
780    return;
781}
782