XKB.c revision e9628295
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->affectMap = (CARD16) affect;
173        req->map = (CARD16) details | (XkbAllClientInfoMask & affect);
174        req->affectWhich = XkbMapNotifyMask;
175        xkbi->selected_map_details &= ~affect;
176        xkbi->selected_map_details |= (details & affect);
177    }
178    else {
179        req->affectMap = req->map = 0;
180        req->affectWhich = (1 << eventType);
181        switch (eventType) {
182        case XkbNewKeyboardNotify:
183            xkbi->selected_nkn_details &= ~affect;
184            xkbi->selected_nkn_details |= (details & affect);
185            if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards))
186                details = (affect & XkbAllNewKeyboardEventsMask);
187        case XkbStateNotify:
188        case XkbNamesNotify:
189        case XkbAccessXNotify:
190        case XkbExtensionDeviceNotify:
191            size = 2;
192            req->length += 1;
193            break;
194        case XkbControlsNotify:
195        case XkbIndicatorStateNotify:
196        case XkbIndicatorMapNotify:
197            size = 4;
198            req->length += 2;
199            break;
200        case XkbBellNotify:
201        case XkbActionMessage:
202        case XkbCompatMapNotify:
203            size = 1;
204            req->length += 1;
205            break;
206        }
207        BufAlloc(char *, out, (((size * 2) + (unsigned) 3) / 4) * 4);
208
209        u.c8 = (CARD8 *) out;
210        if (size == 2) {
211            u.c16[0] = (CARD16) affect;
212            u.c16[1] = (CARD16) details;
213        }
214        else if (size == 4) {
215            u.c32[0] = (CARD32) affect;
216            u.c32[1] = (CARD32) details;
217        }
218        else {
219            u.c8[0] = (CARD8) affect;
220            u.c8[1] = (CARD8) details;
221        }
222    }
223    UnlockDisplay(dpy);
224    SyncHandle();
225    return True;
226}
227
228Bool
229XkbLockModifiers(Display *dpy,
230                 unsigned int deviceSpec,
231                 unsigned int affect,
232                 unsigned int values)
233{
234    register xkbLatchLockStateReq *req;
235    XkbInfoPtr xkbi;
236
237    if ((dpy->flags & XlibDisplayNoXkb) ||
238        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
239        return False;
240    LockDisplay(dpy);
241    xkbi = dpy->xkb_info;
242    GetReq(kbLatchLockState, req);
243    req->reqType = xkbi->codes->major_opcode;
244    req->xkbReqType = X_kbLatchLockState;
245    req->deviceSpec = deviceSpec;
246    req->affectModLocks = affect;
247    req->modLocks = values;
248    req->lockGroup = False;
249    req->groupLock = 0;
250
251    req->affectModLatches = req->modLatches = 0;
252    req->latchGroup = False;
253    req->groupLatch = 0;
254    UnlockDisplay(dpy);
255    SyncHandle();
256    return True;
257}
258
259Bool
260XkbLatchModifiers(Display *dpy,
261                  unsigned int deviceSpec,
262                  unsigned int affect,
263                  unsigned int values)
264{
265    register xkbLatchLockStateReq *req;
266    XkbInfoPtr xkbi;
267
268    if ((dpy->flags & XlibDisplayNoXkb) ||
269        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
270        return False;
271    LockDisplay(dpy);
272    xkbi = dpy->xkb_info;
273    GetReq(kbLatchLockState, req);
274    req->reqType = xkbi->codes->major_opcode;
275    req->xkbReqType = X_kbLatchLockState;
276    req->deviceSpec = deviceSpec;
277
278    req->affectModLatches = affect;
279    req->modLatches = values;
280    req->latchGroup = False;
281    req->groupLatch = 0;
282
283    req->affectModLocks = req->modLocks = 0;
284    req->lockGroup = False;
285    req->groupLock = 0;
286
287    UnlockDisplay(dpy);
288    SyncHandle();
289    return True;
290}
291
292Bool
293XkbLockGroup(Display *dpy, unsigned int deviceSpec, unsigned int group)
294{
295    register xkbLatchLockStateReq *req;
296    XkbInfoPtr xkbi;
297
298    if ((dpy->flags & XlibDisplayNoXkb) ||
299        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
300        return False;
301    LockDisplay(dpy);
302    xkbi = dpy->xkb_info;
303    GetReq(kbLatchLockState, req);
304    req->reqType = xkbi->codes->major_opcode;
305    req->xkbReqType = X_kbLatchLockState;
306    req->deviceSpec = deviceSpec;
307    req->affectModLocks = 0;
308    req->modLocks = 0;
309    req->lockGroup = True;
310    req->groupLock = group;
311
312    req->affectModLatches = req->modLatches = 0;
313    req->latchGroup = False;
314    req->groupLatch = 0;
315    UnlockDisplay(dpy);
316    SyncHandle();
317    return True;
318}
319
320Bool
321XkbLatchGroup(Display *dpy, unsigned int deviceSpec, unsigned int group)
322{
323    register xkbLatchLockStateReq *req;
324    XkbInfoPtr xkbi;
325
326    if ((dpy->flags & XlibDisplayNoXkb) ||
327        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
328        return False;
329    LockDisplay(dpy);
330    xkbi = dpy->xkb_info;
331    GetReq(kbLatchLockState, req);
332    req->reqType = xkbi->codes->major_opcode;
333    req->xkbReqType = X_kbLatchLockState;
334    req->deviceSpec = deviceSpec;
335
336    req->affectModLatches = 0;
337    req->modLatches = 0;
338    req->latchGroup = True;
339    req->groupLatch = group;
340
341    req->affectModLocks = req->modLocks = 0;
342    req->lockGroup = False;
343    req->groupLock = 0;
344
345    UnlockDisplay(dpy);
346    SyncHandle();
347    return True;
348}
349
350unsigned
351XkbSetXlibControls(Display *dpy, unsigned affect, unsigned values)
352{
353    if (!dpy->xkb_info)
354        XkbUseExtension(dpy, NULL, NULL);
355    if (!dpy->xkb_info)
356        return 0;
357    affect &= XkbLC_AllControls;
358    dpy->xkb_info->xlib_ctrls &= ~affect;
359    dpy->xkb_info->xlib_ctrls |= (affect & values);
360    return dpy->xkb_info->xlib_ctrls;
361}
362
363unsigned
364XkbGetXlibControls(Display *dpy)
365{
366    if (!dpy->xkb_info)
367        XkbUseExtension(dpy, NULL, NULL);
368    if (!dpy->xkb_info)
369        return 0;
370    return dpy->xkb_info->xlib_ctrls;
371}
372
373unsigned int
374XkbXlibControlsImplemented(void)
375{
376#ifdef __sgi
377    return XkbLC_AllControls;
378#else
379    return XkbLC_AllControls & ~XkbLC_AllComposeControls;
380#endif
381}
382
383Bool
384XkbSetDebuggingFlags(Display *dpy,
385                     unsigned int mask,
386                     unsigned int flags,
387                     char *msg,
388                     unsigned int ctrls_mask,
389                     unsigned int ctrls,
390                     unsigned int *rtrn_flags,
391                     unsigned int *rtrn_ctrls)
392{
393    register xkbSetDebuggingFlagsReq *req;
394    xkbSetDebuggingFlagsReply rep;
395    XkbInfoPtr xkbi;
396
397    if ((dpy->flags & XlibDisplayNoXkb) ||
398        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
399        return False;
400    LockDisplay(dpy);
401    xkbi = dpy->xkb_info;
402    GetReq(kbSetDebuggingFlags, req);
403    req->reqType        = xkbi->codes->major_opcode;
404    req->xkbReqType     = X_kbSetDebuggingFlags;
405    req->affectFlags    = mask;
406    req->flags          = flags;
407    req->affectCtrls    = ctrls_mask;
408    req->ctrls          = ctrls;
409
410    if (msg) {
411        char *out;
412
413        req->msgLength = (CARD16) (strlen(msg) + 1);
414        req->length += (req->msgLength + (unsigned) 3) >> 2;
415        BufAlloc(char *, out, ((req->msgLength + (unsigned) 3) / 4) * 4);
416        memcpy(out, msg, req->msgLength);
417    }
418    else
419        req->msgLength = 0;
420    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
421        UnlockDisplay(dpy);
422        SyncHandle();
423        return False;
424    }
425    if (rtrn_flags)
426        *rtrn_flags = rep.currentFlags;
427    if (rtrn_ctrls)
428        *rtrn_ctrls = rep.currentCtrls;
429    UnlockDisplay(dpy);
430    SyncHandle();
431    return True;
432}
433
434Bool
435XkbComputeEffectiveMap(XkbDescPtr xkb,
436                       XkbKeyTypePtr type,
437                       unsigned char *map_rtrn)
438{
439    register int i;
440    unsigned tmp;
441    XkbKTMapEntryPtr entry = NULL;
442
443    if ((!xkb) || (!type) || (!xkb->server))
444        return False;
445
446    if (type->mods.vmods != 0) {
447        if (!XkbVirtualModsToReal(xkb, type->mods.vmods, &tmp))
448            return False;
449
450        type->mods.mask = tmp | type->mods.real_mods;
451        entry = type->map;
452        for (i = 0; i < type->map_count; i++, entry++) {
453            tmp = 0;
454            if (entry->mods.vmods != 0) {
455                if (!XkbVirtualModsToReal(xkb, entry->mods.vmods, &tmp))
456                    return False;
457                if (tmp == 0) {
458                    entry->active = False;
459                    continue;
460                }
461            }
462            entry->active = True;
463            entry->mods.mask = (entry->mods.real_mods | tmp) & type->mods.mask;
464        }
465    }
466    else {
467        type->mods.mask = type->mods.real_mods;
468    }
469    if (map_rtrn != NULL) {
470        bzero(map_rtrn, type->mods.mask + 1);
471        for (i = 0; i < type->map_count; i++) {
472            if (entry && entry->active) {
473                map_rtrn[type->map[i].mods.mask] = type->map[i].level;
474            }
475        }
476    }
477    return True;
478}
479
480Status
481XkbGetState(Display *dpy, unsigned deviceSpec, XkbStatePtr rtrn)
482{
483    register xkbGetStateReq *req;
484    xkbGetStateReply rep;
485    XkbInfoPtr xkbi;
486
487    if ((dpy->flags & XlibDisplayNoXkb) ||
488        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
489        return BadAccess;
490    LockDisplay(dpy);
491    xkbi = dpy->xkb_info;
492    GetReq(kbGetState, req);
493    req->reqType = xkbi->codes->major_opcode;
494    req->xkbReqType = X_kbGetState;
495    req->deviceSpec = deviceSpec;
496    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
497        UnlockDisplay(dpy);
498        SyncHandle();
499        return BadImplementation;
500    }
501    rtrn->mods                  = rep.mods;
502    rtrn->base_mods             = rep.baseMods;
503    rtrn->latched_mods          = rep.latchedMods;
504    rtrn->locked_mods           = rep.lockedMods;
505    rtrn->group                 = rep.group;
506    rtrn->base_group            = rep.baseGroup;
507    rtrn->latched_group         = rep.latchedGroup;
508    rtrn->locked_group          = rep.lockedGroup;
509    rtrn->compat_state          = rep.compatState;
510    rtrn->grab_mods             = rep.grabMods;
511    rtrn->compat_grab_mods      = rep.compatGrabMods;
512    rtrn->lookup_mods           = rep.lookupMods;
513    rtrn->compat_lookup_mods    = rep.compatLookupMods;
514    rtrn->ptr_buttons           = rep.ptrBtnState;
515    UnlockDisplay(dpy);
516    SyncHandle();
517    return Success;
518}
519
520Bool
521XkbSetDetectableAutoRepeat(Display *dpy, Bool detectable, Bool *supported)
522{
523    register xkbPerClientFlagsReq *req;
524    xkbPerClientFlagsReply rep;
525    XkbInfoPtr xkbi;
526
527    if ((dpy->flags & XlibDisplayNoXkb) ||
528        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
529        return False;
530    LockDisplay(dpy);
531    xkbi = dpy->xkb_info;
532    GetReq(kbPerClientFlags, req);
533    req->reqType = xkbi->codes->major_opcode;
534    req->xkbReqType = X_kbPerClientFlags;
535    req->deviceSpec = XkbUseCoreKbd;
536    req->change = XkbPCF_DetectableAutoRepeatMask;
537    if (detectable)
538        req->value = XkbPCF_DetectableAutoRepeatMask;
539    else
540        req->value = 0;
541    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
542    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
543        UnlockDisplay(dpy);
544        SyncHandle();
545        return False;
546    }
547    UnlockDisplay(dpy);
548    SyncHandle();
549    if (supported != NULL)
550        *supported = ((rep.supported & XkbPCF_DetectableAutoRepeatMask) != 0);
551    return ((rep.value & XkbPCF_DetectableAutoRepeatMask) != 0);
552}
553
554Bool
555XkbGetDetectableAutoRepeat(Display *dpy, Bool *supported)
556{
557    register xkbPerClientFlagsReq *req;
558    xkbPerClientFlagsReply rep;
559    XkbInfoPtr xkbi;
560
561    if ((dpy->flags & XlibDisplayNoXkb) ||
562        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
563        return False;
564    LockDisplay(dpy);
565    xkbi = dpy->xkb_info;
566    GetReq(kbPerClientFlags, req);
567    req->reqType = xkbi->codes->major_opcode;
568    req->xkbReqType = X_kbPerClientFlags;
569    req->deviceSpec = XkbUseCoreKbd;
570    req->change = 0;
571    req->value = 0;
572    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
573    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
574        UnlockDisplay(dpy);
575        SyncHandle();
576        return False;
577    }
578    UnlockDisplay(dpy);
579    SyncHandle();
580    if (supported != NULL)
581        *supported = ((rep.supported & XkbPCF_DetectableAutoRepeatMask) != 0);
582    return ((rep.value & XkbPCF_DetectableAutoRepeatMask) != 0);
583}
584
585Bool
586XkbSetAutoResetControls(Display *dpy,
587                        unsigned changes,
588                        unsigned *auto_ctrls,
589                        unsigned *auto_values)
590{
591    register xkbPerClientFlagsReq *req;
592    xkbPerClientFlagsReply rep;
593    XkbInfoPtr xkbi;
594
595    if ((dpy->flags & XlibDisplayNoXkb) ||
596        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
597        return False;
598    LockDisplay(dpy);
599    xkbi = dpy->xkb_info;
600    GetReq(kbPerClientFlags, req);
601    req->reqType = xkbi->codes->major_opcode;
602    req->xkbReqType = X_kbPerClientFlags;
603    req->change = XkbPCF_AutoResetControlsMask;
604    req->deviceSpec = XkbUseCoreKbd;
605    req->value = XkbPCF_AutoResetControlsMask;
606    req->ctrlsToChange = changes;
607    req->autoCtrls = *auto_ctrls;
608    req->autoCtrlValues = *auto_values;
609    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
610        UnlockDisplay(dpy);
611        SyncHandle();
612        return False;
613    }
614    UnlockDisplay(dpy);
615    SyncHandle();
616    *auto_ctrls = rep.autoCtrls;
617    *auto_values = rep.autoCtrlValues;
618    return ((rep.value & XkbPCF_AutoResetControlsMask) != 0);
619}
620
621Bool
622XkbGetAutoResetControls(Display *dpy,
623                        unsigned *auto_ctrls,
624                        unsigned *auto_ctrl_values)
625{
626    register xkbPerClientFlagsReq *req;
627    xkbPerClientFlagsReply rep;
628    XkbInfoPtr xkbi;
629
630    if ((dpy->flags & XlibDisplayNoXkb) ||
631        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
632        return False;
633    LockDisplay(dpy);
634    xkbi = dpy->xkb_info;
635    GetReq(kbPerClientFlags, req);
636    req->reqType = xkbi->codes->major_opcode;
637    req->xkbReqType = X_kbPerClientFlags;
638    req->deviceSpec = XkbUseCoreKbd;
639    req->change = 0;
640    req->value = 0;
641    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
642    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
643        UnlockDisplay(dpy);
644        SyncHandle();
645        return False;
646    }
647    UnlockDisplay(dpy);
648    SyncHandle();
649    if (auto_ctrls)
650        *auto_ctrls = rep.autoCtrls;
651    if (auto_ctrl_values)
652        *auto_ctrl_values = rep.autoCtrlValues;
653    return ((rep.value & XkbPCF_AutoResetControlsMask) != 0);
654}
655
656Bool
657XkbSetPerClientControls(Display *dpy, unsigned change, unsigned *values)
658{
659    register xkbPerClientFlagsReq *req;
660    xkbPerClientFlagsReply rep;
661    XkbInfoPtr xkbi;
662    unsigned value_hold = *values;
663
664    if ((dpy->flags & XlibDisplayNoXkb) ||
665        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
666        (change & ~(XkbPCF_GrabsUseXKBStateMask |
667                    XkbPCF_LookupStateWhenGrabbed |
668                    XkbPCF_SendEventUsesXKBState)))
669        return False;
670    LockDisplay(dpy);
671    xkbi = dpy->xkb_info;
672    GetReq(kbPerClientFlags, req);
673    req->reqType = xkbi->codes->major_opcode;
674    req->xkbReqType = X_kbPerClientFlags;
675    req->change = change;
676    req->deviceSpec = XkbUseCoreKbd;
677    req->value = *values;
678    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
679    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
680        UnlockDisplay(dpy);
681        SyncHandle();
682        return False;
683    }
684    UnlockDisplay(dpy);
685    SyncHandle();
686    *values = rep.value;
687    return ((rep.value & value_hold) != 0);
688}
689
690Bool
691XkbGetPerClientControls(Display *dpy, unsigned *ctrls)
692{
693    register xkbPerClientFlagsReq *req;
694    xkbPerClientFlagsReply rep;
695    XkbInfoPtr xkbi;
696
697    if ((dpy->flags & XlibDisplayNoXkb) ||
698        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
699        (ctrls == NULL))
700        return False;
701    LockDisplay(dpy);
702    xkbi = dpy->xkb_info;
703    GetReq(kbPerClientFlags, req);
704    req->reqType = xkbi->codes->major_opcode;
705    req->xkbReqType = X_kbPerClientFlags;
706    req->deviceSpec = XkbUseCoreKbd;
707    req->change = 0;
708    req->value = 0;
709    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
710    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
711        UnlockDisplay(dpy);
712        SyncHandle();
713        return False;
714    }
715    UnlockDisplay(dpy);
716    SyncHandle();
717    *ctrls = (rep.value & (XkbPCF_GrabsUseXKBStateMask |
718                           XkbPCF_LookupStateWhenGrabbed |
719                           XkbPCF_SendEventUsesXKBState));
720    return (True);
721}
722
723Display *
724XkbOpenDisplay(_Xconst char *name,
725               int *ev_rtrn,
726               int *err_rtrn,
727               int *major_rtrn,
728               int *minor_rtrn,
729               int *reason)
730{
731    Display *dpy;
732    int major_num, minor_num;
733
734    if ((major_rtrn != NULL) && (minor_rtrn != NULL)) {
735        if (!XkbLibraryVersion(major_rtrn, minor_rtrn)) {
736            if (reason != NULL)
737                *reason = XkbOD_BadLibraryVersion;
738            return NULL;
739        }
740    }
741    else {
742        major_num = XkbMajorVersion;
743        minor_num = XkbMinorVersion;
744        major_rtrn = &major_num;
745        minor_rtrn = &minor_num;
746    }
747    dpy = XOpenDisplay(name);
748    if (dpy == NULL) {
749        if (reason != NULL)
750            *reason = XkbOD_ConnectionRefused;
751        return NULL;
752    }
753    if (!XkbQueryExtension(dpy, NULL, ev_rtrn, err_rtrn,
754                           major_rtrn, minor_rtrn)) {
755        if (reason != NULL) {
756            if ((*major_rtrn != 0) || (*minor_rtrn != 0))
757                *reason = XkbOD_BadServerVersion;
758            else
759                *reason = XkbOD_NonXkbServer;
760        }
761        XCloseDisplay(dpy);
762        return NULL;
763    }
764    if (reason != NULL)
765        *reason = XkbOD_Success;
766    return dpy;
767}
768
769void
770XkbSetAtomFuncs(XkbInternAtomFunc getAtom, XkbGetAtomNameFunc getName)
771{
772    _XkbInternAtomFunc = (getAtom ? getAtom : XInternAtom);
773    _XkbGetAtomNameFunc = (getName ? getName : XGetAtomName);
774    return;
775}
776