xkbUtils.c revision 35c4bbdf
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], *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_Serbian_DZE)
906            *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
907        else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
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    XkbKeyTypePtr stype = NULL, dtype = NULL;
937
938    /* client map */
939    if (src->map) {
940        if (!dst->map) {
941            tmp = calloc(1, sizeof(XkbClientMapRec));
942            if (!tmp)
943                return FALSE;
944            dst->map = tmp;
945        }
946
947        if (src->map->syms) {
948            if (src->map->size_syms != dst->map->size_syms) {
949                tmp = reallocarray(dst->map->syms,
950                                   src->map->size_syms, sizeof(KeySym));
951                if (!tmp)
952                    return FALSE;
953                dst->map->syms = tmp;
954
955            }
956            memcpy(dst->map->syms, src->map->syms,
957                   src->map->size_syms * sizeof(KeySym));
958        }
959        else {
960            free(dst->map->syms);
961            dst->map->syms = NULL;
962        }
963        dst->map->num_syms = src->map->num_syms;
964        dst->map->size_syms = src->map->size_syms;
965
966        if (src->map->key_sym_map) {
967            if (src->max_key_code != dst->max_key_code) {
968                tmp = reallocarray(dst->map->key_sym_map,
969                                   src->max_key_code + 1, sizeof(XkbSymMapRec));
970                if (!tmp)
971                    return FALSE;
972                dst->map->key_sym_map = tmp;
973            }
974            memcpy(dst->map->key_sym_map, src->map->key_sym_map,
975                   (src->max_key_code + 1) * sizeof(XkbSymMapRec));
976        }
977        else {
978            free(dst->map->key_sym_map);
979            dst->map->key_sym_map = NULL;
980        }
981
982        if (src->map->types && src->map->num_types) {
983            if (src->map->num_types > dst->map->size_types ||
984                !dst->map->types || !dst->map->size_types) {
985                if (dst->map->types && dst->map->size_types) {
986                    tmp = reallocarray(dst->map->types, src->map->num_types,
987                                       sizeof(XkbKeyTypeRec));
988                    if (!tmp)
989                        return FALSE;
990                    dst->map->types = tmp;
991                    memset(dst->map->types + dst->map->num_types, 0,
992                           (src->map->num_types - dst->map->num_types) *
993                           sizeof(XkbKeyTypeRec));
994                }
995                else {
996                    tmp = calloc(src->map->num_types, sizeof(XkbKeyTypeRec));
997                    if (!tmp)
998                        return FALSE;
999                    dst->map->types = tmp;
1000                }
1001            }
1002            else if (src->map->num_types < dst->map->num_types &&
1003                     dst->map->types) {
1004                for (i = src->map->num_types, dtype = (dst->map->types + i);
1005                     i < dst->map->num_types; i++, dtype++) {
1006                    free(dtype->level_names);
1007                    dtype->level_names = NULL;
1008                    dtype->num_levels = 0;
1009                    if (dtype->map_count) {
1010                        free(dtype->map);
1011                        free(dtype->preserve);
1012                    }
1013                }
1014            }
1015
1016            stype = src->map->types;
1017            dtype = dst->map->types;
1018            for (i = 0; i < src->map->num_types; i++, dtype++, stype++) {
1019                if (stype->num_levels && stype->level_names) {
1020                    if (stype->num_levels != dtype->num_levels &&
1021                        dtype->num_levels && dtype->level_names &&
1022                        i < dst->map->num_types) {
1023                        tmp = reallocarray(dtype->level_names,
1024                                           stype->num_levels, sizeof(Atom));
1025                        if (!tmp)
1026                            continue;
1027                        dtype->level_names = tmp;
1028                    }
1029                    else if (!dtype->num_levels || !dtype->level_names ||
1030                             i >= dst->map->num_types) {
1031                        tmp = malloc(stype->num_levels * sizeof(Atom));
1032                        if (!tmp)
1033                            continue;
1034                        dtype->level_names = tmp;
1035                    }
1036                    dtype->num_levels = stype->num_levels;
1037                    memcpy(dtype->level_names, stype->level_names,
1038                           stype->num_levels * sizeof(Atom));
1039                }
1040                else {
1041                    if (dtype->num_levels && dtype->level_names &&
1042                        i < dst->map->num_types)
1043                        free(dtype->level_names);
1044                    dtype->num_levels = 0;
1045                    dtype->level_names = NULL;
1046                }
1047
1048                dtype->name = stype->name;
1049                memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec));
1050
1051                if (stype->map_count) {
1052                    if (stype->map) {
1053                        if (stype->map_count != dtype->map_count &&
1054                            dtype->map_count && dtype->map &&
1055                            i < dst->map->num_types) {
1056                            tmp = reallocarray(dtype->map,
1057                                               stype->map_count,
1058                                               sizeof(XkbKTMapEntryRec));
1059                            if (!tmp)
1060                                return FALSE;
1061                            dtype->map = tmp;
1062                        }
1063                        else if (!dtype->map_count || !dtype->map ||
1064                                 i >= dst->map->num_types) {
1065                            tmp = xallocarray(stype->map_count,
1066                                              sizeof(XkbKTMapEntryRec));
1067                            if (!tmp)
1068                                return FALSE;
1069                            dtype->map = tmp;
1070                        }
1071
1072                        memcpy(dtype->map, stype->map,
1073                               stype->map_count * sizeof(XkbKTMapEntryRec));
1074                    }
1075                    else {
1076                        if (dtype->map && i < dst->map->num_types)
1077                            free(dtype->map);
1078                        dtype->map = NULL;
1079                    }
1080
1081                    if (stype->preserve) {
1082                        if (stype->map_count != dtype->map_count &&
1083                            dtype->map_count && dtype->preserve &&
1084                            i < dst->map->num_types) {
1085                            tmp = reallocarray(dtype->preserve,
1086                                               stype->map_count,
1087                                               sizeof(XkbModsRec));
1088                            if (!tmp)
1089                                return FALSE;
1090                            dtype->preserve = tmp;
1091                        }
1092                        else if (!dtype->preserve || !dtype->map_count ||
1093                                 i >= dst->map->num_types) {
1094                            tmp = xallocarray(stype->map_count,
1095                                              sizeof(XkbModsRec));
1096                            if (!tmp)
1097                                return FALSE;
1098                            dtype->preserve = tmp;
1099                        }
1100
1101                        memcpy(dtype->preserve, stype->preserve,
1102                               stype->map_count * sizeof(XkbModsRec));
1103                    }
1104                    else {
1105                        if (dtype->preserve && i < dst->map->num_types)
1106                            free(dtype->preserve);
1107                        dtype->preserve = NULL;
1108                    }
1109
1110                    dtype->map_count = stype->map_count;
1111                }
1112                else {
1113                    if (dtype->map_count && i < dst->map->num_types) {
1114                        free(dtype->map);
1115                        free(dtype->preserve);
1116                    }
1117                    dtype->map_count = 0;
1118                    dtype->map = NULL;
1119                    dtype->preserve = NULL;
1120                }
1121            }
1122
1123            dst->map->size_types = src->map->num_types;
1124            dst->map->num_types = src->map->num_types;
1125        }
1126        else {
1127            if (dst->map->types) {
1128                for (i = 0, dtype = dst->map->types; i < dst->map->num_types;
1129                     i++, dtype++) {
1130                    free(dtype->level_names);
1131                    if (dtype->map && dtype->map_count)
1132                        free(dtype->map);
1133                    if (dtype->preserve && dtype->map_count)
1134                        free(dtype->preserve);
1135                }
1136            }
1137            free(dst->map->types);
1138            dst->map->types = NULL;
1139            dst->map->num_types = 0;
1140            dst->map->size_types = 0;
1141        }
1142
1143        if (src->map->modmap) {
1144            if (src->max_key_code != dst->max_key_code) {
1145                tmp = realloc(dst->map->modmap, src->max_key_code + 1);
1146                if (!tmp)
1147                    return FALSE;
1148                dst->map->modmap = tmp;
1149            }
1150            memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1);
1151        }
1152        else {
1153            free(dst->map->modmap);
1154            dst->map->modmap = NULL;
1155        }
1156    }
1157    else {
1158        if (dst->map)
1159            XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE);
1160    }
1161
1162    return TRUE;
1163}
1164
1165static Bool
1166_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
1167{
1168    void *tmp = NULL;
1169
1170    /* server map */
1171    if (src->server) {
1172        if (!dst->server) {
1173            tmp = calloc(1, sizeof(XkbServerMapRec));
1174            if (!tmp)
1175                return FALSE;
1176            dst->server = tmp;
1177        }
1178
1179        if (src->server->explicit) {
1180            if (src->max_key_code != dst->max_key_code) {
1181                tmp = realloc(dst->server->explicit, src->max_key_code + 1);
1182                if (!tmp)
1183                    return FALSE;
1184                dst->server->explicit = tmp;
1185            }
1186            memcpy(dst->server->explicit, src->server->explicit,
1187                   src->max_key_code + 1);
1188        }
1189        else {
1190            free(dst->server->explicit);
1191            dst->server->explicit = NULL;
1192        }
1193
1194        if (src->server->acts) {
1195            if (src->server->size_acts != dst->server->size_acts) {
1196                tmp = reallocarray(dst->server->acts,
1197                                   src->server->size_acts, sizeof(XkbAction));
1198                if (!tmp)
1199                    return FALSE;
1200                dst->server->acts = tmp;
1201            }
1202            memcpy(dst->server->acts, src->server->acts,
1203                   src->server->size_acts * sizeof(XkbAction));
1204        }
1205        else {
1206            free(dst->server->acts);
1207            dst->server->acts = NULL;
1208        }
1209        dst->server->size_acts = src->server->size_acts;
1210        dst->server->num_acts = src->server->num_acts;
1211
1212        if (src->server->key_acts) {
1213            if (src->max_key_code != dst->max_key_code) {
1214                tmp = reallocarray(dst->server->key_acts,
1215                                   src->max_key_code + 1, sizeof(unsigned short));
1216                if (!tmp)
1217                    return FALSE;
1218                dst->server->key_acts = tmp;
1219            }
1220            memcpy(dst->server->key_acts, src->server->key_acts,
1221                   (src->max_key_code + 1) * sizeof(unsigned short));
1222        }
1223        else {
1224            free(dst->server->key_acts);
1225            dst->server->key_acts = NULL;
1226        }
1227
1228        if (src->server->behaviors) {
1229            if (src->max_key_code != dst->max_key_code) {
1230                tmp = reallocarray(dst->server->behaviors,
1231                                   src->max_key_code + 1, sizeof(XkbBehavior));
1232                if (!tmp)
1233                    return FALSE;
1234                dst->server->behaviors = tmp;
1235            }
1236            memcpy(dst->server->behaviors, src->server->behaviors,
1237                   (src->max_key_code + 1) * sizeof(XkbBehavior));
1238        }
1239        else {
1240            free(dst->server->behaviors);
1241            dst->server->behaviors = NULL;
1242        }
1243
1244        memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods);
1245
1246        if (src->server->vmodmap) {
1247            if (src->max_key_code != dst->max_key_code) {
1248                tmp = reallocarray(dst->server->vmodmap,
1249                                   src->max_key_code + 1, sizeof(unsigned short));
1250                if (!tmp)
1251                    return FALSE;
1252                dst->server->vmodmap = tmp;
1253            }
1254            memcpy(dst->server->vmodmap, src->server->vmodmap,
1255                   (src->max_key_code + 1) * sizeof(unsigned short));
1256        }
1257        else {
1258            free(dst->server->vmodmap);
1259            dst->server->vmodmap = NULL;
1260        }
1261    }
1262    else {
1263        if (dst->server)
1264            XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE);
1265    }
1266
1267    return TRUE;
1268}
1269
1270static Bool
1271_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst)
1272{
1273    void *tmp = NULL;
1274
1275    /* names */
1276    if (src->names) {
1277        if (!dst->names) {
1278            dst->names = calloc(1, sizeof(XkbNamesRec));
1279            if (!dst->names)
1280                return FALSE;
1281        }
1282
1283        if (src->names->keys) {
1284            if (src->max_key_code != dst->max_key_code) {
1285                tmp = reallocarray(dst->names->keys, src->max_key_code + 1,
1286                                   sizeof(XkbKeyNameRec));
1287                if (!tmp)
1288                    return FALSE;
1289                dst->names->keys = tmp;
1290            }
1291            memcpy(dst->names->keys, src->names->keys,
1292                   (src->max_key_code + 1) * sizeof(XkbKeyNameRec));
1293        }
1294        else {
1295            free(dst->names->keys);
1296            dst->names->keys = NULL;
1297        }
1298
1299        if (src->names->num_key_aliases) {
1300            if (src->names->num_key_aliases != dst->names->num_key_aliases) {
1301                tmp = reallocarray(dst->names->key_aliases,
1302                                   src->names->num_key_aliases,
1303                                   sizeof(XkbKeyAliasRec));
1304                if (!tmp)
1305                    return FALSE;
1306                dst->names->key_aliases = tmp;
1307            }
1308            memcpy(dst->names->key_aliases, src->names->key_aliases,
1309                   src->names->num_key_aliases * sizeof(XkbKeyAliasRec));
1310        }
1311        else {
1312            free(dst->names->key_aliases);
1313            dst->names->key_aliases = NULL;
1314        }
1315        dst->names->num_key_aliases = src->names->num_key_aliases;
1316
1317        if (src->names->num_rg) {
1318            if (src->names->num_rg != dst->names->num_rg) {
1319                tmp = reallocarray(dst->names->radio_groups,
1320                                   src->names->num_rg, sizeof(Atom));
1321                if (!tmp)
1322                    return FALSE;
1323                dst->names->radio_groups = tmp;
1324            }
1325            memcpy(dst->names->radio_groups, src->names->radio_groups,
1326                   src->names->num_rg * sizeof(Atom));
1327        }
1328        else {
1329            free(dst->names->radio_groups);
1330        }
1331        dst->names->num_rg = src->names->num_rg;
1332
1333        dst->names->keycodes = src->names->keycodes;
1334        dst->names->geometry = src->names->geometry;
1335        dst->names->symbols = src->names->symbols;
1336        dst->names->types = src->names->types;
1337        dst->names->compat = src->names->compat;
1338        dst->names->phys_symbols = src->names->phys_symbols;
1339
1340        memcpy(dst->names->vmods, src->names->vmods,
1341               XkbNumVirtualMods * sizeof(Atom));
1342        memcpy(dst->names->indicators, src->names->indicators,
1343               XkbNumIndicators * sizeof(Atom));
1344        memcpy(dst->names->groups, src->names->groups,
1345               XkbNumKbdGroups * sizeof(Atom));
1346    }
1347    else {
1348        if (dst->names)
1349            XkbFreeNames(dst, XkbAllNamesMask, TRUE);
1350    }
1351
1352    return TRUE;
1353}
1354
1355static Bool
1356_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst)
1357{
1358    void *tmp = NULL;
1359
1360    /* compat */
1361    if (src->compat) {
1362        if (!dst->compat) {
1363            dst->compat = calloc(1, sizeof(XkbCompatMapRec));
1364            if (!dst->compat)
1365                return FALSE;
1366        }
1367
1368        if (src->compat->sym_interpret && src->compat->num_si) {
1369            if (src->compat->num_si != dst->compat->size_si) {
1370                tmp = reallocarray(dst->compat->sym_interpret,
1371                                   src->compat->num_si,
1372                                   sizeof(XkbSymInterpretRec));
1373                if (!tmp)
1374                    return FALSE;
1375                dst->compat->sym_interpret = tmp;
1376            }
1377            memcpy(dst->compat->sym_interpret, src->compat->sym_interpret,
1378                   src->compat->num_si * sizeof(XkbSymInterpretRec));
1379
1380            dst->compat->num_si = src->compat->num_si;
1381            dst->compat->size_si = src->compat->num_si;
1382        }
1383        else {
1384            if (dst->compat->sym_interpret && dst->compat->size_si)
1385                free(dst->compat->sym_interpret);
1386
1387            dst->compat->sym_interpret = NULL;
1388            dst->compat->num_si = 0;
1389            dst->compat->size_si = 0;
1390        }
1391
1392        memcpy(dst->compat->groups, src->compat->groups,
1393               XkbNumKbdGroups * sizeof(XkbModsRec));
1394    }
1395    else {
1396        if (dst->compat)
1397            XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE);
1398    }
1399
1400    return TRUE;
1401}
1402
1403static Bool
1404_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst)
1405{
1406    void *tmp = NULL;
1407    int i = 0, j = 0, k = 0;
1408    XkbColorPtr scolor = NULL, dcolor = NULL;
1409    XkbDoodadPtr sdoodad = NULL, ddoodad = NULL;
1410    XkbOutlinePtr soutline = NULL, doutline = NULL;
1411    XkbPropertyPtr sprop = NULL, dprop = NULL;
1412    XkbRowPtr srow = NULL, drow = NULL;
1413    XkbSectionPtr ssection = NULL, dsection = NULL;
1414    XkbShapePtr sshape = NULL, dshape = NULL;
1415
1416    /* geometry */
1417    if (src->geom) {
1418        if (!dst->geom) {
1419            dst->geom = calloc(sizeof(XkbGeometryRec), 1);
1420            if (!dst->geom)
1421                return FALSE;
1422        }
1423
1424        /* properties */
1425        if (src->geom->num_properties) {
1426            /* If we've got more properties in the destination than
1427             * the source, run through and free all the excess ones
1428             * first. */
1429            if (src->geom->num_properties < dst->geom->sz_properties) {
1430                for (i = src->geom->num_properties, dprop =
1431                     dst->geom->properties + i; i < dst->geom->num_properties;
1432                     i++, dprop++) {
1433                    free(dprop->name);
1434                    free(dprop->value);
1435                }
1436            }
1437
1438            /* Reallocate and clear all new items if the buffer grows. */
1439            if (!XkbGeomRealloc
1440                ((void **) &dst->geom->properties, dst->geom->sz_properties,
1441                 src->geom->num_properties, sizeof(XkbPropertyRec),
1442                 XKB_GEOM_CLEAR_EXCESS))
1443                return FALSE;
1444            /* We don't set num_properties as we need it to try and avoid
1445             * too much reallocing. */
1446            dst->geom->sz_properties = src->geom->num_properties;
1447
1448            for (i = 0,
1449                 sprop = src->geom->properties,
1450                 dprop = dst->geom->properties;
1451                 i < src->geom->num_properties; i++, sprop++, dprop++) {
1452                if (i < dst->geom->num_properties) {
1453                    if (strlen(sprop->name) != strlen(dprop->name)) {
1454                        tmp = realloc(dprop->name, strlen(sprop->name) + 1);
1455                        if (!tmp)
1456                            return FALSE;
1457                        dprop->name = tmp;
1458                    }
1459                    if (strlen(sprop->value) != strlen(dprop->value)) {
1460                        tmp = realloc(dprop->value, strlen(sprop->value) + 1);
1461                        if (!tmp)
1462                            return FALSE;
1463                        dprop->value = tmp;
1464                    }
1465                    strcpy(dprop->name, sprop->name);
1466                    strcpy(dprop->value, sprop->value);
1467                }
1468                else {
1469                    dprop->name = xstrdup(sprop->name);
1470                    dprop->value = xstrdup(sprop->value);
1471                }
1472            }
1473
1474            /* ... which is already src->geom->num_properties. */
1475            dst->geom->num_properties = dst->geom->sz_properties;
1476        }
1477        else {
1478            if (dst->geom->sz_properties) {
1479                for (i = 0, dprop = dst->geom->properties;
1480                     i < dst->geom->num_properties; i++, dprop++) {
1481                    free(dprop->name);
1482                    free(dprop->value);
1483                }
1484                free(dst->geom->properties);
1485                dst->geom->properties = NULL;
1486            }
1487
1488            dst->geom->num_properties = 0;
1489            dst->geom->sz_properties = 0;
1490        }
1491
1492        /* colors */
1493        if (src->geom->num_colors) {
1494            if (src->geom->num_colors < dst->geom->sz_colors) {
1495                for (i = src->geom->num_colors, dcolor = dst->geom->colors + i;
1496                     i < dst->geom->num_colors; i++, dcolor++) {
1497                    free(dcolor->spec);
1498                }
1499            }
1500
1501            /* Reallocate and clear all new items if the buffer grows. */
1502            if (!XkbGeomRealloc
1503                ((void **) &dst->geom->colors, dst->geom->sz_colors,
1504                 src->geom->num_colors, sizeof(XkbColorRec),
1505                 XKB_GEOM_CLEAR_EXCESS))
1506                return FALSE;
1507            dst->geom->sz_colors = src->geom->num_colors;
1508
1509            for (i = 0,
1510                 scolor = src->geom->colors,
1511                 dcolor = dst->geom->colors;
1512                 i < src->geom->num_colors; i++, scolor++, dcolor++) {
1513                if (i < dst->geom->num_colors) {
1514                    if (strlen(scolor->spec) != strlen(dcolor->spec)) {
1515                        tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1);
1516                        if (!tmp)
1517                            return FALSE;
1518                        dcolor->spec = tmp;
1519                    }
1520                    strcpy(dcolor->spec, scolor->spec);
1521                }
1522                else {
1523                    dcolor->spec = xstrdup(scolor->spec);
1524                }
1525                dcolor->pixel = scolor->pixel;
1526            }
1527
1528            dst->geom->num_colors = dst->geom->sz_colors;
1529        }
1530        else {
1531            if (dst->geom->sz_colors) {
1532                for (i = 0, dcolor = dst->geom->colors;
1533                     i < dst->geom->num_colors; i++, dcolor++) {
1534                    free(dcolor->spec);
1535                }
1536                free(dst->geom->colors);
1537                dst->geom->colors = NULL;
1538            }
1539
1540            dst->geom->num_colors = 0;
1541            dst->geom->sz_colors = 0;
1542        }
1543
1544        /* shapes */
1545        /* shapes break down into outlines, which break down into points. */
1546        if (dst->geom->num_shapes) {
1547            for (i = 0, dshape = dst->geom->shapes;
1548                 i < dst->geom->num_shapes; i++, dshape++) {
1549                for (j = 0, doutline = dshape->outlines;
1550                     j < dshape->num_outlines; j++, doutline++) {
1551                    if (doutline->sz_points)
1552                        free(doutline->points);
1553                }
1554
1555                if (dshape->sz_outlines) {
1556                    free(dshape->outlines);
1557                    dshape->outlines = NULL;
1558                }
1559
1560                dshape->num_outlines = 0;
1561                dshape->sz_outlines = 0;
1562            }
1563        }
1564
1565        if (src->geom->num_shapes) {
1566            /* Reallocate and clear all items. */
1567            if (!XkbGeomRealloc
1568                ((void **) &dst->geom->shapes, dst->geom->sz_shapes,
1569                 src->geom->num_shapes, sizeof(XkbShapeRec),
1570                 XKB_GEOM_CLEAR_ALL))
1571                return FALSE;
1572
1573            for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes;
1574                 i < src->geom->num_shapes; i++, sshape++, dshape++) {
1575                if (sshape->num_outlines) {
1576                    tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec));
1577                    if (!tmp)
1578                        return FALSE;
1579                    dshape->outlines = tmp;
1580
1581                    for (j = 0,
1582                         soutline = sshape->outlines,
1583                         doutline = dshape->outlines;
1584                         j < sshape->num_outlines;
1585                         j++, soutline++, doutline++) {
1586                        if (soutline->num_points) {
1587                            tmp = xallocarray(soutline->num_points,
1588                                              sizeof(XkbPointRec));
1589                            if (!tmp)
1590                                return FALSE;
1591                            doutline->points = tmp;
1592
1593                            memcpy(doutline->points, soutline->points,
1594                                   soutline->num_points * sizeof(XkbPointRec));
1595
1596                            doutline->corner_radius = soutline->corner_radius;
1597                        }
1598
1599                        doutline->num_points = soutline->num_points;
1600                        doutline->sz_points = soutline->num_points;
1601                    }
1602                }
1603
1604                dshape->num_outlines = sshape->num_outlines;
1605                dshape->sz_outlines = sshape->num_outlines;
1606                dshape->name = sshape->name;
1607                dshape->bounds = sshape->bounds;
1608
1609                dshape->approx = NULL;
1610                if (sshape->approx && sshape->num_outlines > 0) {
1611
1612                    const ptrdiff_t approx_idx =
1613                        sshape->approx - sshape->outlines;
1614
1615                    if (approx_idx < dshape->num_outlines) {
1616                        dshape->approx = dshape->outlines + approx_idx;
1617                    }
1618                    else {
1619                        LogMessage(X_WARNING, "XKB: approx outline "
1620                                   "index is out of range\n");
1621                    }
1622                }
1623
1624                dshape->primary = NULL;
1625                if (sshape->primary && sshape->num_outlines > 0) {
1626
1627                    const ptrdiff_t primary_idx =
1628                        sshape->primary - sshape->outlines;
1629
1630                    if (primary_idx < dshape->num_outlines) {
1631                        dshape->primary = dshape->outlines + primary_idx;
1632                    }
1633                    else {
1634                        LogMessage(X_WARNING, "XKB: primary outline "
1635                                   "index is out of range\n");
1636                    }
1637                }
1638            }
1639
1640            dst->geom->num_shapes = src->geom->num_shapes;
1641            dst->geom->sz_shapes = src->geom->num_shapes;
1642        }
1643        else {
1644            if (dst->geom->sz_shapes) {
1645                free(dst->geom->shapes);
1646            }
1647            dst->geom->shapes = NULL;
1648            dst->geom->num_shapes = 0;
1649            dst->geom->sz_shapes = 0;
1650        }
1651
1652        /* sections */
1653        /* sections break down into doodads, and also into rows, which break
1654         * down into keys. */
1655        if (dst->geom->num_sections) {
1656            for (i = 0, dsection = dst->geom->sections;
1657                 i < dst->geom->num_sections; i++, dsection++) {
1658                for (j = 0, drow = dsection->rows;
1659                     j < dsection->num_rows; j++, drow++) {
1660                    if (drow->num_keys)
1661                        free(drow->keys);
1662                }
1663
1664                if (dsection->num_rows)
1665                    free(dsection->rows);
1666
1667                /* cut and waste from geom/doodad below. */
1668                for (j = 0, ddoodad = dsection->doodads;
1669                     j < dsection->num_doodads; j++, ddoodad++) {
1670                    if (ddoodad->any.type == XkbTextDoodad) {
1671                        free(ddoodad->text.text);
1672                        ddoodad->text.text = NULL;
1673                        free(ddoodad->text.font);
1674                        ddoodad->text.font = NULL;
1675                    }
1676                    else if (ddoodad->any.type == XkbLogoDoodad) {
1677                        free(ddoodad->logo.logo_name);
1678                        ddoodad->logo.logo_name = NULL;
1679                    }
1680                }
1681
1682                free(dsection->doodads);
1683            }
1684
1685            dst->geom->num_sections = 0;
1686        }
1687
1688        if (src->geom->num_sections) {
1689            /* Reallocate and clear all items. */
1690            if (!XkbGeomRealloc
1691                ((void **) &dst->geom->sections, dst->geom->sz_sections,
1692                 src->geom->num_sections, sizeof(XkbSectionRec),
1693                 XKB_GEOM_CLEAR_ALL))
1694                return FALSE;
1695            dst->geom->num_sections = src->geom->num_sections;
1696            dst->geom->sz_sections = src->geom->num_sections;
1697
1698            for (i = 0,
1699                 ssection = src->geom->sections,
1700                 dsection = dst->geom->sections;
1701                 i < src->geom->num_sections; i++, ssection++, dsection++) {
1702                *dsection = *ssection;
1703                if (ssection->num_rows) {
1704                    tmp = calloc(ssection->num_rows, sizeof(XkbRowRec));
1705                    if (!tmp)
1706                        return FALSE;
1707                    dsection->rows = tmp;
1708                }
1709                dsection->num_rows = ssection->num_rows;
1710                dsection->sz_rows = ssection->num_rows;
1711
1712                for (j = 0, srow = ssection->rows, drow = dsection->rows;
1713                     j < ssection->num_rows; j++, srow++, drow++) {
1714                    if (srow->num_keys) {
1715                        tmp = xallocarray(srow->num_keys, sizeof(XkbKeyRec));
1716                        if (!tmp)
1717                            return FALSE;
1718                        drow->keys = tmp;
1719                        memcpy(drow->keys, srow->keys,
1720                               srow->num_keys * sizeof(XkbKeyRec));
1721                    }
1722                    drow->num_keys = srow->num_keys;
1723                    drow->sz_keys = srow->num_keys;
1724                    drow->top = srow->top;
1725                    drow->left = srow->left;
1726                    drow->vertical = srow->vertical;
1727                    drow->bounds = srow->bounds;
1728                }
1729
1730                if (ssection->num_doodads) {
1731                    tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec));
1732                    if (!tmp)
1733                        return FALSE;
1734                    dsection->doodads = tmp;
1735                }
1736                else {
1737                    dsection->doodads = NULL;
1738                }
1739
1740                dsection->sz_doodads = ssection->num_doodads;
1741                for (k = 0,
1742                     sdoodad = ssection->doodads,
1743                     ddoodad = dsection->doodads;
1744                     k < ssection->num_doodads; k++, sdoodad++, ddoodad++) {
1745                    memcpy(ddoodad, sdoodad, sizeof(XkbDoodadRec));
1746                    if (sdoodad->any.type == XkbTextDoodad) {
1747                        if (sdoodad->text.text)
1748                            ddoodad->text.text = strdup(sdoodad->text.text);
1749                        if (sdoodad->text.font)
1750                            ddoodad->text.font = strdup(sdoodad->text.font);
1751                    }
1752                    else if (sdoodad->any.type == XkbLogoDoodad) {
1753                        if (sdoodad->logo.logo_name)
1754                            ddoodad->logo.logo_name =
1755                                strdup(sdoodad->logo.logo_name);
1756                    }
1757                }
1758                dsection->overlays = NULL;
1759                dsection->sz_overlays = 0;
1760                dsection->num_overlays = 0;
1761            }
1762        }
1763        else {
1764            if (dst->geom->sz_sections) {
1765                free(dst->geom->sections);
1766            }
1767
1768            dst->geom->sections = NULL;
1769            dst->geom->num_sections = 0;
1770            dst->geom->sz_sections = 0;
1771        }
1772
1773        /* doodads */
1774        if (dst->geom->num_doodads) {
1775            for (i = src->geom->num_doodads,
1776                 ddoodad = dst->geom->doodads +
1777                 src->geom->num_doodads;
1778                 i < dst->geom->num_doodads; i++, ddoodad++) {
1779                if (ddoodad->any.type == XkbTextDoodad) {
1780                    free(ddoodad->text.text);
1781                    ddoodad->text.text = NULL;
1782                    free(ddoodad->text.font);
1783                    ddoodad->text.font = NULL;
1784                }
1785                else if (ddoodad->any.type == XkbLogoDoodad) {
1786                    free(ddoodad->logo.logo_name);
1787                    ddoodad->logo.logo_name = NULL;
1788                }
1789            }
1790            dst->geom->num_doodads = 0;
1791        }
1792
1793        if (src->geom->num_doodads) {
1794            /* Reallocate and clear all items. */
1795            if (!XkbGeomRealloc
1796                ((void **) &dst->geom->doodads, dst->geom->sz_doodads,
1797                 src->geom->num_doodads, sizeof(XkbDoodadRec),
1798                 XKB_GEOM_CLEAR_ALL))
1799                return FALSE;
1800
1801            dst->geom->sz_doodads = src->geom->num_doodads;
1802
1803            for (i = 0,
1804                 sdoodad = src->geom->doodads,
1805                 ddoodad = dst->geom->doodads;
1806                 i < src->geom->num_doodads; i++, sdoodad++, ddoodad++) {
1807                memcpy(ddoodad, sdoodad, sizeof(XkbDoodadRec));
1808                if (sdoodad->any.type == XkbTextDoodad) {
1809                    if (sdoodad->text.text)
1810                        ddoodad->text.text = strdup(sdoodad->text.text);
1811                    if (sdoodad->text.font)
1812                        ddoodad->text.font = strdup(sdoodad->text.font);
1813                }
1814                else if (sdoodad->any.type == XkbLogoDoodad) {
1815                    if (sdoodad->logo.logo_name)
1816                        ddoodad->logo.logo_name =
1817                            strdup(sdoodad->logo.logo_name);
1818                }
1819            }
1820
1821            dst->geom->num_doodads = dst->geom->sz_doodads;
1822        }
1823        else {
1824            if (dst->geom->sz_doodads) {
1825                free(dst->geom->doodads);
1826            }
1827
1828            dst->geom->doodads = NULL;
1829            dst->geom->num_doodads = 0;
1830            dst->geom->sz_doodads = 0;
1831        }
1832
1833        /* key aliases */
1834        if (src->geom->num_key_aliases) {
1835            /* Reallocate but don't clear any items. There is no need
1836             * to clear anything because data is immediately copied
1837             * over the whole memory area with memcpy. */
1838            if (!XkbGeomRealloc
1839                ((void **) &dst->geom->key_aliases, dst->geom->sz_key_aliases,
1840                 src->geom->num_key_aliases, 2 * XkbKeyNameLength,
1841                 XKB_GEOM_CLEAR_NONE))
1842                return FALSE;
1843
1844            dst->geom->sz_key_aliases = src->geom->num_key_aliases;
1845
1846            memcpy(dst->geom->key_aliases, src->geom->key_aliases,
1847                   src->geom->num_key_aliases * 2 * XkbKeyNameLength);
1848
1849            dst->geom->num_key_aliases = dst->geom->sz_key_aliases;
1850        }
1851        else {
1852            free(dst->geom->key_aliases);
1853            dst->geom->key_aliases = NULL;
1854            dst->geom->num_key_aliases = 0;
1855            dst->geom->sz_key_aliases = 0;
1856        }
1857
1858        /* font */
1859        if (src->geom->label_font) {
1860            if (!dst->geom->label_font) {
1861                tmp = malloc(strlen(src->geom->label_font) + 1);
1862                if (!tmp)
1863                    return FALSE;
1864                dst->geom->label_font = tmp;
1865            }
1866            else if (strlen(src->geom->label_font) !=
1867                     strlen(dst->geom->label_font)) {
1868                tmp = realloc(dst->geom->label_font,
1869                              strlen(src->geom->label_font) + 1);
1870                if (!tmp)
1871                    return FALSE;
1872                dst->geom->label_font = tmp;
1873            }
1874
1875            strcpy(dst->geom->label_font, src->geom->label_font);
1876            i = XkbGeomColorIndex(src->geom, src->geom->label_color);
1877            dst->geom->label_color = &(dst->geom->colors[i]);
1878            i = XkbGeomColorIndex(src->geom, src->geom->base_color);
1879            dst->geom->base_color = &(dst->geom->colors[i]);
1880        }
1881        else {
1882            free(dst->geom->label_font);
1883            dst->geom->label_font = NULL;
1884            dst->geom->label_color = NULL;
1885            dst->geom->base_color = NULL;
1886        }
1887
1888        dst->geom->name = src->geom->name;
1889        dst->geom->width_mm = src->geom->width_mm;
1890        dst->geom->height_mm = src->geom->height_mm;
1891    }
1892    else {
1893        if (dst->geom) {
1894            /* I LOVE THE DIFFERENT CALL SIGNATURE.  REALLY, I DO. */
1895            XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE);
1896            dst->geom = NULL;
1897        }
1898    }
1899
1900    return TRUE;
1901}
1902
1903static Bool
1904_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst)
1905{
1906    /* indicators */
1907    if (src->indicators) {
1908        if (!dst->indicators) {
1909            dst->indicators = malloc(sizeof(XkbIndicatorRec));
1910            if (!dst->indicators)
1911                return FALSE;
1912        }
1913        memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec));
1914    }
1915    else {
1916        free(dst->indicators);
1917        dst->indicators = NULL;
1918    }
1919    return TRUE;
1920}
1921
1922static Bool
1923_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst)
1924{
1925    /* controls */
1926    if (src->ctrls) {
1927        if (!dst->ctrls) {
1928            dst->ctrls = malloc(sizeof(XkbControlsRec));
1929            if (!dst->ctrls)
1930                return FALSE;
1931        }
1932        memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec));
1933    }
1934    else {
1935        free(dst->ctrls);
1936        dst->ctrls = NULL;
1937    }
1938    return TRUE;
1939}
1940
1941/**
1942 * Copy an XKB map from src to dst, reallocating when necessary: if some
1943 * map components are present in one, but not in the other, the destination
1944 * components will be allocated or freed as necessary.
1945 *
1946 * Basic map consistency is assumed on both sides, so maps with random
1947 * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19)
1948 * _will_ cause failures.  You've been warned.
1949 *
1950 * Returns TRUE on success, or FALSE on failure.  If this function fails,
1951 * dst may be in an inconsistent state: all its pointers are guaranteed
1952 * to remain valid, but part of the map may be from src and part from dst.
1953 *
1954 */
1955
1956Bool
1957XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src)
1958{
1959
1960    if (!src || !dst) {
1961        DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst);
1962        return FALSE;
1963    }
1964
1965    if (src == dst)
1966        return TRUE;
1967
1968    if (!_XkbCopyClientMap(src, dst)) {
1969        DebugF("XkbCopyKeymap: failed to copy client map\n");
1970        return FALSE;
1971    }
1972    if (!_XkbCopyServerMap(src, dst)) {
1973        DebugF("XkbCopyKeymap: failed to copy server map\n");
1974        return FALSE;
1975    }
1976    if (!_XkbCopyIndicators(src, dst)) {
1977        DebugF("XkbCopyKeymap: failed to copy indicators\n");
1978        return FALSE;
1979    }
1980    if (!_XkbCopyControls(src, dst)) {
1981        DebugF("XkbCopyKeymap: failed to copy controls\n");
1982        return FALSE;
1983    }
1984    if (!_XkbCopyNames(src, dst)) {
1985        DebugF("XkbCopyKeymap: failed to copy names\n");
1986        return FALSE;
1987    }
1988    if (!_XkbCopyCompat(src, dst)) {
1989        DebugF("XkbCopyKeymap: failed to copy compat map\n");
1990        return FALSE;
1991    }
1992    if (!_XkbCopyGeom(src, dst)) {
1993        DebugF("XkbCopyKeymap: failed to copy geometry\n");
1994        return FALSE;
1995    }
1996
1997    dst->min_key_code = src->min_key_code;
1998    dst->max_key_code = src->max_key_code;
1999
2000    return TRUE;
2001}
2002
2003Bool
2004XkbDeviceApplyKeymap(DeviceIntPtr dst, XkbDescPtr desc)
2005{
2006    xkbNewKeyboardNotify nkn;
2007    Bool ret;
2008
2009    if (!dst->key || !desc)
2010        return FALSE;
2011
2012    memset(&nkn, 0, sizeof(xkbNewKeyboardNotify));
2013    nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code;
2014    nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code;
2015    nkn.deviceID = dst->id;
2016    nkn.oldDeviceID = dst->id;
2017    nkn.minKeyCode = desc->min_key_code;
2018    nkn.maxKeyCode = desc->max_key_code;
2019    nkn.requestMajor = XkbReqCode;
2020    nkn.requestMinor = X_kbSetMap;      /* Near enough's good enough. */
2021    nkn.changed = XkbNKN_KeycodesMask;
2022    if (desc->geom)
2023        nkn.changed |= XkbNKN_GeometryMask;
2024
2025    ret = XkbCopyKeymap(dst->key->xkbInfo->desc, desc);
2026    if (ret)
2027        XkbSendNewKeyboardNotify(dst, &nkn);
2028
2029    return ret;
2030}
2031
2032Bool
2033XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src)
2034{
2035    return XkbDeviceApplyKeymap(dst, src->key->xkbInfo->desc);
2036}
2037
2038int
2039XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode)
2040{
2041    XkbDescPtr xkb = xkbi->desc;
2042    int effectiveGroup = xkbState->group;
2043
2044    if (!XkbKeycodeInRange(xkb, keycode))
2045        return -1;
2046
2047    if (effectiveGroup == XkbGroup1Index)
2048        return effectiveGroup;
2049
2050    if (XkbKeyNumGroups(xkb, keycode) > 1U) {
2051        if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) {
2052            unsigned int gi = XkbKeyGroupInfo(xkb, keycode);
2053
2054            switch (XkbOutOfRangeGroupAction(gi)) {
2055            default:
2056            case XkbWrapIntoRange:
2057                effectiveGroup %= XkbKeyNumGroups(xkb, keycode);
2058                break;
2059            case XkbClampIntoRange:
2060                effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1;
2061                break;
2062            case XkbRedirectIntoRange:
2063                effectiveGroup = XkbOutOfRangeGroupInfo(gi);
2064                if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode))
2065                    effectiveGroup = 0;
2066                break;
2067            }
2068        }
2069    }
2070    else
2071        effectiveGroup = XkbGroup1Index;
2072
2073    return effectiveGroup;
2074}
2075
2076/* Merge the lockedPtrButtons from all attached SDs for the given master
2077 * device into the MD's state.
2078 */
2079void
2080XkbMergeLockedPtrBtns(DeviceIntPtr master)
2081{
2082    DeviceIntPtr d = inputInfo.devices;
2083    XkbSrvInfoPtr xkbi = NULL;
2084
2085    if (!IsMaster(master))
2086        return;
2087
2088    if (!master->key)
2089        return;
2090
2091    xkbi = master->key->xkbInfo;
2092    xkbi->lockedPtrButtons = 0;
2093
2094    for (; d; d = d->next) {
2095        if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key)
2096            continue;
2097
2098        xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons;
2099    }
2100}
2101
2102void
2103XkbCopyControls(XkbDescPtr dst, XkbDescPtr src)
2104{
2105    int i, nG, nTG;
2106
2107    if (!dst || !src)
2108        return;
2109
2110    *dst->ctrls = *src->ctrls;
2111
2112    for (nG = nTG = 0, i = dst->min_key_code; i <= dst->max_key_code; i++) {
2113        nG = XkbKeyNumGroups(dst, i);
2114        if (nG >= XkbNumKbdGroups) {
2115            nTG = XkbNumKbdGroups;
2116            break;
2117        }
2118        if (nG > nTG) {
2119            nTG = nG;
2120        }
2121    }
2122    dst->ctrls->num_groups = nTG;
2123}
2124