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