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    return XkbLC_AllControls & ~XkbLC_AllComposeControls;
377}
378
379Bool
380XkbSetDebuggingFlags(Display *dpy,
381                     unsigned int mask,
382                     unsigned int flags,
383                     char *msg,
384                     unsigned int ctrls_mask,
385                     unsigned int ctrls,
386                     unsigned int *rtrn_flags,
387                     unsigned int *rtrn_ctrls)
388{
389    register xkbSetDebuggingFlagsReq *req;
390    xkbSetDebuggingFlagsReply rep;
391    XkbInfoPtr xkbi;
392
393    if ((dpy->flags & XlibDisplayNoXkb) ||
394        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
395        return False;
396    LockDisplay(dpy);
397    xkbi = dpy->xkb_info;
398    GetReq(kbSetDebuggingFlags, req);
399    req->reqType        = xkbi->codes->major_opcode;
400    req->xkbReqType     = X_kbSetDebuggingFlags;
401    req->affectFlags    = mask;
402    req->flags          = flags;
403    req->affectCtrls    = ctrls_mask;
404    req->ctrls          = ctrls;
405
406    if (msg) {
407        char *out;
408
409        req->msgLength = (CARD16) (strlen(msg) + 1);
410        req->length += (req->msgLength + (unsigned) 3) >> 2;
411        BufAlloc(char *, out, ((req->msgLength + (unsigned) 3) / 4) * 4);
412        memcpy(out, msg, req->msgLength);
413    }
414    else
415        req->msgLength = 0;
416    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
417        UnlockDisplay(dpy);
418        SyncHandle();
419        return False;
420    }
421    if (rtrn_flags)
422        *rtrn_flags = rep.currentFlags;
423    if (rtrn_ctrls)
424        *rtrn_ctrls = rep.currentCtrls;
425    UnlockDisplay(dpy);
426    SyncHandle();
427    return True;
428}
429
430Bool
431XkbComputeEffectiveMap(XkbDescPtr xkb,
432                       XkbKeyTypePtr type,
433                       unsigned char *map_rtrn)
434{
435    register int i;
436    unsigned tmp;
437    XkbKTMapEntryPtr entry = NULL;
438
439    if ((!xkb) || (!type) || (!xkb->server))
440        return False;
441
442    if (type->mods.vmods != 0) {
443        if (!XkbVirtualModsToReal(xkb, type->mods.vmods, &tmp))
444            return False;
445
446        type->mods.mask = tmp | type->mods.real_mods;
447        entry = type->map;
448        for (i = 0; i < type->map_count; i++, entry++) {
449            tmp = 0;
450            if (entry->mods.vmods != 0) {
451                if (!XkbVirtualModsToReal(xkb, entry->mods.vmods, &tmp))
452                    return False;
453                if (tmp == 0) {
454                    entry->active = False;
455                    continue;
456                }
457            }
458            entry->active = True;
459            entry->mods.mask = (entry->mods.real_mods | tmp) & type->mods.mask;
460        }
461    }
462    else {
463        type->mods.mask = type->mods.real_mods;
464    }
465    if (map_rtrn != NULL) {
466        bzero(map_rtrn, type->mods.mask + 1);
467        for (i = 0; i < type->map_count; i++) {
468            if (entry && entry->active) {
469                map_rtrn[type->map[i].mods.mask] = type->map[i].level;
470            }
471        }
472    }
473    return True;
474}
475
476Status
477XkbGetState(Display *dpy, unsigned deviceSpec, XkbStatePtr rtrn)
478{
479    register xkbGetStateReq *req;
480    xkbGetStateReply rep;
481    XkbInfoPtr xkbi;
482
483    if ((dpy->flags & XlibDisplayNoXkb) ||
484        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
485        return BadAccess;
486    LockDisplay(dpy);
487    xkbi = dpy->xkb_info;
488    GetReq(kbGetState, req);
489    req->reqType = xkbi->codes->major_opcode;
490    req->xkbReqType = X_kbGetState;
491    req->deviceSpec = deviceSpec;
492    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
493        UnlockDisplay(dpy);
494        SyncHandle();
495        return BadImplementation;
496    }
497    rtrn->mods                  = rep.mods;
498    rtrn->base_mods             = rep.baseMods;
499    rtrn->latched_mods          = rep.latchedMods;
500    rtrn->locked_mods           = rep.lockedMods;
501    rtrn->group                 = rep.group;
502    rtrn->base_group            = rep.baseGroup;
503    rtrn->latched_group         = rep.latchedGroup;
504    rtrn->locked_group          = rep.lockedGroup;
505    rtrn->compat_state          = rep.compatState;
506    rtrn->grab_mods             = rep.grabMods;
507    rtrn->compat_grab_mods      = rep.compatGrabMods;
508    rtrn->lookup_mods           = rep.lookupMods;
509    rtrn->compat_lookup_mods    = rep.compatLookupMods;
510    rtrn->ptr_buttons           = rep.ptrBtnState;
511    UnlockDisplay(dpy);
512    SyncHandle();
513    return Success;
514}
515
516Bool
517XkbSetDetectableAutoRepeat(Display *dpy, Bool detectable, Bool *supported)
518{
519    register xkbPerClientFlagsReq *req;
520    xkbPerClientFlagsReply rep;
521    XkbInfoPtr xkbi;
522
523    if ((dpy->flags & XlibDisplayNoXkb) ||
524        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
525        return False;
526    LockDisplay(dpy);
527    xkbi = dpy->xkb_info;
528    GetReq(kbPerClientFlags, req);
529    req->reqType = xkbi->codes->major_opcode;
530    req->xkbReqType = X_kbPerClientFlags;
531    req->deviceSpec = XkbUseCoreKbd;
532    req->change = XkbPCF_DetectableAutoRepeatMask;
533    if (detectable)
534        req->value = XkbPCF_DetectableAutoRepeatMask;
535    else
536        req->value = 0;
537    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
538    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
539        UnlockDisplay(dpy);
540        SyncHandle();
541        return False;
542    }
543    UnlockDisplay(dpy);
544    SyncHandle();
545    if (supported != NULL)
546        *supported = ((rep.supported & XkbPCF_DetectableAutoRepeatMask) != 0);
547    return ((rep.value & XkbPCF_DetectableAutoRepeatMask) != 0);
548}
549
550Bool
551XkbGetDetectableAutoRepeat(Display *dpy, Bool *supported)
552{
553    register xkbPerClientFlagsReq *req;
554    xkbPerClientFlagsReply rep;
555    XkbInfoPtr xkbi;
556
557    if ((dpy->flags & XlibDisplayNoXkb) ||
558        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
559        return False;
560    LockDisplay(dpy);
561    xkbi = dpy->xkb_info;
562    GetReq(kbPerClientFlags, req);
563    req->reqType = xkbi->codes->major_opcode;
564    req->xkbReqType = X_kbPerClientFlags;
565    req->deviceSpec = XkbUseCoreKbd;
566    req->change = 0;
567    req->value = 0;
568    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
569    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
570        UnlockDisplay(dpy);
571        SyncHandle();
572        return False;
573    }
574    UnlockDisplay(dpy);
575    SyncHandle();
576    if (supported != NULL)
577        *supported = ((rep.supported & XkbPCF_DetectableAutoRepeatMask) != 0);
578    return ((rep.value & XkbPCF_DetectableAutoRepeatMask) != 0);
579}
580
581Bool
582XkbSetAutoResetControls(Display *dpy,
583                        unsigned changes,
584                        unsigned *auto_ctrls,
585                        unsigned *auto_values)
586{
587    register xkbPerClientFlagsReq *req;
588    xkbPerClientFlagsReply rep;
589    XkbInfoPtr xkbi;
590
591    if ((dpy->flags & XlibDisplayNoXkb) ||
592        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
593        return False;
594    LockDisplay(dpy);
595    xkbi = dpy->xkb_info;
596    GetReq(kbPerClientFlags, req);
597    req->reqType = xkbi->codes->major_opcode;
598    req->xkbReqType = X_kbPerClientFlags;
599    req->change = XkbPCF_AutoResetControlsMask;
600    req->deviceSpec = XkbUseCoreKbd;
601    req->value = XkbPCF_AutoResetControlsMask;
602    req->ctrlsToChange = changes;
603    req->autoCtrls = *auto_ctrls;
604    req->autoCtrlValues = *auto_values;
605    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
606        UnlockDisplay(dpy);
607        SyncHandle();
608        return False;
609    }
610    UnlockDisplay(dpy);
611    SyncHandle();
612    *auto_ctrls = rep.autoCtrls;
613    *auto_values = rep.autoCtrlValues;
614    return ((rep.value & XkbPCF_AutoResetControlsMask) != 0);
615}
616
617Bool
618XkbGetAutoResetControls(Display *dpy,
619                        unsigned *auto_ctrls,
620                        unsigned *auto_ctrl_values)
621{
622    register xkbPerClientFlagsReq *req;
623    xkbPerClientFlagsReply rep;
624    XkbInfoPtr xkbi;
625
626    if ((dpy->flags & XlibDisplayNoXkb) ||
627        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
628        return False;
629    LockDisplay(dpy);
630    xkbi = dpy->xkb_info;
631    GetReq(kbPerClientFlags, req);
632    req->reqType = xkbi->codes->major_opcode;
633    req->xkbReqType = X_kbPerClientFlags;
634    req->deviceSpec = XkbUseCoreKbd;
635    req->change = 0;
636    req->value = 0;
637    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
638    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
639        UnlockDisplay(dpy);
640        SyncHandle();
641        return False;
642    }
643    UnlockDisplay(dpy);
644    SyncHandle();
645    if (auto_ctrls)
646        *auto_ctrls = rep.autoCtrls;
647    if (auto_ctrl_values)
648        *auto_ctrl_values = rep.autoCtrlValues;
649    return ((rep.value & XkbPCF_AutoResetControlsMask) != 0);
650}
651
652Bool
653XkbSetPerClientControls(Display *dpy, unsigned change, unsigned *values)
654{
655    register xkbPerClientFlagsReq *req;
656    xkbPerClientFlagsReply rep;
657    XkbInfoPtr xkbi;
658    unsigned value_hold = *values;
659
660    if ((dpy->flags & XlibDisplayNoXkb) ||
661        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
662        (change & ~(XkbPCF_GrabsUseXKBStateMask |
663                    XkbPCF_LookupStateWhenGrabbed |
664                    XkbPCF_SendEventUsesXKBState)))
665        return False;
666    LockDisplay(dpy);
667    xkbi = dpy->xkb_info;
668    GetReq(kbPerClientFlags, req);
669    req->reqType = xkbi->codes->major_opcode;
670    req->xkbReqType = X_kbPerClientFlags;
671    req->change = change;
672    req->deviceSpec = XkbUseCoreKbd;
673    req->value = *values;
674    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
675    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
676        UnlockDisplay(dpy);
677        SyncHandle();
678        return False;
679    }
680    UnlockDisplay(dpy);
681    SyncHandle();
682    *values = rep.value;
683    return ((rep.value & value_hold) != 0);
684}
685
686Bool
687XkbGetPerClientControls(Display *dpy, unsigned *ctrls)
688{
689    register xkbPerClientFlagsReq *req;
690    xkbPerClientFlagsReply rep;
691    XkbInfoPtr xkbi;
692
693    if ((dpy->flags & XlibDisplayNoXkb) ||
694        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
695        (ctrls == NULL))
696        return False;
697    LockDisplay(dpy);
698    xkbi = dpy->xkb_info;
699    GetReq(kbPerClientFlags, req);
700    req->reqType = xkbi->codes->major_opcode;
701    req->xkbReqType = X_kbPerClientFlags;
702    req->deviceSpec = XkbUseCoreKbd;
703    req->change = 0;
704    req->value = 0;
705    req->ctrlsToChange = req->autoCtrls = req->autoCtrlValues = 0;
706    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
707        UnlockDisplay(dpy);
708        SyncHandle();
709        return False;
710    }
711    UnlockDisplay(dpy);
712    SyncHandle();
713    *ctrls = (rep.value & (XkbPCF_GrabsUseXKBStateMask |
714                           XkbPCF_LookupStateWhenGrabbed |
715                           XkbPCF_SendEventUsesXKBState));
716    return (True);
717}
718
719Display *
720XkbOpenDisplay(_Xconst char *name,
721               int *ev_rtrn,
722               int *err_rtrn,
723               int *major_rtrn,
724               int *minor_rtrn,
725               int *reason)
726{
727    Display *dpy;
728    int major_num, minor_num;
729
730    if ((major_rtrn != NULL) && (minor_rtrn != NULL)) {
731        if (!XkbLibraryVersion(major_rtrn, minor_rtrn)) {
732            if (reason != NULL)
733                *reason = XkbOD_BadLibraryVersion;
734            return NULL;
735        }
736    }
737    else {
738        major_num = XkbMajorVersion;
739        minor_num = XkbMinorVersion;
740        major_rtrn = &major_num;
741        minor_rtrn = &minor_num;
742    }
743    dpy = XOpenDisplay(name);
744    if (dpy == NULL) {
745        if (reason != NULL)
746            *reason = XkbOD_ConnectionRefused;
747        return NULL;
748    }
749    if (!XkbQueryExtension(dpy, NULL, ev_rtrn, err_rtrn,
750                           major_rtrn, minor_rtrn)) {
751        if (reason != NULL) {
752            if ((*major_rtrn != 0) || (*minor_rtrn != 0))
753                *reason = XkbOD_BadServerVersion;
754            else
755                *reason = XkbOD_NonXkbServer;
756        }
757        XCloseDisplay(dpy);
758        return NULL;
759    }
760    if (reason != NULL)
761        *reason = XkbOD_Success;
762    return dpy;
763}
764
765void
766XkbSetAtomFuncs(XkbInternAtomFunc getAtom, XkbGetAtomNameFunc getName)
767{
768    _XkbInternAtomFunc = (getAtom ? getAtom : XInternAtom);
769    _XkbGetAtomNameFunc = (getName ? getName : XGetAtomName);
770    return;
771}
772