1706f2543Smrg/************************************************************
2706f2543SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3706f2543Smrg
4706f2543SmrgPermission to use, copy, modify, and distribute this
5706f2543Smrgsoftware and its documentation for any purpose and without
6706f2543Smrgfee is hereby granted, provided that the above copyright
7706f2543Smrgnotice appear in all copies and that both that copyright
8706f2543Smrgnotice and this permission notice appear in supporting
9706f2543Smrgdocumentation, and that the name of Silicon Graphics not be
10706f2543Smrgused in advertising or publicity pertaining to distribution
11706f2543Smrgof the software without specific prior written permission.
12706f2543SmrgSilicon Graphics makes no representation about the suitability
13706f2543Smrgof this software for any purpose. It is provided "as is"
14706f2543Smrgwithout any express or implied warranty.
15706f2543Smrg
16706f2543SmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17706f2543SmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18706f2543SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19706f2543SmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20706f2543SmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21706f2543SmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22706f2543SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23706f2543SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
24706f2543Smrg
25706f2543Smrg********************************************************/
26706f2543Smrg/*
27706f2543Smrg
28706f2543SmrgCopyright © 2008 Red Hat Inc.
29706f2543Smrg
30706f2543SmrgPermission is hereby granted, free of charge, to any person obtaining a
31706f2543Smrgcopy of this software and associated documentation files (the "Software"),
32706f2543Smrgto deal in the Software without restriction, including without limitation
33706f2543Smrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
34706f2543Smrgand/or sell copies of the Software, and to permit persons to whom the
35706f2543SmrgSoftware is furnished to do so, subject to the following conditions:
36706f2543Smrg
37706f2543SmrgThe above copyright notice and this permission notice (including the next
38706f2543Smrgparagraph) shall be included in all copies or substantial portions of the
39706f2543SmrgSoftware.
40706f2543Smrg
41706f2543SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42706f2543SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43706f2543SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44706f2543SmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45706f2543SmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46706f2543SmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47706f2543SmrgDEALINGS IN THE SOFTWARE.
48706f2543Smrg
49706f2543Smrg*/
50706f2543Smrg
51706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
52706f2543Smrg#include <dix-config.h>
53706f2543Smrg#endif
54706f2543Smrg
55706f2543Smrg#include "os.h"
56706f2543Smrg#include <stdio.h>
57706f2543Smrg#include <ctype.h>
58706f2543Smrg#include <math.h>
59706f2543Smrg#include <X11/X.h>
60706f2543Smrg#include <X11/Xproto.h>
61706f2543Smrg#define	XK_CYRILLIC
62706f2543Smrg#include <X11/keysym.h>
63706f2543Smrg#include "misc.h"
64706f2543Smrg#include "inputstr.h"
65706f2543Smrg#include "eventstr.h"
66706f2543Smrg
67706f2543Smrg#define	XKBSRV_NEED_FILE_FUNCS
68706f2543Smrg#include <xkbsrv.h>
69706f2543Smrg#include "xkbgeom.h"
70706f2543Smrg#include "xkb.h"
71706f2543Smrg
72706f2543Smrg/***====================================================================***/
73706f2543Smrg
74706f2543Smrgint
75706f2543Smrg_XkbLookupAnyDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
76706f2543Smrg		    Mask access_mode, int *xkb_err)
77706f2543Smrg{
78706f2543Smrg    int rc = XkbKeyboardErrorCode;
79706f2543Smrg
80706f2543Smrg    if (id == XkbUseCoreKbd)
81706f2543Smrg        id = PickKeyboard(client)->id;
82706f2543Smrg    else if (id == XkbUseCorePtr)
83706f2543Smrg        id = PickPointer(client)->id;
84706f2543Smrg
85706f2543Smrg    rc = dixLookupDevice(pDev, id, client, access_mode);
86706f2543Smrg    if (rc != Success)
87706f2543Smrg	*xkb_err = XkbErr_BadDevice;
88706f2543Smrg
89706f2543Smrg    return rc;
90706f2543Smrg}
91706f2543Smrg
92706f2543Smrgint
93706f2543Smrg_XkbLookupKeyboard(DeviceIntPtr *pDev, int id, ClientPtr client,
94706f2543Smrg		   Mask access_mode, int *xkb_err)
95706f2543Smrg{
96706f2543Smrg    DeviceIntPtr dev;
97706f2543Smrg    int rc;
98706f2543Smrg
99706f2543Smrg    if (id == XkbDfltXIId)
100706f2543Smrg        id = XkbUseCoreKbd;
101706f2543Smrg
102706f2543Smrg    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
103706f2543Smrg    if (rc != Success)
104706f2543Smrg	return rc;
105706f2543Smrg
106706f2543Smrg    dev = *pDev;
107706f2543Smrg    if (!dev->key || !dev->key->xkbInfo) {
108706f2543Smrg	*pDev = NULL;
109706f2543Smrg	*xkb_err= XkbErr_BadClass;
110706f2543Smrg	return XkbKeyboardErrorCode;
111706f2543Smrg    }
112706f2543Smrg    return Success;
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrgint
116706f2543Smrg_XkbLookupBellDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
117706f2543Smrg		     Mask access_mode, int *xkb_err)
118706f2543Smrg{
119706f2543Smrg    DeviceIntPtr dev;
120706f2543Smrg    int rc;
121706f2543Smrg
122706f2543Smrg    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
123706f2543Smrg    if (rc != Success)
124706f2543Smrg	return rc;
125706f2543Smrg
126706f2543Smrg    dev = *pDev;
127706f2543Smrg    if (!dev->kbdfeed && !dev->bell) {
128706f2543Smrg	*pDev = NULL;
129706f2543Smrg	*xkb_err= XkbErr_BadClass;
130706f2543Smrg	return XkbKeyboardErrorCode;
131706f2543Smrg    }
132706f2543Smrg    return Success;
133706f2543Smrg}
134706f2543Smrg
135706f2543Smrgint
136706f2543Smrg_XkbLookupLedDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
137706f2543Smrg		    Mask access_mode, int *xkb_err)
138706f2543Smrg{
139706f2543Smrg    DeviceIntPtr dev;
140706f2543Smrg    int rc;
141706f2543Smrg
142706f2543Smrg    if (id == XkbDfltXIId)
143706f2543Smrg        id = XkbUseCorePtr;
144706f2543Smrg
145706f2543Smrg    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
146706f2543Smrg    if (rc != Success)
147706f2543Smrg	return rc;
148706f2543Smrg
149706f2543Smrg    dev = *pDev;
150706f2543Smrg    if (!dev->kbdfeed && !dev->leds) {
151706f2543Smrg	*pDev = NULL;
152706f2543Smrg	*xkb_err= XkbErr_BadClass;
153706f2543Smrg	return XkbKeyboardErrorCode;
154706f2543Smrg    }
155706f2543Smrg    return Success;
156706f2543Smrg}
157706f2543Smrg
158706f2543Smrgint
159706f2543Smrg_XkbLookupButtonDevice(DeviceIntPtr *pDev, int id, ClientPtr client,
160706f2543Smrg		       Mask access_mode, int *xkb_err)
161706f2543Smrg{
162706f2543Smrg    DeviceIntPtr dev;
163706f2543Smrg    int rc;
164706f2543Smrg
165706f2543Smrg    rc = _XkbLookupAnyDevice(pDev, id, client, access_mode, xkb_err);
166706f2543Smrg    if (rc != Success)
167706f2543Smrg	return rc;
168706f2543Smrg
169706f2543Smrg    dev = *pDev;
170706f2543Smrg    if (!dev->button) {
171706f2543Smrg	*pDev = NULL;
172706f2543Smrg	*xkb_err= XkbErr_BadClass;
173706f2543Smrg	return XkbKeyboardErrorCode;
174706f2543Smrg    }
175706f2543Smrg    return Success;
176706f2543Smrg}
177706f2543Smrg
178706f2543Smrgvoid
179706f2543SmrgXkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
180706f2543Smrg{
181706f2543Smrgregister unsigned	tmp;
182706f2543Smrg
183706f2543Smrg    switch (act->type) {
184706f2543Smrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
185706f2543Smrg	    if (act->mods.flags&XkbSA_UseModMapMods)
186706f2543Smrg		act->mods.real_mods= act->mods.mask= mods;
187706f2543Smrg	    if ((tmp= XkbModActionVMods(&act->mods))!=0)
188706f2543Smrg		act->mods.mask|= XkbMaskForVMask(xkb,tmp);
189706f2543Smrg	    break;
190706f2543Smrg	case XkbSA_ISOLock:
191706f2543Smrg	    if (act->iso.flags&XkbSA_UseModMapMods)
192706f2543Smrg		act->iso.real_mods= act->iso.mask= mods;
193706f2543Smrg	    if ((tmp= XkbModActionVMods(&act->iso))!=0)
194706f2543Smrg		act->iso.mask|= XkbMaskForVMask(xkb,tmp);
195706f2543Smrg	    break;
196706f2543Smrg    }
197706f2543Smrg    return;
198706f2543Smrg}
199706f2543Smrg
200706f2543Smrgunsigned
201706f2543SmrgXkbMaskForVMask(XkbDescPtr xkb,unsigned vmask)
202706f2543Smrg{
203706f2543Smrgregister int i,bit;
204706f2543Smrgregister unsigned mask;
205706f2543Smrg
206706f2543Smrg    for (mask=i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
207706f2543Smrg	if (vmask&bit)
208706f2543Smrg	    mask|= xkb->server->vmods[i];
209706f2543Smrg    }
210706f2543Smrg    return mask;
211706f2543Smrg}
212706f2543Smrg
213706f2543Smrg/***====================================================================***/
214706f2543Smrg
215706f2543Smrgvoid
216706f2543SmrgXkbUpdateKeyTypesFromCore(	DeviceIntPtr	pXDev,
217706f2543Smrg                                KeySymsPtr      pCore,
218706f2543Smrg				KeyCode	 	first,
219706f2543Smrg				CARD8	 	num,
220706f2543Smrg				XkbChangesPtr	changes)
221706f2543Smrg{
222706f2543SmrgXkbDescPtr		xkb;
223706f2543Smrgunsigned		key,nG,explicit;
224706f2543Smrgint			types[XkbNumKbdGroups];
225706f2543SmrgKeySym			tsyms[XkbMaxSymsPerKey],*syms;
226706f2543SmrgXkbMapChangesPtr	mc;
227706f2543Smrg
228706f2543Smrg    xkb= pXDev->key->xkbInfo->desc;
229706f2543Smrg    if (first+num-1>xkb->max_key_code) {
230706f2543Smrg	/* 1/12/95 (ef) -- XXX! should allow XKB structures to grow */
231706f2543Smrg	num= xkb->max_key_code-first+1;
232706f2543Smrg    }
233706f2543Smrg
234706f2543Smrg    mc= (changes?(&changes->map):NULL);
235706f2543Smrg
236706f2543Smrg    syms= &pCore->map[(first - pCore->minKeyCode) * pCore->mapWidth];
237706f2543Smrg    for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) {
238706f2543Smrg        explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask;
239706f2543Smrg        types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
240706f2543Smrg        types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index);
241706f2543Smrg        types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index);
242706f2543Smrg        types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index);
243706f2543Smrg        nG= XkbKeyTypesForCoreSymbols(xkb,pCore->mapWidth,syms,explicit,types,
244706f2543Smrg									tsyms);
245706f2543Smrg	XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc);
246706f2543Smrg	memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms,
247706f2543Smrg					XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
248706f2543Smrg    }
249706f2543Smrg    if (changes->map.changed&XkbKeySymsMask) {
250706f2543Smrg	CARD8 oldLast,newLast;
251706f2543Smrg	oldLast = changes->map.first_key_sym+changes->map.num_key_syms-1;
252706f2543Smrg	newLast = first+num-1;
253706f2543Smrg
254706f2543Smrg	if (first<changes->map.first_key_sym)
255706f2543Smrg	    changes->map.first_key_sym = first;
256706f2543Smrg	if (oldLast>newLast)
257706f2543Smrg	    newLast= oldLast;
258706f2543Smrg	changes->map.num_key_syms = newLast-changes->map.first_key_sym+1;
259706f2543Smrg    }
260706f2543Smrg    else {
261706f2543Smrg	changes->map.changed|= XkbKeySymsMask;
262706f2543Smrg	changes->map.first_key_sym = first;
263706f2543Smrg	changes->map.num_key_syms = num;
264706f2543Smrg    }
265706f2543Smrg    return;
266706f2543Smrg}
267706f2543Smrg
268706f2543Smrgvoid
269706f2543SmrgXkbUpdateDescActions(	XkbDescPtr		xkb,
270706f2543Smrg			KeyCode		 	first,
271706f2543Smrg			CARD8		 	num,
272706f2543Smrg			XkbChangesPtr	 	changes)
273706f2543Smrg{
274706f2543Smrgregister unsigned	key;
275706f2543Smrg
276706f2543Smrg    for (key=first;key<(first+num);key++) {
277706f2543Smrg	XkbApplyCompatMapToKey(xkb,key,changes);
278706f2543Smrg    }
279706f2543Smrg
280706f2543Smrg    if (changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask)) {
281706f2543Smrg        unsigned char           newVMods[XkbNumVirtualMods];
282706f2543Smrg        register  unsigned      bit,i;
283706f2543Smrg        unsigned                present;
284706f2543Smrg
285706f2543Smrg        memset(newVMods, 0, XkbNumVirtualMods);
286706f2543Smrg        present= 0;
287706f2543Smrg        for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) {
288706f2543Smrg            if (xkb->server->vmodmap[key]==0)
289706f2543Smrg                continue;
290706f2543Smrg            for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
291706f2543Smrg                if (bit&xkb->server->vmodmap[key]) {
292706f2543Smrg                    present|= bit;
293706f2543Smrg                    newVMods[i]|= xkb->map->modmap[key];
294706f2543Smrg                }
295706f2543Smrg            }
296706f2543Smrg        }
297706f2543Smrg        for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
298706f2543Smrg            if ((bit&present)&&(newVMods[i]!=xkb->server->vmods[i])) {
299706f2543Smrg                changes->map.changed|= XkbVirtualModsMask;
300706f2543Smrg                changes->map.vmods|= bit;
301706f2543Smrg                xkb->server->vmods[i]= newVMods[i];
302706f2543Smrg            }
303706f2543Smrg        }
304706f2543Smrg    }
305706f2543Smrg    if (changes->map.changed&XkbVirtualModsMask)
306706f2543Smrg        XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes);
307706f2543Smrg
308706f2543Smrg    if (changes->map.changed&XkbKeyActionsMask) {
309706f2543Smrg	CARD8 oldLast,newLast;
310706f2543Smrg	oldLast= changes->map.first_key_act+changes->map.num_key_acts-1;
311706f2543Smrg	newLast = first+num-1;
312706f2543Smrg
313706f2543Smrg	if (first<changes->map.first_key_act)
314706f2543Smrg	    changes->map.first_key_act = first;
315706f2543Smrg	if (newLast>oldLast)
316706f2543Smrg	    newLast= oldLast;
317706f2543Smrg	changes->map.num_key_acts= newLast-changes->map.first_key_act+1;
318706f2543Smrg    }
319706f2543Smrg    else {
320706f2543Smrg	changes->map.changed|= XkbKeyActionsMask;
321706f2543Smrg	changes->map.first_key_act = first;
322706f2543Smrg	changes->map.num_key_acts = num;
323706f2543Smrg    }
324706f2543Smrg    return;
325706f2543Smrg}
326706f2543Smrg
327706f2543Smrgvoid
328706f2543SmrgXkbUpdateActions(	DeviceIntPtr	 	pXDev,
329706f2543Smrg			KeyCode		 	first,
330706f2543Smrg			CARD8		 	num,
331706f2543Smrg			XkbChangesPtr	 	changes,
332706f2543Smrg			unsigned *	 	needChecksRtrn,
333706f2543Smrg			XkbEventCausePtr	cause)
334706f2543Smrg{
335706f2543SmrgXkbSrvInfoPtr		xkbi;
336706f2543SmrgXkbDescPtr		xkb;
337706f2543SmrgCARD8 *			repeat;
338706f2543Smrg
339706f2543Smrg    if (needChecksRtrn)
340706f2543Smrg	*needChecksRtrn= 0;
341706f2543Smrg    xkbi= pXDev->key->xkbInfo;
342706f2543Smrg    xkb= xkbi->desc;
343706f2543Smrg    repeat= xkb->ctrls->per_key_repeat;
344706f2543Smrg
345706f2543Smrg    /* before letting XKB do any changes, copy the current core values */
346706f2543Smrg    if (pXDev->kbdfeed)
347706f2543Smrg	memcpy(repeat,pXDev->kbdfeed->ctrl.autoRepeats,XkbPerKeyBitArraySize);
348706f2543Smrg
349706f2543Smrg    XkbUpdateDescActions(xkb,first,num,changes);
350706f2543Smrg
351706f2543Smrg    if ((pXDev->kbdfeed)&&
352706f2543Smrg	(changes->ctrls.changed_ctrls&XkbPerKeyRepeatMask)) {
353706f2543Smrg	/* now copy the modified changes back to core */
354706f2543Smrg	memcpy(pXDev->kbdfeed->ctrl.autoRepeats,repeat, XkbPerKeyBitArraySize);
355706f2543Smrg	if (pXDev->kbdfeed->CtrlProc)
356706f2543Smrg	    (*pXDev->kbdfeed->CtrlProc)(pXDev, &pXDev->kbdfeed->ctrl);
357706f2543Smrg    }
358706f2543Smrg    return;
359706f2543Smrg}
360706f2543Smrg
361706f2543SmrgKeySymsPtr
362706f2543SmrgXkbGetCoreMap(DeviceIntPtr keybd)
363706f2543Smrg{
364706f2543Smrgregister int		key,tmp;
365706f2543Smrgint			maxSymsPerKey, maxGroup1Width;
366706f2543SmrgXkbDescPtr		xkb;
367706f2543SmrgKeySymsPtr              syms;
368706f2543Smrgint			maxNumberOfGroups;
369706f2543Smrg
370706f2543Smrg    if (!keybd || !keybd->key || !keybd->key->xkbInfo)
371706f2543Smrg	return NULL;
372706f2543Smrg
373706f2543Smrg    xkb= keybd->key->xkbInfo->desc;
374706f2543Smrg    maxSymsPerKey= maxGroup1Width= 0;
375706f2543Smrg    maxNumberOfGroups = 0;
376706f2543Smrg
377706f2543Smrg    /* determine sizes */
378706f2543Smrg    for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) {
379706f2543Smrg	if (XkbKeycodeInRange(xkb,key)) {
380706f2543Smrg	    int	nGroups;
381706f2543Smrg	    int	w;
382706f2543Smrg	    nGroups= XkbKeyNumGroups(xkb,key);
383706f2543Smrg	    tmp= 0;
384706f2543Smrg	    if (nGroups>0) {
385706f2543Smrg		if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup1Index))<=2)
386706f2543Smrg		     tmp+= 2;
387706f2543Smrg		else tmp+= w + 2;
388706f2543Smrg                /* remember highest G1 width */
389706f2543Smrg                if (w > maxGroup1Width)
390706f2543Smrg                    maxGroup1Width = w;
391706f2543Smrg	    }
392706f2543Smrg	    if (nGroups>1) {
393706f2543Smrg                if (tmp <= 2) {
394706f2543Smrg		     if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))<2)
395706f2543Smrg		          tmp+= 2;
396706f2543Smrg		     else tmp+= w;
397706f2543Smrg                } else {
398706f2543Smrg                     if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2)
399706f2543Smrg                          tmp+= w - 2;
400706f2543Smrg                }
401706f2543Smrg	    }
402706f2543Smrg	    if (nGroups>2)
403706f2543Smrg		tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup3Index);
404706f2543Smrg	    if (nGroups>3)
405706f2543Smrg		tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup4Index);
406706f2543Smrg	    if (tmp>maxSymsPerKey)
407706f2543Smrg		maxSymsPerKey= tmp;
408706f2543Smrg            if (nGroups > maxNumberOfGroups)
409706f2543Smrg		maxNumberOfGroups = nGroups;
410706f2543Smrg	}
411706f2543Smrg    }
412706f2543Smrg
413706f2543Smrg    if (maxSymsPerKey <= 0)
414706f2543Smrg        return NULL;
415706f2543Smrg
416706f2543Smrg    syms = calloc(1, sizeof(*syms));
417706f2543Smrg    if (!syms)
418706f2543Smrg        return NULL;
419706f2543Smrg
420706f2543Smrg    /* See Section 12.4 of the XKB Protocol spec. Because of the
421706f2543Smrg     * single-group distribution for multi-group keyboards, we have to
422706f2543Smrg     * have enough symbols for the largest group 1 to replicate across the
423706f2543Smrg     * number of groups on the keyboard. e.g. a single-group key with 4
424706f2543Smrg     * symbols on a keyboard that has 3 groups -> 12 syms per key */
425706f2543Smrg    if (maxSymsPerKey < maxNumberOfGroups * maxGroup1Width)
426706f2543Smrg        maxSymsPerKey = maxNumberOfGroups * maxGroup1Width;
427706f2543Smrg
428706f2543Smrg    syms->mapWidth = maxSymsPerKey;
429706f2543Smrg    syms->minKeyCode = xkb->min_key_code;
430706f2543Smrg    syms->maxKeyCode = xkb->max_key_code;
431706f2543Smrg
432706f2543Smrg    tmp = syms->mapWidth * (xkb->max_key_code - xkb->min_key_code + 1);
433706f2543Smrg    syms->map = calloc(tmp, sizeof(*syms->map));
434706f2543Smrg    if (!syms->map) {
435706f2543Smrg        free(syms);
436706f2543Smrg        return NULL;
437706f2543Smrg    }
438706f2543Smrg
439706f2543Smrg    for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) {
440706f2543Smrg        KeySym *pCore,*pXKB;
441706f2543Smrg        unsigned nGroups,groupWidth,n,nOut;
442706f2543Smrg
443706f2543Smrg        nGroups= XkbKeyNumGroups(xkb,key);
444706f2543Smrg        n= (key-xkb->min_key_code)*syms->mapWidth;
445706f2543Smrg        pCore= &syms->map[n];
446706f2543Smrg        pXKB= XkbKeySymsPtr(xkb,key);
447706f2543Smrg        nOut= 2;
448706f2543Smrg        if (nGroups>0) {
449706f2543Smrg            groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup1Index);
450706f2543Smrg            if (groupWidth>0)   pCore[0]= pXKB[0];
451706f2543Smrg            if (groupWidth>1)   pCore[1]= pXKB[1];
452706f2543Smrg            for (n=2;n<groupWidth;n++)
453706f2543Smrg                pCore[2+n]= pXKB[n];
454706f2543Smrg            if (groupWidth>2)
455706f2543Smrg                nOut= groupWidth;
456706f2543Smrg        }
457706f2543Smrg
458706f2543Smrg	/* See XKB Protocol Sec, Section 12.4.
459706f2543Smrg           A 1-group key with ABCDE on a 2 group keyboard must be
460706f2543Smrg	   duplicated across all groups as ABABCDECDE.
461706f2543Smrg	 */
462706f2543Smrg	if (nGroups == 1)
463706f2543Smrg	{
464706f2543Smrg	    int idx, j;
465706f2543Smrg
466706f2543Smrg	    groupWidth = XkbKeyGroupWidth(xkb, key, XkbGroup1Index);
467706f2543Smrg
468706f2543Smrg	    /* AB..CDE... -> ABABCDE... */
469706f2543Smrg	    if (groupWidth > 0 && syms->mapWidth >= 3)
470706f2543Smrg	        pCore[2] = pCore[0];
471706f2543Smrg	    if (groupWidth > 1 && syms->mapWidth >= 4)
472706f2543Smrg	        pCore[3] = pCore[1];
473706f2543Smrg
474706f2543Smrg	    /* ABABCDE... -> ABABCDECDE */
475706f2543Smrg	    idx = 2 + groupWidth;
476706f2543Smrg	    while (groupWidth > 2 && idx < syms->mapWidth &&
477706f2543Smrg		   idx < groupWidth * 2)
478706f2543Smrg	    {
479706f2543Smrg		pCore[idx] = pCore[idx - groupWidth + 2];
480706f2543Smrg		idx++;
481706f2543Smrg	    }
482706f2543Smrg	    idx = 2 * groupWidth;
483706f2543Smrg	    if (idx < 4)
484706f2543Smrg		idx = 4;
485706f2543Smrg	    /* 3 or more groups: ABABCDECDEABCDEABCDE */
486706f2543Smrg	    for (j = 3; j <= maxNumberOfGroups; j++)
487706f2543Smrg		for (n = 0; n < groupWidth && idx < maxSymsPerKey; n++)
488706f2543Smrg		    pCore[idx++] = pXKB[n];
489706f2543Smrg	}
490706f2543Smrg
491706f2543Smrg	pXKB+= XkbKeyGroupsWidth(xkb,key);
492706f2543Smrg	nOut+= 2;
493706f2543Smrg	if (nGroups>1) {
494706f2543Smrg	    groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup2Index);
495706f2543Smrg	    if (groupWidth>0)	pCore[2]= pXKB[0];
496706f2543Smrg	    if (groupWidth>1)	pCore[3]= pXKB[1];
497706f2543Smrg	    for (n=2;n<groupWidth;n++) {
498706f2543Smrg		pCore[nOut+(n-2)]= pXKB[n];
499706f2543Smrg	    }
500706f2543Smrg	    if (groupWidth>2)
501706f2543Smrg		nOut+= (groupWidth-2);
502706f2543Smrg	}
503706f2543Smrg	pXKB+= XkbKeyGroupsWidth(xkb,key);
504706f2543Smrg	for (n=XkbGroup3Index;n<nGroups;n++) {
505706f2543Smrg	    register int s;
506706f2543Smrg	    groupWidth= XkbKeyGroupWidth(xkb,key,n);
507706f2543Smrg	    for (s=0;s<groupWidth;s++) {
508706f2543Smrg		pCore[nOut++]= pXKB[s];
509706f2543Smrg	    }
510706f2543Smrg	    pXKB+= XkbKeyGroupsWidth(xkb,key);
511706f2543Smrg	}
512706f2543Smrg    }
513706f2543Smrg
514706f2543Smrg    return syms;
515706f2543Smrg}
516706f2543Smrg
517706f2543Smrgvoid
518706f2543SmrgXkbSetRepeatKeys(DeviceIntPtr pXDev,int key,int onoff)
519706f2543Smrg{
520706f2543Smrg    if (pXDev && pXDev->key && pXDev->key->xkbInfo) {
521706f2543Smrg	xkbControlsNotify	cn;
522706f2543Smrg	XkbControlsPtr		ctrls = pXDev->key->xkbInfo->desc->ctrls;
523706f2543Smrg	XkbControlsRec 		old;
524706f2543Smrg	old = *ctrls;
525706f2543Smrg
526706f2543Smrg	if (key== -1) {	/* global autorepeat setting changed */
527706f2543Smrg	    if (onoff)	ctrls->enabled_ctrls |= XkbRepeatKeysMask;
528706f2543Smrg	    else	ctrls->enabled_ctrls &= ~XkbRepeatKeysMask;
529706f2543Smrg	}
530706f2543Smrg	else if (pXDev->kbdfeed) {
531706f2543Smrg	    ctrls->per_key_repeat[key/8] =
532706f2543Smrg		pXDev->kbdfeed->ctrl.autoRepeats[key/8];
533706f2543Smrg	}
534706f2543Smrg
535706f2543Smrg	if (XkbComputeControlsNotify(pXDev,&old,ctrls,&cn,TRUE))
536706f2543Smrg	    XkbSendControlsNotify(pXDev,&cn);
537706f2543Smrg    }
538706f2543Smrg    return;
539706f2543Smrg}
540706f2543Smrg
541706f2543Smrg/* Applies a change to a single device, does not traverse the device tree. */
542706f2543Smrgvoid
543706f2543SmrgXkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key,
544706f2543Smrg                      CARD8 num_keys, CARD8 *modmap, ClientPtr client)
545706f2543Smrg{
546706f2543Smrg    XkbDescPtr xkb = kbd->key->xkbInfo->desc;
547706f2543Smrg    XkbEventCauseRec cause;
548706f2543Smrg    XkbChangesRec changes;
549706f2543Smrg    unsigned int check;
550706f2543Smrg
551706f2543Smrg    memset(&changes, 0, sizeof(changes));
552706f2543Smrg    memset(&cause, 0, sizeof(cause));
553706f2543Smrg
554706f2543Smrg    if (map && first_key && num_keys) {
555706f2543Smrg        check = 0;
556706f2543Smrg        XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client);
557706f2543Smrg
558706f2543Smrg        XkbUpdateKeyTypesFromCore(kbd, map, first_key, num_keys, &changes);
559706f2543Smrg        XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause);
560706f2543Smrg
561706f2543Smrg        if (check)
562706f2543Smrg            XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause);
563706f2543Smrg    }
564706f2543Smrg
565706f2543Smrg    if (modmap) {
566706f2543Smrg        /* A keymap change can imply a modmap change, se we prefer the
567706f2543Smrg         * former. */
568706f2543Smrg        if (!cause.mjr)
569706f2543Smrg            XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client);
570706f2543Smrg
571706f2543Smrg        check = 0;
572706f2543Smrg        num_keys = xkb->max_key_code - xkb->min_key_code + 1;
573706f2543Smrg        changes.map.changed |= XkbModifierMapMask;
574706f2543Smrg        changes.map.first_modmap_key = xkb->min_key_code;
575706f2543Smrg        changes.map.num_modmap_keys = num_keys;
576706f2543Smrg        memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH);
577706f2543Smrg        XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check,
578706f2543Smrg                         &cause);
579706f2543Smrg
580706f2543Smrg        if (check)
581706f2543Smrg            XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause);
582706f2543Smrg    }
583706f2543Smrg
584706f2543Smrg    XkbSendNotification(kbd, &changes, &cause);
585706f2543Smrg}
586706f2543Smrg
587706f2543Smrgvoid
588706f2543SmrgXkbDisableComputedAutoRepeats(DeviceIntPtr dev,unsigned key)
589706f2543Smrg{
590706f2543SmrgXkbSrvInfoPtr	xkbi = dev->key->xkbInfo;
591706f2543SmrgxkbMapNotify	mn;
592706f2543Smrg
593706f2543Smrg    xkbi->desc->server->explicit[key]|= XkbExplicitAutoRepeatMask;
594706f2543Smrg    memset(&mn, 0, sizeof(mn));
595706f2543Smrg    mn.changed= XkbExplicitComponentsMask;
596706f2543Smrg    mn.firstKeyExplicit= key;
597706f2543Smrg    mn.nKeyExplicit= 1;
598706f2543Smrg    XkbSendMapNotify(dev,&mn);
599706f2543Smrg    return;
600706f2543Smrg}
601706f2543Smrg
602706f2543Smrgunsigned
603706f2543SmrgXkbStateChangedFlags(XkbStatePtr old,XkbStatePtr new)
604706f2543Smrg{
605706f2543Smrgint		changed;
606706f2543Smrg
607706f2543Smrg    changed=(old->group!=new->group?XkbGroupStateMask:0);
608706f2543Smrg    changed|=(old->base_group!=new->base_group?XkbGroupBaseMask:0);
609706f2543Smrg    changed|=(old->latched_group!=new->latched_group?XkbGroupLatchMask:0);
610706f2543Smrg    changed|=(old->locked_group!=new->locked_group?XkbGroupLockMask:0);
611706f2543Smrg    changed|=(old->mods!=new->mods?XkbModifierStateMask:0);
612706f2543Smrg    changed|=(old->base_mods!=new->base_mods?XkbModifierBaseMask:0);
613706f2543Smrg    changed|=(old->latched_mods!=new->latched_mods?XkbModifierLatchMask:0);
614706f2543Smrg    changed|=(old->locked_mods!=new->locked_mods?XkbModifierLockMask:0);
615706f2543Smrg    changed|=(old->compat_state!=new->compat_state?XkbCompatStateMask:0);
616706f2543Smrg    changed|=(old->grab_mods!=new->grab_mods?XkbGrabModsMask:0);
617706f2543Smrg    if (old->compat_grab_mods!=new->compat_grab_mods)
618706f2543Smrg	changed|= XkbCompatGrabModsMask;
619706f2543Smrg    changed|=(old->lookup_mods!=new->lookup_mods?XkbLookupModsMask:0);
620706f2543Smrg    if (old->compat_lookup_mods!=new->compat_lookup_mods)
621706f2543Smrg	changed|= XkbCompatLookupModsMask;
622706f2543Smrg    changed|=(old->ptr_buttons!=new->ptr_buttons?XkbPointerButtonMask:0);
623706f2543Smrg    return changed;
624706f2543Smrg}
625706f2543Smrg
626706f2543Smrgstatic void
627706f2543SmrgXkbComputeCompatState(XkbSrvInfoPtr xkbi)
628706f2543Smrg{
629706f2543SmrgCARD16 		grp_mask;
630706f2543SmrgXkbStatePtr	state= &xkbi->state;
631706f2543SmrgXkbCompatMapPtr	map;
632706f2543Smrg
633706f2543Smrg    if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat)
634706f2543Smrg        return;
635706f2543Smrg
636706f2543Smrg    map= xkbi->desc->compat;
637706f2543Smrg    grp_mask= map->groups[state->group].mask;
638706f2543Smrg    state->compat_state = state->mods|grp_mask;
639706f2543Smrg    state->compat_lookup_mods= state->lookup_mods|grp_mask;
640706f2543Smrg
641706f2543Smrg    if (xkbi->desc->ctrls->enabled_ctrls&XkbIgnoreGroupLockMask)
642706f2543Smrg	 grp_mask= map->groups[state->base_group].mask;
643706f2543Smrg    state->compat_grab_mods= state->grab_mods|grp_mask;
644706f2543Smrg    return;
645706f2543Smrg}
646706f2543Smrg
647706f2543Smrgunsigned
648706f2543SmrgXkbAdjustGroup(int group,XkbControlsPtr ctrls)
649706f2543Smrg{
650706f2543Smrgunsigned	act;
651706f2543Smrg
652706f2543Smrg    act= XkbOutOfRangeGroupAction(ctrls->groups_wrap);
653706f2543Smrg    if (group<0) {
654706f2543Smrg	while ( group < 0 )  {
655706f2543Smrg	    if (act==XkbClampIntoRange) {
656706f2543Smrg		group= XkbGroup1Index;
657706f2543Smrg	    }
658706f2543Smrg	    else if (act==XkbRedirectIntoRange) {
659706f2543Smrg		int newGroup;
660706f2543Smrg		newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap);
661706f2543Smrg		if (newGroup>=ctrls->num_groups)
662706f2543Smrg		     group= XkbGroup1Index;
663706f2543Smrg		else group= newGroup;
664706f2543Smrg	    }
665706f2543Smrg	    else {
666706f2543Smrg		group+= ctrls->num_groups;
667706f2543Smrg	    }
668706f2543Smrg	}
669706f2543Smrg    }
670706f2543Smrg    else if (group>=ctrls->num_groups) {
671706f2543Smrg	if (act==XkbClampIntoRange) {
672706f2543Smrg	    group= ctrls->num_groups-1;
673706f2543Smrg	}
674706f2543Smrg	else if (act==XkbRedirectIntoRange) {
675706f2543Smrg	    int newGroup;
676706f2543Smrg	    newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap);
677706f2543Smrg	    if (newGroup>=ctrls->num_groups)
678706f2543Smrg		 group= XkbGroup1Index;
679706f2543Smrg	    else group= newGroup;
680706f2543Smrg	}
681706f2543Smrg	else {
682706f2543Smrg	    group%= ctrls->num_groups;
683706f2543Smrg	}
684706f2543Smrg    }
685706f2543Smrg    return group;
686706f2543Smrg}
687706f2543Smrg
688706f2543Smrgvoid
689706f2543SmrgXkbComputeDerivedState(XkbSrvInfoPtr xkbi)
690706f2543Smrg{
691706f2543SmrgXkbStatePtr	state= &xkbi->state;
692706f2543SmrgXkbControlsPtr	ctrls= xkbi->desc->ctrls;
693706f2543Smrgunsigned char	grp;
694706f2543Smrg
695706f2543Smrg    if (!state || !ctrls)
696706f2543Smrg        return;
697706f2543Smrg
698706f2543Smrg    state->mods= (state->base_mods|state->latched_mods|state->locked_mods);
699706f2543Smrg    state->lookup_mods= state->mods&(~ctrls->internal.mask);
700706f2543Smrg    state->grab_mods= state->lookup_mods&(~ctrls->ignore_lock.mask);
701706f2543Smrg    state->grab_mods|=
702706f2543Smrg	((state->base_mods|state->latched_mods)&ctrls->ignore_lock.mask);
703706f2543Smrg
704706f2543Smrg
705706f2543Smrg    grp= state->locked_group;
706706f2543Smrg    if (grp>=ctrls->num_groups)
707706f2543Smrg	state->locked_group= XkbAdjustGroup(XkbCharToInt(grp),ctrls);
708706f2543Smrg
709706f2543Smrg    grp= state->locked_group+state->base_group+state->latched_group;
710706f2543Smrg    if (grp>=ctrls->num_groups)
711706f2543Smrg	 state->group= XkbAdjustGroup(XkbCharToInt(grp),ctrls);
712706f2543Smrg    else state->group= grp;
713706f2543Smrg    XkbComputeCompatState(xkbi);
714706f2543Smrg    return;
715706f2543Smrg}
716706f2543Smrg
717706f2543Smrg/***====================================================================***/
718706f2543Smrg
719706f2543Smrgvoid
720706f2543SmrgXkbCheckSecondaryEffects(	XkbSrvInfoPtr		xkbi,
721706f2543Smrg				unsigned		which,
722706f2543Smrg				XkbChangesPtr 		changes,
723706f2543Smrg				XkbEventCausePtr	cause)
724706f2543Smrg{
725706f2543Smrg    if (which&XkbStateNotifyMask) {
726706f2543Smrg	XkbStateRec old;
727706f2543Smrg	old= xkbi->state;
728706f2543Smrg	changes->state_changes|= XkbStateChangedFlags(&old,&xkbi->state);
729706f2543Smrg	XkbComputeDerivedState(xkbi);
730706f2543Smrg    }
731706f2543Smrg    if (which&XkbIndicatorStateNotifyMask)
732706f2543Smrg	XkbUpdateIndicators(xkbi->device,XkbAllIndicatorsMask,TRUE,changes,
733706f2543Smrg									cause);
734706f2543Smrg    return;
735706f2543Smrg}
736706f2543Smrg
737706f2543Smrg/***====================================================================***/
738706f2543Smrg
739706f2543SmrgBool
740706f2543SmrgXkbEnableDisableControls(	XkbSrvInfoPtr		xkbi,
741706f2543Smrg				unsigned long		change,
742706f2543Smrg				unsigned long		newValues,
743706f2543Smrg				XkbChangesPtr		changes,
744706f2543Smrg				XkbEventCausePtr	cause)
745706f2543Smrg{
746706f2543SmrgXkbControlsPtr		ctrls;
747706f2543Smrgunsigned 		old;
748706f2543SmrgXkbSrvLedInfoPtr	sli;
749706f2543Smrg
750706f2543Smrg    ctrls= xkbi->desc->ctrls;
751706f2543Smrg    old= ctrls->enabled_ctrls;
752706f2543Smrg    ctrls->enabled_ctrls&= ~change;
753706f2543Smrg    ctrls->enabled_ctrls|= (change&newValues);
754706f2543Smrg    if (old==ctrls->enabled_ctrls)
755706f2543Smrg	return FALSE;
756706f2543Smrg    if (cause!=NULL) {
757706f2543Smrg	xkbControlsNotify cn;
758706f2543Smrg	cn.numGroups= ctrls->num_groups;
759706f2543Smrg	cn.changedControls= XkbControlsEnabledMask;
760706f2543Smrg	cn.enabledControls= ctrls->enabled_ctrls;
761706f2543Smrg	cn.enabledControlChanges= (ctrls->enabled_ctrls^old);
762706f2543Smrg	cn.keycode= cause->kc;
763706f2543Smrg	cn.eventType= cause->event;
764706f2543Smrg	cn.requestMajor= cause->mjr;
765706f2543Smrg	cn.requestMinor= cause->mnr;
766706f2543Smrg	XkbSendControlsNotify(xkbi->device,&cn);
767706f2543Smrg    }
768706f2543Smrg    else {
769706f2543Smrg	/* Yes, this really should be an XOR.  If ctrls->enabled_ctrls_changes*/
770706f2543Smrg	/* is non-zero, the controls in question changed already in "this" */
771706f2543Smrg	/* request and this change merely undoes the previous one.  By the */
772706f2543Smrg	/* same token, we have to figure out whether or not ControlsEnabled */
773706f2543Smrg	/* should be set or not in the changes structure */
774706f2543Smrg	changes->ctrls.enabled_ctrls_changes^= (ctrls->enabled_ctrls^old);
775706f2543Smrg	if (changes->ctrls.enabled_ctrls_changes)
776706f2543Smrg	     changes->ctrls.changed_ctrls|= XkbControlsEnabledMask;
777706f2543Smrg	else changes->ctrls.changed_ctrls&= ~XkbControlsEnabledMask;
778706f2543Smrg    }
779706f2543Smrg    sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0);
780706f2543Smrg    XkbUpdateIndicators(xkbi->device,sli->usesControls,TRUE,changes,cause);
781706f2543Smrg    return TRUE;
782706f2543Smrg}
783706f2543Smrg
784706f2543Smrg/***====================================================================***/
785706f2543Smrg
786706f2543Smrg#define	MAX_TOC	16
787706f2543Smrg
788706f2543SmrgXkbGeometryPtr
789706f2543SmrgXkbLookupNamedGeometry(DeviceIntPtr dev,Atom name,Bool *shouldFree)
790706f2543Smrg{
791706f2543SmrgXkbSrvInfoPtr	xkbi=	dev->key->xkbInfo;
792706f2543SmrgXkbDescPtr	xkb=	xkbi->desc;
793706f2543Smrg
794706f2543Smrg    *shouldFree= 0;
795706f2543Smrg    if (name==None) {
796706f2543Smrg	if (xkb->geom!=NULL)
797706f2543Smrg	    return xkb->geom;
798706f2543Smrg	name= xkb->names->geometry;
799706f2543Smrg    }
800706f2543Smrg    if ((xkb->geom!=NULL)&&(xkb->geom->name==name))
801706f2543Smrg	return xkb->geom;
802706f2543Smrg    *shouldFree= 1;
803706f2543Smrg    return NULL;
804706f2543Smrg}
805706f2543Smrg
806706f2543Smrgvoid
807706f2543SmrgXkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper)
808706f2543Smrg{
809706f2543Smrg    *lower = sym;
810706f2543Smrg    *upper = sym;
811706f2543Smrg    switch(sym >> 8) {
812706f2543Smrg    case 0: /* Latin 1 */
813706f2543Smrg	if ((sym >= XK_A) && (sym <= XK_Z))
814706f2543Smrg	    *lower += (XK_a - XK_A);
815706f2543Smrg	else if ((sym >= XK_a) && (sym <= XK_z))
816706f2543Smrg	    *upper -= (XK_a - XK_A);
817706f2543Smrg	else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
818706f2543Smrg	    *lower += (XK_agrave - XK_Agrave);
819706f2543Smrg	else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
820706f2543Smrg	    *upper -= (XK_agrave - XK_Agrave);
821706f2543Smrg	else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
822706f2543Smrg	    *lower += (XK_oslash - XK_Ooblique);
823706f2543Smrg	else if ((sym >= XK_oslash) && (sym <= XK_thorn))
824706f2543Smrg	    *upper -= (XK_oslash - XK_Ooblique);
825706f2543Smrg	break;
826706f2543Smrg    case 1: /* Latin 2 */
827706f2543Smrg	/* Assume the KeySym is a legal value (ignore discontinuities) */
828706f2543Smrg	if (sym == XK_Aogonek)
829706f2543Smrg	    *lower = XK_aogonek;
830706f2543Smrg	else if (sym >= XK_Lstroke && sym <= XK_Sacute)
831706f2543Smrg	    *lower += (XK_lstroke - XK_Lstroke);
832706f2543Smrg	else if (sym >= XK_Scaron && sym <= XK_Zacute)
833706f2543Smrg	    *lower += (XK_scaron - XK_Scaron);
834706f2543Smrg	else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
835706f2543Smrg	    *lower += (XK_zcaron - XK_Zcaron);
836706f2543Smrg	else if (sym == XK_aogonek)
837706f2543Smrg	    *upper = XK_Aogonek;
838706f2543Smrg	else if (sym >= XK_lstroke && sym <= XK_sacute)
839706f2543Smrg	    *upper -= (XK_lstroke - XK_Lstroke);
840706f2543Smrg	else if (sym >= XK_scaron && sym <= XK_zacute)
841706f2543Smrg	    *upper -= (XK_scaron - XK_Scaron);
842706f2543Smrg	else if (sym >= XK_zcaron && sym <= XK_zabovedot)
843706f2543Smrg	    *upper -= (XK_zcaron - XK_Zcaron);
844706f2543Smrg	else if (sym >= XK_Racute && sym <= XK_Tcedilla)
845706f2543Smrg	    *lower += (XK_racute - XK_Racute);
846706f2543Smrg	else if (sym >= XK_racute && sym <= XK_tcedilla)
847706f2543Smrg	    *upper -= (XK_racute - XK_Racute);
848706f2543Smrg	break;
849706f2543Smrg    case 2: /* Latin 3 */
850706f2543Smrg	/* Assume the KeySym is a legal value (ignore discontinuities) */
851706f2543Smrg	if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
852706f2543Smrg	    *lower += (XK_hstroke - XK_Hstroke);
853706f2543Smrg	else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
854706f2543Smrg	    *lower += (XK_gbreve - XK_Gbreve);
855706f2543Smrg	else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
856706f2543Smrg	    *upper -= (XK_hstroke - XK_Hstroke);
857706f2543Smrg	else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
858706f2543Smrg	    *upper -= (XK_gbreve - XK_Gbreve);
859706f2543Smrg	else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
860706f2543Smrg	    *lower += (XK_cabovedot - XK_Cabovedot);
861706f2543Smrg	else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
862706f2543Smrg	    *upper -= (XK_cabovedot - XK_Cabovedot);
863706f2543Smrg	break;
864706f2543Smrg    case 3: /* Latin 4 */
865706f2543Smrg	/* Assume the KeySym is a legal value (ignore discontinuities) */
866706f2543Smrg	if (sym >= XK_Rcedilla && sym <= XK_Tslash)
867706f2543Smrg	    *lower += (XK_rcedilla - XK_Rcedilla);
868706f2543Smrg	else if (sym >= XK_rcedilla && sym <= XK_tslash)
869706f2543Smrg	    *upper -= (XK_rcedilla - XK_Rcedilla);
870706f2543Smrg	else if (sym == XK_ENG)
871706f2543Smrg	    *lower = XK_eng;
872706f2543Smrg	else if (sym == XK_eng)
873706f2543Smrg	    *upper = XK_ENG;
874706f2543Smrg	else if (sym >= XK_Amacron && sym <= XK_Umacron)
875706f2543Smrg	    *lower += (XK_amacron - XK_Amacron);
876706f2543Smrg	else if (sym >= XK_amacron && sym <= XK_umacron)
877706f2543Smrg	    *upper -= (XK_amacron - XK_Amacron);
878706f2543Smrg	break;
879706f2543Smrg    case 6: /* Cyrillic */
880706f2543Smrg	/* Assume the KeySym is a legal value (ignore discontinuities) */
881706f2543Smrg	if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
882706f2543Smrg	    *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
883706f2543Smrg	else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
884706f2543Smrg	    *upper += (XK_Serbian_DJE - XK_Serbian_dje);
885706f2543Smrg	else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
886706f2543Smrg	    *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
887706f2543Smrg	else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
888706f2543Smrg	    *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
889706f2543Smrg        break;
890706f2543Smrg    case 7: /* Greek */
891706f2543Smrg	/* Assume the KeySym is a legal value (ignore discontinuities) */
892706f2543Smrg	if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
893706f2543Smrg	    *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
894706f2543Smrg	else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
895706f2543Smrg		 sym != XK_Greek_iotaaccentdieresis &&
896706f2543Smrg		 sym != XK_Greek_upsilonaccentdieresis)
897706f2543Smrg	    *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
898706f2543Smrg	else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
899706f2543Smrg	    *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
900706f2543Smrg	else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
901706f2543Smrg		 sym != XK_Greek_finalsmallsigma)
902706f2543Smrg	    *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
903706f2543Smrg        break;
904706f2543Smrg    }
905706f2543Smrg}
906706f2543Smrg
907706f2543Smrgstatic Bool
908706f2543Smrg_XkbCopyClientMap(XkbDescPtr src, XkbDescPtr dst)
909706f2543Smrg{
910706f2543Smrg    void *tmp = NULL;
911706f2543Smrg    int i;
912706f2543Smrg    XkbKeyTypePtr stype = NULL, dtype = NULL;
913706f2543Smrg
914706f2543Smrg    /* client map */
915706f2543Smrg    if (src->map) {
916706f2543Smrg        if (!dst->map) {
917706f2543Smrg            tmp = calloc(1, sizeof(XkbClientMapRec));
918706f2543Smrg            if (!tmp)
919706f2543Smrg                return FALSE;
920706f2543Smrg            dst->map = tmp;
921706f2543Smrg        }
922706f2543Smrg
923706f2543Smrg        if (src->map->syms) {
924706f2543Smrg            if (src->map->size_syms != dst->map->size_syms) {
925706f2543Smrg                tmp = realloc(dst->map->syms,
926706f2543Smrg                              src->map->size_syms * sizeof(KeySym));
927706f2543Smrg                if (!tmp)
928706f2543Smrg                    return FALSE;
929706f2543Smrg                dst->map->syms = tmp;
930706f2543Smrg
931706f2543Smrg            }
932706f2543Smrg            memcpy(dst->map->syms, src->map->syms,
933706f2543Smrg                   src->map->size_syms * sizeof(KeySym));
934706f2543Smrg        }
935706f2543Smrg        else {
936706f2543Smrg            free(dst->map->syms);
937706f2543Smrg            dst->map->syms = NULL;
938706f2543Smrg        }
939706f2543Smrg        dst->map->num_syms = src->map->num_syms;
940706f2543Smrg        dst->map->size_syms = src->map->size_syms;
941706f2543Smrg
942706f2543Smrg        if (src->map->key_sym_map) {
943706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
944706f2543Smrg                tmp = realloc(dst->map->key_sym_map,
945706f2543Smrg                              (src->max_key_code + 1) * sizeof(XkbSymMapRec));
946706f2543Smrg                if (!tmp)
947706f2543Smrg                    return FALSE;
948706f2543Smrg                dst->map->key_sym_map = tmp;
949706f2543Smrg            }
950706f2543Smrg            memcpy(dst->map->key_sym_map, src->map->key_sym_map,
951706f2543Smrg                   (src->max_key_code + 1) * sizeof(XkbSymMapRec));
952706f2543Smrg        }
953706f2543Smrg        else {
954706f2543Smrg            free(dst->map->key_sym_map);
955706f2543Smrg            dst->map->key_sym_map = NULL;
956706f2543Smrg        }
957706f2543Smrg
958706f2543Smrg        if (src->map->types && src->map->num_types) {
959706f2543Smrg            if (src->map->num_types > dst->map->size_types ||
960706f2543Smrg                !dst->map->types || !dst->map->size_types) {
961706f2543Smrg                if (dst->map->types && dst->map->size_types) {
962706f2543Smrg                    tmp = realloc(dst->map->types,
963706f2543Smrg                                   src->map->num_types * sizeof(XkbKeyTypeRec));
964706f2543Smrg                    if (!tmp)
965706f2543Smrg                        return FALSE;
966706f2543Smrg                    dst->map->types = tmp;
967706f2543Smrg                    memset(dst->map->types + dst->map->num_types, 0,
968706f2543Smrg                          (src->map->num_types - dst->map->num_types) *
969706f2543Smrg                            sizeof(XkbKeyTypeRec));
970706f2543Smrg                }
971706f2543Smrg                else {
972706f2543Smrg                    tmp = calloc(src->map->num_types, sizeof(XkbKeyTypeRec));
973706f2543Smrg                    if (!tmp)
974706f2543Smrg                        return FALSE;
975706f2543Smrg                    dst->map->types = tmp;
976706f2543Smrg                }
977706f2543Smrg            }
978706f2543Smrg            else if (src->map->num_types < dst->map->num_types &&
979706f2543Smrg                     dst->map->types) {
980706f2543Smrg                for (i = src->map->num_types, dtype = (dst->map->types + i);
981706f2543Smrg                     i < dst->map->num_types; i++, dtype++) {
982706f2543Smrg                    free(dtype->level_names);
983706f2543Smrg                    dtype->level_names = NULL;
984706f2543Smrg                    dtype->num_levels = 0;
985706f2543Smrg                    if (dtype->map_count) {
986706f2543Smrg                        free(dtype->map);
987706f2543Smrg                        free(dtype->preserve);
988706f2543Smrg                    }
989706f2543Smrg                }
990706f2543Smrg            }
991706f2543Smrg
992706f2543Smrg            stype = src->map->types;
993706f2543Smrg            dtype = dst->map->types;
994706f2543Smrg            for (i = 0; i < src->map->num_types; i++, dtype++, stype++) {
995706f2543Smrg                if (stype->num_levels && stype->level_names) {
996706f2543Smrg                    if (stype->num_levels != dtype->num_levels &&
997706f2543Smrg                        dtype->num_levels && dtype->level_names &&
998706f2543Smrg                        i < dst->map->num_types) {
999706f2543Smrg                        tmp = realloc(dtype->level_names,
1000706f2543Smrg                                       stype->num_levels * sizeof(Atom));
1001706f2543Smrg                        if (!tmp)
1002706f2543Smrg                            continue;
1003706f2543Smrg                        dtype->level_names = tmp;
1004706f2543Smrg                    }
1005706f2543Smrg                    else if (!dtype->num_levels || !dtype->level_names ||
1006706f2543Smrg                             i >= dst->map->num_types) {
1007706f2543Smrg                        tmp = malloc(stype->num_levels * sizeof(Atom));
1008706f2543Smrg                        if (!tmp)
1009706f2543Smrg                            continue;
1010706f2543Smrg                        dtype->level_names = tmp;
1011706f2543Smrg                    }
1012706f2543Smrg                    dtype->num_levels = stype->num_levels;
1013706f2543Smrg                    memcpy(dtype->level_names, stype->level_names,
1014706f2543Smrg                           stype->num_levels * sizeof(Atom));
1015706f2543Smrg                }
1016706f2543Smrg                else {
1017706f2543Smrg                    if (dtype->num_levels && dtype->level_names &&
1018706f2543Smrg                        i < dst->map->num_types)
1019706f2543Smrg                        free(dtype->level_names);
1020706f2543Smrg                    dtype->num_levels = 0;
1021706f2543Smrg                    dtype->level_names = NULL;
1022706f2543Smrg                }
1023706f2543Smrg
1024706f2543Smrg                dtype->name = stype->name;
1025706f2543Smrg                memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec));
1026706f2543Smrg
1027706f2543Smrg                if (stype->map_count) {
1028706f2543Smrg                    if (stype->map) {
1029706f2543Smrg                        if (stype->map_count != dtype->map_count &&
1030706f2543Smrg                            dtype->map_count && dtype->map &&
1031706f2543Smrg                            i < dst->map->num_types) {
1032706f2543Smrg                            tmp = realloc(dtype->map,
1033706f2543Smrg                                           stype->map_count *
1034706f2543Smrg                                             sizeof(XkbKTMapEntryRec));
1035706f2543Smrg                            if (!tmp)
1036706f2543Smrg                                return FALSE;
1037706f2543Smrg                            dtype->map = tmp;
1038706f2543Smrg                        }
1039706f2543Smrg                        else if (!dtype->map_count || !dtype->map ||
1040706f2543Smrg                                 i >= dst->map->num_types) {
1041706f2543Smrg                            tmp = malloc(stype->map_count *
1042706f2543Smrg                                           sizeof(XkbKTMapEntryRec));
1043706f2543Smrg                            if (!tmp)
1044706f2543Smrg                                return FALSE;
1045706f2543Smrg                            dtype->map = tmp;
1046706f2543Smrg                        }
1047706f2543Smrg
1048706f2543Smrg                        memcpy(dtype->map, stype->map,
1049706f2543Smrg                               stype->map_count * sizeof(XkbKTMapEntryRec));
1050706f2543Smrg                    }
1051706f2543Smrg                    else {
1052706f2543Smrg                        if (dtype->map && i < dst->map->num_types)
1053706f2543Smrg                            free(dtype->map);
1054706f2543Smrg                        dtype->map = NULL;
1055706f2543Smrg                    }
1056706f2543Smrg
1057706f2543Smrg                    if (stype->preserve) {
1058706f2543Smrg                        if (stype->map_count != dtype->map_count &&
1059706f2543Smrg                            dtype->map_count && dtype->preserve &&
1060706f2543Smrg                            i < dst->map->num_types) {
1061706f2543Smrg                            tmp = realloc(dtype->preserve,
1062706f2543Smrg                                           stype->map_count *
1063706f2543Smrg                                             sizeof(XkbModsRec));
1064706f2543Smrg                            if (!tmp)
1065706f2543Smrg                                return FALSE;
1066706f2543Smrg                            dtype->preserve = tmp;
1067706f2543Smrg                        }
1068706f2543Smrg                        else if (!dtype->preserve || !dtype->map_count ||
1069706f2543Smrg                                 i >= dst->map->num_types) {
1070706f2543Smrg                            tmp = malloc(stype->map_count *
1071706f2543Smrg                                         sizeof(XkbModsRec));
1072706f2543Smrg                            if (!tmp)
1073706f2543Smrg                                return FALSE;
1074706f2543Smrg                            dtype->preserve = tmp;
1075706f2543Smrg                        }
1076706f2543Smrg
1077706f2543Smrg                        memcpy(dtype->preserve, stype->preserve,
1078706f2543Smrg                               stype->map_count * sizeof(XkbModsRec));
1079706f2543Smrg                    }
1080706f2543Smrg                    else {
1081706f2543Smrg                        if (dtype->preserve && i < dst->map->num_types)
1082706f2543Smrg                            free(dtype->preserve);
1083706f2543Smrg                        dtype->preserve = NULL;
1084706f2543Smrg                    }
1085706f2543Smrg
1086706f2543Smrg                    dtype->map_count = stype->map_count;
1087706f2543Smrg                }
1088706f2543Smrg                else {
1089706f2543Smrg                    if (dtype->map_count && i < dst->map->num_types) {
1090706f2543Smrg                        free(dtype->map);
1091706f2543Smrg                        free(dtype->preserve);
1092706f2543Smrg                    }
1093706f2543Smrg                    dtype->map_count = 0;
1094706f2543Smrg                    dtype->map = NULL;
1095706f2543Smrg                    dtype->preserve = NULL;
1096706f2543Smrg                }
1097706f2543Smrg            }
1098706f2543Smrg
1099706f2543Smrg            dst->map->size_types = src->map->num_types;
1100706f2543Smrg            dst->map->num_types = src->map->num_types;
1101706f2543Smrg        }
1102706f2543Smrg        else {
1103706f2543Smrg            if (dst->map->types) {
1104706f2543Smrg                for (i = 0, dtype = dst->map->types; i < dst->map->num_types;
1105706f2543Smrg                     i++, dtype++) {
1106706f2543Smrg                    free(dtype->level_names);
1107706f2543Smrg                    if (dtype->map && dtype->map_count)
1108706f2543Smrg                        free(dtype->map);
1109706f2543Smrg                    if (dtype->preserve && dtype->map_count)
1110706f2543Smrg                        free(dtype->preserve);
1111706f2543Smrg                }
1112706f2543Smrg            }
1113706f2543Smrg            free(dst->map->types);
1114706f2543Smrg            dst->map->types = NULL;
1115706f2543Smrg            dst->map->num_types = 0;
1116706f2543Smrg            dst->map->size_types = 0;
1117706f2543Smrg        }
1118706f2543Smrg
1119706f2543Smrg        if (src->map->modmap) {
1120706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
1121706f2543Smrg                tmp = realloc(dst->map->modmap, src->max_key_code + 1);
1122706f2543Smrg                if (!tmp)
1123706f2543Smrg                    return FALSE;
1124706f2543Smrg                dst->map->modmap = tmp;
1125706f2543Smrg            }
1126706f2543Smrg            memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1);
1127706f2543Smrg        }
1128706f2543Smrg        else {
1129706f2543Smrg            free(dst->map->modmap);
1130706f2543Smrg            dst->map->modmap = NULL;
1131706f2543Smrg        }
1132706f2543Smrg    }
1133706f2543Smrg    else {
1134706f2543Smrg        if (dst->map)
1135706f2543Smrg            XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE);
1136706f2543Smrg    }
1137706f2543Smrg
1138706f2543Smrg    return TRUE;
1139706f2543Smrg}
1140706f2543Smrg
1141706f2543Smrgstatic Bool
1142706f2543Smrg_XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst)
1143706f2543Smrg{
1144706f2543Smrg    void *tmp = NULL;
1145706f2543Smrg
1146706f2543Smrg    /* server map */
1147706f2543Smrg    if (src->server) {
1148706f2543Smrg        if (!dst->server) {
1149706f2543Smrg            tmp = calloc(1, sizeof(XkbServerMapRec));
1150706f2543Smrg            if (!tmp)
1151706f2543Smrg                return FALSE;
1152706f2543Smrg            dst->server = tmp;
1153706f2543Smrg        }
1154706f2543Smrg
1155706f2543Smrg        if (src->server->explicit) {
1156706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
1157706f2543Smrg                tmp = realloc(dst->server->explicit, src->max_key_code + 1);
1158706f2543Smrg                if (!tmp)
1159706f2543Smrg                    return FALSE;
1160706f2543Smrg                dst->server->explicit = tmp;
1161706f2543Smrg            }
1162706f2543Smrg            memcpy(dst->server->explicit, src->server->explicit,
1163706f2543Smrg                   src->max_key_code + 1);
1164706f2543Smrg        }
1165706f2543Smrg        else {
1166706f2543Smrg            free(dst->server->explicit);
1167706f2543Smrg            dst->server->explicit = NULL;
1168706f2543Smrg        }
1169706f2543Smrg
1170706f2543Smrg        if (src->server->acts) {
1171706f2543Smrg            if (src->server->size_acts != dst->server->size_acts) {
1172706f2543Smrg                tmp = realloc(dst->server->acts,
1173706f2543Smrg                              src->server->size_acts * sizeof(XkbAction));
1174706f2543Smrg                if (!tmp)
1175706f2543Smrg                    return FALSE;
1176706f2543Smrg                dst->server->acts = tmp;
1177706f2543Smrg            }
1178706f2543Smrg            memcpy(dst->server->acts, src->server->acts,
1179706f2543Smrg                   src->server->size_acts * sizeof(XkbAction));
1180706f2543Smrg        }
1181706f2543Smrg        else {
1182706f2543Smrg            free(dst->server->acts);
1183706f2543Smrg            dst->server->acts = NULL;
1184706f2543Smrg        }
1185706f2543Smrg       dst->server->size_acts = src->server->size_acts;
1186706f2543Smrg       dst->server->num_acts = src->server->num_acts;
1187706f2543Smrg
1188706f2543Smrg        if (src->server->key_acts) {
1189706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
1190706f2543Smrg                tmp = realloc(dst->server->key_acts,
1191706f2543Smrg                              (src->max_key_code + 1) * sizeof(unsigned short));
1192706f2543Smrg                if (!tmp)
1193706f2543Smrg                    return FALSE;
1194706f2543Smrg                dst->server->key_acts = tmp;
1195706f2543Smrg            }
1196706f2543Smrg            memcpy(dst->server->key_acts, src->server->key_acts,
1197706f2543Smrg                   (src->max_key_code + 1) * sizeof(unsigned short));
1198706f2543Smrg        }
1199706f2543Smrg        else {
1200706f2543Smrg            free(dst->server->key_acts);
1201706f2543Smrg            dst->server->key_acts = NULL;
1202706f2543Smrg        }
1203706f2543Smrg
1204706f2543Smrg        if (src->server->behaviors) {
1205706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
1206706f2543Smrg                tmp = realloc(dst->server->behaviors,
1207706f2543Smrg                              (src->max_key_code + 1) * sizeof(XkbBehavior));
1208706f2543Smrg                if (!tmp)
1209706f2543Smrg                    return FALSE;
1210706f2543Smrg                dst->server->behaviors = tmp;
1211706f2543Smrg            }
1212706f2543Smrg            memcpy(dst->server->behaviors, src->server->behaviors,
1213706f2543Smrg                   (src->max_key_code + 1) * sizeof(XkbBehavior));
1214706f2543Smrg        }
1215706f2543Smrg        else {
1216706f2543Smrg            free(dst->server->behaviors);
1217706f2543Smrg            dst->server->behaviors = NULL;
1218706f2543Smrg        }
1219706f2543Smrg
1220706f2543Smrg        memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods);
1221706f2543Smrg
1222706f2543Smrg        if (src->server->vmodmap) {
1223706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
1224706f2543Smrg                tmp = realloc(dst->server->vmodmap,
1225706f2543Smrg                              (src->max_key_code + 1) * sizeof(unsigned short));
1226706f2543Smrg                if (!tmp)
1227706f2543Smrg                    return FALSE;
1228706f2543Smrg                dst->server->vmodmap = tmp;
1229706f2543Smrg            }
1230706f2543Smrg            memcpy(dst->server->vmodmap, src->server->vmodmap,
1231706f2543Smrg                   (src->max_key_code + 1) * sizeof(unsigned short));
1232706f2543Smrg        }
1233706f2543Smrg        else {
1234706f2543Smrg            free(dst->server->vmodmap);
1235706f2543Smrg            dst->server->vmodmap = NULL;
1236706f2543Smrg        }
1237706f2543Smrg    }
1238706f2543Smrg    else {
1239706f2543Smrg        if (dst->server)
1240706f2543Smrg            XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE);
1241706f2543Smrg    }
1242706f2543Smrg
1243706f2543Smrg    return TRUE;
1244706f2543Smrg}
1245706f2543Smrg
1246706f2543Smrgstatic Bool
1247706f2543Smrg_XkbCopyNames(XkbDescPtr src, XkbDescPtr dst)
1248706f2543Smrg{
1249706f2543Smrg    void *tmp = NULL;
1250706f2543Smrg
1251706f2543Smrg    /* names */
1252706f2543Smrg    if (src->names) {
1253706f2543Smrg        if (!dst->names) {
1254706f2543Smrg            dst->names = calloc(1, sizeof(XkbNamesRec));
1255706f2543Smrg            if (!dst->names)
1256706f2543Smrg                return FALSE;
1257706f2543Smrg        }
1258706f2543Smrg
1259706f2543Smrg        if (src->names->keys) {
1260706f2543Smrg            if (src->max_key_code != dst->max_key_code) {
1261706f2543Smrg                tmp = realloc(dst->names->keys,
1262706f2543Smrg                              (src->max_key_code + 1) * sizeof(XkbKeyNameRec));
1263706f2543Smrg                if (!tmp)
1264706f2543Smrg                    return FALSE;
1265706f2543Smrg                dst->names->keys = tmp;
1266706f2543Smrg            }
1267706f2543Smrg            memcpy(dst->names->keys, src->names->keys,
1268706f2543Smrg                   (src->max_key_code + 1) * sizeof(XkbKeyNameRec));
1269706f2543Smrg        }
1270706f2543Smrg        else {
1271706f2543Smrg            free(dst->names->keys);
1272706f2543Smrg            dst->names->keys = NULL;
1273706f2543Smrg        }
1274706f2543Smrg
1275706f2543Smrg        if (src->names->num_key_aliases) {
1276706f2543Smrg            if (src->names->num_key_aliases != dst->names->num_key_aliases) {
1277706f2543Smrg                tmp = realloc(dst->names->key_aliases,
1278706f2543Smrg                              src->names->num_key_aliases *
1279706f2543Smrg                              sizeof(XkbKeyAliasRec));
1280706f2543Smrg                if (!tmp)
1281706f2543Smrg                    return FALSE;
1282706f2543Smrg                dst->names->key_aliases = tmp;
1283706f2543Smrg            }
1284706f2543Smrg            memcpy(dst->names->key_aliases, src->names->key_aliases,
1285706f2543Smrg                   src->names->num_key_aliases * sizeof(XkbKeyAliasRec));
1286706f2543Smrg        }
1287706f2543Smrg        else {
1288706f2543Smrg            free(dst->names->key_aliases);
1289706f2543Smrg            dst->names->key_aliases = NULL;
1290706f2543Smrg        }
1291706f2543Smrg        dst->names->num_key_aliases = src->names->num_key_aliases;
1292706f2543Smrg
1293706f2543Smrg        if (src->names->num_rg) {
1294706f2543Smrg            if (src->names->num_rg != dst->names->num_rg) {
1295706f2543Smrg                tmp = realloc(dst->names->radio_groups,
1296706f2543Smrg                              src->names->num_rg * sizeof(Atom));
1297706f2543Smrg                if (!tmp)
1298706f2543Smrg                    return FALSE;
1299706f2543Smrg                dst->names->radio_groups = tmp;
1300706f2543Smrg            }
1301706f2543Smrg            memcpy(dst->names->radio_groups, src->names->radio_groups,
1302706f2543Smrg                   src->names->num_rg * sizeof(Atom));
1303706f2543Smrg        }
1304706f2543Smrg        else {
1305706f2543Smrg            free(dst->names->radio_groups);
1306706f2543Smrg        }
1307706f2543Smrg        dst->names->num_rg = src->names->num_rg;
1308706f2543Smrg
1309706f2543Smrg        dst->names->keycodes = src->names->keycodes;
1310706f2543Smrg        dst->names->geometry = src->names->geometry;
1311706f2543Smrg        dst->names->symbols = src->names->symbols;
1312706f2543Smrg        dst->names->types = src->names->types;
1313706f2543Smrg        dst->names->compat = src->names->compat;
1314706f2543Smrg        dst->names->phys_symbols = src->names->phys_symbols;
1315706f2543Smrg
1316706f2543Smrg        memcpy(dst->names->vmods, src->names->vmods,
1317706f2543Smrg               XkbNumVirtualMods * sizeof(Atom));
1318706f2543Smrg        memcpy(dst->names->indicators, src->names->indicators,
1319706f2543Smrg               XkbNumIndicators * sizeof(Atom));
1320706f2543Smrg        memcpy(dst->names->groups, src->names->groups,
1321706f2543Smrg               XkbNumKbdGroups * sizeof(Atom));
1322706f2543Smrg    }
1323706f2543Smrg    else {
1324706f2543Smrg        if (dst->names)
1325706f2543Smrg            XkbFreeNames(dst, XkbAllNamesMask, TRUE);
1326706f2543Smrg    }
1327706f2543Smrg
1328706f2543Smrg    return TRUE;
1329706f2543Smrg}
1330706f2543Smrg
1331706f2543Smrgstatic Bool
1332706f2543Smrg_XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst)
1333706f2543Smrg{
1334706f2543Smrg    void *tmp = NULL;
1335706f2543Smrg
1336706f2543Smrg    /* compat */
1337706f2543Smrg    if (src->compat) {
1338706f2543Smrg        if (!dst->compat) {
1339706f2543Smrg            dst->compat = calloc(1, sizeof(XkbCompatMapRec));
1340706f2543Smrg            if (!dst->compat)
1341706f2543Smrg                return FALSE;
1342706f2543Smrg        }
1343706f2543Smrg
1344706f2543Smrg        if (src->compat->sym_interpret && src->compat->num_si) {
1345706f2543Smrg            if (src->compat->num_si != dst->compat->size_si) {
1346706f2543Smrg                tmp = realloc(dst->compat->sym_interpret,
1347706f2543Smrg                              src->compat->num_si * sizeof(XkbSymInterpretRec));
1348706f2543Smrg                if (!tmp)
1349706f2543Smrg                    return FALSE;
1350706f2543Smrg                dst->compat->sym_interpret = tmp;
1351706f2543Smrg            }
1352706f2543Smrg            memcpy(dst->compat->sym_interpret, src->compat->sym_interpret,
1353706f2543Smrg                   src->compat->num_si * sizeof(XkbSymInterpretRec));
1354706f2543Smrg
1355706f2543Smrg            dst->compat->num_si = src->compat->num_si;
1356706f2543Smrg            dst->compat->size_si = src->compat->num_si;
1357706f2543Smrg        }
1358706f2543Smrg        else {
1359706f2543Smrg            if (dst->compat->sym_interpret && dst->compat->size_si)
1360706f2543Smrg                free(dst->compat->sym_interpret);
1361706f2543Smrg
1362706f2543Smrg            dst->compat->sym_interpret = NULL;
1363706f2543Smrg            dst->compat->num_si = 0;
1364706f2543Smrg            dst->compat->size_si = 0;
1365706f2543Smrg        }
1366706f2543Smrg
1367706f2543Smrg        memcpy(dst->compat->groups, src->compat->groups,
1368706f2543Smrg               XkbNumKbdGroups * sizeof(XkbModsRec));
1369706f2543Smrg    }
1370706f2543Smrg    else {
1371706f2543Smrg        if (dst->compat)
1372706f2543Smrg            XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE);
1373706f2543Smrg    }
1374706f2543Smrg
1375706f2543Smrg    return TRUE;
1376706f2543Smrg}
1377706f2543Smrg
1378706f2543Smrgstatic Bool
1379706f2543Smrg_XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst)
1380706f2543Smrg{
1381706f2543Smrg    void *tmp = NULL;
1382706f2543Smrg    int i = 0, j = 0, k = 0;
1383706f2543Smrg    XkbColorPtr scolor = NULL, dcolor = NULL;
1384706f2543Smrg    XkbDoodadPtr sdoodad = NULL, ddoodad = NULL;
1385706f2543Smrg    XkbOutlinePtr soutline = NULL, doutline = NULL;
1386706f2543Smrg    XkbPropertyPtr sprop = NULL, dprop = NULL;
1387706f2543Smrg    XkbRowPtr srow = NULL, drow = NULL;
1388706f2543Smrg    XkbSectionPtr ssection = NULL, dsection = NULL;
1389706f2543Smrg    XkbShapePtr sshape = NULL, dshape = NULL;
1390706f2543Smrg
1391706f2543Smrg    /* geometry */
1392706f2543Smrg    if (src->geom) {
1393706f2543Smrg        if (!dst->geom) {
1394706f2543Smrg            dst->geom = calloc(sizeof(XkbGeometryRec), 1);
1395706f2543Smrg            if (!dst->geom)
1396706f2543Smrg                return FALSE;
1397706f2543Smrg        }
1398706f2543Smrg
1399706f2543Smrg        /* properties */
1400706f2543Smrg        if (src->geom->num_properties) {
1401706f2543Smrg            if (src->geom->num_properties != dst->geom->sz_properties) {
1402706f2543Smrg                /* If we've got more properties in the destination than
1403706f2543Smrg                 * the source, run through and free all the excess ones
1404706f2543Smrg                 * first. */
1405706f2543Smrg                if (src->geom->num_properties < dst->geom->sz_properties) {
1406706f2543Smrg                    for (i = src->geom->num_properties,
1407706f2543Smrg                         dprop = dst->geom->properties + i;
1408706f2543Smrg                         i < dst->geom->num_properties;
1409706f2543Smrg                         i++, dprop++) {
1410706f2543Smrg                        free(dprop->name);
1411706f2543Smrg                        free(dprop->value);
1412706f2543Smrg                    }
1413706f2543Smrg                }
1414706f2543Smrg
1415706f2543Smrg                if (dst->geom->sz_properties)
1416706f2543Smrg                    tmp = realloc(dst->geom->properties,
1417706f2543Smrg                                   src->geom->num_properties *
1418706f2543Smrg                                    sizeof(XkbPropertyRec));
1419706f2543Smrg                else
1420706f2543Smrg                    tmp = malloc(src->geom->num_properties *
1421706f2543Smrg                                  sizeof(XkbPropertyRec));
1422706f2543Smrg                if (!tmp)
1423706f2543Smrg                    return FALSE;
1424706f2543Smrg                dst->geom->properties = tmp;
1425706f2543Smrg            }
1426706f2543Smrg
1427706f2543Smrg            /* We don't set num_properties as we need it to try and avoid
1428706f2543Smrg             * too much reallocing. */
1429706f2543Smrg            dst->geom->sz_properties = src->geom->num_properties;
1430706f2543Smrg
1431706f2543Smrg            if (dst->geom->sz_properties > dst->geom->num_properties) {
1432706f2543Smrg                memset(dst->geom->properties + dst->geom->num_properties, 0,
1433706f2543Smrg                      (dst->geom->sz_properties - dst->geom->num_properties) *
1434706f2543Smrg                      sizeof(XkbPropertyRec));
1435706f2543Smrg            }
1436706f2543Smrg
1437706f2543Smrg            for (i = 0,
1438706f2543Smrg                  sprop = src->geom->properties,
1439706f2543Smrg                  dprop = dst->geom->properties;
1440706f2543Smrg                 i < src->geom->num_properties;
1441706f2543Smrg                 i++, sprop++, dprop++) {
1442706f2543Smrg                if (i < dst->geom->num_properties) {
1443706f2543Smrg                    if (strlen(sprop->name) != strlen(dprop->name)) {
1444706f2543Smrg                        tmp = realloc(dprop->name, strlen(sprop->name) + 1);
1445706f2543Smrg                        if (!tmp)
1446706f2543Smrg                            return FALSE;
1447706f2543Smrg                        dprop->name = tmp;
1448706f2543Smrg                    }
1449706f2543Smrg                    if (strlen(sprop->value) != strlen(dprop->value)) {
1450706f2543Smrg                        tmp = realloc(dprop->value, strlen(sprop->value) + 1);
1451706f2543Smrg                        if (!tmp)
1452706f2543Smrg                            return FALSE;
1453706f2543Smrg                        dprop->value = tmp;
1454706f2543Smrg                    }
1455706f2543Smrg                    strcpy(dprop->name, sprop->name);
1456706f2543Smrg                    strcpy(dprop->value, sprop->value);
1457706f2543Smrg                }
1458706f2543Smrg                else {
1459706f2543Smrg                    dprop->name = xstrdup(sprop->name);
1460706f2543Smrg                    dprop->value = xstrdup(sprop->value);
1461706f2543Smrg                }
1462706f2543Smrg            }
1463706f2543Smrg
1464706f2543Smrg            /* ... which is already src->geom->num_properties. */
1465706f2543Smrg            dst->geom->num_properties = dst->geom->sz_properties;
1466706f2543Smrg        }
1467706f2543Smrg        else {
1468706f2543Smrg            if (dst->geom->sz_properties) {
1469706f2543Smrg                for (i = 0, dprop = dst->geom->properties;
1470706f2543Smrg                     i < dst->geom->num_properties;
1471706f2543Smrg                     i++, dprop++) {
1472706f2543Smrg                    free(dprop->name);
1473706f2543Smrg                    free(dprop->value);
1474706f2543Smrg                }
1475706f2543Smrg                free(dst->geom->properties);
1476706f2543Smrg                dst->geom->properties = NULL;
1477706f2543Smrg            }
1478706f2543Smrg
1479706f2543Smrg            dst->geom->num_properties = 0;
1480706f2543Smrg            dst->geom->sz_properties = 0;
1481706f2543Smrg        }
1482706f2543Smrg
1483706f2543Smrg        /* colors */
1484706f2543Smrg        if (src->geom->num_colors) {
1485706f2543Smrg            if (src->geom->num_colors != dst->geom->sz_colors) {
1486706f2543Smrg                if (src->geom->num_colors < dst->geom->sz_colors) {
1487706f2543Smrg                    for (i = src->geom->num_colors,
1488706f2543Smrg                         dcolor = dst->geom->colors + i;
1489706f2543Smrg                         i < dst->geom->num_colors;
1490706f2543Smrg                         i++, dcolor++) {
1491706f2543Smrg                        free(dcolor->spec);
1492706f2543Smrg                    }
1493706f2543Smrg                }
1494706f2543Smrg
1495706f2543Smrg                if (dst->geom->sz_colors)
1496706f2543Smrg                    tmp = realloc(dst->geom->colors,
1497706f2543Smrg                                   src->geom->num_colors *
1498706f2543Smrg                                    sizeof(XkbColorRec));
1499706f2543Smrg                else
1500706f2543Smrg                    tmp = malloc(src->geom->num_colors *
1501706f2543Smrg                                  sizeof(XkbColorRec));
1502706f2543Smrg                if (!tmp)
1503706f2543Smrg                    return FALSE;
1504706f2543Smrg                dst->geom->colors = tmp;
1505706f2543Smrg            }
1506706f2543Smrg
1507706f2543Smrg            dst->geom->sz_colors = src->geom->num_colors;
1508706f2543Smrg
1509706f2543Smrg            if (dst->geom->sz_colors > dst->geom->num_colors) {
1510706f2543Smrg                memset(dst->geom->colors + dst->geom->num_colors, 0,
1511706f2543Smrg                      (dst->geom->sz_colors - dst->geom->num_colors) *
1512706f2543Smrg                      sizeof(XkbColorRec));
1513706f2543Smrg            }
1514706f2543Smrg
1515706f2543Smrg            for (i = 0,
1516706f2543Smrg                  scolor = src->geom->colors,
1517706f2543Smrg                  dcolor = dst->geom->colors;
1518706f2543Smrg                 i < src->geom->num_colors;
1519706f2543Smrg                 i++, scolor++, dcolor++) {
1520706f2543Smrg                if (i < dst->geom->num_colors) {
1521706f2543Smrg                    if (strlen(scolor->spec) != strlen(dcolor->spec)) {
1522706f2543Smrg                        tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1);
1523706f2543Smrg                        if (!tmp)
1524706f2543Smrg                            return FALSE;
1525706f2543Smrg                        dcolor->spec = tmp;
1526706f2543Smrg                    }
1527706f2543Smrg                    strcpy(dcolor->spec, scolor->spec);
1528706f2543Smrg                }
1529706f2543Smrg                else {
1530706f2543Smrg                    dcolor->spec = xstrdup(scolor->spec);
1531706f2543Smrg                }
1532706f2543Smrg                dcolor->pixel = scolor->pixel;
1533706f2543Smrg            }
1534706f2543Smrg
1535706f2543Smrg            dst->geom->num_colors = dst->geom->sz_colors;
1536706f2543Smrg        }
1537706f2543Smrg        else {
1538706f2543Smrg            if (dst->geom->sz_colors) {
1539706f2543Smrg                for (i = 0, dcolor = dst->geom->colors;
1540706f2543Smrg                     i < dst->geom->num_colors;
1541706f2543Smrg                     i++, dcolor++) {
1542706f2543Smrg                    free(dcolor->spec);
1543706f2543Smrg                }
1544706f2543Smrg                free(dst->geom->colors);
1545706f2543Smrg                dst->geom->colors = NULL;
1546706f2543Smrg            }
1547706f2543Smrg
1548706f2543Smrg            dst->geom->num_colors = 0;
1549706f2543Smrg            dst->geom->sz_colors = 0;
1550706f2543Smrg        }
1551706f2543Smrg
1552706f2543Smrg        /* shapes */
1553706f2543Smrg        /* shapes break down into outlines, which break down into points. */
1554706f2543Smrg        if (dst->geom->num_shapes) {
1555706f2543Smrg            for (i = 0, dshape = dst->geom->shapes;
1556706f2543Smrg                 i < dst->geom->num_shapes;
1557706f2543Smrg                 i++, dshape++) {
1558706f2543Smrg                for (j = 0, doutline = dshape->outlines;
1559706f2543Smrg                     j < dshape->num_outlines;
1560706f2543Smrg                     j++, doutline++) {
1561706f2543Smrg                    if (doutline->sz_points)
1562706f2543Smrg                        free(doutline->points);
1563706f2543Smrg                }
1564706f2543Smrg
1565706f2543Smrg                if (dshape->sz_outlines) {
1566706f2543Smrg                    free(dshape->outlines);
1567706f2543Smrg                    dshape->outlines = NULL;
1568706f2543Smrg                }
1569706f2543Smrg
1570706f2543Smrg                dshape->num_outlines = 0;
1571706f2543Smrg                dshape->sz_outlines = 0;
1572706f2543Smrg            }
1573706f2543Smrg        }
1574706f2543Smrg
1575706f2543Smrg        if (src->geom->num_shapes) {
1576706f2543Smrg            tmp = calloc(src->geom->num_shapes, sizeof(XkbShapeRec));
1577706f2543Smrg            if (!tmp)
1578706f2543Smrg                return FALSE;
1579706f2543Smrg            dst->geom->shapes = tmp;
1580706f2543Smrg
1581706f2543Smrg            for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes;
1582706f2543Smrg                 i < src->geom->num_shapes;
1583706f2543Smrg                 i++, sshape++, dshape++) {
1584706f2543Smrg                if (sshape->num_outlines) {
1585706f2543Smrg                    tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec));
1586706f2543Smrg                    if (!tmp)
1587706f2543Smrg                        return FALSE;
1588706f2543Smrg                    dshape->outlines = tmp;
1589706f2543Smrg
1590706f2543Smrg                    for (j = 0,
1591706f2543Smrg                          soutline = sshape->outlines,
1592706f2543Smrg                          doutline = dshape->outlines;
1593706f2543Smrg                         j < sshape->num_outlines;
1594706f2543Smrg                         j++, soutline++, doutline++) {
1595706f2543Smrg                        if (soutline->num_points) {
1596706f2543Smrg                            tmp = malloc(soutline->num_points *
1597706f2543Smrg                                          sizeof(XkbPointRec));
1598706f2543Smrg                            if (!tmp)
1599706f2543Smrg                                return FALSE;
1600706f2543Smrg                            doutline->points = tmp;
1601706f2543Smrg
1602706f2543Smrg                            memcpy(doutline->points, soutline->points,
1603706f2543Smrg                                   soutline->num_points * sizeof(XkbPointRec));
1604706f2543Smrg
1605706f2543Smrg                            doutline->corner_radius = soutline->corner_radius;
1606706f2543Smrg                        }
1607706f2543Smrg
1608706f2543Smrg                        doutline->num_points = soutline->num_points;
1609706f2543Smrg                        doutline->sz_points = soutline->num_points;
1610706f2543Smrg                    }
1611706f2543Smrg                }
1612706f2543Smrg
1613706f2543Smrg                dshape->num_outlines = sshape->num_outlines;
1614706f2543Smrg                dshape->sz_outlines = sshape->num_outlines;
1615706f2543Smrg                dshape->name = sshape->name;
1616706f2543Smrg                dshape->bounds = sshape->bounds;
1617706f2543Smrg
1618706f2543Smrg                dshape->approx = NULL;
1619706f2543Smrg                if (sshape->approx && sshape->num_outlines > 0) {
1620706f2543Smrg
1621706f2543Smrg                    const ptrdiff_t approx_idx =
1622706f2543Smrg                            sshape->approx - sshape->outlines;
1623706f2543Smrg
1624706f2543Smrg                    if (approx_idx < dshape->num_outlines) {
1625706f2543Smrg                            dshape->approx = dshape->outlines + approx_idx;
1626706f2543Smrg                    } else {
1627706f2543Smrg                            LogMessage(X_WARNING, "XKB: approx outline "
1628706f2543Smrg                                            "index is out of range\n");
1629706f2543Smrg                    }
1630706f2543Smrg                }
1631706f2543Smrg
1632706f2543Smrg                dshape->primary = NULL;
1633706f2543Smrg                if (sshape->primary && sshape->num_outlines > 0) {
1634706f2543Smrg
1635706f2543Smrg                    const ptrdiff_t primary_idx =
1636706f2543Smrg                            sshape->primary - sshape->outlines;
1637706f2543Smrg
1638706f2543Smrg                    if (primary_idx < dshape->num_outlines) {
1639706f2543Smrg                            dshape->primary = dshape->outlines + primary_idx;
1640706f2543Smrg                    } else {
1641706f2543Smrg                            LogMessage(X_WARNING, "XKB: primary outline "
1642706f2543Smrg                                            "index is out of range\n");
1643706f2543Smrg                    }
1644706f2543Smrg                }
1645706f2543Smrg            }
1646706f2543Smrg
1647706f2543Smrg            dst->geom->num_shapes = src->geom->num_shapes;
1648706f2543Smrg            dst->geom->sz_shapes = src->geom->num_shapes;
1649706f2543Smrg        }
1650706f2543Smrg        else {
1651706f2543Smrg            if (dst->geom->sz_shapes) {
1652706f2543Smrg                free(dst->geom->shapes);
1653706f2543Smrg            }
1654706f2543Smrg            dst->geom->shapes = NULL;
1655706f2543Smrg            dst->geom->num_shapes = 0;
1656706f2543Smrg            dst->geom->sz_shapes = 0;
1657706f2543Smrg        }
1658706f2543Smrg
1659706f2543Smrg        /* sections */
1660706f2543Smrg        /* sections break down into doodads, and also into rows, which break
1661706f2543Smrg         * down into keys. */
1662706f2543Smrg        if (dst->geom->num_sections) {
1663706f2543Smrg            for (i = 0, dsection = dst->geom->sections;
1664706f2543Smrg                 i < dst->geom->num_sections;
1665706f2543Smrg                 i++, dsection++) {
1666706f2543Smrg                for (j = 0, drow = dsection->rows;
1667706f2543Smrg                     j < dsection->num_rows;
1668706f2543Smrg                     j++, drow++) {
1669706f2543Smrg                    if (drow->num_keys)
1670706f2543Smrg                        free(drow->keys);
1671706f2543Smrg                }
1672706f2543Smrg
1673706f2543Smrg                if (dsection->num_rows)
1674706f2543Smrg                    free(dsection->rows);
1675706f2543Smrg
1676706f2543Smrg                /* cut and waste from geom/doodad below. */
1677706f2543Smrg                for (j = 0, ddoodad = dsection->doodads;
1678706f2543Smrg                     j < dsection->num_doodads;
1679706f2543Smrg                     j++, ddoodad++) {
1680706f2543Smrg                    if (ddoodad->any.type == XkbTextDoodad) {
1681706f2543Smrg                        free(ddoodad->text.text);
1682706f2543Smrg                        ddoodad->text.text = NULL;
1683706f2543Smrg                        free(ddoodad->text.font);
1684706f2543Smrg                        ddoodad->text.font = NULL;
1685706f2543Smrg                     }
1686706f2543Smrg                     else if (ddoodad->any.type == XkbLogoDoodad) {
1687706f2543Smrg                         free(ddoodad->logo.logo_name);
1688706f2543Smrg                         ddoodad->logo.logo_name = NULL;
1689706f2543Smrg                    }
1690706f2543Smrg                }
1691706f2543Smrg
1692706f2543Smrg                free(dsection->doodads);
1693706f2543Smrg            }
1694706f2543Smrg
1695706f2543Smrg            dst->geom->num_sections = 0;
1696706f2543Smrg            dst->geom->sections = NULL;
1697706f2543Smrg        }
1698706f2543Smrg
1699706f2543Smrg        if (src->geom->num_sections) {
1700706f2543Smrg            if (dst->geom->sz_sections)
1701706f2543Smrg                tmp = realloc(dst->geom->sections,
1702706f2543Smrg                               src->geom->num_sections *
1703706f2543Smrg                                sizeof(XkbSectionRec));
1704706f2543Smrg            else
1705706f2543Smrg                tmp = malloc(src->geom->num_sections * sizeof(XkbSectionRec));
1706706f2543Smrg            if (!tmp)
1707706f2543Smrg                return FALSE;
1708706f2543Smrg            memset(tmp, 0, src->geom->num_sections * sizeof(XkbSectionRec));
1709706f2543Smrg            dst->geom->sections = tmp;
1710706f2543Smrg            dst->geom->num_sections = src->geom->num_sections;
1711706f2543Smrg            dst->geom->sz_sections = src->geom->num_sections;
1712706f2543Smrg
1713706f2543Smrg            for (i = 0,
1714706f2543Smrg                  ssection = src->geom->sections,
1715706f2543Smrg                  dsection = dst->geom->sections;
1716706f2543Smrg                 i < src->geom->num_sections;
1717706f2543Smrg                 i++, ssection++, dsection++) {
1718706f2543Smrg                *dsection = *ssection;
1719706f2543Smrg                if (ssection->num_rows) {
1720706f2543Smrg                    tmp = calloc(ssection->num_rows, sizeof(XkbRowRec));
1721706f2543Smrg                    if (!tmp)
1722706f2543Smrg                        return FALSE;
1723706f2543Smrg                    dsection->rows = tmp;
1724706f2543Smrg                }
1725706f2543Smrg                dsection->num_rows = ssection->num_rows;
1726706f2543Smrg                dsection->sz_rows = ssection->num_rows;
1727706f2543Smrg
1728706f2543Smrg                for (j = 0, srow = ssection->rows, drow = dsection->rows;
1729706f2543Smrg                     j < ssection->num_rows;
1730706f2543Smrg                     j++, srow++, drow++) {
1731706f2543Smrg                    if (srow->num_keys) {
1732706f2543Smrg                        tmp = malloc(srow->num_keys * sizeof(XkbKeyRec));
1733706f2543Smrg                        if (!tmp)
1734706f2543Smrg                            return FALSE;
1735706f2543Smrg                        drow->keys = tmp;
1736706f2543Smrg                        memcpy(drow->keys, srow->keys,
1737706f2543Smrg                               srow->num_keys * sizeof(XkbKeyRec));
1738706f2543Smrg                    }
1739706f2543Smrg                    drow->num_keys = srow->num_keys;
1740706f2543Smrg                    drow->sz_keys = srow->num_keys;
1741706f2543Smrg                    drow->top = srow->top;
1742706f2543Smrg                    drow->left = srow->left;
1743706f2543Smrg                    drow->vertical = srow->vertical;
1744706f2543Smrg                    drow->bounds = srow->bounds;
1745706f2543Smrg                }
1746706f2543Smrg
1747706f2543Smrg                if (ssection->num_doodads) {
1748706f2543Smrg                    tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec));
1749706f2543Smrg                    if (!tmp)
1750706f2543Smrg                        return FALSE;
1751706f2543Smrg                    dsection->doodads = tmp;
1752706f2543Smrg                }
1753706f2543Smrg                else {
1754706f2543Smrg                    dsection->doodads = NULL;
1755706f2543Smrg                }
1756706f2543Smrg
1757706f2543Smrg                dsection->sz_doodads = ssection->num_doodads;
1758706f2543Smrg                for (k = 0,
1759706f2543Smrg                      sdoodad = ssection->doodads,
1760706f2543Smrg                      ddoodad = dsection->doodads;
1761706f2543Smrg                     k < ssection->num_doodads;
1762706f2543Smrg                     k++, sdoodad++, ddoodad++) {
1763706f2543Smrg                    memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec));
1764706f2543Smrg                    if (sdoodad->any.type == XkbTextDoodad) {
1765706f2543Smrg                        if (sdoodad->text.text)
1766706f2543Smrg                            ddoodad->text.text =
1767706f2543Smrg                             strdup(sdoodad->text.text);
1768706f2543Smrg                        if (sdoodad->text.font)
1769706f2543Smrg                            ddoodad->text.font =
1770706f2543Smrg                             strdup(sdoodad->text.font);
1771706f2543Smrg                    }
1772706f2543Smrg                    else if (sdoodad->any.type == XkbLogoDoodad) {
1773706f2543Smrg                        if (sdoodad->logo.logo_name)
1774706f2543Smrg                            ddoodad->logo.logo_name =
1775706f2543Smrg                             strdup(sdoodad->logo.logo_name);
1776706f2543Smrg                    }
1777706f2543Smrg                }
1778706f2543Smrg                dsection->overlays = NULL;
1779706f2543Smrg                dsection->sz_overlays = 0;
1780706f2543Smrg                dsection->num_overlays = 0;
1781706f2543Smrg            }
1782706f2543Smrg        }
1783706f2543Smrg        else {
1784706f2543Smrg            if (dst->geom->sz_sections) {
1785706f2543Smrg                free(dst->geom->sections);
1786706f2543Smrg            }
1787706f2543Smrg
1788706f2543Smrg            dst->geom->sections = NULL;
1789706f2543Smrg            dst->geom->num_sections = 0;
1790706f2543Smrg            dst->geom->sz_sections = 0;
1791706f2543Smrg        }
1792706f2543Smrg
1793706f2543Smrg        /* doodads */
1794706f2543Smrg        if (dst->geom->num_doodads) {
1795706f2543Smrg            for (i = src->geom->num_doodads,
1796706f2543Smrg                  ddoodad = dst->geom->doodads +
1797706f2543Smrg                             src->geom->num_doodads;
1798706f2543Smrg                 i < dst->geom->num_doodads;
1799706f2543Smrg                 i++, ddoodad++) {
1800706f2543Smrg                 if (ddoodad->any.type == XkbTextDoodad) {
1801706f2543Smrg                     free(ddoodad->text.text);
1802706f2543Smrg                     ddoodad->text.text = NULL;
1803706f2543Smrg                     free(ddoodad->text.font);
1804706f2543Smrg                     ddoodad->text.font = NULL;
1805706f2543Smrg                 }
1806706f2543Smrg                 else if (ddoodad->any.type == XkbLogoDoodad) {
1807706f2543Smrg                     free(ddoodad->logo.logo_name);
1808706f2543Smrg                     ddoodad->logo.logo_name = NULL;
1809706f2543Smrg                }
1810706f2543Smrg            }
1811706f2543Smrg            dst->geom->num_doodads = 0;
1812706f2543Smrg            dst->geom->doodads = NULL;
1813706f2543Smrg        }
1814706f2543Smrg
1815706f2543Smrg        if (src->geom->num_doodads) {
1816706f2543Smrg            if (dst->geom->sz_doodads)
1817706f2543Smrg                tmp = realloc(dst->geom->doodads,
1818706f2543Smrg                               src->geom->num_doodads *
1819706f2543Smrg                                sizeof(XkbDoodadRec));
1820706f2543Smrg            else
1821706f2543Smrg                tmp = malloc(src->geom->num_doodads *
1822706f2543Smrg                              sizeof(XkbDoodadRec));
1823706f2543Smrg            if (!tmp)
1824706f2543Smrg                return FALSE;
1825706f2543Smrg            memset(tmp, 0, src->geom->num_doodads * sizeof(XkbDoodadRec));
1826706f2543Smrg            dst->geom->doodads = tmp;
1827706f2543Smrg
1828706f2543Smrg            dst->geom->sz_doodads = src->geom->num_doodads;
1829706f2543Smrg
1830706f2543Smrg            for (i = 0,
1831706f2543Smrg                  sdoodad = src->geom->doodads,
1832706f2543Smrg                  ddoodad = dst->geom->doodads;
1833706f2543Smrg                 i < src->geom->num_doodads;
1834706f2543Smrg                 i++, sdoodad++, ddoodad++) {
1835706f2543Smrg                memcpy(ddoodad , sdoodad, sizeof(XkbDoodadRec));
1836706f2543Smrg                if (sdoodad->any.type == XkbTextDoodad) {
1837706f2543Smrg                    if (sdoodad->text.text)
1838706f2543Smrg                        ddoodad->text.text = strdup(sdoodad->text.text);
1839706f2543Smrg                    if (sdoodad->text.font)
1840706f2543Smrg                        ddoodad->text.font = strdup(sdoodad->text.font);
1841706f2543Smrg                }
1842706f2543Smrg                else if (sdoodad->any.type == XkbLogoDoodad) {
1843706f2543Smrg                    if (sdoodad->logo.logo_name)
1844706f2543Smrg                        ddoodad->logo.logo_name =
1845706f2543Smrg                          strdup(sdoodad->logo.logo_name);
1846706f2543Smrg                }
1847706f2543Smrg            }
1848706f2543Smrg
1849706f2543Smrg            dst->geom->num_doodads = dst->geom->sz_doodads;
1850706f2543Smrg        }
1851706f2543Smrg        else {
1852706f2543Smrg            if (dst->geom->sz_doodads) {
1853706f2543Smrg                free(dst->geom->doodads);
1854706f2543Smrg            }
1855706f2543Smrg
1856706f2543Smrg            dst->geom->doodads = NULL;
1857706f2543Smrg            dst->geom->num_doodads = 0;
1858706f2543Smrg            dst->geom->sz_doodads = 0;
1859706f2543Smrg        }
1860706f2543Smrg
1861706f2543Smrg        /* key aliases */
1862706f2543Smrg        if (src->geom->num_key_aliases) {
1863706f2543Smrg            if (src->geom->num_key_aliases != dst->geom->sz_key_aliases) {
1864706f2543Smrg                if (dst->geom->sz_key_aliases)
1865706f2543Smrg                    tmp = realloc(dst->geom->key_aliases,
1866706f2543Smrg                                   src->geom->num_key_aliases *
1867706f2543Smrg                                    2 * XkbKeyNameLength);
1868706f2543Smrg                else
1869706f2543Smrg                    tmp = malloc(src->geom->num_key_aliases *
1870706f2543Smrg                                  2 * XkbKeyNameLength);
1871706f2543Smrg                if (!tmp)
1872706f2543Smrg                    return FALSE;
1873706f2543Smrg                dst->geom->key_aliases = tmp;
1874706f2543Smrg
1875706f2543Smrg                dst->geom->sz_key_aliases = src->geom->num_key_aliases;
1876706f2543Smrg            }
1877706f2543Smrg
1878706f2543Smrg            memcpy(dst->geom->key_aliases, src->geom->key_aliases,
1879706f2543Smrg                   src->geom->num_key_aliases * 2 * XkbKeyNameLength);
1880706f2543Smrg
1881706f2543Smrg            dst->geom->num_key_aliases = dst->geom->sz_key_aliases;
1882706f2543Smrg        }
1883706f2543Smrg        else {
1884706f2543Smrg            free(dst->geom->key_aliases);
1885706f2543Smrg            dst->geom->key_aliases = NULL;
1886706f2543Smrg            dst->geom->num_key_aliases = 0;
1887706f2543Smrg            dst->geom->sz_key_aliases = 0;
1888706f2543Smrg        }
1889706f2543Smrg
1890706f2543Smrg        /* font */
1891706f2543Smrg        if (src->geom->label_font) {
1892706f2543Smrg            if (!dst->geom->label_font) {
1893706f2543Smrg                tmp = malloc(strlen(src->geom->label_font) + 1);
1894706f2543Smrg                if (!tmp)
1895706f2543Smrg                    return FALSE;
1896706f2543Smrg                dst->geom->label_font = tmp;
1897706f2543Smrg            }
1898706f2543Smrg            else if (strlen(src->geom->label_font) !=
1899706f2543Smrg                strlen(dst->geom->label_font)) {
1900706f2543Smrg                tmp = realloc(dst->geom->label_font,
1901706f2543Smrg                               strlen(src->geom->label_font) + 1);
1902706f2543Smrg                if (!tmp)
1903706f2543Smrg                    return FALSE;
1904706f2543Smrg                dst->geom->label_font = tmp;
1905706f2543Smrg            }
1906706f2543Smrg
1907706f2543Smrg            strcpy(dst->geom->label_font, src->geom->label_font);
1908706f2543Smrg            i = XkbGeomColorIndex(src->geom, src->geom->label_color);
1909706f2543Smrg            dst->geom->label_color = &(dst->geom->colors[i]);
1910706f2543Smrg            i = XkbGeomColorIndex(src->geom, src->geom->base_color);
1911706f2543Smrg            dst->geom->base_color = &(dst->geom->colors[i]);
1912706f2543Smrg        }
1913706f2543Smrg        else {
1914706f2543Smrg            free(dst->geom->label_font);
1915706f2543Smrg            dst->geom->label_font = NULL;
1916706f2543Smrg            dst->geom->label_color = NULL;
1917706f2543Smrg            dst->geom->base_color = NULL;
1918706f2543Smrg        }
1919706f2543Smrg
1920706f2543Smrg        dst->geom->name = src->geom->name;
1921706f2543Smrg        dst->geom->width_mm = src->geom->width_mm;
1922706f2543Smrg        dst->geom->height_mm = src->geom->height_mm;
1923706f2543Smrg    }
1924706f2543Smrg    else
1925706f2543Smrg    {
1926706f2543Smrg        if (dst->geom) {
1927706f2543Smrg            /* I LOVE THE DIFFERENT CALL SIGNATURE.  REALLY, I DO. */
1928706f2543Smrg            XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE);
1929706f2543Smrg            dst->geom = NULL;
1930706f2543Smrg        }
1931706f2543Smrg    }
1932706f2543Smrg
1933706f2543Smrg    return TRUE;
1934706f2543Smrg}
1935706f2543Smrg
1936706f2543Smrgstatic Bool
1937706f2543Smrg_XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst)
1938706f2543Smrg{
1939706f2543Smrg    /* indicators */
1940706f2543Smrg    if (src->indicators) {
1941706f2543Smrg        if (!dst->indicators) {
1942706f2543Smrg            dst->indicators = malloc(sizeof(XkbIndicatorRec));
1943706f2543Smrg            if (!dst->indicators)
1944706f2543Smrg                return FALSE;
1945706f2543Smrg        }
1946706f2543Smrg        memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec));
1947706f2543Smrg    }
1948706f2543Smrg    else {
1949706f2543Smrg        free(dst->indicators);
1950706f2543Smrg        dst->indicators = NULL;
1951706f2543Smrg    }
1952706f2543Smrg    return TRUE;
1953706f2543Smrg}
1954706f2543Smrg
1955706f2543Smrgstatic Bool
1956706f2543Smrg_XkbCopyControls(XkbDescPtr src, XkbDescPtr dst)
1957706f2543Smrg{
1958706f2543Smrg    /* controls */
1959706f2543Smrg    if (src->ctrls) {
1960706f2543Smrg        if (!dst->ctrls) {
1961706f2543Smrg            dst->ctrls = malloc(sizeof(XkbControlsRec));
1962706f2543Smrg            if (!dst->ctrls)
1963706f2543Smrg                return FALSE;
1964706f2543Smrg        }
1965706f2543Smrg        memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec));
1966706f2543Smrg    }
1967706f2543Smrg    else {
1968706f2543Smrg        free(dst->ctrls);
1969706f2543Smrg        dst->ctrls = NULL;
1970706f2543Smrg    }
1971706f2543Smrg    return TRUE;
1972706f2543Smrg}
1973706f2543Smrg
1974706f2543Smrg/**
1975706f2543Smrg * Copy an XKB map from src to dst, reallocating when necessary: if some
1976706f2543Smrg * map components are present in one, but not in the other, the destination
1977706f2543Smrg * components will be allocated or freed as necessary.
1978706f2543Smrg *
1979706f2543Smrg * Basic map consistency is assumed on both sides, so maps with random
1980706f2543Smrg * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19)
1981706f2543Smrg * _will_ cause failures.  You've been warned.
1982706f2543Smrg *
1983706f2543Smrg * Returns TRUE on success, or FALSE on failure.  If this function fails,
1984706f2543Smrg * dst may be in an inconsistent state: all its pointers are guaranteed
1985706f2543Smrg * to remain valid, but part of the map may be from src and part from dst.
1986706f2543Smrg *
1987706f2543Smrg */
1988706f2543Smrg
1989706f2543SmrgBool
1990706f2543SmrgXkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src)
1991706f2543Smrg{
1992706f2543Smrg
1993706f2543Smrg    if (!src || !dst) {
1994706f2543Smrg        DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst);
1995706f2543Smrg        return FALSE;
1996706f2543Smrg    }
1997706f2543Smrg
1998706f2543Smrg    if (src == dst)
1999706f2543Smrg        return TRUE;
2000706f2543Smrg
2001706f2543Smrg    if (!_XkbCopyClientMap(src, dst)) {
2002706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy client map\n");
2003706f2543Smrg        return FALSE;
2004706f2543Smrg    }
2005706f2543Smrg    if (!_XkbCopyServerMap(src, dst)) {
2006706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy server map\n");
2007706f2543Smrg        return FALSE;
2008706f2543Smrg    }
2009706f2543Smrg    if (!_XkbCopyIndicators(src, dst)) {
2010706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy indicators\n");
2011706f2543Smrg        return FALSE;
2012706f2543Smrg    }
2013706f2543Smrg    if (!_XkbCopyControls(src, dst)) {
2014706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy controls\n");
2015706f2543Smrg        return FALSE;
2016706f2543Smrg    }
2017706f2543Smrg    if (!_XkbCopyNames(src, dst)) {
2018706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy names\n");
2019706f2543Smrg        return FALSE;
2020706f2543Smrg    }
2021706f2543Smrg    if (!_XkbCopyCompat(src, dst)) {
2022706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy compat map\n");
2023706f2543Smrg        return FALSE;
2024706f2543Smrg    }
2025706f2543Smrg    if (!_XkbCopyGeom(src, dst)) {
2026706f2543Smrg        DebugF("XkbCopyKeymap: failed to copy geometry\n");
2027706f2543Smrg        return FALSE;
2028706f2543Smrg    }
2029706f2543Smrg
2030706f2543Smrg    dst->min_key_code = src->min_key_code;
2031706f2543Smrg    dst->max_key_code = src->max_key_code;
2032706f2543Smrg
2033706f2543Smrg    return TRUE;
2034706f2543Smrg}
2035706f2543Smrg
2036706f2543SmrgBool
2037706f2543SmrgXkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src)
2038706f2543Smrg{
2039706f2543Smrg    xkbNewKeyboardNotify nkn;
2040706f2543Smrg    Bool ret;
2041706f2543Smrg
2042706f2543Smrg    if (!dst->key || !src->key)
2043706f2543Smrg        return FALSE;
2044706f2543Smrg
2045706f2543Smrg    memset(&nkn, 0, sizeof(xkbNewKeyboardNotify));
2046706f2543Smrg    nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code;
2047706f2543Smrg    nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code;
2048706f2543Smrg    nkn.deviceID = dst->id;
2049706f2543Smrg    nkn.oldDeviceID = dst->id; /* maybe src->id? */
2050706f2543Smrg    nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code;
2051706f2543Smrg    nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code;
2052706f2543Smrg    nkn.requestMajor = XkbReqCode;
2053706f2543Smrg    nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */
2054706f2543Smrg    nkn.changed = XkbNKN_KeycodesMask;
2055706f2543Smrg    if (src->key->xkbInfo->desc->geom)
2056706f2543Smrg        nkn.changed |= XkbNKN_GeometryMask;
2057706f2543Smrg
2058706f2543Smrg    ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc);
2059706f2543Smrg    if (ret)
2060706f2543Smrg        XkbSendNewKeyboardNotify(dst, &nkn);
2061706f2543Smrg
2062706f2543Smrg    return ret;
2063706f2543Smrg}
2064706f2543Smrg
2065706f2543Smrgint
2066706f2543SmrgXkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode)
2067706f2543Smrg{
2068706f2543Smrg    XkbDescPtr xkb = xkbi->desc;
2069706f2543Smrg    int effectiveGroup = xkbState->group;
2070706f2543Smrg
2071706f2543Smrg    if (!XkbKeycodeInRange(xkb, keycode))
2072706f2543Smrg        return -1;
2073706f2543Smrg
2074706f2543Smrg    if (effectiveGroup == XkbGroup1Index)
2075706f2543Smrg        return effectiveGroup;
2076706f2543Smrg
2077706f2543Smrg    if (XkbKeyNumGroups(xkb,keycode) > 1U) {
2078706f2543Smrg        if (effectiveGroup >= XkbKeyNumGroups(xkb,keycode)) {
2079706f2543Smrg            unsigned int gi = XkbKeyGroupInfo(xkb,keycode);
2080706f2543Smrg            switch (XkbOutOfRangeGroupAction(gi)) {
2081706f2543Smrg                default:
2082706f2543Smrg                case XkbWrapIntoRange:
2083706f2543Smrg                    effectiveGroup %= XkbKeyNumGroups(xkb, keycode);
2084706f2543Smrg                    break;
2085706f2543Smrg                case XkbClampIntoRange:
2086706f2543Smrg                    effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1;
2087706f2543Smrg                    break;
2088706f2543Smrg                case XkbRedirectIntoRange:
2089706f2543Smrg                    effectiveGroup = XkbOutOfRangeGroupInfo(gi);
2090706f2543Smrg                    if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode))
2091706f2543Smrg                        effectiveGroup = 0;
2092706f2543Smrg                    break;
2093706f2543Smrg            }
2094706f2543Smrg        }
2095706f2543Smrg    }
2096706f2543Smrg    else effectiveGroup = XkbGroup1Index;
2097706f2543Smrg
2098706f2543Smrg    return effectiveGroup;
2099706f2543Smrg}
2100706f2543Smrg
2101706f2543Smrg/* Merge the lockedPtrButtons from all attached SDs for the given master
2102706f2543Smrg * device into the MD's state.
2103706f2543Smrg */
2104706f2543Smrgvoid
2105706f2543SmrgXkbMergeLockedPtrBtns(DeviceIntPtr master)
2106706f2543Smrg{
2107706f2543Smrg    DeviceIntPtr d = inputInfo.devices;
2108706f2543Smrg    XkbSrvInfoPtr xkbi = NULL;
2109706f2543Smrg
2110706f2543Smrg    if (!IsMaster(master))
2111706f2543Smrg        return;
2112706f2543Smrg
2113706f2543Smrg    if (!master->key)
2114706f2543Smrg        return;
2115706f2543Smrg
2116706f2543Smrg    xkbi = master->key->xkbInfo;
2117706f2543Smrg    xkbi->lockedPtrButtons = 0;
2118706f2543Smrg
2119706f2543Smrg    for (; d; d = d->next) {
2120706f2543Smrg        if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key)
2121706f2543Smrg            continue;
2122706f2543Smrg
2123706f2543Smrg        xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons;
2124706f2543Smrg    }
2125706f2543Smrg}
2126