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