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