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
35static int
36_XkbSizeKeyTypes(XkbDescPtr xkb, xkbSetMapReq *req)
37{
38    XkbKeyTypePtr map;
39    int i, len;
40
41    if (((req->present & XkbKeyTypesMask) == 0) || (req->nTypes == 0)) {
42        req->present &= ~XkbKeyTypesMask;
43        req->firstType = req->nTypes = 0;
44        return 0;
45    }
46    len = 0;
47    map = &xkb->map->types[req->firstType];
48    for (i = 0; i < req->nTypes; i++, map++) {
49        len += SIZEOF(xkbKeyTypeWireDesc);
50        len += map->map_count * SIZEOF(xkbKTSetMapEntryWireDesc);
51        if (map->preserve)
52            len += map->map_count * SIZEOF(xkbModsWireDesc);
53    }
54    return len;
55}
56
57static void
58_XkbWriteKeyTypes(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
59{
60    char *buf;
61    XkbKeyTypePtr type;
62    int i, n;
63    xkbKeyTypeWireDesc *desc;
64
65    if ((req->present & XkbKeyTypesMask) == 0)
66        return;
67    type = &xkb->map->types[req->firstType];
68    for (i = 0; i < req->nTypes; i++, type++) {
69        int sz = SIZEOF(xkbKeyTypeWireDesc);
70        sz += type->map_count * SIZEOF(xkbKTSetMapEntryWireDesc);
71        if (type->preserve)
72            sz += type->map_count * SIZEOF(xkbModsWireDesc);
73        BufAlloc(xkbKeyTypeWireDesc *, desc, sz);
74        desc->mask = type->mods.mask;
75        desc->realMods = type->mods.real_mods;
76        desc->virtualMods = type->mods.vmods;
77        desc->numLevels = type->num_levels;
78        desc->nMapEntries = type->map_count;
79        desc->preserve = (type->preserve != NULL);
80        buf = (char *) &desc[1];
81        if (desc->nMapEntries > 0) {
82            xkbKTSetMapEntryWireDesc *wire = (xkbKTSetMapEntryWireDesc *) buf;
83
84            for (n = 0; n < type->map_count; n++, wire++) {
85                wire->level = type->map[n].level;
86                wire->realMods = type->map[n].mods.real_mods;
87                wire->virtualMods = type->map[n].mods.vmods;
88            }
89            buf = (char *) wire;
90            if (type->preserve) {
91                xkbModsWireDesc *pwire = (xkbModsWireDesc *) buf;
92
93                for (n = 0; n < type->map_count; n++, pwire++) {
94                    pwire->realMods = type->preserve[n].real_mods;
95                    pwire->virtualMods = type->preserve[n].vmods;
96                }
97            }
98        }
99    }
100    return;
101}
102
103static int
104_XkbSizeKeySyms(XkbDescPtr xkb, xkbSetMapReq *req)
105{
106    int i, len;
107    unsigned nSyms;
108
109    if (((req->present & XkbKeySymsMask) == 0) || (req->nKeySyms == 0)) {
110        req->present &= ~XkbKeySymsMask;
111        req->firstKeySym = req->nKeySyms = 0;
112        req->totalSyms = 0;
113        return 0;
114    }
115    len = (int) (req->nKeySyms * sizeof(XkbSymMapRec));
116    for (i = nSyms = 0; i < req->nKeySyms; i++) {
117        nSyms += XkbKeyNumSyms(xkb, i + req->firstKeySym);
118    }
119    len += nSyms * sizeof(CARD32);
120    req->totalSyms = nSyms;
121    return len;
122}
123
124static void
125_XkbWriteKeySyms(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
126{
127    register KeySym *pSym;
128    CARD32 *outSym;
129    XkbSymMapPtr symMap;
130    xkbSymMapWireDesc *desc;
131    register int i;
132
133    if ((req->present & XkbKeySymsMask) == 0)
134        return;
135    symMap = &xkb->map->key_sym_map[req->firstKeySym];
136    for (i = 0; i < req->nKeySyms; i++, symMap++) {
137        BufAlloc(xkbSymMapWireDesc *, desc,
138                 SIZEOF(xkbSymMapWireDesc) +
139                 (XkbKeyNumSyms(xkb, i + req->firstKeySym) * sizeof(CARD32)));
140        desc->ktIndex[0] = symMap->kt_index[0];
141        desc->ktIndex[1] = symMap->kt_index[1];
142        desc->ktIndex[2] = symMap->kt_index[2];
143        desc->ktIndex[3] = symMap->kt_index[3];
144        desc->groupInfo = symMap->group_info;
145        desc->width = symMap->width;
146        desc->nSyms = XkbKeyNumSyms(xkb, i + req->firstKeySym);
147        outSym = (CARD32 *) &desc[1];
148        if (desc->nSyms > 0) {
149            pSym = XkbKeySymsPtr(xkb, i + req->firstKeySym);
150            _XkbWriteCopyKeySyms(pSym, outSym, desc->nSyms);
151        }
152    }
153    return;
154}
155
156static int
157_XkbSizeKeyActions(XkbDescPtr xkb, xkbSetMapReq *req)
158{
159    int i, len, nActs;
160
161    if (((req->present & XkbKeyActionsMask) == 0) || (req->nKeyActs == 0)) {
162        req->present &= ~XkbKeyActionsMask;
163        req->firstKeyAct = req->nKeyActs = 0;
164        req->totalActs = 0;
165        return 0;
166    }
167    for (nActs = i = 0; i < req->nKeyActs; i++) {
168        if (xkb->server->key_acts[i + req->firstKeyAct] != 0)
169            nActs += XkbKeyNumActions(xkb, i + req->firstKeyAct);
170    }
171    len = XkbPaddedSize(req->nKeyActs) + (nActs * SIZEOF(xkbActionWireDesc));
172    req->totalActs = nActs;
173    return len;
174}
175
176static void
177_XkbWriteKeyActions(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
178{
179    register int i;
180    int n;
181    CARD8 *numDesc;
182    XkbAction *actDesc;
183
184    if ((req->present & XkbKeyActionsMask) == 0)
185        return;
186    n = XkbPaddedSize(req->nKeyActs);
187    n += (req->totalActs * SIZEOF(xkbActionWireDesc));
188
189    BufAlloc(CARD8 *, numDesc, n);
190    for (i = 0; i < req->nKeyActs; i++) {
191        if (xkb->server->key_acts[i + req->firstKeyAct] == 0)
192            numDesc[i] = 0;
193        else
194            numDesc[i] = XkbKeyNumActions(xkb, (i + req->firstKeyAct));
195    }
196    actDesc = (XkbAction *) &numDesc[XkbPaddedSize(req->nKeyActs)];
197    for (i = 0; i < req->nKeyActs; i++) {
198        if (xkb->server->key_acts[i + req->firstKeyAct] != 0) {
199            n = XkbKeyNumActions(xkb, (i + req->firstKeyAct));
200            memcpy(actDesc, XkbKeyActionsPtr(xkb, (i + req->firstKeyAct)),
201                   n * SIZEOF(xkbActionWireDesc));
202            actDesc += n;
203        }
204    }
205    return;
206}
207
208static int
209_XkbSizeKeyBehaviors(XkbDescPtr xkb, xkbSetMapReq *req)
210{
211    register int i, first, last, nFound;
212
213    if (((req->present & XkbKeyBehaviorsMask) == 0) || (req->nKeyBehaviors < 1)) {
214        req->present &= ~XkbKeyBehaviorsMask;
215        req->firstKeyBehavior = req->nKeyBehaviors = 0;
216        req->totalKeyBehaviors = 0;
217        return 0;
218    }
219    first = req->firstKeyBehavior;
220    last = first + req->nKeyBehaviors - 1;
221    for (i = first, nFound = 0; i <= last; i++) {
222        if (xkb->server->behaviors[i].type != XkbKB_Default)
223            nFound++;
224    }
225    req->totalKeyBehaviors = nFound;
226    return (nFound * SIZEOF(xkbBehaviorWireDesc));
227}
228
229static void
230_XkbWriteKeyBehaviors(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
231{
232    register int i, first, last;
233    xkbBehaviorWireDesc *wire;
234    char *buf;
235
236    if ((req->present & XkbKeyBehaviorsMask) == 0)
237        return;
238    first = req->firstKeyBehavior;
239    last = first + req->nKeyBehaviors - 1;
240
241    i = req->totalKeyBehaviors * SIZEOF(xkbBehaviorWireDesc);
242    BufAlloc(char *, buf, i);
243    wire = (xkbBehaviorWireDesc *) buf;
244    for (i = first; i <= last; i++) {
245        if (xkb->server->behaviors[i].type != XkbKB_Default) {
246            wire->key = i;
247            wire->type = xkb->server->behaviors[i].type;
248            wire->data = xkb->server->behaviors[i].data;
249            buf += SIZEOF(xkbBehaviorWireDesc);
250            wire = (xkbBehaviorWireDesc *) buf;
251        }
252    }
253    return;
254}
255
256static unsigned
257_XkbSizeVirtualMods(xkbSetMapReq *req)
258{
259    register int i, bit, nMods;
260
261    if (((req->present & XkbVirtualModsMask) == 0) || (req->virtualMods == 0)) {
262        req->present &= ~XkbVirtualModsMask;
263        req->virtualMods = 0;
264        return 0;
265    }
266    for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
267        if (req->virtualMods & bit)
268            nMods++;
269    }
270    return XkbPaddedSize(nMods);
271}
272
273static void
274_XkbWriteVirtualMods(Display *dpy,
275                     XkbDescPtr xkb,
276                     xkbSetMapReq *req,
277                     unsigned size)
278{
279    register int i, bit;
280    CARD8 *vmods;
281
282    /* This was req->present&XkbVirtualModsMask==0, and '==' beats '&' */
283    if (((req->present & XkbVirtualModsMask) == 0) || (size < 1))
284        return;
285    BufAlloc(CARD8 *, vmods, size);
286    for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
287        if (req->virtualMods & bit)
288            *vmods++ = xkb->server->vmods[i];
289    }
290    return;
291}
292
293static int
294_XkbSizeKeyExplicit(XkbDescPtr xkb, xkbSetMapReq *req)
295{
296    register int i, first, last, nFound;
297
298    if (((req->present & XkbExplicitComponentsMask) == 0) ||
299        (req->nKeyExplicit == 0)) {
300        req->present &= ~XkbExplicitComponentsMask;
301        req->firstKeyExplicit = req->nKeyExplicit = 0;
302        req->totalKeyExplicit = 0;
303        return 0;
304    }
305    first = req->firstKeyExplicit;
306    last = first + req->nKeyExplicit - 1;
307
308    for (i = first, nFound = 0; i <= last; i++) {
309        if (xkb->server->explicit[i] != 0)
310            nFound++;
311    }
312    req->totalKeyExplicit = nFound;
313    return XkbPaddedSize((nFound * 2));
314}
315
316static void
317_XkbWriteKeyExplicit(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
318{
319    register int i, first, last;
320    CARD8 *wire;
321
322    if ((req->present & XkbExplicitComponentsMask) == 0)
323        return;
324    first = req->firstKeyExplicit;
325    last = first + req->nKeyExplicit - 1;
326    i = XkbPaddedSize((req->totalKeyExplicit * 2));
327    BufAlloc(CARD8 *, wire, i);
328    for (i = first; i <= last; i++) {
329        if (xkb->server->explicit[i] != 0) {
330            wire[0] = i;
331            wire[1] = xkb->server->explicit[i];
332            wire += 2;
333        }
334    }
335    return;
336}
337
338static int
339_XkbSizeModifierMap(XkbDescPtr xkb, xkbSetMapReq *req)
340{
341    register int i, first, last, nFound;
342
343    if (((req->present & XkbModifierMapMask) == 0) || (req->nModMapKeys == 0)) {
344        req->present &= ~XkbModifierMapMask;
345        req->firstModMapKey = req->nModMapKeys = 0;
346        req->totalModMapKeys = 0;
347        return 0;
348    }
349    first = req->firstModMapKey;
350    last = first + req->nModMapKeys - 1;
351
352    for (i = first, nFound = 0; i <= last; i++) {
353        if (xkb->map->modmap[i] != 0)
354            nFound++;
355    }
356    req->totalModMapKeys = nFound;
357    return XkbPaddedSize((nFound * 2));
358}
359
360static void
361_XkbWriteModifierMap(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
362{
363    register int i, first, last;
364    CARD8 *wire;
365
366    if ((req->present & XkbModifierMapMask) == 0)
367        return;
368    first = req->firstModMapKey;
369    last = first + req->nModMapKeys - 1;
370    if (req->totalModMapKeys > 0) {
371        i = XkbPaddedSize((req->totalModMapKeys * 2));
372        BufAlloc(CARD8 *, wire, i);
373
374        for (i = first; i <= last; i++) {
375            if (xkb->map->modmap[i] != 0) {
376                wire[0] = i;
377                wire[1] = xkb->map->modmap[i];
378                wire += 2;
379            }
380        }
381    }
382    return;
383}
384
385static int
386_XkbSizeVirtualModMap(XkbDescPtr xkb, xkbSetMapReq *req)
387{
388    register int i, first, last, nFound;
389
390    if (((req->present & XkbVirtualModMapMask) == 0) ||
391        (req->nVModMapKeys == 0)) {
392        req->present &= ~XkbVirtualModMapMask;
393        req->firstVModMapKey = req->nVModMapKeys = 0;
394        req->totalVModMapKeys = 0;
395        return 0;
396    }
397    first = req->firstVModMapKey;
398    last = first + req->nVModMapKeys - 1;
399
400    for (i = first, nFound = 0; i <= last; i++) {
401        if (xkb->server->vmodmap[i] != 0)
402            nFound++;
403    }
404    req->totalVModMapKeys = nFound;
405    return nFound * SIZEOF(xkbVModMapWireDesc);
406}
407
408static void
409_XkbWriteVirtualModMap(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
410{
411    register int i, first, last;
412    xkbVModMapWireDesc *wire;
413
414    if ((req->present & XkbVirtualModMapMask) == 0)
415        return;
416    first = req->firstVModMapKey;
417    last = first + req->nVModMapKeys - 1;
418    if (req->totalVModMapKeys > 0) {
419        i = req->totalVModMapKeys * SIZEOF(xkbVModMapWireDesc);
420        BufAlloc(xkbVModMapWireDesc *, wire, i);
421        for (i = first; i <= last; i++) {
422            if (xkb->server->vmodmap[i] != 0) {
423                wire->key = i;
424                wire->vmods = xkb->server->vmodmap[i];
425                wire++;
426            }
427        }
428    }
429    return;
430}
431
432static void
433SendSetMap(Display *dpy, XkbDescPtr xkb, xkbSetMapReq *req)
434{
435    xkbSetMapReq tmp;
436    unsigned szMods;
437
438    req->length += _XkbSizeKeyTypes(xkb, req) / 4;
439    req->length += _XkbSizeKeySyms(xkb, req) / 4;
440    req->length += _XkbSizeKeyActions(xkb, req) / 4;
441    req->length += _XkbSizeKeyBehaviors(xkb, req) / 4;
442    szMods = _XkbSizeVirtualMods(req);
443    req->length += szMods / 4;
444    req->length += _XkbSizeKeyExplicit(xkb, req) / 4;
445    req->length += _XkbSizeModifierMap(xkb, req) / 4;
446    req->length += _XkbSizeVirtualModMap(xkb, req) / 4;
447
448    tmp = *req;
449    if (tmp.nTypes > 0)
450        _XkbWriteKeyTypes(dpy, xkb, &tmp);
451    if (tmp.nKeySyms > 0)
452        _XkbWriteKeySyms(dpy, xkb, &tmp);
453    if (tmp.nKeyActs)
454        _XkbWriteKeyActions(dpy, xkb, &tmp);
455    if (tmp.totalKeyBehaviors > 0)
456        _XkbWriteKeyBehaviors(dpy, xkb, &tmp);
457    if (tmp.virtualMods)
458        _XkbWriteVirtualMods(dpy, xkb, &tmp, szMods);
459    if (tmp.totalKeyExplicit > 0)
460        _XkbWriteKeyExplicit(dpy, xkb, &tmp);
461    if (tmp.totalModMapKeys > 0)
462        _XkbWriteModifierMap(dpy, xkb, &tmp);
463    if (tmp.totalVModMapKeys > 0)
464        _XkbWriteVirtualModMap(dpy, xkb, &tmp);
465    return;
466}
467
468Bool
469XkbSetMap(Display *dpy, unsigned which, XkbDescPtr xkb)
470{
471    register xkbSetMapReq *req;
472    XkbInfoPtr xkbi;
473    XkbServerMapPtr srv;
474    XkbClientMapPtr map;
475
476    if ((dpy->flags & XlibDisplayNoXkb) ||
477        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) || (!xkb))
478        return False;
479    map = xkb->map;
480    srv = xkb->server;
481
482    if (((which & XkbKeyTypesMask) && ((!map) || (!map->types))) ||
483        ((which & XkbKeySymsMask) &&
484         ((!map) || (!map->syms) || (!map->key_sym_map))) ||
485        ((which & XkbKeyActionsMask) && ((!srv) || (!srv->key_acts))) ||
486        ((which & XkbKeyBehaviorsMask) && ((!srv) || (!srv->behaviors))) ||
487        ((which & XkbVirtualModsMask) && (!srv)) ||
488        ((which & XkbExplicitComponentsMask) && ((!srv) || (!srv->explicit))) ||
489        ((which & XkbModifierMapMask) && ((!map) || (!map->modmap))) ||
490        ((which & XkbVirtualModMapMask) && ((!srv) || (!srv->vmodmap))))
491        return False;
492
493    LockDisplay(dpy);
494    xkbi = dpy->xkb_info;
495    GetReq(kbSetMap, req);
496    req->reqType = xkbi->codes->major_opcode;
497    req->xkbReqType = X_kbSetMap;
498    req->deviceSpec = xkb->device_spec;
499    req->present = which;
500    req->flags = XkbSetMapAllFlags;
501    req->minKeyCode = xkb->min_key_code;
502    req->maxKeyCode = xkb->max_key_code;
503    req->firstType = 0;
504    if (which & XkbKeyTypesMask)
505        req->nTypes = map->num_types;
506    else
507        req->nTypes = 0;
508    if (which & XkbKeySymsMask) {
509        req->firstKeySym = xkb->min_key_code;
510        req->nKeySyms = XkbNumKeys(xkb);
511    }
512    if (which & XkbKeyActionsMask) {
513        req->firstKeyAct = xkb->min_key_code;
514        req->nKeyActs = XkbNumKeys(xkb);
515    }
516    if (which & XkbKeyBehaviorsMask) {
517        req->firstKeyBehavior = xkb->min_key_code;
518        req->nKeyBehaviors = XkbNumKeys(xkb);
519    }
520    if (which & XkbVirtualModsMask)
521        req->virtualMods = ~0;
522    if (which & XkbExplicitComponentsMask) {
523        req->firstKeyExplicit = xkb->min_key_code;
524        req->nKeyExplicit = XkbNumKeys(xkb);
525    }
526    if (which & XkbModifierMapMask) {
527        req->firstModMapKey = xkb->min_key_code;
528        req->nModMapKeys = XkbNumKeys(xkb);
529    }
530    if (which & XkbVirtualModMapMask) {
531        req->firstVModMapKey = xkb->min_key_code;
532        req->nVModMapKeys = XkbNumKeys(xkb);
533    }
534    SendSetMap(dpy, xkb, req);
535    UnlockDisplay(dpy);
536    SyncHandle();
537    return True;
538}
539
540Bool
541XkbChangeMap(Display *dpy, XkbDescPtr xkb, XkbMapChangesPtr changes)
542{
543    register xkbSetMapReq *req;
544    XkbInfoPtr xkbi;
545    XkbServerMapPtr srv;
546    XkbClientMapPtr map;
547
548    if ((dpy->flags & XlibDisplayNoXkb) ||
549        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)) ||
550        (!xkb) || (!changes))
551        return False;
552    srv = xkb->server;
553    map = xkb->map;
554
555    if (((changes->changed & XkbKeyTypesMask) && ((!map) || (!map->types))) ||
556        ((changes->changed & XkbKeySymsMask) && ((!map) || (!map->syms) ||
557                                                 (!map->key_sym_map))) ||
558        ((changes->changed & XkbKeyActionsMask) && ((!srv) || (!srv->key_acts)))
559        || ((changes->changed & XkbKeyBehaviorsMask) &&
560            ((!srv) || (!srv->behaviors))) ||
561        ((changes->changed & XkbVirtualModsMask) && (!srv)) ||
562        ((changes->changed & XkbExplicitComponentsMask) &&
563         ((!srv) || (!srv->explicit))) ||
564        ((changes->changed & XkbModifierMapMask) && ((!map) || (!map->modmap)))
565        || ((changes->changed & XkbVirtualModMapMask) &&
566            ((!srv) || (!srv->vmodmap))))
567        return False;
568
569    LockDisplay(dpy);
570    xkbi = dpy->xkb_info;
571    GetReq(kbSetMap, req);
572    req->reqType = xkbi->codes->major_opcode;
573    req->xkbReqType = X_kbSetMap;
574    req->deviceSpec = xkb->device_spec;
575    req->present = changes->changed;
576    req->flags = XkbSetMapRecomputeActions;
577    req->minKeyCode = xkb->min_key_code;
578    req->maxKeyCode = xkb->max_key_code;
579    req->firstType = changes->first_type;
580    req->nTypes = changes->num_types;
581    req->firstKeySym = changes->first_key_sym;
582    req->nKeySyms = changes->num_key_syms;
583    req->firstKeyAct = changes->first_key_act;
584    req->nKeyActs = changes->num_key_acts;
585    req->firstKeyBehavior = changes->first_key_behavior;
586    req->nKeyBehaviors = changes->num_key_behaviors;
587    req->virtualMods = changes->vmods;
588    req->firstKeyExplicit = changes->first_key_explicit;
589    req->nKeyExplicit = changes->num_key_explicit;
590    req->firstModMapKey = changes->first_modmap_key;
591    req->nModMapKeys = changes->num_modmap_keys;
592    req->firstVModMapKey = changes->first_vmodmap_key;
593    req->nVModMapKeys = changes->num_vmodmap_keys;
594    SendSetMap(dpy, xkb, req);
595    UnlockDisplay(dpy);
596    SyncHandle();
597    return True;
598}
599