xkbUtils.c revision f2346221
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
28Copyright © 2008 Red Hat Inc.
29
30Permission is hereby granted, free of charge, to any person obtaining a
31copy of this software and associated documentation files (the "Software"),
32to deal in the Software without restriction, including without limitation
33the rights to use, copy, modify, merge, publish, distribute, sublicense,
34and/or sell copies of the Software, and to permit persons to whom the
35Software is furnished to do so, subject to the following conditions:
36
37The above copyright notice and this permission notice (including the next
38paragraph) shall be included in all copies or substantial portions of the
39Software.
40
41THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47DEALINGS IN THE SOFTWARE.
48
49*/
50
51#ifdef HAVE_DIX_CONFIG_H
52#include <dix-config.h>
53#endif
54
55#include "os.h"
56#include <stdio.h>
57#include <ctype.h>
58#include <math.h>
59#include <X11/X.h>
60#include <X11/Xproto.h>
61#define	XK_CYRILLIC
62#include <X11/keysym.h>
63#include "misc.h"
64#include "inputstr.h"
65#include "eventstr.h"
66
67#define	XKBSRV_NEED_FILE_FUNCS
68#include <xkbsrv.h>
69#include "xkbgeom.h"
70#include "xkb.h"
71
72/***====================================================================***/
73
74int
75_XkbLookupAnyDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
76                    Mask access_mode, int *xkb_err)
77{
78    int rc = XkbKeyboardErrorCode;
79
80    if (id == XkbUseCoreKbd)
81        id = PickKeyboard(client)->id;
82    else if (id == XkbUseCorePtr)
83        id = PickPointer(client)->id;
84
85    rc = dixLookupDevice(pDev, id, client, access_mode);
86    if (rc != Success)
87        *xkb_err = XkbErr_BadDevice;
88
89    return rc;
90}
91
92int
93_XkbLookupKeyboard(DeviceIntPtr *pDev, int id, ClientPtr client,
94                   Mask access_mode, int *xkb_err)
95{
96    DeviceIntPtr dev;
97    int rc;
98
99    if (id == XkbDfltXIId)
100        id = XkbUseCoreKbd;
101
102    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
103    if (rc != Success)
104        return rc;
105
106    dev = *pDev;
107    if (!dev->key || !dev->key->xkbInfo) {
108        *pDev = NULL;
109        *xkb_err = XkbErr_BadClass;
110        return XkbKeyboardErrorCode;
111    }
112    return Success;
113}
114
115int
116_XkbLookupBellDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
117                     Mask access_mode, int *xkb_err)
118{
119    DeviceIntPtr dev;
120    int rc;
121
122    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
123    if (rc != Success)
124        return rc;
125
126    dev = *pDev;
127    if (!dev->kbdfeed && !dev->bell) {
128        *pDev = NULL;
129        *xkb_err = XkbErr_BadClass;
130        return XkbKeyboardErrorCode;
131    }
132    return Success;
133}
134
135int
136_XkbLookupLedDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
137                    Mask access_mode, int *xkb_err)
138{
139    DeviceIntPtr dev;
140    int rc;
141
142    if (id == XkbDfltXIId)
143        id = XkbUseCorePtr;
144
145    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
146    if (rc != Success)
147        return rc;
148
149    dev = *pDev;
150    if (!dev->kbdfeed && !dev->leds) {
151        *pDev = NULL;
152        *xkb_err = XkbErr_BadClass;
153        return XkbKeyboardErrorCode;
154    }
155    return Success;
156}
157
158int
159_XkbLookupButtonDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
160                       Mask access_mode, int *xkb_err)
161{
162    DeviceIntPtr dev;
163    int rc;
164
165    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
166    if (rc != Success)
167        return rc;
168
169    dev = *pDev;
170    if (!dev->button) {
171        *pDev = NULL;
172        *xkb_err = XkbErr_BadClass;
173        return XkbKeyboardErrorCode;
174    }
175    return Success;
176}
177
178void
179XkbSetActionKeyMods(XkbDescPtr xkb, XkbAction *act, unsigned mods)
180{
181    register unsigned tmp;
182
183    switch (act->type) {
184    case XkbSA_SetMods:
185    case XkbSA_LatchMods:
186    case XkbSA_LockMods:
187        if (act->mods.flags & XkbSA_UseModMapMods)
188            act->mods.real_mods = act->mods.mask = mods;
189        if ((tmp = XkbModActionVMods(&act->mods)) != 0)
190            act->mods.mask |= XkbMaskForVMask(xkb, tmp);
191        break;
192    case XkbSA_ISOLock:
193        if (act->iso.flags & XkbSA_UseModMapMods)
194            act->iso.real_mods = act->iso.mask = mods;
195        if ((tmp = XkbModActionVMods(&act->iso)) != 0)
196            act->iso.mask |= XkbMaskForVMask(xkb, tmp);
197        break;
198    }
199    return;
200}
201
202unsigned
203XkbMaskForVMask(XkbDescPtr xkb, unsigned vmask)
204{
205    register int i, bit;
206    register unsigned mask;
207
208    for (mask = i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
209        if (vmask & bit)
210            mask |= xkb->server->vmods[i];
211    }
212    return mask;
213}
214
215/***====================================================================***/
216
217void
218XkbUpdateKeyTypesFromCore(DeviceIntPtr pXDev,
219                          KeySymsPtr pCore,
220                          KeyCode first, CARD8 num, XkbChangesPtr changes)
221{
222    XkbDescPtr xkb;
223    unsigned key, nG, explicit;
224    int types[XkbNumKbdGroups];
225    KeySym tsyms[XkbMaxSymsPerKey] = {NoSymbol}, *syms;
226    XkbMapChangesPtr mc;
227
228    xkb = pXDev->key->xkbInfo->desc;
229    if (first + num - 1 > xkb->max_key_code) {
230        /* 1/12/95 (ef) -- XXX! should allow XKB structures to grow */
231        num = xkb->max_key_code - first + 1;
232    }
233
234    mc = (changes ? (&changes->map) : NULL);
235
236    syms = &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth];
237    for (key = first; key < (first + num); key++, syms += pCore->mapWidth) {
238        explicit = xkb->server->explicit[key] & XkbExplicitKeyTypesMask;
239        types[XkbGroup1Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
240        types[XkbGroup2Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup2Index);
241        types[XkbGroup3Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup3Index);
242        types[XkbGroup4Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup4Index);
243        nG = XkbKeyTypesForCoreSymbols(xkb, pCore->mapWidth, syms, explicit,
244                                       types, tsyms);
245        XkbChangeTypesOfKey(xkb, key, nG, XkbAllGroupsMask, types, mc);
246        memcpy((char *) XkbKeySymsPtr(xkb, key), (char *) tsyms,
247               XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
248    }
249    if (changes->map.changed & XkbKeySymsMask) {
250        CARD8 oldLast, newLast;
251
252        oldLast = changes->map.first_key_sym + changes->map.num_key_syms - 1;
253        newLast = first + num - 1;
254
255        if (first < changes->map.first_key_sym)
256            changes->map.first_key_sym = first;
257        if (oldLast > newLast)
258            newLast = oldLast;
259        changes->map.num_key_syms = newLast - changes->map.first_key_sym + 1;
260    }
261    else {
262        changes->map.changed |= XkbKeySymsMask;
263        changes->map.first_key_sym = first;
264        changes->map.num_key_syms = num;
265    }
266    return;
267}
268
269void
270XkbUpdateDescActions(XkbDescPtr xkb,
271                     KeyCode first, CARD8 num, XkbChangesPtr changes)
272{
273    register unsigned key;
274
275    for (key = first; key < (first + num); key++) {
276        XkbApplyCompatMapToKey(xkb, key, changes);
277    }
278
279    if (changes->map.changed & (XkbVirtualModMapMask | XkbModifierMapMask)) {
280        unsigned char newVMods[XkbNumVirtualMods];
281        register unsigned bit, i;
282        unsigned present;
283
284        memset(newVMods, 0, XkbNumVirtualMods);
285        present = 0;
286        for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
287            if (xkb->server->vmodmap[key] == 0)
288                continue;
289            for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
290                if (bit & xkb->server->vmodmap[key]) {
291                    present |= bit;
292                    newVMods[i] |= xkb->map->modmap[key];
293                }
294            }
295        }
296        for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
297            if ((bit & present) && (newVMods[i] != xkb->server->vmods[i])) {
298                changes->map.changed |= XkbVirtualModsMask;
299                changes->map.vmods |= bit;
300                xkb->server->vmods[i] = newVMods[i];
301            }
302        }
303    }
304    if (changes->map.changed & XkbVirtualModsMask)
305        XkbApplyVirtualModChanges(xkb, changes->map.vmods, changes);
306
307    if (changes->map.changed & XkbKeyActionsMask) {
308        CARD8 oldLast, newLast;
309
310        oldLast = changes->map.first_key_act + changes->map.num_key_acts - 1;
311        newLast = first + num - 1;
312
313        if (first < changes->map.first_key_act)
314            changes->map.first_key_act = first;
315        if (newLast > oldLast)
316            newLast = oldLast;
317        changes->map.num_key_acts = newLast - changes->map.first_key_act + 1;
318    }
319    else {
320        changes->map.changed |= XkbKeyActionsMask;
321        changes->map.first_key_act = first;
322        changes->map.num_key_acts = num;
323    }
324    return;
325}
326
327void
328XkbUpdateActions(DeviceIntPtr pXDev,
329                 KeyCode first,
330                 CARD8 num,
331                 XkbChangesPtr changes,
332                 unsigned *needChecksRtrn, XkbEventCausePtr cause)
333{
334    XkbSrvInfoPtr xkbi;
335    XkbDescPtr xkb;
336    CARD8 *repeat;
337
338    if (needChecksRtrn)
339        *needChecksRtrn = 0;
340    xkbi = pXDev->key->xkbInfo;
341    xkb = xkbi->desc;
342    repeat = xkb->ctrls->per_key_repeat;
343
344    /* before letting XKB do any changes, copy the current core values */
345    if (pXDev->kbdfeed)
346        memcpy(repeat, pXDev->kbdfeed->ctrl.autoRepeats, XkbPerKeyBitArraySize);
347
348    XkbUpdateDescActions(xkb, first, num, changes);
349
350    if ((pXDev->kbdfeed) &&
351        (changes->ctrls.changed_ctrls & XkbPerKeyRepeatMask)) {
352        /* now copy the modified changes back to core */
353        memcpy(pXDev->kbdfeed->ctrl.autoRepeats, repeat, XkbPerKeyBitArraySize);
354        if (pXDev->kbdfeed->CtrlProc)
355            (*pXDev->kbdfeed->CtrlProc) (pXDev, &pXDev->kbdfeed->ctrl);
356    }
357    return;
358}
359
360KeySymsPtr
361XkbGetCoreMap(DeviceIntPtr keybd)
362{
363    register int key, tmp;
364    int maxSymsPerKey, maxGroup1Width;
365    XkbDescPtr xkb;
366    KeySymsPtr syms;
367    int maxNumberOfGroups;
368
369    if (!keybd || !keybd->key || !keybd->key->xkbInfo)
370        return NULL;
371
372    xkb = keybd->key->xkbInfo->desc;
373    maxSymsPerKey = maxGroup1Width = 0;
374    maxNumberOfGroups = 0;
375
376    /* determine sizes */
377    for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
378        if (XkbKeycodeInRange(xkb, key)) {
379            int nGroups;
380            int w;
381
382            nGroups = XkbKeyNumGroups(xkb, key);
383            tmp = 0;
384            if (nGroups > 0) {
385                if ((w = XkbKeyGroupWidth(xkb, key, XkbGroup1Index)) <= 2)
386                    tmp += 2;
387                else
388                    tmp += w + 2;
389                /* remember highest G1 width */
390                if (w > maxGroup1Width)
391                    maxGroup1Width = w;
392            }
393            if (nGroups > 1) {
394                if (tmp <= 2) {
395                    if ((w = XkbKeyGroupWidth(xkb, key, XkbGroup2Index)) < 2)
396                        tmp += 2;
397                    else
398                        tmp += w;
399                }
400                else {
401                    if ((w = XkbKeyGroupWidth(xkb, key, XkbGroup2Index)) > 2)
402                        tmp += w - 2;
403                }
404            }
405            if (nGroups > 2)
406                tmp += XkbKeyGroupWidth(xkb, key, XkbGroup3Index);
407            if (nGroups > 3)
408                tmp += XkbKeyGroupWidth(xkb, key, XkbGroup4Index);
409            if (tmp > maxSymsPerKey)
410                maxSymsPerKey = tmp;
411            if (nGroups > maxNumberOfGroups)
412                maxNumberOfGroups = nGroups;
413        }
414    }
415
416    if (maxSymsPerKey <= 0)
417        return NULL;
418
419    syms = calloc(1, sizeof(*syms));
420    if (!syms)
421        return NULL;
422
423    /* See Section 12.4 of the XKB Protocol spec. Because of the
424     * single-group distribution for multi-group keyboards, we have to
425     * have enough symbols for the largest group 1 to replicate across the
426     * number of groups on the keyboard. e.g. a single-group key with 4
427     * symbols on a keyboard that has 3 groups -> 12 syms per key */
428    if (maxSymsPerKey < maxNumberOfGroups * maxGroup1Width)
429        maxSymsPerKey = maxNumberOfGroups * maxGroup1Width;
430
431    syms->mapWidth = maxSymsPerKey;
432    syms->minKeyCode = xkb->min_key_code;
433    syms->maxKeyCode = xkb->max_key_code;
434
435    tmp = syms->mapWidth * (xkb->max_key_code - xkb->min_key_code + 1);
436    syms->map = calloc(tmp, sizeof(*syms->map));
437    if (!syms->map) {
438        free(syms);
439        return NULL;
440    }
441
442    for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
443        KeySym *pCore, *pXKB;
444        unsigned nGroups, groupWidth, n, nOut;
445
446        nGroups = XkbKeyNumGroups(xkb, key);
447        n = (key - xkb->min_key_code) * syms->mapWidth;
448        pCore = &syms->map[n];
449        pXKB = XkbKeySymsPtr(xkb, key);
450        nOut = 2;
451        if (nGroups > 0) {
452            groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index);
453            if (groupWidth > 0)
454                pCore[0] = pXKB[0];
455            if (groupWidth > 1)
456                pCore[1] = pXKB[1];
457            for (n = 2; n < groupWidth; n++)
458                pCore[2 + n] = pXKB[n];
459            if (groupWidth > 2)
460                nOut = groupWidth;
461        }
462
463        /* See XKB Protocol Sec, Section 12.4.
464           A 1-group key with ABCDE on a 2 group keyboard must be
465           duplicated across all groups as ABABCDECDE.
466         */
467        if (nGroups == 1) {
468            int idx, j;
469
470            groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index);
471
472            /* AB..CDE... -> ABABCDE... */
473            if (groupWidth > 0 && syms->mapWidth >= 3)
474                pCore[2] = pCore[0];
475            if (groupWidth > 1 && syms->mapWidth >= 4)
476                pCore[3] = pCore[1];
477
478            /* ABABCDE... -> ABABCDECDE */
479            idx = 2 + groupWidth;
480            while (groupWidth > 2 && idx < syms->mapWidth &&
481                   idx < groupWidth * 2) {
482                pCore[idx] = pCore[idx - groupWidth + 2];
483                idx++;
484            }
485            idx = 2 * groupWidth;
486            if (idx < 4)
487                idx = 4;
488            /* 3 or more groups: ABABCDECDEABCDEABCDE */
489            for (j = 3; j <= maxNumberOfGroups; j++)
490                for (n = 0; n < groupWidth && idx < maxSymsPerKey; n++)
491                    pCore[idx++] = pXKB[n];
492        }
493
494        pXKB += XkbKeyGroupsWidth(xkb, key);
495        nOut += 2;
496        if (nGroups > 1) {
497            groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup2Index);
498            if (groupWidth > 0)
499                pCore[2] = pXKB[0];
500            if (groupWidth > 1)
501                pCore[3] = pXKB[1];
502            for (n = 2; n < groupWidth; n++) {
503                pCore[nOut + (n - 2)] = pXKB[n];
504            }
505            if (groupWidth > 2)
506                nOut += (groupWidth - 2);
507        }
508        pXKB += XkbKeyGroupsWidth(xkb, key);
509        for (n = XkbGroup3Index; n < nGroups; n++) {
510            register int s;
511
512            groupWidth = XkbKeyGroupWidth(xkb, key, n);
513            for (s = 0; s < groupWidth; s++) {
514                pCore[nOut++] = pXKB[s];
515            }
516            pXKB += XkbKeyGroupsWidth(xkb, key);
517        }
518    }
519
520    return syms;
521}
522
523void
524XkbSetRepeatKeys(DeviceIntPtr pXDev, int key, int onoff)
525{
526    if (pXDev && pXDev->key && pXDev->key->xkbInfo) {
527        xkbControlsNotify cn;
528        XkbControlsPtr ctrls = pXDev->key->xkbInfo->desc->ctrls;
529        XkbControlsRec old;
530
531        old = *ctrls;
532
533        if (key == -1) {        /* global autorepeat setting changed */
534            if (onoff)
535                ctrls->enabled_ctrls |= XkbRepeatKeysMask;
536            else
537                ctrls->enabled_ctrls &= ~XkbRepeatKeysMask;
538        }
539        else if (pXDev->kbdfeed) {
540            ctrls->per_key_repeat[key / 8] =
541                pXDev->kbdfeed->ctrl.autoRepeats[key / 8];
542        }
543
544        if (XkbComputeControlsNotify(pXDev, &old, ctrls, &cn, TRUE))
545            XkbSendControlsNotify(pXDev, &cn);
546    }
547    return;
548}
549
550/* Applies a change to a single device, does not traverse the device tree. */
551void
552XkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key,
553                      CARD8 num_keys, CARD8 *modmap, ClientPtr client)
554{
555    XkbDescPtr xkb = kbd->key->xkbInfo->desc;
556    XkbEventCauseRec cause;
557    XkbChangesRec changes;
558    unsigned int check;
559
560    memset(&changes, 0, sizeof(changes));
561    memset(&cause, 0, sizeof(cause));
562
563    if (map && first_key && num_keys) {
564        check = 0;
565        XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client);
566
567        XkbUpdateKeyTypesFromCore(kbd, map, first_key, num_keys, &changes);
568        XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause);
569
570        if (check)
571            XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause);
572    }
573
574    if (modmap) {
575        /* A keymap change can imply a modmap change, se we prefer the
576         * former. */
577        if (!cause.mjr)
578            XkbSetCauseCoreReq(&cause, X_SetModifierMapping, client);
579
580        check = 0;
581        num_keys = xkb->max_key_code - xkb->min_key_code + 1;
582        changes.map.changed |= XkbModifierMapMask;
583        changes.map.first_modmap_key = xkb->min_key_code;
584        changes.map.num_modmap_keys = num_keys;
585        memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH);
586        XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check,
587                         &cause);
588
589        if (check)
590            XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause);
591    }
592
593    XkbSendNotification(kbd, &changes, &cause);
594}
595
596void
597XkbDisableComputedAutoRepeats(DeviceIntPtr dev, unsigned key)
598{
599    XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
600    xkbMapNotify mn;
601
602    xkbi->desc->server->explicit[key] |= XkbExplicitAutoRepeatMask;
603    memset(&mn, 0, sizeof(mn));
604    mn.changed = XkbExplicitComponentsMask;
605    mn.firstKeyExplicit = key;
606    mn.nKeyExplicit = 1;
607    XkbSendMapNotify(dev, &mn);
608    return;
609}
610
611unsigned
612XkbStateChangedFlags(XkbStatePtr old, XkbStatePtr new)
613{
614    int changed;
615
616    changed = (old->group != new->group ? XkbGroupStateMask : 0);
617    changed |= (old->base_group != new->base_group ? XkbGroupBaseMask : 0);
618    changed |=
619        (old->latched_group != new->latched_group ? XkbGroupLatchMask : 0);
620    changed |= (old->locked_group != new->locked_group ? XkbGroupLockMask : 0);
621    changed |= (old->mods != new->mods ? XkbModifierStateMask : 0);
622    changed |= (old->base_mods != new->base_mods ? XkbModifierBaseMask : 0);
623    changed |=
624        (old->latched_mods != new->latched_mods ? XkbModifierLatchMask : 0);
625    changed |= (old->locked_mods != new->locked_mods ? XkbModifierLockMask : 0);
626    changed |=
627        (old->compat_state != new->compat_state ? XkbCompatStateMask : 0);
628    changed |= (old->grab_mods != new->grab_mods ? XkbGrabModsMask : 0);
629    if (old->compat_grab_mods != new->compat_grab_mods)
630        changed |= XkbCompatGrabModsMask;
631    changed |= (old->lookup_mods != new->lookup_mods ? XkbLookupModsMask : 0);
632    if (old->compat_lookup_mods != new->compat_lookup_mods)
633        changed |= XkbCompatLookupModsMask;
634    changed |=
635        (old->ptr_buttons != new->ptr_buttons ? XkbPointerButtonMask : 0);
636    return changed;
637}
638
639static void
640XkbComputeCompatState(XkbSrvInfoPtr xkbi)
641{
642    CARD16 grp_mask;
643    XkbStatePtr state = &xkbi->state;
644    XkbCompatMapPtr map;
645    XkbControlsPtr ctrls;
646
647    if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat)
648        return;
649
650    map = xkbi->desc->compat;
651    grp_mask = map->groups[state->group].mask;
652    state->compat_state = state->mods | grp_mask;
653    state->compat_lookup_mods = state->lookup_mods | grp_mask;
654    ctrls= xkbi->desc->ctrls;
655
656    if (ctrls->enabled_ctrls & XkbIgnoreGroupLockMask) {
657	unsigned char grp = state->base_group+state->latched_group;
658	if (grp >= ctrls->num_groups)
659	    grp = XkbAdjustGroup(XkbCharToInt(grp), ctrls);
660        grp_mask = map->groups[grp].mask;
661    }
662    state->compat_grab_mods = state->grab_mods | grp_mask;
663    return;
664}
665
666unsigned
667XkbAdjustGroup(int group, XkbControlsPtr ctrls)
668{
669    unsigned act;
670
671    act = XkbOutOfRangeGroupAction(ctrls->groups_wrap);
672    if (group < 0) {
673        while (group < 0) {
674            if (act == XkbClampIntoRange) {
675                group = XkbGroup1Index;
676            }
677            else if (act == XkbRedirectIntoRange) {
678                int newGroup;
679
680                newGroup = XkbOutOfRangeGroupNumber(ctrls->groups_wrap);
681                if (newGroup >= ctrls->num_groups)
682                    group = XkbGroup1Index;
683                else
684                    group = newGroup;
685            }
686            else {
687                group += ctrls->num_groups;
688            }
689        }
690    }
691    else if (group >= ctrls->num_groups) {
692        if (act == XkbClampIntoRange) {
693            group = ctrls->num_groups - 1;
694        }
695        else if (act == XkbRedirectIntoRange) {
696            int newGroup;
697
698            newGroup = XkbOutOfRangeGroupNumber(ctrls->groups_wrap);
699            if (newGroup >= ctrls->num_groups)
700                group = XkbGroup1Index;
701            else
702                group = newGroup;
703        }
704        else {
705            group %= ctrls->num_groups;
706        }
707    }
708    return group;
709}
710
711void
712XkbComputeDerivedState(XkbSrvInfoPtr xkbi)
713{
714    XkbStatePtr state = &xkbi->state;
715    XkbControlsPtr ctrls = xkbi->desc->ctrls;
716    unsigned char grp;
717
718    if (!state || !ctrls)
719        return;
720
721    state->mods = (state->base_mods | state->latched_mods | state->locked_mods);
722    state->lookup_mods = state->mods & (~ctrls->internal.mask);
723    state->grab_mods = state->lookup_mods & (~ctrls->ignore_lock.mask);
724    state->grab_mods |=
725        ((state->base_mods | state->latched_mods) & ctrls->ignore_lock.mask);
726
727    grp = state->locked_group;
728    if (grp >= ctrls->num_groups)
729        state->locked_group = XkbAdjustGroup(XkbCharToInt(grp), ctrls);
730
731    grp = state->locked_group + state->base_group + state->latched_group;
732    if (grp >= ctrls->num_groups)
733        state->group = XkbAdjustGroup(XkbCharToInt(grp), ctrls);
734    else
735        state->group = grp;
736    XkbComputeCompatState(xkbi);
737    return;
738}
739
740/***====================================================================***/
741
742void
743XkbCheckSecondaryEffects(XkbSrvInfoPtr xkbi,
744                         unsigned which,
745                         XkbChangesPtr changes, XkbEventCausePtr cause)
746{
747    if (which & XkbStateNotifyMask) {
748        XkbStateRec old;
749
750        old = xkbi->state;
751        changes->state_changes |= XkbStateChangedFlags(&old, &xkbi->state);
752        XkbComputeDerivedState(xkbi);
753    }
754    if (which & XkbIndicatorStateNotifyMask)
755        XkbUpdateIndicators(xkbi->device, XkbAllIndicatorsMask, TRUE, changes,
756                            cause);
757    return;
758}
759
760/***====================================================================***/
761
762Bool
763XkbEnableDisableControls(XkbSrvInfoPtr xkbi,
764                         unsigned long change,
765                         unsigned long newValues,
766                         XkbChangesPtr changes, XkbEventCausePtr cause)
767{
768    XkbControlsPtr ctrls;
769    unsigned old;
770    XkbSrvLedInfoPtr sli;
771
772    ctrls = xkbi->desc->ctrls;
773    old = ctrls->enabled_ctrls;
774    ctrls->enabled_ctrls &= ~change;
775    ctrls->enabled_ctrls |= (change & newValues);
776    if (old == ctrls->enabled_ctrls)
777        return FALSE;
778    if (cause != NULL) {
779        xkbControlsNotify cn;
780
781        cn.numGroups = ctrls->num_groups;
782        cn.changedControls = XkbControlsEnabledMask;
783        cn.enabledControls = ctrls->enabled_ctrls;
784        cn.enabledControlChanges = (ctrls->enabled_ctrls ^ old);
785        cn.keycode = cause->kc;
786        cn.eventType = cause->event;
787        cn.requestMajor = cause->mjr;
788        cn.requestMinor = cause->mnr;
789        XkbSendControlsNotify(xkbi->device, &cn);
790    }
791    else {
792        /* Yes, this really should be an XOR.  If ctrls->enabled_ctrls_changes */
793        /* is non-zero, the controls in question changed already in "this" */
794        /* request and this change merely undoes the previous one.  By the */
795        /* same token, we have to figure out whether or not ControlsEnabled */
796        /* should be set or not in the changes structure */
797        changes->ctrls.enabled_ctrls_changes ^= (ctrls->enabled_ctrls ^ old);
798        if (changes->ctrls.enabled_ctrls_changes)
799            changes->ctrls.changed_ctrls |= XkbControlsEnabledMask;
800        else
801            changes->ctrls.changed_ctrls &= ~XkbControlsEnabledMask;
802    }
803    sli = XkbFindSrvLedInfo(xkbi->device, XkbDfltXIClass, XkbDfltXIId, 0);
804    XkbUpdateIndicators(xkbi->device, sli->usesControls, TRUE, changes, cause);
805    return TRUE;
806}
807
808/***====================================================================***/
809
810#define	MAX_TOC	16
811
812XkbGeometryPtr
813XkbLookupNamedGeometry(DeviceIntPtr dev, Atom name, Bool *shouldFree)
814{
815    XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
816    XkbDescPtr xkb = xkbi->desc;
817
818    *shouldFree = 0;
819    if (name == None) {
820        if (xkb->geom != NULL)
821            return xkb->geom;
822        name = xkb->names->geometry;
823    }
824    if ((xkb->geom != NULL) && (xkb->geom->name == name))
825        return xkb->geom;
826    *shouldFree = 1;
827    return NULL;
828}
829
830void
831XkbConvertCase(register KeySym sym, KeySym * lower, KeySym * upper)
832{
833    *lower = sym;
834    *upper = sym;
835    switch (sym >> 8) {
836    case 0:                    /* Latin 1 */
837        if ((sym >= XK_A) && (sym <= XK_Z))
838            *lower += (XK_a - XK_A);
839        else if ((sym >= XK_a) && (sym <= XK_z))
840            *upper -= (XK_a - XK_A);
841        else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
842            *lower += (XK_agrave - XK_Agrave);
843        else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
844            *upper -= (XK_agrave - XK_Agrave);
845        else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
846            *lower += (XK_oslash - XK_Ooblique);
847        else if ((sym >= XK_oslash) && (sym <= XK_thorn))
848            *upper -= (XK_oslash - XK_Ooblique);
849        break;
850    case 1:                    /* Latin 2 */
851        /* Assume the KeySym is a legal value (ignore discontinuities) */
852        if (sym == XK_Aogonek)
853            *lower = XK_aogonek;
854        else if (sym >= XK_Lstroke && sym <= XK_Sacute)
855            *lower += (XK_lstroke - XK_Lstroke);
856        else if (sym >= XK_Scaron && sym <= XK_Zacute)
857            *lower += (XK_scaron - XK_Scaron);
858        else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
859            *lower += (XK_zcaron - XK_Zcaron);
860        else if (sym == XK_aogonek)
861            *upper = XK_Aogonek;
862        else if (sym >= XK_lstroke && sym <= XK_sacute)
863            *upper -= (XK_lstroke - XK_Lstroke);
864        else if (sym >= XK_scaron && sym <= XK_zacute)
865            *upper -= (XK_scaron - XK_Scaron);
866        else if (sym >= XK_zcaron && sym <= XK_zabovedot)
867            *upper -= (XK_zcaron - XK_Zcaron);
868        else if (sym >= XK_Racute && sym <= XK_Tcedilla)
869            *lower += (XK_racute - XK_Racute);
870        else if (sym >= XK_racute && sym <= XK_tcedilla)
871            *upper -= (XK_racute - XK_Racute);
872        break;
873    case 2:                    /* Latin 3 */
874        /* Assume the KeySym is a legal value (ignore discontinuities) */
875        if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
876            *lower += (XK_hstroke - XK_Hstroke);
877        else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
878            *lower += (XK_gbreve - XK_Gbreve);
879        else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
880            *upper -= (XK_hstroke - XK_Hstroke);
881        else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
882            *upper -= (XK_gbreve - XK_Gbreve);
883        else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
884            *lower += (XK_cabovedot - XK_Cabovedot);
885        else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
886            *upper -= (XK_cabovedot - XK_Cabovedot);
887        break;
888    case 3:                    /* Latin 4 */
889        /* Assume the KeySym is a legal value (ignore discontinuities) */
890        if (sym >= XK_Rcedilla && sym <= XK_Tslash)
891            *lower += (XK_rcedilla - XK_Rcedilla);
892        else if (sym >= XK_rcedilla && sym <= XK_tslash)
893            *upper -= (XK_rcedilla - XK_Rcedilla);
894        else if (sym == XK_ENG)
895            *lower = XK_eng;
896        else if (sym == XK_eng)
897            *upper = XK_ENG;
898        else if (sym >= XK_Amacron && sym <= XK_Umacron)
899            *lower += (XK_amacron - XK_Amacron);
900        else if (sym >= XK_amacron && sym <= XK_umacron)
901            *upper -= (XK_amacron - XK_Amacron);
902        break;
903    case 6:                    /* Cyrillic */
904        /* Assume the KeySym is a legal value (ignore discontinuities) */
905        if (sym >= XK_Serbian_DJE && sym <= XK_Cyrillic_DZHE)
906            *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
907        else if (sym >= XK_Serbian_dje && sym <= XK_Cyrillic_dzhe)
908            *upper += (XK_Serbian_DJE - XK_Serbian_dje);
909        else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
910            *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
911        else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
912            *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
913        break;
914    case 7:                    /* Greek */
915        /* Assume the KeySym is a legal value (ignore discontinuities) */
916        if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
917            *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
918        else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
919                 sym != XK_Greek_iotaaccentdieresis &&
920                 sym != XK_Greek_upsilonaccentdieresis)
921            *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
922        else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
923            *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
924        else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
925                 sym != XK_Greek_finalsmallsigma)
926            *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
927        break;
928    }
929}
930
931static Bool
932_XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst)
933{
934    void *tmp = NULL;
935    int i;
936    int gap;
937    XkbKeyTypePtr stype = NULL, dtype = NULL;
938
939    /* client map */
940    if (src->map) {
941        if (!dst->map) {
942            tmp = calloc(1, sizeof(XkbClientMapRec));
943            if (!tmp)
944                return FALSE;
945            dst->map = tmp;
946        }
947
948        if (src->map->syms) {
949            if (src->map->size_syms != dst->map->size_syms) {
950                tmp = reallocarray(dst->map->syms,
951                                   src->map->size_syms, sizeof(KeySym));
952                if (!tmp)
953                    return FALSE;
954                dst->map->syms = tmp;
955
956            }
957            memcpy(dst->map->syms, src->map->syms,
958                   src->map->size_syms * sizeof(KeySym));
959        }
960        else {
961            free(dst->map->syms);
962            dst->map->syms = NULL;
963        }
964        dst->map->num_syms = src->map->num_syms;
965        dst->map->size_syms = src->map->size_syms;
966        gap = MAP_LENGTH - (src->max_key_code + 1);
967
968        if (src->map->key_sym_map) {
969            if (!dst->map->key_sym_map) {
970                tmp = reallocarray(dst->map->key_sym_map,
971                                   MAP_LENGTH, sizeof(XkbSymMapRec));
972                if (!tmp)
973                    return FALSE;
974                dst->map->key_sym_map = tmp;
975            }
976            if (gap > 0) {
977                memset((char *) &dst->map->key_sym_map[gap], 0,
978                       gap * sizeof(XkbSymMapRec));
979            }
980            memcpy(dst->map->key_sym_map, src->map->key_sym_map,
981                   (src->max_key_code + 1) * sizeof(XkbSymMapRec));
982        }
983        else {
984            free(dst->map->key_sym_map);
985            dst->map->key_sym_map = NULL;
986        }
987
988        if (src->map->types && src->map->num_types) {
989            if (src->map->num_types > dst->map->size_types ||
990                !dst->map->types || !dst->map->size_types) {
991                if (dst->map->types && dst->map->size_types) {
992                    tmp = reallocarray(dst->map->types, src->map->num_types,
993                                       sizeof(XkbKeyTypeRec));
994                    if (!tmp)
995                        return FALSE;
996                    dst->map->types = tmp;
997                    memset(dst->map->types + dst->map->num_types, 0,
998                           (src->map->num_types - dst->map->num_types) *
999                           sizeof(XkbKeyTypeRec));
1000                }
1001                else {
1002                    tmp = calloc(src->map->num_types, sizeof(XkbKeyTypeRec));
1003                    if (!tmp)
1004                        return FALSE;
1005                    dst->map->types = tmp;
1006                }
1007            }
1008            else if (src->map->num_types < dst->map->num_types &&
1009                     dst->map->types) {
1010                for (i = src->map->num_types, dtype = (dst->map->types + i);
1011                     i < dst->map->num_types; i++, dtype++) {
1012                    free(dtype->level_names);
1013                    dtype->level_names = NULL;
1014                    dtype->num_levels = 0;
1015                    if (dtype->map_count) {
1016                        free(dtype->map);
1017                        free(dtype->preserve);
1018                    }
1019                }
1020            }
1021
1022            stype = src->map->types;
1023            dtype = dst->map->types;
1024            for (i = 0; i < src->map->num_types; i++, dtype++, stype++) {
1025                if (stype->num_levels && stype->level_names) {
1026                    if (stype->num_levels != dtype->num_levels &&
1027                        dtype->num_levels && dtype->level_names &&
1028                        i < dst->map->num_types) {
1029                        tmp = reallocarray(dtype->level_names,
1030                                           stype->num_levels, sizeof(Atom));
1031                        if (!tmp)
1032                            continue;
1033                        dtype->level_names = tmp;
1034                    }
1035                    else if (!dtype->num_levels || !dtype->level_names ||
1036                             i >= dst->map->num_types) {
1037                        tmp = malloc(stype->num_levels * sizeof(Atom));
1038                        if (!tmp)
1039                            continue;
1040                        dtype->level_names = tmp;
1041                    }
1042                    dtype->num_levels = stype->num_levels;
1043                    memcpy(dtype->level_names, stype->level_names,
1044                           stype->num_levels * sizeof(Atom));
1045                }
1046                else {
1047                    if (dtype->num_levels && dtype->level_names &&
1048                        i < dst->map->num_types)
1049                        free(dtype->level_names);
1050                    dtype->num_levels = 0;
1051                    dtype->level_names = NULL;
1052                }
1053
1054                dtype->name = stype->name;
1055                memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec));
1056
1057                if (stype->map_count) {
1058                    if (stype->map) {
1059                        if (stype->map_count != dtype->map_count &&
1060                            dtype->map_count && dtype->map &&
1061                            i < dst->map->num_types) {
1062                            tmp = reallocarray(dtype->map,
1063                                               stype->map_count,
1064                                               sizeof(XkbKTMapEntryRec));
1065                            if (!tmp)
1066                                return FALSE;
1067                            dtype->map = tmp;
1068                        }
1069                        else if (!dtype->map_count || !dtype->map ||
1070                                 i >= dst->map->num_types) {
1071                            tmp = xallocarray(stype->map_count,
1072                                              sizeof(XkbKTMapEntryRec));
1073                            if (!tmp)
1074                                return FALSE;
1075                            dtype->map = tmp;
1076                        }
1077
1078                        memcpy(dtype->map, stype->map,
1079                               stype->map_count * sizeof(XkbKTMapEntryRec));
1080                    }
1081                    else {
1082                        if (dtype->map && i < dst->map->num_types)
1083                            free(dtype->map);
1084                        dtype->map = NULL;
1085                    }
1086
1087                    if (stype->preserve) {
1088                        if (stype->map_count != dtype->map_count &&
1089                            dtype->map_count && dtype->preserve &&
1090                            i < dst->map->num_types) {
1091                            tmp = reallocarray(dtype->preserve,
1092                                               stype->map_count,
1093                                               sizeof(XkbModsRec));
1094                            if (!tmp)
1095                                return FALSE;
1096                            dtype->preserve = tmp;
1097                        }
1098                        else if (!dtype->preserve || !dtype->map_count ||
1099                                 i >= dst->map->num_types) {
1100                            tmp = xallocarray(stype->map_count,
1101                                              sizeof(XkbModsRec));
1102                            if (!tmp)
1103                                return FALSE;
1104                            dtype->preserve = tmp;
1105                        }
1106
1107                        memcpy(dtype->preserve, stype->preserve,
1108                               stype->map_count * sizeof(XkbModsRec));
1109                    }
1110                    else {
1111                        if (dtype->preserve && i < dst->map->num_types)
1112                            free(dtype->preserve);
1113                        dtype->preserve = NULL;
1114                    }
1115
1116                    dtype->map_count = stype->map_count;
1117                }
1118                else {
1119                    if (dtype->map_count && i < dst->map->num_types) {
1120                        free(dtype->map);
1121                        free(dtype->preserve);
1122                    }
1123                    dtype->map_count = 0;
1124                    dtype->map = NULL;
1125                    dtype->preserve = NULL;
1126                }
1127            }
1128
1129            dst->map->size_types = src->map->num_types;
1130            dst->map->num_types = src->map->num_types;
1131        }
1132        else {
1133            if (dst->map->types) {
1134                for (i = 0, dtype = dst->map->types; i < dst->map->num_types;
1135                     i++, dtype++) {
1136                    free(dtype->level_names);
1137                    if (dtype->map && dtype->map_count)
1138                        free(dtype->map);
1139                    if (dtype->preserve && dtype->map_count)
1140                        free(dtype->preserve);
1141                }
1142            }
1143            free(dst->map->types);
1144            dst->map->types = NULL;
1145            dst->map->num_types = 0;
1146            dst->map->size_types = 0;
1147        }
1148
1149        if (src->map->modmap) {
1150            if (!dst->map->modmap) {
1151                tmp = realloc(dst->map->modmap, MAP_LENGTH);
1152                if (!tmp)
1153                    return FALSE;
1154                dst->map->modmap = tmp;
1155            }
1156            if (gap > 0) {
1157                memset(dst->map->modmap + gap, 0, gap);
1158            }
1159            memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1);
1160        }
1161        else {
1162            free(dst->map->modmap);
1163            dst->map->modmap = NULL;
1164        }
1165    }
1166    else {
1167        if (dst->map)
1168            XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE);
1169    }
1170
1171    return TRUE;
1172}
1173
1174static Bool
1175_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
1176{
1177    void *tmp = NULL;
1178    int gap;
1179
1180    /* server map */
1181    if (src->server) {
1182        if (!dst->server) {
1183            tmp = calloc(1, sizeof(XkbServerMapRec));
1184            if (!tmp)
1185                return FALSE;
1186            dst->server = tmp;
1187        }
1188
1189        gap = MAP_LENGTH - (src->max_key_code + 1);
1190        if (src->server->explicit) {
1191            if (!dst->server->explicit) {
1192                tmp = realloc(dst->server->explicit, MAP_LENGTH);
1193                if (!tmp)
1194                    return FALSE;
1195                dst->server->explicit = tmp;
1196            }
1197            if (gap > 0)
1198                memset(dst->server->explicit + gap, 0, gap);
1199            memcpy(dst->server->explicit, src->server->explicit,
1200                   src->max_key_code + 1);
1201        }
1202        else {
1203            free(dst->server->explicit);
1204            dst->server->explicit = NULL;
1205        }
1206
1207        if (src->server->acts) {
1208            if (src->server->size_acts != dst->server->size_acts) {
1209                tmp = reallocarray(dst->server->acts,
1210                                   src->server->size_acts, sizeof(XkbAction));
1211                if (!tmp)
1212                    return FALSE;
1213                dst->server->acts = tmp;
1214            }
1215            memcpy(dst->server->acts, src->server->acts,
1216                   src->server->size_acts * sizeof(XkbAction));
1217        }
1218        else {
1219            free(dst->server->acts);
1220            dst->server->acts = NULL;
1221        }
1222        dst->server->size_acts = src->server->size_acts;
1223        dst->server->num_acts = src->server->num_acts;
1224
1225        if (src->server->key_acts) {
1226            if (!dst->server->key_acts) {
1227                tmp = reallocarray(dst->server->key_acts,
1228                                   MAP_LENGTH, sizeof(unsigned short));
1229                if (!tmp)
1230                    return FALSE;
1231                dst->server->key_acts = tmp;
1232            }
1233            if (gap > 0)
1234                memset((char *) &dst->server->key_acts[gap], 0, gap * sizeof(unsigned short));
1235            memcpy(dst->server->key_acts, src->server->key_acts,
1236                   (src->max_key_code + 1) * sizeof(unsigned short));
1237        }
1238        else {
1239            free(dst->server->key_acts);
1240            dst->server->key_acts = NULL;
1241        }
1242
1243        if (src->server->behaviors) {
1244            if (!dst->server->behaviors) {
1245                tmp = reallocarray(dst->server->behaviors,
1246                                   MAP_LENGTH, sizeof(XkbBehavior));
1247                if (!tmp)
1248                    return FALSE;
1249                dst->server->behaviors = tmp;
1250            }
1251            if (gap > 0)
1252                memset((char *) &dst->server->behaviors[gap], 0, gap * sizeof(XkbBehavior));
1253            memcpy(dst->server->behaviors, src->server->behaviors,
1254                   (src->max_key_code + 1) * sizeof(XkbBehavior));
1255        }
1256        else {
1257            free(dst->server->behaviors);
1258            dst->server->behaviors = NULL;
1259        }
1260
1261        memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods);
1262
1263        if (src->server->vmodmap) {
1264            if (!dst->server->vmodmap) {
1265                tmp = reallocarray(dst->server->vmodmap,
1266                                   MAP_LENGTH, sizeof(unsigned short));
1267                if (!tmp)
1268                    return FALSE;
1269                dst->server->vmodmap = tmp;
1270            }
1271            if (gap > 0)
1272                memset((char *) &dst->server->vmodmap[gap], 0, gap * sizeof(unsigned short));
1273            memcpy(dst->server->vmodmap, src->server->vmodmap,
1274                   (src->max_key_code + 1) * sizeof(unsigned short));
1275        }
1276        else {
1277            free(dst->server->vmodmap);
1278            dst->server->vmodmap = NULL;
1279        }
1280    }
1281    else {
1282        if (dst->server)
1283            XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE);
1284    }
1285
1286    return TRUE;
1287}
1288
1289static Bool
1290_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst)
1291{
1292    void *tmp = NULL;
1293    int gap;
1294
1295    /* names */
1296    if (src->names) {
1297        if (!dst->names) {
1298            dst->names = calloc(1, sizeof(XkbNamesRec));
1299            if (!dst->names)
1300                return FALSE;
1301        }
1302
1303        gap = MAP_LENGTH - (src->max_key_code + 1);
1304        if (src->names->keys) {
1305            if (!dst->names->keys) {
1306                tmp = reallocarray(dst->names->keys, MAP_LENGTH,
1307                                   sizeof(XkbKeyNameRec));
1308                if (!tmp)
1309                    return FALSE;
1310                dst->names->keys = tmp;
1311            }
1312            if (gap > 0)
1313                memset((char *) &dst->names->keys[gap], 0, gap * sizeof(XkbKeyNameRec));
1314            memcpy(dst->names->keys, src->names->keys,
1315                   (src->max_key_code + 1) * sizeof(XkbKeyNameRec));
1316        }
1317        else {
1318            free(dst->names->keys);
1319            dst->names->keys = NULL;
1320        }
1321
1322        if (src->names->num_key_aliases) {
1323            if (src->names->num_key_aliases != dst->names->num_key_aliases) {
1324                tmp = reallocarray(dst->names->key_aliases,
1325                                   src->names->num_key_aliases,
1326                                   sizeof(XkbKeyAliasRec));
1327                if (!tmp)
1328                    return FALSE;
1329                dst->names->key_aliases = tmp;
1330            }
1331            memcpy(dst->names->key_aliases, src->names->key_aliases,
1332                   src->names->num_key_aliases * sizeof(XkbKeyAliasRec));
1333        }
1334        else {
1335            free(dst->names->key_aliases);
1336            dst->names->key_aliases = NULL;
1337        }
1338        dst->names->num_key_aliases = src->names->num_key_aliases;
1339
1340        if (src->names->num_rg) {
1341            if (src->names->num_rg != dst->names->num_rg) {
1342                tmp = reallocarray(dst->names->radio_groups,
1343                                   src->names->num_rg, sizeof(Atom));
1344                if (!tmp)
1345                    return FALSE;
1346                dst->names->radio_groups = tmp;
1347            }
1348            memcpy(dst->names->radio_groups, src->names->radio_groups,
1349                   src->names->num_rg * sizeof(Atom));
1350        }
1351        else {
1352            free(dst->names->radio_groups);
1353            dst->names->radio_groups = NULL;
1354        }
1355        dst->names->num_rg = src->names->num_rg;
1356
1357        dst->names->keycodes = src->names->keycodes;
1358        dst->names->geometry = src->names->geometry;
1359        dst->names->symbols = src->names->symbols;
1360        dst->names->types = src->names->types;
1361        dst->names->compat = src->names->compat;
1362        dst->names->phys_symbols = src->names->phys_symbols;
1363
1364        memcpy(dst->names->vmods, src->names->vmods,
1365               XkbNumVirtualMods * sizeof(Atom));
1366        memcpy(dst->names->indicators, src->names->indicators,
1367               XkbNumIndicators * sizeof(Atom));
1368        memcpy(dst->names->groups, src->names->groups,
1369               XkbNumKbdGroups * sizeof(Atom));
1370    }
1371    else {
1372        if (dst->names)
1373            XkbFreeNames(dst, XkbAllNamesMask, TRUE);
1374    }
1375
1376    return TRUE;
1377}
1378
1379static Bool
1380_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst)
1381{
1382    void *tmp = NULL;
1383
1384    /* compat */
1385    if (src->compat) {
1386        if (!dst->compat) {
1387            dst->compat = calloc(1, sizeof(XkbCompatMapRec));
1388            if (!dst->compat)
1389                return FALSE;
1390        }
1391
1392        if (src->compat->sym_interpret && src->compat->num_si) {
1393            if (src->compat->num_si != dst->compat->size_si) {
1394                tmp = reallocarray(dst->compat->sym_interpret,
1395                                   src->compat->num_si,
1396                                   sizeof(XkbSymInterpretRec));
1397                if (!tmp)
1398                    return FALSE;
1399                dst->compat->sym_interpret = tmp;
1400            }
1401            memcpy(dst->compat->sym_interpret, src->compat->sym_interpret,
1402                   src->compat->num_si * sizeof(XkbSymInterpretRec));
1403
1404            dst->compat->num_si = src->compat->num_si;
1405            dst->compat->size_si = src->compat->num_si;
1406        }
1407        else {
1408            if (dst->compat->sym_interpret && dst->compat->size_si)
1409                free(dst->compat->sym_interpret);
1410
1411            dst->compat->sym_interpret = NULL;
1412            dst->compat->num_si = 0;
1413            dst->compat->size_si = 0;
1414        }
1415
1416        memcpy(dst->compat->groups, src->compat->groups,
1417               XkbNumKbdGroups * sizeof(XkbModsRec));
1418    }
1419    else {
1420        if (dst->compat)
1421            XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE);
1422    }
1423
1424    return TRUE;
1425}
1426
1427static Bool
1428_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst)
1429{
1430    void *tmp = NULL;
1431    int i = 0, j = 0, k = 0;
1432    XkbColorPtr scolor = NULL, dcolor = NULL;
1433    XkbDoodadPtr sdoodad = NULL, ddoodad = NULL;
1434    XkbOutlinePtr soutline = NULL, doutline = NULL;
1435    XkbPropertyPtr sprop = NULL, dprop = NULL;
1436    XkbRowPtr srow = NULL, drow = NULL;
1437    XkbSectionPtr ssection = NULL, dsection = NULL;
1438    XkbShapePtr sshape = NULL, dshape = NULL;
1439
1440    /* geometry */
1441    if (src->geom) {
1442        if (!dst->geom) {
1443            dst->geom = calloc(sizeof(XkbGeometryRec), 1);
1444            if (!dst->geom)
1445                return FALSE;
1446        }
1447
1448        /* properties */
1449        if (src->geom->num_properties) {
1450            /* If we've got more properties in the destination than
1451             * the source, run through and free all the excess ones
1452             * first. */
1453            if (src->geom->num_properties < dst->geom->sz_properties) {
1454                for (i = src->geom->num_properties, dprop =
1455                     dst->geom->properties + i; i < dst->geom->num_properties;
1456                     i++, dprop++) {
1457                    free(dprop->name);
1458                    free(dprop->value);
1459                }
1460            }
1461
1462            /* Reallocate and clear all new items if the buffer grows. */
1463            if (!XkbGeomRealloc
1464                ((void **) &dst->geom->properties, dst->geom->sz_properties,
1465                 src->geom->num_properties, sizeof(XkbPropertyRec),
1466                 XKB_GEOM_CLEAR_EXCESS))
1467                return FALSE;
1468            /* We don't set num_properties as we need it to try and avoid
1469             * too much reallocing. */
1470            dst->geom->sz_properties = src->geom->num_properties;
1471
1472            for (i = 0,
1473                 sprop = src->geom->properties,
1474                 dprop = dst->geom->properties;
1475                 i < src->geom->num_properties; i++, sprop++, dprop++) {
1476                if (i < dst->geom->num_properties) {
1477                    if (strlen(sprop->name) != strlen(dprop->name)) {
1478                        tmp = realloc(dprop->name, strlen(sprop->name) + 1);
1479                        if (!tmp)
1480                            return FALSE;
1481                        dprop->name = tmp;
1482                    }
1483                    if (strlen(sprop->value) != strlen(dprop->value)) {
1484                        tmp = realloc(dprop->value, strlen(sprop->value) + 1);
1485                        if (!tmp)
1486                            return FALSE;
1487                        dprop->value = tmp;
1488                    }
1489                    strcpy(dprop->name, sprop->name);
1490                    strcpy(dprop->value, sprop->value);
1491                }
1492                else {
1493                    dprop->name = xstrdup(sprop->name);
1494                    dprop->value = xstrdup(sprop->value);
1495                }
1496            }
1497
1498            /* ... which is already src->geom->num_properties. */
1499            dst->geom->num_properties = dst->geom->sz_properties;
1500        }
1501        else {
1502            if (dst->geom->sz_properties) {
1503                for (i = 0, dprop = dst->geom->properties;
1504                     i < dst->geom->num_properties; i++, dprop++) {
1505                    free(dprop->name);
1506                    free(dprop->value);
1507                }
1508                free(dst->geom->properties);
1509                dst->geom->properties = NULL;
1510            }
1511
1512            dst->geom->num_properties = 0;
1513            dst->geom->sz_properties = 0;
1514        }
1515
1516        /* colors */
1517        if (src->geom->num_colors) {
1518            if (src->geom->num_colors < dst->geom->sz_colors) {
1519                for (i = src->geom->num_colors, dcolor = dst->geom->colors + i;
1520                     i < dst->geom->num_colors; i++, dcolor++) {
1521                    free(dcolor->spec);
1522                }
1523            }
1524
1525            /* Reallocate and clear all new items if the buffer grows. */
1526            if (!XkbGeomRealloc
1527                ((void **) &dst->geom->colors, dst->geom->sz_colors,
1528                 src->geom->num_colors, sizeof(XkbColorRec),
1529                 XKB_GEOM_CLEAR_EXCESS))
1530                return FALSE;
1531            dst->geom->sz_colors = src->geom->num_colors;
1532
1533            for (i = 0,
1534                 scolor = src->geom->colors,
1535                 dcolor = dst->geom->colors;
1536                 i < src->geom->num_colors; i++, scolor++, dcolor++) {
1537                if (i < dst->geom->num_colors) {
1538                    if (strlen(scolor->spec) != strlen(dcolor->spec)) {
1539                        tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1);
1540                        if (!tmp)
1541                            return FALSE;
1542                        dcolor->spec = tmp;
1543                    }
1544                    strcpy(dcolor->spec, scolor->spec);
1545                }
1546                else {
1547                    dcolor->spec = xstrdup(scolor->spec);
1548                }
1549                dcolor->pixel = scolor->pixel;
1550            }
1551
1552            dst->geom->num_colors = dst->geom->sz_colors;
1553        }
1554        else {
1555            if (dst->geom->sz_colors) {
1556                for (i = 0, dcolor = dst->geom->colors;
1557                     i < dst->geom->num_colors; i++, dcolor++) {
1558                    free(dcolor->spec);
1559                }
1560                free(dst->geom->colors);
1561                dst->geom->colors = NULL;
1562            }
1563
1564            dst->geom->num_colors = 0;
1565            dst->geom->sz_colors = 0;
1566        }
1567
1568        /* shapes */
1569        /* shapes break down into outlines, which break down into points. */
1570        if (dst->geom->num_shapes) {
1571            for (i = 0, dshape = dst->geom->shapes;
1572                 i < dst->geom->num_shapes; i++, dshape++) {
1573                for (j = 0, doutline = dshape->outlines;
1574                     j < dshape->num_outlines; j++, doutline++) {
1575                    if (doutline->sz_points)
1576                        free(doutline->points);
1577                }
1578
1579                if (dshape->sz_outlines) {
1580                    free(dshape->outlines);
1581                    dshape->outlines = NULL;
1582                }
1583
1584                dshape->num_outlines = 0;
1585                dshape->sz_outlines = 0;
1586            }
1587        }
1588
1589        if (src->geom->num_shapes) {
1590            /* Reallocate and clear all items. */
1591            if (!XkbGeomRealloc
1592                ((void **) &dst->geom->shapes, dst->geom->sz_shapes,
1593                 src->geom->num_shapes, sizeof(XkbShapeRec),
1594                 XKB_GEOM_CLEAR_ALL))
1595                return FALSE;
1596
1597            for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes;
1598                 i < src->geom->num_shapes; i++, sshape++, dshape++) {
1599                if (sshape->num_outlines) {
1600                    tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec));
1601                    if (!tmp)
1602                        return FALSE;
1603                    dshape->outlines = tmp;
1604
1605                    for (j = 0,
1606                         soutline = sshape->outlines,
1607                         doutline = dshape->outlines;
1608                         j < sshape->num_outlines;
1609                         j++, soutline++, doutline++) {
1610                        if (soutline->num_points) {
1611                            tmp = xallocarray(soutline->num_points,
1612                                              sizeof(XkbPointRec));
1613                            if (!tmp)
1614                                return FALSE;
1615                            doutline->points = tmp;
1616
1617                            memcpy(doutline->points, soutline->points,
1618                                   soutline->num_points * sizeof(XkbPointRec));
1619
1620                            doutline->corner_radius = soutline->corner_radius;
1621                        }
1622
1623                        doutline->num_points = soutline->num_points;
1624                        doutline->sz_points = soutline->num_points;
1625                    }
1626                }
1627
1628                dshape->num_outlines = sshape->num_outlines;
1629                dshape->sz_outlines = sshape->num_outlines;
1630                dshape->name = sshape->name;
1631                dshape->bounds = sshape->bounds;
1632
1633                dshape->approx = NULL;
1634                if (sshape->approx && sshape->num_outlines > 0) {
1635
1636                    const ptrdiff_t approx_idx =
1637                        sshape->approx - sshape->outlines;
1638
1639                    if (approx_idx < dshape->num_outlines) {
1640                        dshape->approx = dshape->outlines + approx_idx;
1641                    }
1642                    else {
1643                        LogMessage(X_WARNING, "XKB: approx outline "
1644                                   "index is out of range\n");
1645                    }
1646                }
1647
1648                dshape->primary = NULL;
1649                if (sshape->primary && sshape->num_outlines > 0) {
1650
1651                    const ptrdiff_t primary_idx =
1652                        sshape->primary - sshape->outlines;
1653
1654                    if (primary_idx < dshape->num_outlines) {
1655                        dshape->primary = dshape->outlines + primary_idx;
1656                    }
1657                    else {
1658                        LogMessage(X_WARNING, "XKB: primary outline "
1659                                   "index is out of range\n");
1660                    }
1661                }
1662            }
1663
1664            dst->geom->num_shapes = src->geom->num_shapes;
1665            dst->geom->sz_shapes = src->geom->num_shapes;
1666        }
1667        else {
1668            if (dst->geom->sz_shapes) {
1669                free(dst->geom->shapes);
1670            }
1671            dst->geom->shapes = NULL;
1672            dst->geom->num_shapes = 0;
1673            dst->geom->sz_shapes = 0;
1674        }
1675
1676        /* sections */
1677        /* sections break down into doodads, and also into rows, which break
1678         * down into keys. */
1679        if (dst->geom->num_sections) {
1680            for (i = 0, dsection = dst->geom->sections;
1681                 i < dst->geom->num_sections; i++, dsection++) {
1682                for (j = 0, drow = dsection->rows;
1683                     j < dsection->num_rows; j++, drow++) {
1684                    if (drow->num_keys)
1685                        free(drow->keys);
1686                }
1687
1688                if (dsection->num_rows)
1689                    free(dsection->rows);
1690
1691                /* cut and waste from geom/doodad below. */
1692                for (j = 0, ddoodad = dsection->doodads;
1693                     j < dsection->num_doodads; j++, ddoodad++) {
1694                    if (ddoodad->any.type == XkbTextDoodad) {
1695                        free(ddoodad->text.text);
1696                        ddoodad->text.text = NULL;
1697                        free(ddoodad->text.font);
1698                        ddoodad->text.font = NULL;
1699                    }
1700                    else if (ddoodad->any.type == XkbLogoDoodad) {
1701                        free(ddoodad->logo.logo_name);
1702                        ddoodad->logo.logo_name = NULL;
1703                    }
1704                }
1705
1706                free(dsection->doodads);
1707            }
1708
1709            dst->geom->num_sections = 0;
1710        }
1711
1712        if (src->geom->num_sections) {
1713            /* Reallocate and clear all items. */
1714            if (!XkbGeomRealloc
1715                ((void **) &dst->geom->sections, dst->geom->sz_sections,
1716                 src->geom->num_sections, sizeof(XkbSectionRec),
1717                 XKB_GEOM_CLEAR_ALL))
1718                return FALSE;
1719            dst->geom->num_sections = src->geom->num_sections;
1720            dst->geom->sz_sections = src->geom->num_sections;
1721
1722            for (i = 0,
1723                 ssection = src->geom->sections,
1724                 dsection = dst->geom->sections;
1725                 i < src->geom->num_sections; i++, ssection++, dsection++) {
1726                *dsection = *ssection;
1727                if (ssection->num_rows) {
1728                    tmp = calloc(ssection->num_rows, sizeof(XkbRowRec));
1729                    if (!tmp)
1730                        return FALSE;
1731                    dsection->rows = tmp;
1732                }
1733                dsection->num_rows = ssection->num_rows;
1734                dsection->sz_rows = ssection->num_rows;
1735
1736                for (j = 0, srow = ssection->rows, drow = dsection->rows;
1737                     j < ssection->num_rows; j++, srow++, drow++) {
1738                    if (srow->num_keys) {
1739                        tmp = xallocarray(srow->num_keys, sizeof(XkbKeyRec));
1740                        if (!tmp)
1741                            return FALSE;
1742                        drow->keys = tmp;
1743                        memcpy(drow->keys, srow->keys,
1744                               srow->num_keys * sizeof(XkbKeyRec));
1745                    }
1746                    drow->num_keys = srow->num_keys;
1747                    drow->sz_keys = srow->num_keys;
1748                    drow->top = srow->top;
1749                    drow->left = srow->left;
1750                    drow->vertical = srow->vertical;
1751                    drow->bounds = srow->bounds;
1752                }
1753
1754                if (ssection->num_doodads) {
1755                    tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec));
1756                    if (!tmp)
1757                        return FALSE;
1758                    dsection->doodads = tmp;
1759                }
1760                else {
1761                    dsection->doodads = NULL;
1762                }
1763
1764                dsection->sz_doodads = ssection->num_doodads;
1765                for (k = 0,
1766                     sdoodad = ssection->doodads,
1767                     ddoodad = dsection->doodads;
1768                     k < ssection->num_doodads; k++, sdoodad++, ddoodad++) {
1769                    memcpy(ddoodad, sdoodad, sizeof(XkbDoodadRec));
1770                    if (sdoodad->any.type == XkbTextDoodad) {
1771                        if (sdoodad->text.text)
1772                            ddoodad->text.text = strdup(sdoodad->text.text);
1773                        if (sdoodad->text.font)
1774                            ddoodad->text.font = strdup(sdoodad->text.font);
1775                    }
1776                    else if (sdoodad->any.type == XkbLogoDoodad) {
1777                        if (sdoodad->logo.logo_name)
1778                            ddoodad->logo.logo_name =
1779                                strdup(sdoodad->logo.logo_name);
1780                    }
1781                }
1782                dsection->overlays = NULL;
1783                dsection->sz_overlays = 0;
1784                dsection->num_overlays = 0;
1785            }
1786        }
1787        else {
1788            if (dst->geom->sz_sections) {
1789                free(dst->geom->sections);
1790            }
1791
1792            dst->geom->sections = NULL;
1793            dst->geom->num_sections = 0;
1794            dst->geom->sz_sections = 0;
1795        }
1796
1797        /* doodads */
1798        if (dst->geom->num_doodads) {
1799            for (i = src->geom->num_doodads,
1800                 ddoodad = dst->geom->doodads +
1801                 src->geom->num_doodads;
1802                 i < dst->geom->num_doodads; i++, ddoodad++) {
1803                if (ddoodad->any.type == XkbTextDoodad) {
1804                    free(ddoodad->text.text);
1805                    ddoodad->text.text = NULL;
1806                    free(ddoodad->text.font);
1807                    ddoodad->text.font = NULL;
1808                }
1809                else if (ddoodad->any.type == XkbLogoDoodad) {
1810                    free(ddoodad->logo.logo_name);
1811                    ddoodad->logo.logo_name = NULL;
1812                }
1813            }
1814            dst->geom->num_doodads = 0;
1815        }
1816
1817        if (src->geom->num_doodads) {
1818            /* Reallocate and clear all items. */
1819            if (!XkbGeomRealloc
1820                ((void **) &dst->geom->doodads, dst->geom->sz_doodads,
1821                 src->geom->num_doodads, sizeof(XkbDoodadRec),
1822                 XKB_GEOM_CLEAR_ALL))
1823                return FALSE;
1824
1825            dst->geom->sz_doodads = src->geom->num_doodads;
1826
1827            for (i = 0,
1828                 sdoodad = src->geom->doodads,
1829                 ddoodad = dst->geom->doodads;
1830                 i < src->geom->num_doodads; i++, sdoodad++, ddoodad++) {
1831                memcpy(ddoodad, sdoodad, sizeof(XkbDoodadRec));
1832                if (sdoodad->any.type == XkbTextDoodad) {
1833                    if (sdoodad->text.text)
1834                        ddoodad->text.text = strdup(sdoodad->text.text);
1835                    if (sdoodad->text.font)
1836                        ddoodad->text.font = strdup(sdoodad->text.font);
1837                }
1838                else if (sdoodad->any.type == XkbLogoDoodad) {
1839                    if (sdoodad->logo.logo_name)
1840                        ddoodad->logo.logo_name =
1841                            strdup(sdoodad->logo.logo_name);
1842                }
1843            }
1844
1845            dst->geom->num_doodads = dst->geom->sz_doodads;
1846        }
1847        else {
1848            if (dst->geom->sz_doodads) {
1849                free(dst->geom->doodads);
1850            }
1851
1852            dst->geom->doodads = NULL;
1853            dst->geom->num_doodads = 0;
1854            dst->geom->sz_doodads = 0;
1855        }
1856
1857        /* key aliases */
1858        if (src->geom->num_key_aliases) {
1859            /* Reallocate but don't clear any items. There is no need
1860             * to clear anything because data is immediately copied
1861             * over the whole memory area with memcpy. */
1862            if (!XkbGeomRealloc
1863                ((void **) &dst->geom->key_aliases, dst->geom->sz_key_aliases,
1864                 src->geom->num_key_aliases, 2 * XkbKeyNameLength,
1865                 XKB_GEOM_CLEAR_NONE))
1866                return FALSE;
1867
1868            dst->geom->sz_key_aliases = src->geom->num_key_aliases;
1869
1870            memcpy(dst->geom->key_aliases, src->geom->key_aliases,
1871                   src->geom->num_key_aliases * 2 * XkbKeyNameLength);
1872
1873            dst->geom->num_key_aliases = dst->geom->sz_key_aliases;
1874        }
1875        else {
1876            free(dst->geom->key_aliases);
1877            dst->geom->key_aliases = NULL;
1878            dst->geom->num_key_aliases = 0;
1879            dst->geom->sz_key_aliases = 0;
1880        }
1881
1882        /* font */
1883        if (src->geom->label_font) {
1884            if (!dst->geom->label_font) {
1885                tmp = malloc(strlen(src->geom->label_font) + 1);
1886                if (!tmp)
1887                    return FALSE;
1888                dst->geom->label_font = tmp;
1889            }
1890            else if (strlen(src->geom->label_font) !=
1891                     strlen(dst->geom->label_font)) {
1892                tmp = realloc(dst->geom->label_font,
1893                              strlen(src->geom->label_font) + 1);
1894                if (!tmp)
1895                    return FALSE;
1896                dst->geom->label_font = tmp;
1897            }
1898
1899            strcpy(dst->geom->label_font, src->geom->label_font);
1900            i = XkbGeomColorIndex(src->geom, src->geom->label_color);
1901            dst->geom->label_color = &(dst->geom->colors[i]);
1902            i = XkbGeomColorIndex(src->geom, src->geom->base_color);
1903            dst->geom->base_color = &(dst->geom->colors[i]);
1904        }
1905        else {
1906            free(dst->geom->label_font);
1907            dst->geom->label_font = NULL;
1908            dst->geom->label_color = NULL;
1909            dst->geom->base_color = NULL;
1910        }
1911
1912        dst->geom->name = src->geom->name;
1913        dst->geom->width_mm = src->geom->width_mm;
1914        dst->geom->height_mm = src->geom->height_mm;
1915    }
1916    else {
1917        if (dst->geom) {
1918            /* I LOVE THE DIFFERENT CALL SIGNATURE.  REALLY, I DO. */
1919            XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE);
1920            dst->geom = NULL;
1921        }
1922    }
1923
1924    return TRUE;
1925}
1926
1927static Bool
1928_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst)
1929{
1930    /* indicators */
1931    if (src->indicators) {
1932        if (!dst->indicators) {
1933            dst->indicators = malloc(sizeof(XkbIndicatorRec));
1934            if (!dst->indicators)
1935                return FALSE;
1936        }
1937        memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec));
1938    }
1939    else {
1940        free(dst->indicators);
1941        dst->indicators = NULL;
1942    }
1943    return TRUE;
1944}
1945
1946static Bool
1947_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst)
1948{
1949    /* controls */
1950    if (src->ctrls) {
1951        if (!dst->ctrls) {
1952            dst->ctrls = malloc(sizeof(XkbControlsRec));
1953            if (!dst->ctrls)
1954                return FALSE;
1955        }
1956        memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec));
1957    }
1958    else {
1959        free(dst->ctrls);
1960        dst->ctrls = NULL;
1961    }
1962    return TRUE;
1963}
1964
1965/**
1966 * Copy an XKB map from src to dst, reallocating when necessary: if some
1967 * map components are present in one, but not in the other, the destination
1968 * components will be allocated or freed as necessary.
1969 *
1970 * Basic map consistency is assumed on both sides, so maps with random
1971 * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19)
1972 * _will_ cause failures.  You've been warned.
1973 *
1974 * Returns TRUE on success, or FALSE on failure.  If this function fails,
1975 * dst may be in an inconsistent state: all its pointers are guaranteed
1976 * to remain valid, but part of the map may be from src and part from dst.
1977 *
1978 */
1979
1980Bool
1981XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src)
1982{
1983
1984    if (!src || !dst) {
1985        DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst);
1986        return FALSE;
1987    }
1988
1989    if (src == dst)
1990        return TRUE;
1991
1992    if (!_XkbCopyClientMap(src, dst)) {
1993        DebugF("XkbCopyKeymap: failed to copy client map\n");
1994        return FALSE;
1995    }
1996    if (!_XkbCopyServerMap(src, dst)) {
1997        DebugF("XkbCopyKeymap: failed to copy server map\n");
1998        return FALSE;
1999    }
2000    if (!_XkbCopyIndicators(src, dst)) {
2001        DebugF("XkbCopyKeymap: failed to copy indicators\n");
2002        return FALSE;
2003    }
2004    if (!_XkbCopyControls(src, dst)) {
2005        DebugF("XkbCopyKeymap: failed to copy controls\n");
2006        return FALSE;
2007    }
2008    if (!_XkbCopyNames(src, dst)) {
2009        DebugF("XkbCopyKeymap: failed to copy names\n");
2010        return FALSE;
2011    }
2012    if (!_XkbCopyCompat(src, dst)) {
2013        DebugF("XkbCopyKeymap: failed to copy compat map\n");
2014        return FALSE;
2015    }
2016    if (!_XkbCopyGeom(src, dst)) {
2017        DebugF("XkbCopyKeymap: failed to copy geometry\n");
2018        return FALSE;
2019    }
2020
2021    dst->min_key_code = src->min_key_code;
2022    dst->max_key_code = src->max_key_code;
2023
2024    return TRUE;
2025}
2026
2027Bool
2028XkbDeviceApplyKeymap(DeviceIntPtr dst, XkbDescPtr desc)
2029{
2030    xkbNewKeyboardNotify nkn;
2031    Bool ret;
2032
2033    if (!dst->key || !desc)
2034        return FALSE;
2035
2036    memset(&nkn, 0, sizeof(xkbNewKeyboardNotify));
2037    nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code;
2038    nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code;
2039    nkn.deviceID = dst->id;
2040    nkn.oldDeviceID = dst->id;
2041    nkn.minKeyCode = desc->min_key_code;
2042    nkn.maxKeyCode = desc->max_key_code;
2043    nkn.requestMajor = XkbReqCode;
2044    nkn.requestMinor = X_kbSetMap;      /* Near enough's good enough. */
2045    nkn.changed = XkbNKN_KeycodesMask;
2046    if (desc->geom)
2047        nkn.changed |= XkbNKN_GeometryMask;
2048
2049    ret = XkbCopyKeymap(dst->key->xkbInfo->desc, desc);
2050    if (ret)
2051        XkbSendNewKeyboardNotify(dst, &nkn);
2052
2053    return ret;
2054}
2055
2056Bool
2057XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src)
2058{
2059    return XkbDeviceApplyKeymap(dst, src->key->xkbInfo->desc);
2060}
2061
2062int
2063XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode)
2064{
2065    XkbDescPtr xkb = xkbi->desc;
2066    int effectiveGroup = xkbState->group;
2067
2068    if (!XkbKeycodeInRange(xkb, keycode))
2069        return -1;
2070
2071    if (effectiveGroup == XkbGroup1Index)
2072        return effectiveGroup;
2073
2074    if (XkbKeyNumGroups(xkb, keycode) > 1U) {
2075        if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) {
2076            unsigned int gi = XkbKeyGroupInfo(xkb, keycode);
2077
2078            switch (XkbOutOfRangeGroupAction(gi)) {
2079            default:
2080            case XkbWrapIntoRange:
2081                effectiveGroup %= XkbKeyNumGroups(xkb, keycode);
2082                break;
2083            case XkbClampIntoRange:
2084                effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1;
2085                break;
2086            case XkbRedirectIntoRange:
2087                effectiveGroup = XkbOutOfRangeGroupInfo(gi);
2088                if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode))
2089                    effectiveGroup = 0;
2090                break;
2091            }
2092        }
2093    }
2094    else
2095        effectiveGroup = XkbGroup1Index;
2096
2097    return effectiveGroup;
2098}
2099
2100/* Merge the lockedPtrButtons from all attached SDs for the given master
2101 * device into the MD's state.
2102 */
2103void
2104XkbMergeLockedPtrBtns(DeviceIntPtr master)
2105{
2106    DeviceIntPtr d = inputInfo.devices;
2107    XkbSrvInfoPtr xkbi = NULL;
2108
2109    if (!IsMaster(master))
2110        return;
2111
2112    if (!master->key)
2113        return;
2114
2115    xkbi = master->key->xkbInfo;
2116    xkbi->lockedPtrButtons = 0;
2117
2118    for (; d; d = d->next) {
2119        if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key)
2120            continue;
2121
2122        xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons;
2123    }
2124}
2125
2126void
2127XkbCopyControls(XkbDescPtr dst, XkbDescPtr src)
2128{
2129    int i, nG, nTG;
2130
2131    if (!dst || !src)
2132        return;
2133
2134    *dst->ctrls = *src->ctrls;
2135
2136    for (nG = nTG = 0, i = dst->min_key_code; i <= dst->max_key_code; i++) {
2137        nG = XkbKeyNumGroups(dst, i);
2138        if (nG >= XkbNumKbdGroups) {
2139            nTG = XkbNumKbdGroups;
2140            break;
2141        }
2142        if (nG > nTG) {
2143            nTG = nG;
2144        }
2145    }
2146    dst->ctrls->num_groups = nTG;
2147}
2148