Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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], *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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 = realloc(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 = realloc(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 = realloc(dst->map->types, | |
987 | src->map->num_types * 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 = realloc(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 = realloc(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 = malloc(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 = realloc(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 = malloc(stype->map_count * sizeof(XkbModsRec)); | |
1095 | if (!tmp) | |
1096 | return FALSE; | |
1097 | dtype->preserve = tmp; | |
1098 | } | |
1099 | ||
1100 | memcpy(dtype->preserve, stype->preserve, | |
1101 | stype->map_count * sizeof(XkbModsRec)); | |
1102 | } | |
1103 | else { | |
1104 | if (dtype->preserve && i < dst->map->num_types) | |
1105 | free(dtype->preserve); | |
1106 | dtype->preserve = NULL; | |
1107 | } | |
1108 | ||
1109 | dtype->map_count = stype->map_count; | |
1110 | } | |
1111 | else { | |
1112 | if (dtype->map_count && i < dst->map->num_types) { | |
1113 | free(dtype->map); | |
1114 | free(dtype->preserve); | |
1115 | } | |
1116 | dtype->map_count = 0; | |
1117 | dtype->map = NULL; | |
1118 | dtype->preserve = NULL; | |
1119 | } | |
1120 | } | |
1121 | ||
1122 | dst->map->size_types = src->map->num_types; | |
1123 | dst->map->num_types = src->map->num_types; | |
1124 | } | |
1125 | else { | |
1126 | if (dst->map->types) { | |
1127 | for (i = 0, dtype = dst->map->types; i < dst->map->num_types; | |
1128 | i++, dtype++) { | |
1129 | free(dtype->level_names); | |
1130 | if (dtype->map && dtype->map_count) | |
1131 | free(dtype->map); | |
1132 | if (dtype->preserve && dtype->map_count) | |
1133 | free(dtype->preserve); | |
1134 | } | |
1135 | } | |
1136 | free(dst->map->types); | |
1137 | dst->map->types = NULL; | |
1138 | dst->map->num_types = 0; | |
1139 | dst->map->size_types = 0; | |
1140 | } | |
1141 | ||
1142 | if (src->map->modmap) { | |
1143 | if (src->max_key_code != dst->max_key_code) { | |
1144 | tmp = realloc(dst->map->modmap, src->max_key_code + 1); | |
1145 | if (!tmp) | |
1146 | return FALSE; | |
1147 | dst->map->modmap = tmp; | |
1148 | } | |
1149 | memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1); | |
1150 | } | |
1151 | else { | |
1152 | free(dst->map->modmap); | |
1153 | dst->map->modmap = NULL; | |
1154 | } | |
1155 | } | |
1156 | else { | |
1157 | if (dst->map) | |
1158 | XkbFreeClientMap(dst, XkbAllClientInfoMask, TRUE); | |
1159 | } | |
1160 | ||
1161 | return TRUE; | |
1162 | } | |
1163 | ||
1164 | static Bool | |
1165 | _XkbCopyServerMap(XkbDescPtr src, XkbDescPtr dst) | |
1166 | { | |
1167 | void *tmp = NULL; | |
1168 | ||
1169 | /* server map */ | |
1170 | if (src->server) { | |
1171 | if (!dst->server) { | |
1172 | tmp = calloc(1, sizeof(XkbServerMapRec)); | |
1173 | if (!tmp) | |
1174 | return FALSE; | |
1175 | dst->server = tmp; | |
1176 | } | |
1177 | ||
1178 | if (src->server->explicit) { | |
1179 | if (src->max_key_code != dst->max_key_code) { | |
1180 | tmp = realloc(dst->server->explicit, src->max_key_code + 1); | |
1181 | if (!tmp) | |
1182 | return FALSE; | |
1183 | dst->server->explicit = tmp; | |
1184 | } | |
1185 | memcpy(dst->server->explicit, src->server->explicit, | |
1186 | src->max_key_code + 1); | |
1187 | } | |
1188 | else { | |
1189 | free(dst->server->explicit); | |
1190 | dst->server->explicit = NULL; | |
1191 | } | |
1192 | ||
1193 | if (src->server->acts) { | |
1194 | if (src->server->size_acts != dst->server->size_acts) { | |
1195 | tmp = realloc(dst->server->acts, | |
1196 | src->server->size_acts * sizeof(XkbAction)); | |
1197 | if (!tmp) | |
1198 | return FALSE; | |
1199 | dst->server->acts = tmp; | |
1200 | } | |
1201 | memcpy(dst->server->acts, src->server->acts, | |
1202 | src->server->size_acts * sizeof(XkbAction)); | |
1203 | } | |
1204 | else { | |
1205 | free(dst->server->acts); | |
1206 | dst->server->acts = NULL; | |
1207 | } | |
1208 | dst->server->size_acts = src->server->size_acts; | |
1209 | dst->server->num_acts = src->server->num_acts; | |
1210 | ||
1211 | if (src->server->key_acts) { | |
1212 | if (src->max_key_code != dst->max_key_code) { | |
1213 | tmp = realloc(dst->server->key_acts, | |
1214 | (src->max_key_code + 1) * sizeof(unsigned short)); | |
1215 | if (!tmp) | |
1216 | return FALSE; | |
1217 | dst->server->key_acts = tmp; | |
1218 | } | |
1219 | memcpy(dst->server->key_acts, src->server->key_acts, | |
1220 | (src->max_key_code + 1) * sizeof(unsigned short)); | |
1221 | } | |
1222 | else { | |
1223 | free(dst->server->key_acts); | |
1224 | dst->server->key_acts = NULL; | |
1225 | } | |
1226 | ||
1227 | if (src->server->behaviors) { | |
1228 | if (src->max_key_code != dst->max_key_code) { | |
1229 | tmp = realloc(dst->server->behaviors, | |
1230 | (src->max_key_code + 1) * sizeof(XkbBehavior)); | |
1231 | if (!tmp) | |
1232 | return FALSE; | |
1233 | dst->server->behaviors = tmp; | |
1234 | } | |
1235 | memcpy(dst->server->behaviors, src->server->behaviors, | |
1236 | (src->max_key_code + 1) * sizeof(XkbBehavior)); | |
1237 | } | |
1238 | else { | |
1239 | free(dst->server->behaviors); | |
1240 | dst->server->behaviors = NULL; | |
1241 | } | |
1242 | ||
1243 | memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods); | |
1244 | ||
1245 | if (src->server->vmodmap) { | |
1246 | if (src->max_key_code != dst->max_key_code) { | |
1247 | tmp = realloc(dst->server->vmodmap, | |
1248 | (src->max_key_code + 1) * sizeof(unsigned short)); | |
1249 | if (!tmp) | |
1250 | return FALSE; | |
1251 | dst->server->vmodmap = tmp; | |
1252 | } | |
1253 | memcpy(dst->server->vmodmap, src->server->vmodmap, | |
1254 | (src->max_key_code + 1) * sizeof(unsigned short)); | |
1255 | } | |
1256 | else { | |
1257 | free(dst->server->vmodmap); | |
1258 | dst->server->vmodmap = NULL; | |
1259 | } | |
1260 | } | |
1261 | else { | |
1262 | if (dst->server) | |
1263 | XkbFreeServerMap(dst, XkbAllServerInfoMask, TRUE); | |
1264 | } | |
1265 | ||
1266 | return TRUE; | |
1267 | } | |
1268 | ||
1269 | static Bool | |
1270 | _XkbCopyNames(XkbDescPtr src, XkbDescPtr dst) | |
1271 | { | |
1272 | void *tmp = NULL; | |
1273 | ||
1274 | /* names */ | |
1275 | if (src->names) { | |
1276 | if (!dst->names) { | |
1277 | dst->names = calloc(1, sizeof(XkbNamesRec)); | |
1278 | if (!dst->names) | |
1279 | return FALSE; | |
1280 | } | |
1281 | ||
1282 | if (src->names->keys) { | |
1283 | if (src->max_key_code != dst->max_key_code) { | |
1284 | tmp = realloc(dst->names->keys, | |
1285 | (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); | |
1286 | if (!tmp) | |
1287 | return FALSE; | |
1288 | dst->names->keys = tmp; | |
1289 | } | |
1290 | memcpy(dst->names->keys, src->names->keys, | |
1291 | (src->max_key_code + 1) * sizeof(XkbKeyNameRec)); | |
1292 | } | |
1293 | else { | |
1294 | free(dst->names->keys); | |
1295 | dst->names->keys = NULL; | |
1296 | } | |
1297 | ||
1298 | if (src->names->num_key_aliases) { | |
1299 | if (src->names->num_key_aliases != dst->names->num_key_aliases) { | |
1300 | tmp = realloc(dst->names->key_aliases, | |
1301 | src->names->num_key_aliases * | |
1302 | sizeof(XkbKeyAliasRec)); | |
1303 | if (!tmp) | |
1304 | return FALSE; | |
1305 | dst->names->key_aliases = tmp; | |
1306 | } | |
1307 | memcpy(dst->names->key_aliases, src->names->key_aliases, | |
1308 | src->names->num_key_aliases * sizeof(XkbKeyAliasRec)); | |
1309 | } | |
1310 | else { | |
1311 | free(dst->names->key_aliases); | |
1312 | dst->names->key_aliases = NULL; | |
1313 | } | |
1314 | dst->names->num_key_aliases = src->names->num_key_aliases; | |
1315 | ||
1316 | if (src->names->num_rg) { | |
1317 | if (src->names->num_rg != dst->names->num_rg) { | |
1318 | tmp = realloc(dst->names->radio_groups, | |
1319 | src->names->num_rg * sizeof(Atom)); | |
1320 | if (!tmp) | |
1321 | return FALSE; | |
1322 | dst->names->radio_groups = tmp; | |
1323 | } | |
1324 | memcpy(dst->names->radio_groups, src->names->radio_groups, | |
1325 | src->names->num_rg * sizeof(Atom)); | |
1326 | } | |
1327 | else { | |
1328 | free(dst->names->radio_groups); | |
1329 | } | |
1330 | dst->names->num_rg = src->names->num_rg; | |
1331 | ||
1332 | dst->names->keycodes = src->names->keycodes; | |
1333 | dst->names->geometry = src->names->geometry; | |
1334 | dst->names->symbols = src->names->symbols; | |
1335 | dst->names->types = src->names->types; | |
1336 | dst->names->compat = src->names->compat; | |
1337 | dst->names->phys_symbols = src->names->phys_symbols; | |
1338 | ||
1339 | memcpy(dst->names->vmods, src->names->vmods, | |
1340 | XkbNumVirtualMods * sizeof(Atom)); | |
1341 | memcpy(dst->names->indicators, src->names->indicators, | |
1342 | XkbNumIndicators * sizeof(Atom)); | |
1343 | memcpy(dst->names->groups, src->names->groups, | |
1344 | XkbNumKbdGroups * sizeof(Atom)); | |
1345 | } | |
1346 | else { | |
1347 | if (dst->names) | |
1348 | XkbFreeNames(dst, XkbAllNamesMask, TRUE); | |
1349 | } | |
1350 | ||
1351 | return TRUE; | |
1352 | } | |
1353 | ||
1354 | static Bool | |
1355 | _XkbCopyCompat(XkbDescPtr src, XkbDescPtr dst) | |
1356 | { | |
1357 | void *tmp = NULL; | |
1358 | ||
1359 | /* compat */ | |
1360 | if (src->compat) { | |
1361 | if (!dst->compat) { | |
1362 | dst->compat = calloc(1, sizeof(XkbCompatMapRec)); | |
1363 | if (!dst->compat) | |
1364 | return FALSE; | |
1365 | } | |
1366 | ||
1367 | if (src->compat->sym_interpret && src->compat->num_si) { | |
1368 | if (src->compat->num_si != dst->compat->size_si) { | |
1369 | tmp = realloc(dst->compat->sym_interpret, | |
1370 | src->compat->num_si * sizeof(XkbSymInterpretRec)); | |
1371 | if (!tmp) | |
1372 | return FALSE; | |
1373 | dst->compat->sym_interpret = tmp; | |
1374 | } | |
1375 | memcpy(dst->compat->sym_interpret, src->compat->sym_interpret, | |
1376 | src->compat->num_si * sizeof(XkbSymInterpretRec)); | |
1377 | ||
1378 | dst->compat->num_si = src->compat->num_si; | |
1379 | dst->compat->size_si = src->compat->num_si; | |
1380 | } | |
1381 | else { | |
1382 | if (dst->compat->sym_interpret && dst->compat->size_si) | |
1383 | free(dst->compat->sym_interpret); | |
1384 | ||
1385 | dst->compat->sym_interpret = NULL; | |
1386 | dst->compat->num_si = 0; | |
1387 | dst->compat->size_si = 0; | |
1388 | } | |
1389 | ||
1390 | memcpy(dst->compat->groups, src->compat->groups, | |
1391 | XkbNumKbdGroups * sizeof(XkbModsRec)); | |
1392 | } | |
1393 | else { | |
1394 | if (dst->compat) | |
1395 | XkbFreeCompatMap(dst, XkbAllCompatMask, TRUE); | |
1396 | } | |
1397 | ||
1398 | return TRUE; | |
1399 | } | |
1400 | ||
1401 | static Bool | |
1402 | _XkbCopyGeom(XkbDescPtr src, XkbDescPtr dst) | |
1403 | { | |
1404 | void *tmp = NULL; | |
1405 | int i = 0, j = 0, k = 0; | |
1406 | XkbColorPtr scolor = NULL, dcolor = NULL; | |
1407 | XkbDoodadPtr sdoodad = NULL, ddoodad = NULL; | |
1408 | XkbOutlinePtr soutline = NULL, doutline = NULL; | |
1409 | XkbPropertyPtr sprop = NULL, dprop = NULL; | |
1410 | XkbRowPtr srow = NULL, drow = NULL; | |
1411 | XkbSectionPtr ssection = NULL, dsection = NULL; | |
1412 | XkbShapePtr sshape = NULL, dshape = NULL; | |
1413 | ||
1414 | /* geometry */ | |
1415 | if (src->geom) { | |
1416 | if (!dst->geom) { | |
1417 | dst->geom = calloc(sizeof(XkbGeometryRec), 1); | |
1418 | if (!dst->geom) | |
1419 | return FALSE; | |
1420 | } | |
1421 | ||
1422 | /* properties */ | |
1423 | if (src->geom->num_properties) { | |
1424 | /* If we've got more properties in the destination than | |
1425 | * the source, run through and free all the excess ones | |
1426 | * first. */ | |
1427 | if (src->geom->num_properties < dst->geom->sz_properties) { | |
1428 | for (i = src->geom->num_properties, dprop = | |
1429 | dst->geom->properties + i; i < dst->geom->num_properties; | |
1430 | i++, dprop++) { | |
1431 | free(dprop->name); | |
1432 | free(dprop->value); | |
1433 | } | |
1434 | } | |
1435 | ||
1436 | /* Reallocate and clear all new items if the buffer grows. */ | |
1437 | if (!XkbGeomRealloc | |
1438 | ((void **) &dst->geom->properties, dst->geom->sz_properties, | |
1439 | src->geom->num_properties, sizeof(XkbPropertyRec), | |
1440 | XKB_GEOM_CLEAR_EXCESS)) | |
1441 | return FALSE; | |
1442 | /* We don't set num_properties as we need it to try and avoid | |
1443 | * too much reallocing. */ | |
1444 | dst->geom->sz_properties = src->geom->num_properties; | |
1445 | ||
1446 | for (i = 0, | |
1447 | sprop = src->geom->properties, | |
1448 | dprop = dst->geom->properties; | |
1449 | i < src->geom->num_properties; i++, sprop++, dprop++) { | |
1450 | if (i < dst->geom->num_properties) { | |
1451 | if (strlen(sprop->name) != strlen(dprop->name)) { | |
1452 | tmp = realloc(dprop->name, strlen(sprop->name) + 1); | |
1453 | if (!tmp) | |
1454 | return FALSE; | |
1455 | dprop->name = tmp; | |
1456 | } | |
1457 | if (strlen(sprop->value) != strlen(dprop->value)) { | |
1458 | tmp = realloc(dprop->value, strlen(sprop->value) + 1); | |
1459 | if (!tmp) | |
1460 | return FALSE; | |
1461 | dprop->value = tmp; | |
1462 | } | |
1463 | strcpy(dprop->name, sprop->name); | |
1464 | strcpy(dprop->value, sprop->value); | |
1465 | } | |
1466 | else { | |
1467 | dprop->name = xstrdup(sprop->name); | |
1468 | dprop->value = xstrdup(sprop->value); | |
1469 | } | |
1470 | } | |
1471 | ||
1472 | /* ... which is already src->geom->num_properties. */ | |
1473 | dst->geom->num_properties = dst->geom->sz_properties; | |
1474 | } | |
1475 | else { | |
1476 | if (dst->geom->sz_properties) { | |
1477 | for (i = 0, dprop = dst->geom->properties; | |
1478 | i < dst->geom->num_properties; i++, dprop++) { | |
1479 | free(dprop->name); | |
1480 | free(dprop->value); | |
1481 | } | |
1482 | free(dst->geom->properties); | |
1483 | dst->geom->properties = NULL; | |
1484 | } | |
1485 | ||
1486 | dst->geom->num_properties = 0; | |
1487 | dst->geom->sz_properties = 0; | |
1488 | } | |
1489 | ||
1490 | /* colors */ | |
1491 | if (src->geom->num_colors) { | |
1492 | if (src->geom->num_colors < dst->geom->sz_colors) { | |
1493 | for (i = src->geom->num_colors, dcolor = dst->geom->colors + i; | |
1494 | i < dst->geom->num_colors; i++, dcolor++) { | |
1495 | free(dcolor->spec); | |
1496 | } | |
1497 | } | |
1498 | ||
1499 | /* Reallocate and clear all new items if the buffer grows. */ | |
1500 | if (!XkbGeomRealloc | |
1501 | ((void **) &dst->geom->colors, dst->geom->sz_colors, | |
1502 | src->geom->num_colors, sizeof(XkbColorRec), | |
1503 | XKB_GEOM_CLEAR_EXCESS)) | |
1504 | return FALSE; | |
1505 | dst->geom->sz_colors = src->geom->num_colors; | |
1506 | ||
1507 | for (i = 0, | |
1508 | scolor = src->geom->colors, | |
1509 | dcolor = dst->geom->colors; | |
1510 | i < src->geom->num_colors; i++, scolor++, dcolor++) { | |
1511 | if (i < dst->geom->num_colors) { | |
1512 | if (strlen(scolor->spec) != strlen(dcolor->spec)) { | |
1513 | tmp = realloc(dcolor->spec, strlen(scolor->spec) + 1); | |
1514 | if (!tmp) | |
1515 | return FALSE; | |
1516 | dcolor->spec = tmp; | |
1517 | } | |
1518 | strcpy(dcolor->spec, scolor->spec); | |
1519 | } | |
1520 | else { | |
1521 | dcolor->spec = xstrdup(scolor->spec); | |
1522 | } | |
1523 | dcolor->pixel = scolor->pixel; | |
1524 | } | |
1525 | ||
1526 | dst->geom->num_colors = dst->geom->sz_colors; | |
1527 | } | |
1528 | else { | |
1529 | if (dst->geom->sz_colors) { | |
1530 | for (i = 0, dcolor = dst->geom->colors; | |
1531 | i < dst->geom->num_colors; i++, dcolor++) { | |
1532 | free(dcolor->spec); | |
1533 | } | |
1534 | free(dst->geom->colors); | |
1535 | dst->geom->colors = NULL; | |
1536 | } | |
1537 | ||
1538 | dst->geom->num_colors = 0; | |
1539 | dst->geom->sz_colors = 0; | |
1540 | } | |
1541 | ||
1542 | /* shapes */ | |
1543 | /* shapes break down into outlines, which break down into points. */ | |
1544 | if (dst->geom->num_shapes) { | |
1545 | for (i = 0, dshape = dst->geom->shapes; | |
1546 | i < dst->geom->num_shapes; i++, dshape++) { | |
1547 | for (j = 0, doutline = dshape->outlines; | |
1548 | j < dshape->num_outlines; j++, doutline++) { | |
1549 | if (doutline->sz_points) | |
1550 | free(doutline->points); | |
1551 | } | |
1552 | ||
1553 | if (dshape->sz_outlines) { | |
1554 | free(dshape->outlines); | |
1555 | dshape->outlines = NULL; | |
1556 | } | |
1557 | ||
1558 | dshape->num_outlines = 0; | |
1559 | dshape->sz_outlines = 0; | |
1560 | } | |
1561 | } | |
1562 | ||
1563 | if (src->geom->num_shapes) { | |
1564 | /* Reallocate and clear all items. */ | |
1565 | if (!XkbGeomRealloc | |
1566 | ((void **) &dst->geom->shapes, dst->geom->sz_shapes, | |
1567 | src->geom->num_shapes, sizeof(XkbShapeRec), | |
1568 | XKB_GEOM_CLEAR_ALL)) | |
1569 | return FALSE; | |
1570 | ||
1571 | for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes; | |
1572 | i < src->geom->num_shapes; i++, sshape++, dshape++) { | |
1573 | if (sshape->num_outlines) { | |
1574 | tmp = calloc(sshape->num_outlines, sizeof(XkbOutlineRec)); | |
1575 | if (!tmp) | |
1576 | return FALSE; | |
1577 | dshape->outlines = tmp; | |
1578 | ||
1579 | for (j = 0, | |
1580 | soutline = sshape->outlines, | |
1581 | doutline = dshape->outlines; | |
1582 | j < sshape->num_outlines; | |
1583 | j++, soutline++, doutline++) { | |
1584 | if (soutline->num_points) { | |
1585 | tmp = malloc(soutline->num_points * | |
1586 | sizeof(XkbPointRec)); | |
1587 | if (!tmp) | |
1588 | return FALSE; | |
1589 | doutline->points = tmp; | |
1590 | ||
1591 | memcpy(doutline->points, soutline->points, | |
1592 | soutline->num_points * sizeof(XkbPointRec)); | |
1593 | ||
1594 | doutline->corner_radius = soutline->corner_radius; | |
1595 | } | |
1596 | ||
1597 | doutline->num_points = soutline->num_points; | |
1598 | doutline->sz_points = soutline->num_points; | |
1599 | } | |
1600 | } | |
1601 | ||
1602 | dshape->num_outlines = sshape->num_outlines; | |
1603 | dshape->sz_outlines = sshape->num_outlines; | |
1604 | dshape->name = sshape->name; | |
1605 | dshape->bounds = sshape->bounds; | |
1606 | ||
1607 | dshape->approx = NULL; | |
1608 | if (sshape->approx && sshape->num_outlines > 0) { | |
1609 | ||
1610 | const ptrdiff_t approx_idx = | |
1611 | sshape->approx - sshape->outlines; | |
1612 | ||
1613 | if (approx_idx < dshape->num_outlines) { | |
1614 | dshape->approx = dshape->outlines + approx_idx; | |
1615 | } | |
1616 | else { | |
1617 | LogMessage(X_WARNING, "XKB: approx outline " | |
1618 | "index is out of range\n"); | |
1619 | } | |
1620 | } | |
1621 | ||
1622 | dshape->primary = NULL; | |
1623 | if (sshape->primary && sshape->num_outlines > 0) { | |
1624 | ||
1625 | const ptrdiff_t primary_idx = | |
1626 | sshape->primary - sshape->outlines; | |
1627 | ||
1628 | if (primary_idx < dshape->num_outlines) { | |
1629 | dshape->primary = dshape->outlines + primary_idx; | |
1630 | } | |
1631 | else { | |
1632 | LogMessage(X_WARNING, "XKB: primary outline " | |
1633 | "index is out of range\n"); | |
1634 | } | |
1635 | } | |
1636 | } | |
1637 | ||
1638 | dst->geom->num_shapes = src->geom->num_shapes; | |
1639 | dst->geom->sz_shapes = src->geom->num_shapes; | |
1640 | } | |
1641 | else { | |
1642 | if (dst->geom->sz_shapes) { | |
1643 | free(dst->geom->shapes); | |
1644 | } | |
1645 | dst->geom->shapes = NULL; | |
1646 | dst->geom->num_shapes = 0; | |
1647 | dst->geom->sz_shapes = 0; | |
1648 | } | |
1649 | ||
1650 | /* sections */ | |
1651 | /* sections break down into doodads, and also into rows, which break | |
1652 | * down into keys. */ | |
1653 | if (dst->geom->num_sections) { | |
1654 | for (i = 0, dsection = dst->geom->sections; | |
1655 | i < dst->geom->num_sections; i++, dsection++) { | |
1656 | for (j = 0, drow = dsection->rows; | |
1657 | j < dsection->num_rows; j++, drow++) { | |
1658 | if (drow->num_keys) | |
1659 | free(drow->keys); | |
1660 | } | |
1661 | ||
1662 | if (dsection->num_rows) | |
1663 | free(dsection->rows); | |
1664 | ||
1665 | /* cut and waste from geom/doodad below. */ | |
1666 | for (j = 0, ddoodad = dsection->doodads; | |
1667 | j < dsection->num_doodads; j++, ddoodad++) { | |
1668 | if (ddoodad->any.type == XkbTextDoodad) { | |
1669 | free(ddoodad->text.text); | |
1670 | ddoodad->text.text = NULL; | |
1671 | free(ddoodad->text.font); | |
1672 | ddoodad->text.font = NULL; | |
1673 | } | |
1674 | else if (ddoodad->any.type == XkbLogoDoodad) { | |
1675 | free(ddoodad->logo.logo_name); | |
1676 | ddoodad->logo.logo_name = NULL; | |
1677 | } | |
1678 | } | |
1679 | ||
1680 | free(dsection->doodads); | |
1681 | } | |
1682 | ||
1683 | dst->geom->num_sections = 0; | |
1684 | } | |
1685 | ||
1686 | if (src->geom->num_sections) { | |
1687 | /* Reallocate and clear all items. */ | |
1688 | if (!XkbGeomRealloc | |
1689 | ((void **) &dst->geom->sections, dst->geom->sz_sections, | |
1690 | src->geom->num_sections, sizeof(XkbSectionRec), | |
1691 | XKB_GEOM_CLEAR_ALL)) | |
1692 | return FALSE; | |
1693 | dst->geom->num_sections = src->geom->num_sections; | |
1694 | dst->geom->sz_sections = src->geom->num_sections; | |
1695 | ||
1696 | for (i = 0, | |
1697 | ssection = src->geom->sections, | |
1698 | dsection = dst->geom->sections; | |
1699 | i < src->geom->num_sections; i++, ssection++, dsection++) { | |
1700 | *dsection = *ssection; | |
1701 | if (ssection->num_rows) { | |
1702 | tmp = calloc(ssection->num_rows, sizeof(XkbRowRec)); | |
1703 | if (!tmp) | |
1704 | return FALSE; | |
1705 | dsection->rows = tmp; | |
1706 | } | |
1707 | dsection->num_rows = ssection->num_rows; | |
1708 | dsection->sz_rows = ssection->num_rows; | |
1709 | ||
1710 | for (j = 0, srow = ssection->rows, drow = dsection->rows; | |
1711 | j < ssection->num_rows; j++, srow++, drow++) { | |
1712 | if (srow->num_keys) { | |
1713 | tmp = malloc(srow->num_keys * sizeof(XkbKeyRec)); | |
1714 | if (!tmp) | |
1715 | return FALSE; | |
1716 | drow->keys = tmp; | |
1717 | memcpy(drow->keys, srow->keys, | |
1718 | srow->num_keys * sizeof(XkbKeyRec)); | |
1719 | } | |
1720 | drow->num_keys = srow->num_keys; | |
1721 | drow->sz_keys = srow->num_keys; | |
1722 | drow->top = srow->top; | |
1723 | drow->left = srow->left; | |
1724 | drow->vertical = srow->vertical; | |
1725 | drow->bounds = srow->bounds; | |
1726 | } | |
1727 | ||
1728 | if (ssection->num_doodads) { | |
1729 | tmp = calloc(ssection->num_doodads, sizeof(XkbDoodadRec)); | |
1730 | if (!tmp) | |
1731 | return FALSE; | |
1732 | dsection->doodads = tmp; | |
1733 | } | |
1734 | else { | |
1735 | dsection->doodads = NULL; | |
1736 | } | |
1737 | ||
1738 | dsection->sz_doodads = ssection->num_doodads; | |
1739 | for (k = 0, | |
1740 | sdoodad = ssection->doodads, | |
1741 | ddoodad = dsection->doodads; | |
1742 | k < ssection->num_doodads; k++, sdoodad++, ddoodad++) { | |
1743 | memcpy(ddoodad, sdoodad, sizeof(XkbDoodadRec)); | |
1744 | if (sdoodad->any.type == XkbTextDoodad) { | |
1745 | if (sdoodad->text.text) | |
1746 | ddoodad->text.text = strdup(sdoodad->text.text); | |
1747 | if (sdoodad->text.font) | |
1748 | ddoodad->text.font = strdup(sdoodad->text.font); | |
1749 | } | |
1750 | else if (sdoodad->any.type == XkbLogoDoodad) { | |
1751 | if (sdoodad->logo.logo_name) | |
1752 | ddoodad->logo.logo_name = | |
1753 | strdup(sdoodad->logo.logo_name); | |
1754 | } | |
1755 | } | |
1756 | dsection->overlays = NULL; | |
1757 | dsection->sz_overlays = 0; | |
1758 | dsection->num_overlays = 0; | |
1759 | } | |
1760 | } | |
1761 | else { | |
1762 | if (dst->geom->sz_sections) { | |
1763 | free(dst->geom->sections); | |
1764 | } | |
1765 | ||
1766 | dst->geom->sections = NULL; | |
1767 | dst->geom->num_sections = 0; | |
1768 | dst->geom->sz_sections = 0; | |
1769 | } | |
1770 | ||
1771 | /* doodads */ | |
1772 | if (dst->geom->num_doodads) { | |
1773 | for (i = src->geom->num_doodads, | |
1774 | ddoodad = dst->geom->doodads + | |
1775 | src->geom->num_doodads; | |
1776 | i < dst->geom->num_doodads; i++, ddoodad++) { | |
1777 | if (ddoodad->any.type == XkbTextDoodad) { | |
1778 | free(ddoodad->text.text); | |
1779 | ddoodad->text.text = NULL; | |
1780 | free(ddoodad->text.font); | |
1781 | ddoodad->text.font = NULL; | |
1782 | } | |
1783 | else if (ddoodad->any.type == XkbLogoDoodad) { | |
1784 | free(ddoodad->logo.logo_name); | |
1785 | ddoodad->logo.logo_name = NULL; | |
1786 | } | |
1787 | } | |
1788 | dst->geom->num_doodads = 0; | |
1789 | } | |
1790 | ||
1791 | if (src->geom->num_doodads) { | |
1792 | /* Reallocate and clear all items. */ | |
1793 | if (!XkbGeomRealloc | |
1794 | ((void **) &dst->geom->doodads, dst->geom->sz_doodads, | |
1795 | src->geom->num_doodads, sizeof(XkbDoodadRec), | |
1796 | XKB_GEOM_CLEAR_ALL)) | |
1797 | return FALSE; | |
1798 | ||
1799 | dst->geom->sz_doodads = src->geom->num_doodads; | |
1800 | ||
1801 | for (i = 0, | |
1802 | sdoodad = src->geom->doodads, | |
1803 | ddoodad = dst->geom->doodads; | |
1804 | i < src->geom->num_doodads; i++, sdoodad++, ddoodad++) { | |
1805 | memcpy(ddoodad, sdoodad, sizeof(XkbDoodadRec)); | |
1806 | if (sdoodad->any.type == XkbTextDoodad) { | |
1807 | if (sdoodad->text.text) | |
1808 | ddoodad->text.text = strdup(sdoodad->text.text); | |
1809 | if (sdoodad->text.font) | |
1810 | ddoodad->text.font = strdup(sdoodad->text.font); | |
1811 | } | |
1812 | else if (sdoodad->any.type == XkbLogoDoodad) { | |
1813 | if (sdoodad->logo.logo_name) | |
1814 | ddoodad->logo.logo_name = | |
1815 | strdup(sdoodad->logo.logo_name); | |
1816 | } | |
1817 | } | |
1818 | ||
1819 | dst->geom->num_doodads = dst->geom->sz_doodads; | |
1820 | } | |
1821 | else { | |
1822 | if (dst->geom->sz_doodads) { | |
1823 | free(dst->geom->doodads); | |
1824 | } | |
1825 | ||
1826 | dst->geom->doodads = NULL; | |
1827 | dst->geom->num_doodads = 0; | |
1828 | dst->geom->sz_doodads = 0; | |
1829 | } | |
1830 | ||
1831 | /* key aliases */ | |
1832 | if (src->geom->num_key_aliases) { | |
1833 | /* Reallocate but don't clear any items. There is no need | |
1834 | * to clear anything because data is immediately copied | |
1835 | * over the whole memory area with memcpy. */ | |
1836 | if (!XkbGeomRealloc | |
1837 | ((void **) &dst->geom->key_aliases, dst->geom->sz_key_aliases, | |
1838 | src->geom->num_key_aliases, 2 * XkbKeyNameLength, | |
1839 | XKB_GEOM_CLEAR_NONE)) | |
1840 | return FALSE; | |
1841 | ||
1842 | dst->geom->sz_key_aliases = src->geom->num_key_aliases; | |
1843 | ||
1844 | memcpy(dst->geom->key_aliases, src->geom->key_aliases, | |
1845 | src->geom->num_key_aliases * 2 * XkbKeyNameLength); | |
1846 | ||
1847 | dst->geom->num_key_aliases = dst->geom->sz_key_aliases; | |
1848 | } | |
1849 | else { | |
1850 | free(dst->geom->key_aliases); | |
1851 | dst->geom->key_aliases = NULL; | |
1852 | dst->geom->num_key_aliases = 0; | |
1853 | dst->geom->sz_key_aliases = 0; | |
1854 | } | |
1855 | ||
1856 | /* font */ | |
1857 | if (src->geom->label_font) { | |
1858 | if (!dst->geom->label_font) { | |
1859 | tmp = malloc(strlen(src->geom->label_font) + 1); | |
1860 | if (!tmp) | |
1861 | return FALSE; | |
1862 | dst->geom->label_font = tmp; | |
1863 | } | |
1864 | else if (strlen(src->geom->label_font) != | |
1865 | strlen(dst->geom->label_font)) { | |
1866 | tmp = realloc(dst->geom->label_font, | |
1867 | strlen(src->geom->label_font) + 1); | |
1868 | if (!tmp) | |
1869 | return FALSE; | |
1870 | dst->geom->label_font = tmp; | |
1871 | } | |
1872 | ||
1873 | strcpy(dst->geom->label_font, src->geom->label_font); | |
1874 | i = XkbGeomColorIndex(src->geom, src->geom->label_color); | |
1875 | dst->geom->label_color = &(dst->geom->colors[i]); | |
1876 | i = XkbGeomColorIndex(src->geom, src->geom->base_color); | |
1877 | dst->geom->base_color = &(dst->geom->colors[i]); | |
1878 | } | |
1879 | else { | |
1880 | free(dst->geom->label_font); | |
1881 | dst->geom->label_font = NULL; | |
1882 | dst->geom->label_color = NULL; | |
1883 | dst->geom->base_color = NULL; | |
1884 | } | |
1885 | ||
1886 | dst->geom->name = src->geom->name; | |
1887 | dst->geom->width_mm = src->geom->width_mm; | |
1888 | dst->geom->height_mm = src->geom->height_mm; | |
1889 | } | |
1890 | else { | |
1891 | if (dst->geom) { | |
1892 | /* I LOVE THE DIFFERENT CALL SIGNATURE. REALLY, I DO. */ | |
1893 | XkbFreeGeometry(dst->geom, XkbGeomAllMask, TRUE); | |
1894 | dst->geom = NULL; | |
1895 | } | |
1896 | } | |
1897 | ||
1898 | return TRUE; | |
1899 | } | |
1900 | ||
1901 | static Bool | |
1902 | _XkbCopyIndicators(XkbDescPtr src, XkbDescPtr dst) | |
1903 | { | |
1904 | /* indicators */ | |
1905 | if (src->indicators) { | |
1906 | if (!dst->indicators) { | |
1907 | dst->indicators = malloc(sizeof(XkbIndicatorRec)); | |
1908 | if (!dst->indicators) | |
1909 | return FALSE; | |
1910 | } | |
1911 | memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec)); | |
1912 | } | |
1913 | else { | |
1914 | free(dst->indicators); | |
1915 | dst->indicators = NULL; | |
1916 | } | |
1917 | return TRUE; | |
1918 | } | |
1919 | ||
1920 | static Bool | |
1921 | _XkbCopyControls(XkbDescPtr src, XkbDescPtr dst) | |
1922 | { | |
1923 | /* controls */ | |
1924 | if (src->ctrls) { | |
1925 | if (!dst->ctrls) { | |
1926 | dst->ctrls = malloc(sizeof(XkbControlsRec)); | |
1927 | if (!dst->ctrls) | |
1928 | return FALSE; | |
1929 | } | |
1930 | memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec)); | |
1931 | } | |
1932 | else { | |
1933 | free(dst->ctrls); | |
1934 | dst->ctrls = NULL; | |
1935 | } | |
1936 | return TRUE; | |
1937 | } | |
1938 | ||
1939 | /** | |
1940 | * Copy an XKB map from src to dst, reallocating when necessary: if some | |
1941 | * map components are present in one, but not in the other, the destination | |
1942 | * components will be allocated or freed as necessary. | |
1943 | * | |
1944 | * Basic map consistency is assumed on both sides, so maps with random | |
1945 | * uninitialised data (e.g. names->radio_grous == NULL, names->num_rg == 19) | |
1946 | * _will_ cause failures. You've been warned. | |
1947 | * | |
1948 | * Returns TRUE on success, or FALSE on failure. If this function fails, | |
1949 | * dst may be in an inconsistent state: all its pointers are guaranteed | |
1950 | * to remain valid, but part of the map may be from src and part from dst. | |
1951 | * | |
1952 | */ | |
1953 | ||
1954 | Bool | |
1955 | XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src) | |
1956 | { | |
1957 | ||
1958 | if (!src || !dst) { | |
1959 | DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst); | |
1960 | return FALSE; | |
1961 | } | |
1962 | ||
1963 | if (src == dst) | |
1964 | return TRUE; | |
1965 | ||
1966 | if (!_XkbCopyClientMap(src, dst)) { | |
1967 | DebugF("XkbCopyKeymap: failed to copy client map\n"); | |
1968 | return FALSE; | |
1969 | } | |
1970 | if (!_XkbCopyServerMap(src, dst)) { | |
1971 | DebugF("XkbCopyKeymap: failed to copy server map\n"); | |
1972 | return FALSE; | |
1973 | } | |
1974 | if (!_XkbCopyIndicators(src, dst)) { | |
1975 | DebugF("XkbCopyKeymap: failed to copy indicators\n"); | |
1976 | return FALSE; | |
1977 | } | |
1978 | if (!_XkbCopyControls(src, dst)) { | |
1979 | DebugF("XkbCopyKeymap: failed to copy controls\n"); | |
1980 | return FALSE; | |
1981 | } | |
1982 | if (!_XkbCopyNames(src, dst)) { | |
1983 | DebugF("XkbCopyKeymap: failed to copy names\n"); | |
1984 | return FALSE; | |
1985 | } | |
1986 | if (!_XkbCopyCompat(src, dst)) { | |
1987 | DebugF("XkbCopyKeymap: failed to copy compat map\n"); | |
1988 | return FALSE; | |
1989 | } | |
1990 | if (!_XkbCopyGeom(src, dst)) { | |
1991 | DebugF("XkbCopyKeymap: failed to copy geometry\n"); | |
1992 | return FALSE; | |
1993 | } | |
1994 | ||
1995 | dst->min_key_code = src->min_key_code; | |
1996 | dst->max_key_code = src->max_key_code; | |
1997 | ||
1998 | return TRUE; | |
1999 | } | |
2000 | ||
2001 | Bool | |
2002 | XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src) | |
2003 | { | |
2004 | xkbNewKeyboardNotify nkn; | |
2005 | Bool ret; | |
2006 | ||
2007 | if (!dst->key || !src->key) | |
2008 | return FALSE; | |
2009 | ||
2010 | memset(&nkn, 0, sizeof(xkbNewKeyboardNotify)); | |
2011 | nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code; | |
2012 | nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code; | |
2013 | nkn.deviceID = dst->id; | |
2014 | nkn.oldDeviceID = dst->id; /* maybe src->id? */ | |
2015 | nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code; | |
2016 | nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code; | |
2017 | nkn.requestMajor = XkbReqCode; | |
2018 | nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */ | |
2019 | nkn.changed = XkbNKN_KeycodesMask; | |
2020 | if (src->key->xkbInfo->desc->geom) | |
2021 | nkn.changed |= XkbNKN_GeometryMask; | |
2022 | ||
2023 | ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc); | |
2024 | if (ret) | |
2025 | XkbSendNewKeyboardNotify(dst, &nkn); | |
2026 | ||
2027 | return ret; | |
2028 | } | |
2029 | ||
2030 | int | |
2031 | XkbGetEffectiveGroup(XkbSrvInfoPtr xkbi, XkbStatePtr xkbState, CARD8 keycode) | |
2032 | { | |
2033 | XkbDescPtr xkb = xkbi->desc; | |
2034 | int effectiveGroup = xkbState->group; | |
2035 | ||
2036 | if (!XkbKeycodeInRange(xkb, keycode)) | |
2037 | return -1; | |
2038 | ||
2039 | if (effectiveGroup == XkbGroup1Index) | |
2040 | return effectiveGroup; | |
2041 | ||
2042 | if (XkbKeyNumGroups(xkb, keycode) > 1U) { | |
2043 | if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) { | |
2044 | unsigned int gi = XkbKeyGroupInfo(xkb, keycode); | |
2045 | ||
2046 | switch (XkbOutOfRangeGroupAction(gi)) { | |
2047 | default: | |
2048 | case XkbWrapIntoRange: | |
2049 | effectiveGroup %= XkbKeyNumGroups(xkb, keycode); | |
2050 | break; | |
2051 | case XkbClampIntoRange: | |
2052 | effectiveGroup = XkbKeyNumGroups(xkb, keycode) - 1; | |
2053 | break; | |
2054 | case XkbRedirectIntoRange: | |
2055 | effectiveGroup = XkbOutOfRangeGroupInfo(gi); | |
2056 | if (effectiveGroup >= XkbKeyNumGroups(xkb, keycode)) | |
2057 | effectiveGroup = 0; | |
2058 | break; | |
2059 | } | |
2060 | } | |
2061 | } | |
2062 | else | |
2063 | effectiveGroup = XkbGroup1Index; | |
2064 | ||
2065 | return effectiveGroup; | |
2066 | } | |
2067 | ||
2068 | /* Merge the lockedPtrButtons from all attached SDs for the given master | |
2069 | * device into the MD's state. | |
2070 | */ | |
2071 | void | |
2072 | XkbMergeLockedPtrBtns(DeviceIntPtr master) | |
2073 | { | |
2074 | DeviceIntPtr d = inputInfo.devices; | |
2075 | XkbSrvInfoPtr xkbi = NULL; | |
2076 | ||
2077 | if (!IsMaster(master)) | |
2078 | return; | |
2079 | ||
2080 | if (!master->key) | |
2081 | return; | |
2082 | ||
2083 | xkbi = master->key->xkbInfo; | |
2084 | xkbi->lockedPtrButtons = 0; | |
2085 | ||
2086 | for (; d; d = d->next) { | |
2087 | if (IsMaster(d) || GetMaster(d, MASTER_KEYBOARD) != master || !d->key) | |
2088 | continue; | |
2089 | ||
2090 | xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons; | |
2091 | } | |
2092 | } |