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