xkb.c revision 5a112b11
1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#endif
30
31#include <stdio.h>
32#include <X11/X.h>
33#include <X11/Xproto.h>
34#include "misc.h"
35#include "inputstr.h"
36#define	XKBSRV_NEED_FILE_FUNCS
37#include <xkbsrv.h>
38#include "extnsionst.h"
39#include "extinit.h"
40#include "xace.h"
41#include "xkb.h"
42#include "protocol-versions.h"
43
44#include <X11/extensions/XI.h>
45#include <X11/extensions/XKMformat.h>
46
47int XkbEventBase;
48static int XkbErrorBase;
49int XkbReqCode;
50int XkbKeyboardErrorCode;
51CARD32 xkbDebugFlags = 0;
52static CARD32 xkbDebugCtrls = 0;
53
54static RESTYPE RT_XKBCLIENT;
55
56/***====================================================================***/
57
58#define	CHK_DEVICE(dev, id, client, access_mode, lf) {\
59    int why;\
60    int tmprc = lf(&(dev), id, client, access_mode, &why);\
61    if (tmprc != Success) {\
62	client->errorValue = _XkbErrCode2(why, id);\
63	return tmprc;\
64    }\
65}
66
67#define	CHK_KBD_DEVICE(dev, id, client, mode) \
68    CHK_DEVICE(dev, id, client, mode, _XkbLookupKeyboard)
69#define	CHK_LED_DEVICE(dev, id, client, mode) \
70    CHK_DEVICE(dev, id, client, mode, _XkbLookupLedDevice)
71#define	CHK_BELL_DEVICE(dev, id, client, mode) \
72    CHK_DEVICE(dev, id, client, mode, _XkbLookupBellDevice)
73#define	CHK_ANY_DEVICE(dev, id, client, mode) \
74    CHK_DEVICE(dev, id, client, mode, _XkbLookupAnyDevice)
75
76#define	CHK_ATOM_ONLY2(a,ev,er) {\
77	if (((a)==None)||(!ValidAtom((a)))) {\
78	    (ev)= (XID)(a);\
79	    return er;\
80	}\
81}
82#define	CHK_ATOM_ONLY(a) \
83	CHK_ATOM_ONLY2(a,client->errorValue,BadAtom)
84
85#define	CHK_ATOM_OR_NONE3(a,ev,er,ret) {\
86	if (((a)!=None)&&(!ValidAtom((a)))) {\
87	    (ev)= (XID)(a);\
88	    (er)= BadAtom;\
89	    return ret;\
90	}\
91}
92#define	CHK_ATOM_OR_NONE2(a,ev,er) {\
93	if (((a)!=None)&&(!ValidAtom((a)))) {\
94	    (ev)= (XID)(a);\
95	    return er;\
96	}\
97}
98#define	CHK_ATOM_OR_NONE(a) \
99	CHK_ATOM_OR_NONE2(a,client->errorValue,BadAtom)
100
101#define	CHK_MASK_LEGAL3(err,mask,legal,ev,er,ret)	{\
102	if ((mask)&(~(legal))) { \
103	    (ev)= _XkbErrCode2((err),((mask)&(~(legal))));\
104	    (er)= BadValue;\
105	    return ret;\
106	}\
107}
108#define	CHK_MASK_LEGAL2(err,mask,legal,ev,er)	{\
109	if ((mask)&(~(legal))) { \
110	    (ev)= _XkbErrCode2((err),((mask)&(~(legal))));\
111	    return er;\
112	}\
113}
114#define	CHK_MASK_LEGAL(err,mask,legal) \
115	CHK_MASK_LEGAL2(err,mask,legal,client->errorValue,BadValue)
116
117#define	CHK_MASK_MATCH(err,affect,value) {\
118	if ((value)&(~(affect))) { \
119	    client->errorValue= _XkbErrCode2((err),((value)&(~(affect))));\
120	    return BadMatch;\
121	}\
122}
123#define	CHK_MASK_OVERLAP(err,m1,m2) {\
124	if ((m1)&(m2)) { \
125	    client->errorValue= _XkbErrCode2((err),((m1)&(m2)));\
126	    return BadMatch;\
127	}\
128}
129#define	CHK_KEY_RANGE2(err,first,num,x,ev,er) {\
130	if (((unsigned)(first)+(num)-1)>(x)->max_key_code) {\
131	    (ev)=_XkbErrCode4(err,(first),(num),(x)->max_key_code);\
132	    return er;\
133	}\
134	else if ( (first)<(x)->min_key_code ) {\
135	    (ev)=_XkbErrCode3(err+1,(first),xkb->min_key_code);\
136	    return er;\
137	}\
138}
139#define	CHK_KEY_RANGE(err,first,num,x)  \
140	CHK_KEY_RANGE2(err,first,num,x,client->errorValue,BadValue)
141
142#define	CHK_REQ_KEY_RANGE2(err,first,num,r,ev,er) {\
143	if (((unsigned)(first)+(num)-1)>(r)->maxKeyCode) {\
144	    (ev)=_XkbErrCode4(err,(first),(num),(r)->maxKeyCode);\
145	    return er;\
146	}\
147	else if ( (first)<(r)->minKeyCode ) {\
148	    (ev)=_XkbErrCode3(err+1,(first),(r)->minKeyCode);\
149	    return er;\
150	}\
151}
152#define	CHK_REQ_KEY_RANGE(err,first,num,r)  \
153	CHK_REQ_KEY_RANGE2(err,first,num,r,client->errorValue,BadValue)
154
155static Bool
156_XkbCheckRequestBounds(ClientPtr client, void *stuff, void *from, void *to) {
157    char *cstuff = (char *)stuff;
158    char *cfrom = (char *)from;
159    char *cto = (char *)to;
160
161    return cfrom < cto &&
162           cfrom >= cstuff &&
163           cfrom < cstuff + ((size_t)client->req_len << 2) &&
164           cto >= cstuff &&
165           cto <= cstuff + ((size_t)client->req_len << 2);
166}
167
168/***====================================================================***/
169
170int
171ProcXkbUseExtension(ClientPtr client)
172{
173    REQUEST(xkbUseExtensionReq);
174    xkbUseExtensionReply rep;
175    int supported;
176
177    REQUEST_SIZE_MATCH(xkbUseExtensionReq);
178    if (stuff->wantedMajor != SERVER_XKB_MAJOR_VERSION) {
179        /* pre-release version 0.65 is compatible with 1.00 */
180        supported = ((SERVER_XKB_MAJOR_VERSION == 1) &&
181                     (stuff->wantedMajor == 0) && (stuff->wantedMinor == 65));
182    }
183    else
184        supported = 1;
185
186    if ((supported) && (!(client->xkbClientFlags & _XkbClientInitialized))) {
187        client->xkbClientFlags = _XkbClientInitialized;
188        if (stuff->wantedMajor == 0)
189            client->xkbClientFlags |= _XkbClientIsAncient;
190    }
191    else if (xkbDebugFlags & 0x1) {
192        ErrorF
193            ("[xkb] Rejecting client %d (0x%lx) (wants %d.%02d, have %d.%02d)\n",
194             client->index, (long) client->clientAsMask, stuff->wantedMajor,
195             stuff->wantedMinor, SERVER_XKB_MAJOR_VERSION,
196             SERVER_XKB_MINOR_VERSION);
197    }
198    rep = (xkbUseExtensionReply) {
199        .type = X_Reply,
200        .supported = supported,
201        .sequenceNumber = client->sequence,
202        .length = 0,
203        .serverMajor = SERVER_XKB_MAJOR_VERSION,
204        .serverMinor = SERVER_XKB_MINOR_VERSION
205    };
206    if (client->swapped) {
207        swaps(&rep.sequenceNumber);
208        swaps(&rep.serverMajor);
209        swaps(&rep.serverMinor);
210    }
211    WriteToClient(client, SIZEOF(xkbUseExtensionReply), &rep);
212    return Success;
213}
214
215/***====================================================================***/
216
217int
218ProcXkbSelectEvents(ClientPtr client)
219{
220    unsigned legal;
221    DeviceIntPtr dev;
222    XkbInterestPtr masks;
223
224    REQUEST(xkbSelectEventsReq);
225
226    REQUEST_AT_LEAST_SIZE(xkbSelectEventsReq);
227
228    if (!(client->xkbClientFlags & _XkbClientInitialized))
229        return BadAccess;
230
231    CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixUseAccess);
232
233    if (((stuff->affectWhich & XkbMapNotifyMask) != 0) && (stuff->affectMap)) {
234        client->mapNotifyMask &= ~stuff->affectMap;
235        client->mapNotifyMask |= (stuff->affectMap & stuff->map);
236    }
237    if ((stuff->affectWhich & (~XkbMapNotifyMask)) == 0)
238        return Success;
239
240    masks = XkbFindClientResource((DevicePtr) dev, client);
241    if (!masks) {
242        XID id = FakeClientID(client->index);
243
244        if (!AddResource(id, RT_XKBCLIENT, dev))
245            return BadAlloc;
246        masks = XkbAddClientResource((DevicePtr) dev, client, id);
247    }
248    if (masks) {
249        union {
250            CARD8 *c8;
251            CARD16 *c16;
252            CARD32 *c32;
253        } from, to;
254        register unsigned bit, ndx, maskLeft, dataLeft, size;
255
256        from.c8 = (CARD8 *) &stuff[1];
257        dataLeft = (stuff->length * 4) - SIZEOF(xkbSelectEventsReq);
258        maskLeft = (stuff->affectWhich & (~XkbMapNotifyMask));
259        for (ndx = 0, bit = 1; (maskLeft != 0); ndx++, bit <<= 1) {
260            if ((bit & maskLeft) == 0)
261                continue;
262            maskLeft &= ~bit;
263            switch (ndx) {
264            case XkbNewKeyboardNotify:
265                to.c16 = &client->newKeyboardNotifyMask;
266                legal = XkbAllNewKeyboardEventsMask;
267                size = 2;
268                break;
269            case XkbStateNotify:
270                to.c16 = &masks->stateNotifyMask;
271                legal = XkbAllStateEventsMask;
272                size = 2;
273                break;
274            case XkbControlsNotify:
275                to.c32 = &masks->ctrlsNotifyMask;
276                legal = XkbAllControlEventsMask;
277                size = 4;
278                break;
279            case XkbIndicatorStateNotify:
280                to.c32 = &masks->iStateNotifyMask;
281                legal = XkbAllIndicatorEventsMask;
282                size = 4;
283                break;
284            case XkbIndicatorMapNotify:
285                to.c32 = &masks->iMapNotifyMask;
286                legal = XkbAllIndicatorEventsMask;
287                size = 4;
288                break;
289            case XkbNamesNotify:
290                to.c16 = &masks->namesNotifyMask;
291                legal = XkbAllNameEventsMask;
292                size = 2;
293                break;
294            case XkbCompatMapNotify:
295                to.c8 = &masks->compatNotifyMask;
296                legal = XkbAllCompatMapEventsMask;
297                size = 1;
298                break;
299            case XkbBellNotify:
300                to.c8 = &masks->bellNotifyMask;
301                legal = XkbAllBellEventsMask;
302                size = 1;
303                break;
304            case XkbActionMessage:
305                to.c8 = &masks->actionMessageMask;
306                legal = XkbAllActionMessagesMask;
307                size = 1;
308                break;
309            case XkbAccessXNotify:
310                to.c16 = &masks->accessXNotifyMask;
311                legal = XkbAllAccessXEventsMask;
312                size = 2;
313                break;
314            case XkbExtensionDeviceNotify:
315                to.c16 = &masks->extDevNotifyMask;
316                legal = XkbAllExtensionDeviceEventsMask;
317                size = 2;
318                break;
319            default:
320                client->errorValue = _XkbErrCode2(33, bit);
321                return BadValue;
322            }
323
324            if (stuff->clear & bit) {
325                if (size == 2)
326                    to.c16[0] = 0;
327                else if (size == 4)
328                    to.c32[0] = 0;
329                else
330                    to.c8[0] = 0;
331            }
332            else if (stuff->selectAll & bit) {
333                if (size == 2)
334                    to.c16[0] = ~0;
335                else if (size == 4)
336                    to.c32[0] = ~0;
337                else
338                    to.c8[0] = ~0;
339            }
340            else {
341                if (dataLeft < (size * 2))
342                    return BadLength;
343                if (size == 2) {
344                    CHK_MASK_MATCH(ndx, from.c16[0], from.c16[1]);
345                    CHK_MASK_LEGAL(ndx, from.c16[0], legal);
346                    to.c16[0] &= ~from.c16[0];
347                    to.c16[0] |= (from.c16[0] & from.c16[1]);
348                }
349                else if (size == 4) {
350                    CHK_MASK_MATCH(ndx, from.c32[0], from.c32[1]);
351                    CHK_MASK_LEGAL(ndx, from.c32[0], legal);
352                    to.c32[0] &= ~from.c32[0];
353                    to.c32[0] |= (from.c32[0] & from.c32[1]);
354                }
355                else {
356                    CHK_MASK_MATCH(ndx, from.c8[0], from.c8[1]);
357                    CHK_MASK_LEGAL(ndx, from.c8[0], legal);
358                    to.c8[0] &= ~from.c8[0];
359                    to.c8[0] |= (from.c8[0] & from.c8[1]);
360                    size = 2;
361                }
362                from.c8 += (size * 2);
363                dataLeft -= (size * 2);
364            }
365        }
366        if (dataLeft > 2) {
367            ErrorF("[xkb] Extra data (%d bytes) after SelectEvents\n",
368                   dataLeft);
369            return BadLength;
370        }
371        return Success;
372    }
373    return BadAlloc;
374}
375
376/***====================================================================***/
377/**
378 * Ring a bell on the given device for the given client.
379 */
380static int
381_XkbBell(ClientPtr client, DeviceIntPtr dev, WindowPtr pWin,
382         int bellClass, int bellID, int pitch, int duration,
383         int percent, int forceSound, int eventOnly, Atom name)
384{
385    int base;
386    void *ctrl;
387    int oldPitch, oldDuration;
388    int newPercent;
389
390    if (bellClass == KbdFeedbackClass) {
391        KbdFeedbackPtr k;
392
393        if (bellID == XkbDfltXIId)
394            k = dev->kbdfeed;
395        else {
396            for (k = dev->kbdfeed; k; k = k->next) {
397                if (k->ctrl.id == bellID)
398                    break;
399            }
400        }
401        if (!k) {
402            client->errorValue = _XkbErrCode2(0x5, bellID);
403            return BadValue;
404        }
405        base = k->ctrl.bell;
406        ctrl = (void *) &(k->ctrl);
407        oldPitch = k->ctrl.bell_pitch;
408        oldDuration = k->ctrl.bell_duration;
409        if (pitch != 0) {
410            if (pitch == -1)
411                k->ctrl.bell_pitch = defaultKeyboardControl.bell_pitch;
412            else
413                k->ctrl.bell_pitch = pitch;
414        }
415        if (duration != 0) {
416            if (duration == -1)
417                k->ctrl.bell_duration = defaultKeyboardControl.bell_duration;
418            else
419                k->ctrl.bell_duration = duration;
420        }
421    }
422    else if (bellClass == BellFeedbackClass) {
423        BellFeedbackPtr b;
424
425        if (bellID == XkbDfltXIId)
426            b = dev->bell;
427        else {
428            for (b = dev->bell; b; b = b->next) {
429                if (b->ctrl.id == bellID)
430                    break;
431            }
432        }
433        if (!b) {
434            client->errorValue = _XkbErrCode2(0x6, bellID);
435            return BadValue;
436        }
437        base = b->ctrl.percent;
438        ctrl = (void *) &(b->ctrl);
439        oldPitch = b->ctrl.pitch;
440        oldDuration = b->ctrl.duration;
441        if (pitch != 0) {
442            if (pitch == -1)
443                b->ctrl.pitch = defaultKeyboardControl.bell_pitch;
444            else
445                b->ctrl.pitch = pitch;
446        }
447        if (duration != 0) {
448            if (duration == -1)
449                b->ctrl.duration = defaultKeyboardControl.bell_duration;
450            else
451                b->ctrl.duration = duration;
452        }
453    }
454    else {
455        client->errorValue = _XkbErrCode2(0x7, bellClass);
456        return BadValue;
457    }
458
459    newPercent = (base * percent) / 100;
460    if (percent < 0)
461        newPercent = base + newPercent;
462    else
463        newPercent = base - newPercent + percent;
464
465    XkbHandleBell(forceSound, eventOnly,
466                  dev, newPercent, ctrl, bellClass, name, pWin, client);
467    if ((pitch != 0) || (duration != 0)) {
468        if (bellClass == KbdFeedbackClass) {
469            KbdFeedbackPtr k;
470
471            k = (KbdFeedbackPtr) ctrl;
472            if (pitch != 0)
473                k->ctrl.bell_pitch = oldPitch;
474            if (duration != 0)
475                k->ctrl.bell_duration = oldDuration;
476        }
477        else {
478            BellFeedbackPtr b;
479
480            b = (BellFeedbackPtr) ctrl;
481            if (pitch != 0)
482                b->ctrl.pitch = oldPitch;
483            if (duration != 0)
484                b->ctrl.duration = oldDuration;
485        }
486    }
487
488    return Success;
489}
490
491int
492ProcXkbBell(ClientPtr client)
493{
494    REQUEST(xkbBellReq);
495    DeviceIntPtr dev;
496    WindowPtr pWin;
497    int rc;
498
499    REQUEST_SIZE_MATCH(xkbBellReq);
500
501    if (!(client->xkbClientFlags & _XkbClientInitialized))
502        return BadAccess;
503
504    CHK_BELL_DEVICE(dev, stuff->deviceSpec, client, DixBellAccess);
505    CHK_ATOM_OR_NONE(stuff->name);
506
507    /* device-independent checks request for sane values */
508    if ((stuff->forceSound) && (stuff->eventOnly)) {
509        client->errorValue =
510            _XkbErrCode3(0x1, stuff->forceSound, stuff->eventOnly);
511        return BadMatch;
512    }
513    if (stuff->percent < -100 || stuff->percent > 100) {
514        client->errorValue = _XkbErrCode2(0x2, stuff->percent);
515        return BadValue;
516    }
517    if (stuff->duration < -1) {
518        client->errorValue = _XkbErrCode2(0x3, stuff->duration);
519        return BadValue;
520    }
521    if (stuff->pitch < -1) {
522        client->errorValue = _XkbErrCode2(0x4, stuff->pitch);
523        return BadValue;
524    }
525
526    if (stuff->bellClass == XkbDfltXIClass) {
527        if (dev->kbdfeed != NULL)
528            stuff->bellClass = KbdFeedbackClass;
529        else
530            stuff->bellClass = BellFeedbackClass;
531    }
532
533    if (stuff->window != None) {
534        rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
535        if (rc != Success) {
536            client->errorValue = stuff->window;
537            return rc;
538        }
539    }
540    else
541        pWin = NULL;
542
543    /* Client wants to ring a bell on the core keyboard?
544       Ring the bell on the core keyboard (which does nothing, but if that
545       fails the client is screwed anyway), and then on all extension devices.
546       Fail if the core keyboard fails but not the extension devices.  this
547       may cause some keyboards to ding and others to stay silent. Fix
548       your client to use explicit keyboards to avoid this.
549
550       dev is the device the client requested.
551     */
552    rc = _XkbBell(client, dev, pWin, stuff->bellClass, stuff->bellID,
553                  stuff->pitch, stuff->duration, stuff->percent,
554                  stuff->forceSound, stuff->eventOnly, stuff->name);
555
556    if ((rc == Success) && ((stuff->deviceSpec == XkbUseCoreKbd) ||
557                            (stuff->deviceSpec == XkbUseCorePtr))) {
558        DeviceIntPtr other;
559
560        for (other = inputInfo.devices; other; other = other->next) {
561            if ((other != dev) && other->key && !IsMaster(other) &&
562                GetMaster(other, MASTER_KEYBOARD) == dev) {
563                rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixBellAccess);
564                if (rc == Success)
565                    _XkbBell(client, other, pWin, stuff->bellClass,
566                             stuff->bellID, stuff->pitch, stuff->duration,
567                             stuff->percent, stuff->forceSound,
568                             stuff->eventOnly, stuff->name);
569            }
570        }
571        rc = Success;           /* reset to success, that's what we got for the VCK */
572    }
573
574    return rc;
575}
576
577/***====================================================================***/
578
579int
580ProcXkbGetState(ClientPtr client)
581{
582    REQUEST(xkbGetStateReq);
583    DeviceIntPtr dev;
584    xkbGetStateReply rep;
585    XkbStateRec *xkb;
586
587    REQUEST_SIZE_MATCH(xkbGetStateReq);
588
589    if (!(client->xkbClientFlags & _XkbClientInitialized))
590        return BadAccess;
591
592    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
593
594    xkb = &dev->key->xkbInfo->state;
595    rep = (xkbGetStateReply) {
596        .type = X_Reply,
597        .deviceID = dev->id,
598        .sequenceNumber = client->sequence,
599        .length = 0,
600        .mods = XkbStateFieldFromRec(xkb) & 0xff,
601        .baseMods = xkb->base_mods,
602        .latchedMods = xkb->latched_mods,
603        .lockedMods = xkb->locked_mods,
604        .group = xkb->group,
605        .lockedGroup = xkb->locked_group,
606        .baseGroup = xkb->base_group,
607        .latchedGroup = xkb->latched_group,
608        .compatState = xkb->compat_state,
609        .ptrBtnState = xkb->ptr_buttons
610    };
611    if (client->swapped) {
612        swaps(&rep.sequenceNumber);
613        swaps(&rep.ptrBtnState);
614    }
615    WriteToClient(client, SIZEOF(xkbGetStateReply), &rep);
616    return Success;
617}
618
619/***====================================================================***/
620
621int
622ProcXkbLatchLockState(ClientPtr client)
623{
624    int status;
625    DeviceIntPtr dev, tmpd;
626    XkbStateRec oldState, *newState;
627    CARD16 changed;
628    xkbStateNotify sn;
629    XkbEventCauseRec cause;
630
631    REQUEST(xkbLatchLockStateReq);
632    REQUEST_SIZE_MATCH(xkbLatchLockStateReq);
633
634    if (!(client->xkbClientFlags & _XkbClientInitialized))
635        return BadAccess;
636
637    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
638    CHK_MASK_MATCH(0x01, stuff->affectModLocks, stuff->modLocks);
639    CHK_MASK_MATCH(0x01, stuff->affectModLatches, stuff->modLatches);
640
641    status = Success;
642
643    for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
644        if ((tmpd == dev) ||
645            (!IsMaster(tmpd) && GetMaster(tmpd, MASTER_KEYBOARD) == dev)) {
646            if (!tmpd->key || !tmpd->key->xkbInfo)
647                continue;
648
649            oldState = tmpd->key->xkbInfo->state;
650            newState = &tmpd->key->xkbInfo->state;
651            if (stuff->affectModLocks) {
652                newState->locked_mods &= ~stuff->affectModLocks;
653                newState->locked_mods |=
654                    (stuff->affectModLocks & stuff->modLocks);
655            }
656            if (status == Success && stuff->lockGroup)
657                newState->locked_group = stuff->groupLock;
658            if (status == Success && stuff->affectModLatches)
659                status = XkbLatchModifiers(tmpd, stuff->affectModLatches,
660                                           stuff->modLatches);
661            if (status == Success && stuff->latchGroup)
662                status = XkbLatchGroup(tmpd, stuff->groupLatch);
663
664            if (status != Success)
665                return status;
666
667            XkbComputeDerivedState(tmpd->key->xkbInfo);
668
669            changed = XkbStateChangedFlags(&oldState, newState);
670            if (changed) {
671                sn.keycode = 0;
672                sn.eventType = 0;
673                sn.requestMajor = XkbReqCode;
674                sn.requestMinor = X_kbLatchLockState;
675                sn.changed = changed;
676                XkbSendStateNotify(tmpd, &sn);
677                changed = XkbIndicatorsToUpdate(tmpd, changed, FALSE);
678                if (changed) {
679                    XkbSetCauseXkbReq(&cause, X_kbLatchLockState, client);
680                    XkbUpdateIndicators(tmpd, changed, TRUE, NULL, &cause);
681                }
682            }
683        }
684    }
685
686    return Success;
687}
688
689/***====================================================================***/
690
691int
692ProcXkbGetControls(ClientPtr client)
693{
694    xkbGetControlsReply rep;
695    XkbControlsPtr xkb;
696    DeviceIntPtr dev;
697
698    REQUEST(xkbGetControlsReq);
699    REQUEST_SIZE_MATCH(xkbGetControlsReq);
700
701    if (!(client->xkbClientFlags & _XkbClientInitialized))
702        return BadAccess;
703
704    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
705
706    xkb = dev->key->xkbInfo->desc->ctrls;
707    rep = (xkbGetControlsReply) {
708        .type = X_Reply,
709        .deviceID = ((DeviceIntPtr) dev)->id,
710        .sequenceNumber = client->sequence,
711        .length = bytes_to_int32(SIZEOF(xkbGetControlsReply) -
712                                 SIZEOF(xGenericReply)),
713        .mkDfltBtn = xkb->mk_dflt_btn,
714        .numGroups = xkb->num_groups,
715        .groupsWrap = xkb->groups_wrap,
716        .internalMods = xkb->internal.mask,
717        .ignoreLockMods = xkb->ignore_lock.mask,
718        .internalRealMods = xkb->internal.real_mods,
719        .ignoreLockRealMods = xkb->ignore_lock.real_mods,
720        .internalVMods = xkb->internal.vmods,
721        .ignoreLockVMods = xkb->ignore_lock.vmods,
722        .repeatDelay = xkb->repeat_delay,
723        .repeatInterval = xkb->repeat_interval,
724        .slowKeysDelay = xkb->slow_keys_delay,
725        .debounceDelay = xkb->debounce_delay,
726        .mkDelay = xkb->mk_delay,
727        .mkInterval = xkb->mk_interval,
728        .mkTimeToMax = xkb->mk_time_to_max,
729        .mkMaxSpeed = xkb->mk_max_speed,
730        .mkCurve = xkb->mk_curve,
731        .axOptions = xkb->ax_options,
732        .axTimeout = xkb->ax_timeout,
733        .axtOptsMask = xkb->axt_opts_mask,
734        .axtOptsValues = xkb->axt_opts_values,
735        .axtCtrlsMask = xkb->axt_ctrls_mask,
736        .axtCtrlsValues = xkb->axt_ctrls_values,
737        .enabledCtrls = xkb->enabled_ctrls,
738    };
739    memcpy(rep.perKeyRepeat, xkb->per_key_repeat, XkbPerKeyBitArraySize);
740    if (client->swapped) {
741        swaps(&rep.sequenceNumber);
742        swapl(&rep.length);
743        swaps(&rep.internalVMods);
744        swaps(&rep.ignoreLockVMods);
745        swapl(&rep.enabledCtrls);
746        swaps(&rep.repeatDelay);
747        swaps(&rep.repeatInterval);
748        swaps(&rep.slowKeysDelay);
749        swaps(&rep.debounceDelay);
750        swaps(&rep.mkDelay);
751        swaps(&rep.mkInterval);
752        swaps(&rep.mkTimeToMax);
753        swaps(&rep.mkMaxSpeed);
754        swaps(&rep.mkCurve);
755        swaps(&rep.axTimeout);
756        swapl(&rep.axtCtrlsMask);
757        swapl(&rep.axtCtrlsValues);
758        swaps(&rep.axtOptsMask);
759        swaps(&rep.axtOptsValues);
760        swaps(&rep.axOptions);
761    }
762    WriteToClient(client, SIZEOF(xkbGetControlsReply), &rep);
763    return Success;
764}
765
766int
767ProcXkbSetControls(ClientPtr client)
768{
769    DeviceIntPtr dev, tmpd;
770    XkbSrvInfoPtr xkbi;
771    XkbControlsPtr ctrl;
772    XkbControlsRec new, old;
773    xkbControlsNotify cn;
774    XkbEventCauseRec cause;
775    XkbSrvLedInfoPtr sli;
776
777    REQUEST(xkbSetControlsReq);
778    REQUEST_SIZE_MATCH(xkbSetControlsReq);
779
780    if (!(client->xkbClientFlags & _XkbClientInitialized))
781        return BadAccess;
782
783    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
784    CHK_MASK_LEGAL(0x01, stuff->changeCtrls, XkbAllControlsMask);
785
786    for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
787        if (!tmpd->key || !tmpd->key->xkbInfo)
788            continue;
789        if ((tmpd == dev) ||
790            (!IsMaster(tmpd) && GetMaster(tmpd, MASTER_KEYBOARD) == dev)) {
791            xkbi = tmpd->key->xkbInfo;
792            ctrl = xkbi->desc->ctrls;
793            new = *ctrl;
794            XkbSetCauseXkbReq(&cause, X_kbSetControls, client);
795
796            if (stuff->changeCtrls & XkbInternalModsMask) {
797                CHK_MASK_MATCH(0x02, stuff->affectInternalMods,
798                               stuff->internalMods);
799                CHK_MASK_MATCH(0x03, stuff->affectInternalVMods,
800                               stuff->internalVMods);
801
802                new.internal.real_mods &= ~(stuff->affectInternalMods);
803                new.internal.real_mods |= (stuff->affectInternalMods &
804                                           stuff->internalMods);
805                new.internal.vmods &= ~(stuff->affectInternalVMods);
806                new.internal.vmods |= (stuff->affectInternalVMods &
807                                       stuff->internalVMods);
808                new.internal.mask = new.internal.real_mods |
809                    XkbMaskForVMask(xkbi->desc, new.internal.vmods);
810            }
811
812            if (stuff->changeCtrls & XkbIgnoreLockModsMask) {
813                CHK_MASK_MATCH(0x4, stuff->affectIgnoreLockMods,
814                               stuff->ignoreLockMods);
815                CHK_MASK_MATCH(0x5, stuff->affectIgnoreLockVMods,
816                               stuff->ignoreLockVMods);
817
818                new.ignore_lock.real_mods &= ~(stuff->affectIgnoreLockMods);
819                new.ignore_lock.real_mods |= (stuff->affectIgnoreLockMods &
820                                              stuff->ignoreLockMods);
821                new.ignore_lock.vmods &= ~(stuff->affectIgnoreLockVMods);
822                new.ignore_lock.vmods |= (stuff->affectIgnoreLockVMods &
823                                          stuff->ignoreLockVMods);
824                new.ignore_lock.mask = new.ignore_lock.real_mods |
825                    XkbMaskForVMask(xkbi->desc, new.ignore_lock.vmods);
826            }
827
828            CHK_MASK_MATCH(0x06, stuff->affectEnabledCtrls,
829                           stuff->enabledCtrls);
830            if (stuff->affectEnabledCtrls) {
831                CHK_MASK_LEGAL(0x07, stuff->affectEnabledCtrls,
832                               XkbAllBooleanCtrlsMask);
833
834                new.enabled_ctrls &= ~(stuff->affectEnabledCtrls);
835                new.enabled_ctrls |= (stuff->affectEnabledCtrls &
836                                      stuff->enabledCtrls);
837            }
838
839            if (stuff->changeCtrls & XkbRepeatKeysMask) {
840                if (stuff->repeatDelay < 1 || stuff->repeatInterval < 1) {
841                    client->errorValue = _XkbErrCode3(0x08, stuff->repeatDelay,
842                                                      stuff->repeatInterval);
843                    return BadValue;
844                }
845
846                new.repeat_delay = stuff->repeatDelay;
847                new.repeat_interval = stuff->repeatInterval;
848            }
849
850            if (stuff->changeCtrls & XkbSlowKeysMask) {
851                if (stuff->slowKeysDelay < 1) {
852                    client->errorValue = _XkbErrCode2(0x09,
853                                                      stuff->slowKeysDelay);
854                    return BadValue;
855                }
856
857                new.slow_keys_delay = stuff->slowKeysDelay;
858            }
859
860            if (stuff->changeCtrls & XkbBounceKeysMask) {
861                if (stuff->debounceDelay < 1) {
862                    client->errorValue = _XkbErrCode2(0x0A,
863                                                      stuff->debounceDelay);
864                    return BadValue;
865                }
866
867                new.debounce_delay = stuff->debounceDelay;
868            }
869
870            if (stuff->changeCtrls & XkbMouseKeysMask) {
871                if (stuff->mkDfltBtn > XkbMaxMouseKeysBtn) {
872                    client->errorValue = _XkbErrCode2(0x0B, stuff->mkDfltBtn);
873                    return BadValue;
874                }
875
876                new.mk_dflt_btn = stuff->mkDfltBtn;
877            }
878
879            if (stuff->changeCtrls & XkbMouseKeysAccelMask) {
880                if (stuff->mkDelay < 1 || stuff->mkInterval < 1 ||
881                    stuff->mkTimeToMax < 1 || stuff->mkMaxSpeed < 1 ||
882                    stuff->mkCurve < -1000) {
883                    client->errorValue = _XkbErrCode2(0x0C, 0);
884                    return BadValue;
885                }
886
887                new.mk_delay = stuff->mkDelay;
888                new.mk_interval = stuff->mkInterval;
889                new.mk_time_to_max = stuff->mkTimeToMax;
890                new.mk_max_speed = stuff->mkMaxSpeed;
891                new.mk_curve = stuff->mkCurve;
892                AccessXComputeCurveFactor(xkbi, &new);
893            }
894
895            if (stuff->changeCtrls & XkbGroupsWrapMask) {
896                unsigned act, num;
897
898                act = XkbOutOfRangeGroupAction(stuff->groupsWrap);
899                switch (act) {
900                case XkbRedirectIntoRange:
901                    num = XkbOutOfRangeGroupNumber(stuff->groupsWrap);
902                    if (num >= new.num_groups) {
903                        client->errorValue = _XkbErrCode3(0x0D, new.num_groups,
904                                                          num);
905                        return BadValue;
906                    }
907                case XkbWrapIntoRange:
908                case XkbClampIntoRange:
909                    break;
910                default:
911                    client->errorValue = _XkbErrCode2(0x0E, act);
912                    return BadValue;
913                }
914
915                new.groups_wrap = stuff->groupsWrap;
916            }
917
918            CHK_MASK_LEGAL(0x0F, stuff->axOptions, XkbAX_AllOptionsMask);
919            if (stuff->changeCtrls & XkbAccessXKeysMask) {
920                new.ax_options = stuff->axOptions & XkbAX_AllOptionsMask;
921            }
922            else {
923                if (stuff->changeCtrls & XkbStickyKeysMask) {
924                    new.ax_options &= ~(XkbAX_SKOptionsMask);
925                    new.ax_options |= (stuff->axOptions & XkbAX_SKOptionsMask);
926                }
927
928                if (stuff->changeCtrls & XkbAccessXFeedbackMask) {
929                    new.ax_options &= ~(XkbAX_FBOptionsMask);
930                    new.ax_options |= (stuff->axOptions & XkbAX_FBOptionsMask);
931                }
932            }
933
934            if (stuff->changeCtrls & XkbAccessXTimeoutMask) {
935                if (stuff->axTimeout < 1) {
936                    client->errorValue = _XkbErrCode2(0x10, stuff->axTimeout);
937                    return BadValue;
938                }
939                CHK_MASK_MATCH(0x11, stuff->axtCtrlsMask,
940                               stuff->axtCtrlsValues);
941                CHK_MASK_LEGAL(0x12, stuff->axtCtrlsMask,
942                               XkbAllBooleanCtrlsMask);
943                CHK_MASK_MATCH(0x13, stuff->axtOptsMask, stuff->axtOptsValues);
944                CHK_MASK_LEGAL(0x14, stuff->axtOptsMask, XkbAX_AllOptionsMask);
945                new.ax_timeout = stuff->axTimeout;
946                new.axt_ctrls_mask = stuff->axtCtrlsMask;
947                new.axt_ctrls_values = (stuff->axtCtrlsValues &
948                                        stuff->axtCtrlsMask);
949                new.axt_opts_mask = stuff->axtOptsMask;
950                new.axt_opts_values = (stuff->axtOptsValues &
951                                       stuff->axtOptsMask);
952            }
953
954            if (stuff->changeCtrls & XkbPerKeyRepeatMask) {
955                memcpy(new.per_key_repeat, stuff->perKeyRepeat,
956                       XkbPerKeyBitArraySize);
957                if (xkbi->repeatKey &&
958                    !BitIsOn(new.per_key_repeat, xkbi->repeatKey)) {
959                    AccessXCancelRepeatKey(xkbi, xkbi->repeatKey);
960                }
961            }
962
963            old = *ctrl;
964            *ctrl = new;
965            XkbDDXChangeControls(tmpd, &old, ctrl);
966
967            if (XkbComputeControlsNotify(tmpd, &old, ctrl, &cn, FALSE)) {
968                cn.keycode = 0;
969                cn.eventType = 0;
970                cn.requestMajor = XkbReqCode;
971                cn.requestMinor = X_kbSetControls;
972                XkbSendControlsNotify(tmpd, &cn);
973            }
974
975            sli = XkbFindSrvLedInfo(tmpd, XkbDfltXIClass, XkbDfltXIId, 0);
976            if (sli)
977                XkbUpdateIndicators(tmpd, sli->usesControls, TRUE, NULL,
978                                    &cause);
979
980            /* If sticky keys were disabled, clear all locks and latches */
981            if ((old.enabled_ctrls & XkbStickyKeysMask) &&
982                !(ctrl->enabled_ctrls & XkbStickyKeysMask))
983                XkbClearAllLatchesAndLocks(tmpd, xkbi, TRUE, &cause);
984        }
985    }
986
987    return Success;
988}
989
990/***====================================================================***/
991
992static int
993XkbSizeKeyTypes(XkbDescPtr xkb, xkbGetMapReply * rep)
994{
995    XkbKeyTypeRec *type;
996    unsigned i, len;
997
998    len = 0;
999    if (((rep->present & XkbKeyTypesMask) == 0) || (rep->nTypes < 1) ||
1000        (!xkb) || (!xkb->map) || (!xkb->map->types)) {
1001        rep->present &= ~XkbKeyTypesMask;
1002        rep->firstType = rep->nTypes = 0;
1003        return 0;
1004    }
1005    type = &xkb->map->types[rep->firstType];
1006    for (i = 0; i < rep->nTypes; i++, type++) {
1007        len += SIZEOF(xkbKeyTypeWireDesc);
1008        if (type->map_count > 0) {
1009            len += (type->map_count * SIZEOF(xkbKTMapEntryWireDesc));
1010            if (type->preserve)
1011                len += (type->map_count * SIZEOF(xkbModsWireDesc));
1012        }
1013    }
1014    return len;
1015}
1016
1017static char *
1018XkbWriteKeyTypes(XkbDescPtr xkb,
1019                 xkbGetMapReply * rep, char *buf, ClientPtr client)
1020{
1021    XkbKeyTypePtr type;
1022    unsigned i;
1023    xkbKeyTypeWireDesc *wire;
1024
1025    type = &xkb->map->types[rep->firstType];
1026    for (i = 0; i < rep->nTypes; i++, type++) {
1027        register unsigned n;
1028
1029        wire = (xkbKeyTypeWireDesc *) buf;
1030        wire->mask = type->mods.mask;
1031        wire->realMods = type->mods.real_mods;
1032        wire->virtualMods = type->mods.vmods;
1033        wire->numLevels = type->num_levels;
1034        wire->nMapEntries = type->map_count;
1035        wire->preserve = (type->preserve != NULL);
1036        if (client->swapped) {
1037            swaps(&wire->virtualMods);
1038        }
1039
1040        buf = (char *) &wire[1];
1041        if (wire->nMapEntries > 0) {
1042            xkbKTMapEntryWireDesc *ewire;
1043            XkbKTMapEntryPtr entry;
1044
1045            ewire = (xkbKTMapEntryWireDesc *) buf;
1046            entry = type->map;
1047            for (n = 0; n < type->map_count; n++, ewire++, entry++) {
1048                ewire->active = entry->active;
1049                ewire->mask = entry->mods.mask;
1050                ewire->level = entry->level;
1051                ewire->realMods = entry->mods.real_mods;
1052                ewire->virtualMods = entry->mods.vmods;
1053                if (client->swapped) {
1054                    swaps(&ewire->virtualMods);
1055                }
1056            }
1057            buf = (char *) ewire;
1058            if (type->preserve != NULL) {
1059                xkbModsWireDesc *pwire;
1060                XkbModsPtr preserve;
1061
1062                pwire = (xkbModsWireDesc *) buf;
1063                preserve = type->preserve;
1064                for (n = 0; n < type->map_count; n++, pwire++, preserve++) {
1065                    pwire->mask = preserve->mask;
1066                    pwire->realMods = preserve->real_mods;
1067                    pwire->virtualMods = preserve->vmods;
1068                    if (client->swapped) {
1069                        swaps(&pwire->virtualMods);
1070                    }
1071                }
1072                buf = (char *) pwire;
1073            }
1074        }
1075    }
1076    return buf;
1077}
1078
1079static int
1080XkbSizeKeySyms(XkbDescPtr xkb, xkbGetMapReply * rep)
1081{
1082    XkbSymMapPtr symMap;
1083    unsigned i, len;
1084    unsigned nSyms, nSymsThisKey;
1085
1086    if (((rep->present & XkbKeySymsMask) == 0) || (rep->nKeySyms < 1) ||
1087        (!xkb) || (!xkb->map) || (!xkb->map->key_sym_map)) {
1088        rep->present &= ~XkbKeySymsMask;
1089        rep->firstKeySym = rep->nKeySyms = 0;
1090        rep->totalSyms = 0;
1091        return 0;
1092    }
1093    len = rep->nKeySyms * SIZEOF(xkbSymMapWireDesc);
1094    symMap = &xkb->map->key_sym_map[rep->firstKeySym];
1095    for (i = nSyms = 0; i < rep->nKeySyms; i++, symMap++) {
1096        if (symMap->offset != 0) {
1097            nSymsThisKey = XkbNumGroups(symMap->group_info) * symMap->width;
1098            nSyms += nSymsThisKey;
1099        }
1100    }
1101    len += nSyms * 4;
1102    rep->totalSyms = nSyms;
1103    return len;
1104}
1105
1106static int
1107XkbSizeVirtualMods(XkbDescPtr xkb, xkbGetMapReply * rep)
1108{
1109    register unsigned i, nMods, bit;
1110
1111    if (((rep->present & XkbVirtualModsMask) == 0) || (rep->virtualMods == 0) ||
1112        (!xkb) || (!xkb->server)) {
1113        rep->present &= ~XkbVirtualModsMask;
1114        rep->virtualMods = 0;
1115        return 0;
1116    }
1117    for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
1118        if (rep->virtualMods & bit)
1119            nMods++;
1120    }
1121    return XkbPaddedSize(nMods);
1122}
1123
1124static char *
1125XkbWriteKeySyms(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
1126                ClientPtr client)
1127{
1128    register KeySym *pSym;
1129    XkbSymMapPtr symMap;
1130    xkbSymMapWireDesc *outMap;
1131    register unsigned i;
1132
1133    symMap = &xkb->map->key_sym_map[rep->firstKeySym];
1134    for (i = 0; i < rep->nKeySyms; i++, symMap++) {
1135        outMap = (xkbSymMapWireDesc *) buf;
1136        outMap->ktIndex[0] = symMap->kt_index[0];
1137        outMap->ktIndex[1] = symMap->kt_index[1];
1138        outMap->ktIndex[2] = symMap->kt_index[2];
1139        outMap->ktIndex[3] = symMap->kt_index[3];
1140        outMap->groupInfo = symMap->group_info;
1141        outMap->width = symMap->width;
1142        outMap->nSyms = symMap->width * XkbNumGroups(symMap->group_info);
1143        buf = (char *) &outMap[1];
1144        if (outMap->nSyms == 0)
1145            continue;
1146
1147        pSym = &xkb->map->syms[symMap->offset];
1148        memcpy((char *) buf, (char *) pSym, outMap->nSyms * 4);
1149        if (client->swapped) {
1150            register int nSyms = outMap->nSyms;
1151
1152            swaps(&outMap->nSyms);
1153            while (nSyms-- > 0) {
1154                swapl((int *) buf);
1155                buf += 4;
1156            }
1157        }
1158        else
1159            buf += outMap->nSyms * 4;
1160    }
1161    return buf;
1162}
1163
1164static int
1165XkbSizeKeyActions(XkbDescPtr xkb, xkbGetMapReply * rep)
1166{
1167    unsigned i, len, nActs;
1168    register KeyCode firstKey;
1169
1170    if (((rep->present & XkbKeyActionsMask) == 0) || (rep->nKeyActs < 1) ||
1171        (!xkb) || (!xkb->server) || (!xkb->server->key_acts)) {
1172        rep->present &= ~XkbKeyActionsMask;
1173        rep->firstKeyAct = rep->nKeyActs = 0;
1174        rep->totalActs = 0;
1175        return 0;
1176    }
1177    firstKey = rep->firstKeyAct;
1178    for (nActs = i = 0; i < rep->nKeyActs; i++) {
1179        if (xkb->server->key_acts[i + firstKey] != 0)
1180            nActs += XkbKeyNumActions(xkb, i + firstKey);
1181    }
1182    len = XkbPaddedSize(rep->nKeyActs) + (nActs * SIZEOF(xkbActionWireDesc));
1183    rep->totalActs = nActs;
1184    return len;
1185}
1186
1187static char *
1188XkbWriteKeyActions(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
1189                   ClientPtr client)
1190{
1191    unsigned i;
1192    CARD8 *numDesc;
1193    XkbAnyAction *actDesc;
1194
1195    numDesc = (CARD8 *) buf;
1196    for (i = 0; i < rep->nKeyActs; i++) {
1197        if (xkb->server->key_acts[i + rep->firstKeyAct] == 0)
1198            numDesc[i] = 0;
1199        else
1200            numDesc[i] = XkbKeyNumActions(xkb, (i + rep->firstKeyAct));
1201    }
1202    buf += XkbPaddedSize(rep->nKeyActs);
1203
1204    actDesc = (XkbAnyAction *) buf;
1205    for (i = 0; i < rep->nKeyActs; i++) {
1206        if (xkb->server->key_acts[i + rep->firstKeyAct] != 0) {
1207            unsigned int num;
1208
1209            num = XkbKeyNumActions(xkb, (i + rep->firstKeyAct));
1210            memcpy((char *) actDesc,
1211                   (char *) XkbKeyActionsPtr(xkb, (i + rep->firstKeyAct)),
1212                   num * SIZEOF(xkbActionWireDesc));
1213            actDesc += num;
1214        }
1215    }
1216    buf = (char *) actDesc;
1217    return buf;
1218}
1219
1220static int
1221XkbSizeKeyBehaviors(XkbDescPtr xkb, xkbGetMapReply * rep)
1222{
1223    unsigned i, len, nBhvr;
1224    XkbBehavior *bhv;
1225
1226    if (((rep->present & XkbKeyBehaviorsMask) == 0) || (rep->nKeyBehaviors < 1)
1227        || (!xkb) || (!xkb->server) || (!xkb->server->behaviors)) {
1228        rep->present &= ~XkbKeyBehaviorsMask;
1229        rep->firstKeyBehavior = rep->nKeyBehaviors = 0;
1230        rep->totalKeyBehaviors = 0;
1231        return 0;
1232    }
1233    bhv = &xkb->server->behaviors[rep->firstKeyBehavior];
1234    for (nBhvr = i = 0; i < rep->nKeyBehaviors; i++, bhv++) {
1235        if (bhv->type != XkbKB_Default)
1236            nBhvr++;
1237    }
1238    len = nBhvr * SIZEOF(xkbBehaviorWireDesc);
1239    rep->totalKeyBehaviors = nBhvr;
1240    return len;
1241}
1242
1243static char *
1244XkbWriteKeyBehaviors(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
1245                     ClientPtr client)
1246{
1247    unsigned i;
1248    xkbBehaviorWireDesc *wire;
1249    XkbBehavior *pBhvr;
1250
1251    wire = (xkbBehaviorWireDesc *) buf;
1252    pBhvr = &xkb->server->behaviors[rep->firstKeyBehavior];
1253    for (i = 0; i < rep->nKeyBehaviors; i++, pBhvr++) {
1254        if (pBhvr->type != XkbKB_Default) {
1255            wire->key = i + rep->firstKeyBehavior;
1256            wire->type = pBhvr->type;
1257            wire->data = pBhvr->data;
1258            wire++;
1259        }
1260    }
1261    buf = (char *) wire;
1262    return buf;
1263}
1264
1265static int
1266XkbSizeExplicit(XkbDescPtr xkb, xkbGetMapReply * rep)
1267{
1268    unsigned i, len, nRtrn;
1269
1270    if (((rep->present & XkbExplicitComponentsMask) == 0) ||
1271        (rep->nKeyExplicit < 1) || (!xkb) || (!xkb->server) ||
1272        (!xkb->server->explicit)) {
1273        rep->present &= ~XkbExplicitComponentsMask;
1274        rep->firstKeyExplicit = rep->nKeyExplicit = 0;
1275        rep->totalKeyExplicit = 0;
1276        return 0;
1277    }
1278    for (nRtrn = i = 0; i < rep->nKeyExplicit; i++) {
1279        if (xkb->server->explicit[i + rep->firstKeyExplicit] != 0)
1280            nRtrn++;
1281    }
1282    rep->totalKeyExplicit = nRtrn;
1283    len = XkbPaddedSize(nRtrn * 2);     /* two bytes per non-zero explicit component */
1284    return len;
1285}
1286
1287static char *
1288XkbWriteExplicit(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
1289                 ClientPtr client)
1290{
1291    unsigned i;
1292    char *start;
1293    unsigned char *pExp;
1294
1295    start = buf;
1296    pExp = &xkb->server->explicit[rep->firstKeyExplicit];
1297    for (i = 0; i < rep->nKeyExplicit; i++, pExp++) {
1298        if (*pExp != 0) {
1299            *buf++ = i + rep->firstKeyExplicit;
1300            *buf++ = *pExp;
1301        }
1302    }
1303    i = XkbPaddedSize(buf - start) - (buf - start);     /* pad to word boundary */
1304    return buf + i;
1305}
1306
1307static int
1308XkbSizeModifierMap(XkbDescPtr xkb, xkbGetMapReply * rep)
1309{
1310    unsigned i, len, nRtrn;
1311
1312    if (((rep->present & XkbModifierMapMask) == 0) || (rep->nModMapKeys < 1) ||
1313        (!xkb) || (!xkb->map) || (!xkb->map->modmap)) {
1314        rep->present &= ~XkbModifierMapMask;
1315        rep->firstModMapKey = rep->nModMapKeys = 0;
1316        rep->totalModMapKeys = 0;
1317        return 0;
1318    }
1319    for (nRtrn = i = 0; i < rep->nModMapKeys; i++) {
1320        if (xkb->map->modmap[i + rep->firstModMapKey] != 0)
1321            nRtrn++;
1322    }
1323    rep->totalModMapKeys = nRtrn;
1324    len = XkbPaddedSize(nRtrn * 2);     /* two bytes per non-zero modmap component */
1325    return len;
1326}
1327
1328static char *
1329XkbWriteModifierMap(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
1330                    ClientPtr client)
1331{
1332    unsigned i;
1333    char *start;
1334    unsigned char *pMap;
1335
1336    start = buf;
1337    pMap = &xkb->map->modmap[rep->firstModMapKey];
1338    for (i = 0; i < rep->nModMapKeys; i++, pMap++) {
1339        if (*pMap != 0) {
1340            *buf++ = i + rep->firstModMapKey;
1341            *buf++ = *pMap;
1342        }
1343    }
1344    i = XkbPaddedSize(buf - start) - (buf - start);     /* pad to word boundary */
1345    return buf + i;
1346}
1347
1348static int
1349XkbSizeVirtualModMap(XkbDescPtr xkb, xkbGetMapReply * rep)
1350{
1351    unsigned i, len, nRtrn;
1352
1353    if (((rep->present & XkbVirtualModMapMask) == 0) || (rep->nVModMapKeys < 1)
1354        || (!xkb) || (!xkb->server) || (!xkb->server->vmodmap)) {
1355        rep->present &= ~XkbVirtualModMapMask;
1356        rep->firstVModMapKey = rep->nVModMapKeys = 0;
1357        rep->totalVModMapKeys = 0;
1358        return 0;
1359    }
1360    for (nRtrn = i = 0; i < rep->nVModMapKeys; i++) {
1361        if (xkb->server->vmodmap[i + rep->firstVModMapKey] != 0)
1362            nRtrn++;
1363    }
1364    rep->totalVModMapKeys = nRtrn;
1365    len = nRtrn * SIZEOF(xkbVModMapWireDesc);
1366    return len;
1367}
1368
1369static char *
1370XkbWriteVirtualModMap(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
1371                      ClientPtr client)
1372{
1373    unsigned i;
1374    xkbVModMapWireDesc *wire;
1375    unsigned short *pMap;
1376
1377    wire = (xkbVModMapWireDesc *) buf;
1378    pMap = &xkb->server->vmodmap[rep->firstVModMapKey];
1379    for (i = 0; i < rep->nVModMapKeys; i++, pMap++) {
1380        if (*pMap != 0) {
1381            wire->key = i + rep->firstVModMapKey;
1382            wire->vmods = *pMap;
1383            wire++;
1384        }
1385    }
1386    return (char *) wire;
1387}
1388
1389static Status
1390XkbComputeGetMapReplySize(XkbDescPtr xkb, xkbGetMapReply * rep)
1391{
1392    int len;
1393
1394    rep->minKeyCode = xkb->min_key_code;
1395    rep->maxKeyCode = xkb->max_key_code;
1396    len = XkbSizeKeyTypes(xkb, rep);
1397    len += XkbSizeKeySyms(xkb, rep);
1398    len += XkbSizeKeyActions(xkb, rep);
1399    len += XkbSizeKeyBehaviors(xkb, rep);
1400    len += XkbSizeVirtualMods(xkb, rep);
1401    len += XkbSizeExplicit(xkb, rep);
1402    len += XkbSizeModifierMap(xkb, rep);
1403    len += XkbSizeVirtualModMap(xkb, rep);
1404    rep->length += (len / 4);
1405    return Success;
1406}
1407
1408static int
1409XkbSendMap(ClientPtr client, XkbDescPtr xkb, xkbGetMapReply * rep)
1410{
1411    unsigned i, len;
1412    char *desc, *start;
1413
1414    len = (rep->length * 4) - (SIZEOF(xkbGetMapReply) - SIZEOF(xGenericReply));
1415    start = desc = calloc(1, len);
1416    if (!start)
1417        return BadAlloc;
1418    if (rep->nTypes > 0)
1419        desc = XkbWriteKeyTypes(xkb, rep, desc, client);
1420    if (rep->nKeySyms > 0)
1421        desc = XkbWriteKeySyms(xkb, rep, desc, client);
1422    if (rep->nKeyActs > 0)
1423        desc = XkbWriteKeyActions(xkb, rep, desc, client);
1424    if (rep->totalKeyBehaviors > 0)
1425        desc = XkbWriteKeyBehaviors(xkb, rep, desc, client);
1426    if (rep->virtualMods) {
1427        register int sz, bit;
1428
1429        for (i = sz = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
1430            if (rep->virtualMods & bit) {
1431                desc[sz++] = xkb->server->vmods[i];
1432            }
1433        }
1434        desc += XkbPaddedSize(sz);
1435    }
1436    if (rep->totalKeyExplicit > 0)
1437        desc = XkbWriteExplicit(xkb, rep, desc, client);
1438    if (rep->totalModMapKeys > 0)
1439        desc = XkbWriteModifierMap(xkb, rep, desc, client);
1440    if (rep->totalVModMapKeys > 0)
1441        desc = XkbWriteVirtualModMap(xkb, rep, desc, client);
1442    if ((desc - start) != (len)) {
1443        ErrorF
1444            ("[xkb] BOGUS LENGTH in write keyboard desc, expected %d, got %ld\n",
1445             len, (unsigned long) (desc - start));
1446    }
1447    if (client->swapped) {
1448        swaps(&rep->sequenceNumber);
1449        swapl(&rep->length);
1450        swaps(&rep->present);
1451        swaps(&rep->totalSyms);
1452        swaps(&rep->totalActs);
1453    }
1454    WriteToClient(client, (i = SIZEOF(xkbGetMapReply)), rep);
1455    WriteToClient(client, len, start);
1456    free((char *) start);
1457    return Success;
1458}
1459
1460int
1461ProcXkbGetMap(ClientPtr client)
1462{
1463    DeviceIntPtr dev;
1464    xkbGetMapReply rep;
1465    XkbDescRec *xkb;
1466    int n, status;
1467
1468    REQUEST(xkbGetMapReq);
1469    REQUEST_SIZE_MATCH(xkbGetMapReq);
1470
1471    if (!(client->xkbClientFlags & _XkbClientInitialized))
1472        return BadAccess;
1473
1474    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
1475    CHK_MASK_OVERLAP(0x01, stuff->full, stuff->partial);
1476    CHK_MASK_LEGAL(0x02, stuff->full, XkbAllMapComponentsMask);
1477    CHK_MASK_LEGAL(0x03, stuff->partial, XkbAllMapComponentsMask);
1478
1479    xkb = dev->key->xkbInfo->desc;
1480    rep = (xkbGetMapReply) {
1481        .type = X_Reply,
1482        .deviceID = dev->id,
1483        .sequenceNumber = client->sequence,
1484        .length = (SIZEOF(xkbGetMapReply) - SIZEOF(xGenericReply)) >> 2,
1485        .present = stuff->partial | stuff->full,
1486        .minKeyCode = xkb->min_key_code,
1487        .maxKeyCode = xkb->max_key_code
1488    };
1489
1490    if (stuff->full & XkbKeyTypesMask) {
1491        rep.firstType = 0;
1492        rep.nTypes = xkb->map->num_types;
1493    }
1494    else if (stuff->partial & XkbKeyTypesMask) {
1495        if (((unsigned) stuff->firstType + stuff->nTypes) > xkb->map->num_types) {
1496            client->errorValue = _XkbErrCode4(0x04, xkb->map->num_types,
1497                                              stuff->firstType, stuff->nTypes);
1498            return BadValue;
1499        }
1500        rep.firstType = stuff->firstType;
1501        rep.nTypes = stuff->nTypes;
1502    }
1503    else
1504        rep.nTypes = 0;
1505    rep.totalTypes = xkb->map->num_types;
1506
1507    n = XkbNumKeys(xkb);
1508    if (stuff->full & XkbKeySymsMask) {
1509        rep.firstKeySym = xkb->min_key_code;
1510        rep.nKeySyms = n;
1511    }
1512    else if (stuff->partial & XkbKeySymsMask) {
1513        CHK_KEY_RANGE(0x05, stuff->firstKeySym, stuff->nKeySyms, xkb);
1514        rep.firstKeySym = stuff->firstKeySym;
1515        rep.nKeySyms = stuff->nKeySyms;
1516    }
1517    else
1518        rep.nKeySyms = 0;
1519    rep.totalSyms = 0;
1520
1521    if (stuff->full & XkbKeyActionsMask) {
1522        rep.firstKeyAct = xkb->min_key_code;
1523        rep.nKeyActs = n;
1524    }
1525    else if (stuff->partial & XkbKeyActionsMask) {
1526        CHK_KEY_RANGE(0x07, stuff->firstKeyAct, stuff->nKeyActs, xkb);
1527        rep.firstKeyAct = stuff->firstKeyAct;
1528        rep.nKeyActs = stuff->nKeyActs;
1529    }
1530    else
1531        rep.nKeyActs = 0;
1532    rep.totalActs = 0;
1533
1534    if (stuff->full & XkbKeyBehaviorsMask) {
1535        rep.firstKeyBehavior = xkb->min_key_code;
1536        rep.nKeyBehaviors = n;
1537    }
1538    else if (stuff->partial & XkbKeyBehaviorsMask) {
1539        CHK_KEY_RANGE(0x09, stuff->firstKeyBehavior, stuff->nKeyBehaviors, xkb);
1540        rep.firstKeyBehavior = stuff->firstKeyBehavior;
1541        rep.nKeyBehaviors = stuff->nKeyBehaviors;
1542    }
1543    else
1544        rep.nKeyBehaviors = 0;
1545    rep.totalKeyBehaviors = 0;
1546
1547    if (stuff->full & XkbVirtualModsMask)
1548        rep.virtualMods = ~0;
1549    else if (stuff->partial & XkbVirtualModsMask)
1550        rep.virtualMods = stuff->virtualMods;
1551
1552    if (stuff->full & XkbExplicitComponentsMask) {
1553        rep.firstKeyExplicit = xkb->min_key_code;
1554        rep.nKeyExplicit = n;
1555    }
1556    else if (stuff->partial & XkbExplicitComponentsMask) {
1557        CHK_KEY_RANGE(0x0B, stuff->firstKeyExplicit, stuff->nKeyExplicit, xkb);
1558        rep.firstKeyExplicit = stuff->firstKeyExplicit;
1559        rep.nKeyExplicit = stuff->nKeyExplicit;
1560    }
1561    else
1562        rep.nKeyExplicit = 0;
1563    rep.totalKeyExplicit = 0;
1564
1565    if (stuff->full & XkbModifierMapMask) {
1566        rep.firstModMapKey = xkb->min_key_code;
1567        rep.nModMapKeys = n;
1568    }
1569    else if (stuff->partial & XkbModifierMapMask) {
1570        CHK_KEY_RANGE(0x0D, stuff->firstModMapKey, stuff->nModMapKeys, xkb);
1571        rep.firstModMapKey = stuff->firstModMapKey;
1572        rep.nModMapKeys = stuff->nModMapKeys;
1573    }
1574    else
1575        rep.nModMapKeys = 0;
1576    rep.totalModMapKeys = 0;
1577
1578    if (stuff->full & XkbVirtualModMapMask) {
1579        rep.firstVModMapKey = xkb->min_key_code;
1580        rep.nVModMapKeys = n;
1581    }
1582    else if (stuff->partial & XkbVirtualModMapMask) {
1583        CHK_KEY_RANGE(0x0F, stuff->firstVModMapKey, stuff->nVModMapKeys, xkb);
1584        rep.firstVModMapKey = stuff->firstVModMapKey;
1585        rep.nVModMapKeys = stuff->nVModMapKeys;
1586    }
1587    else
1588        rep.nVModMapKeys = 0;
1589    rep.totalVModMapKeys = 0;
1590
1591    if ((status = XkbComputeGetMapReplySize(xkb, &rep)) != Success)
1592        return status;
1593    return XkbSendMap(client, xkb, &rep);
1594}
1595
1596/***====================================================================***/
1597
1598static int
1599CheckKeyTypes(ClientPtr client,
1600              XkbDescPtr xkb,
1601              xkbSetMapReq * req,
1602              xkbKeyTypeWireDesc ** wireRtrn,
1603              int *nMapsRtrn, CARD8 *mapWidthRtrn, Bool doswap)
1604{
1605    unsigned nMaps;
1606    register unsigned i, n;
1607    register CARD8 *map;
1608    register xkbKeyTypeWireDesc *wire = *wireRtrn;
1609
1610    if (req->firstType > ((unsigned) xkb->map->num_types)) {
1611        *nMapsRtrn = _XkbErrCode3(0x01, req->firstType, xkb->map->num_types);
1612        return 0;
1613    }
1614    if (req->flags & XkbSetMapResizeTypes) {
1615        nMaps = req->firstType + req->nTypes;
1616        if (nMaps < XkbNumRequiredTypes) {      /* canonical types must be there */
1617            *nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes, 4);
1618            return 0;
1619        }
1620    }
1621    else if (req->present & XkbKeyTypesMask) {
1622        nMaps = xkb->map->num_types;
1623        if ((req->firstType + req->nTypes) > nMaps) {
1624            *nMapsRtrn = req->firstType + req->nTypes;
1625            return 0;
1626        }
1627    }
1628    else {
1629        *nMapsRtrn = xkb->map->num_types;
1630        for (i = 0; i < xkb->map->num_types; i++) {
1631            mapWidthRtrn[i] = xkb->map->types[i].num_levels;
1632        }
1633        return 1;
1634    }
1635
1636    for (i = 0; i < req->firstType; i++) {
1637        mapWidthRtrn[i] = xkb->map->types[i].num_levels;
1638    }
1639    for (i = 0; i < req->nTypes; i++) {
1640        unsigned width;
1641
1642        if (client->swapped && doswap) {
1643            swaps(&wire->virtualMods);
1644        }
1645        n = i + req->firstType;
1646        width = wire->numLevels;
1647        if (width < 1) {
1648            *nMapsRtrn = _XkbErrCode3(0x04, n, width);
1649            return 0;
1650        }
1651        else if ((n == XkbOneLevelIndex) && (width != 1)) {     /* must be width 1 */
1652            *nMapsRtrn = _XkbErrCode3(0x05, n, width);
1653            return 0;
1654        }
1655        else if ((width != 2) &&
1656                 ((n == XkbTwoLevelIndex) || (n == XkbKeypadIndex) ||
1657                  (n == XkbAlphabeticIndex))) {
1658            /* TWO_LEVEL, ALPHABETIC and KEYPAD must be width 2 */
1659            *nMapsRtrn = _XkbErrCode3(0x05, n, width);
1660            return 0;
1661        }
1662        if (wire->nMapEntries > 0) {
1663            xkbKTSetMapEntryWireDesc *mapWire;
1664            xkbModsWireDesc *preWire;
1665
1666            mapWire = (xkbKTSetMapEntryWireDesc *) &wire[1];
1667            preWire = (xkbModsWireDesc *) &mapWire[wire->nMapEntries];
1668            for (n = 0; n < wire->nMapEntries; n++) {
1669                if (client->swapped && doswap) {
1670                    swaps(&mapWire[n].virtualMods);
1671                }
1672                if (mapWire[n].realMods & (~wire->realMods)) {
1673                    *nMapsRtrn = _XkbErrCode4(0x06, n, mapWire[n].realMods,
1674                                              wire->realMods);
1675                    return 0;
1676                }
1677                if (mapWire[n].virtualMods & (~wire->virtualMods)) {
1678                    *nMapsRtrn = _XkbErrCode3(0x07, n, mapWire[n].virtualMods);
1679                    return 0;
1680                }
1681                if (mapWire[n].level >= wire->numLevels) {
1682                    *nMapsRtrn = _XkbErrCode4(0x08, n, wire->numLevels,
1683                                              mapWire[n].level);
1684                    return 0;
1685                }
1686                if (wire->preserve) {
1687                    if (client->swapped && doswap) {
1688                        swaps(&preWire[n].virtualMods);
1689                    }
1690                    if (preWire[n].realMods & (~mapWire[n].realMods)) {
1691                        *nMapsRtrn = _XkbErrCode4(0x09, n, preWire[n].realMods,
1692                                                  mapWire[n].realMods);
1693                        return 0;
1694                    }
1695                    if (preWire[n].virtualMods & (~mapWire[n].virtualMods)) {
1696                        *nMapsRtrn =
1697                            _XkbErrCode3(0x0a, n, preWire[n].virtualMods);
1698                        return 0;
1699                    }
1700                }
1701            }
1702            if (wire->preserve)
1703                map = (CARD8 *) &preWire[wire->nMapEntries];
1704            else
1705                map = (CARD8 *) &mapWire[wire->nMapEntries];
1706        }
1707        else
1708            map = (CARD8 *) &wire[1];
1709        mapWidthRtrn[i + req->firstType] = wire->numLevels;
1710        wire = (xkbKeyTypeWireDesc *) map;
1711    }
1712    for (i = req->firstType + req->nTypes; i < nMaps; i++) {
1713        mapWidthRtrn[i] = xkb->map->types[i].num_levels;
1714    }
1715    *nMapsRtrn = nMaps;
1716    *wireRtrn = wire;
1717    return 1;
1718}
1719
1720static int
1721CheckKeySyms(ClientPtr client,
1722             XkbDescPtr xkb,
1723             xkbSetMapReq * req,
1724             int nTypes,
1725             CARD8 *mapWidths,
1726             CARD16 *symsPerKey, xkbSymMapWireDesc ** wireRtrn, int *errorRtrn, Bool doswap)
1727{
1728    register unsigned i;
1729    XkbSymMapPtr map;
1730    xkbSymMapWireDesc *wire = *wireRtrn;
1731
1732    if (!(XkbKeySymsMask & req->present))
1733        return 1;
1734    CHK_REQ_KEY_RANGE2(0x11, req->firstKeySym, req->nKeySyms, req, (*errorRtrn),
1735                       0);
1736    for (i = 0; i < req->nKeySyms; i++) {
1737        KeySym *pSyms;
1738        register unsigned nG;
1739
1740        if (client->swapped && doswap) {
1741            swaps(&wire->nSyms);
1742        }
1743        nG = XkbNumGroups(wire->groupInfo);
1744        if (nG > XkbNumKbdGroups) {
1745            *errorRtrn = _XkbErrCode3(0x14, i + req->firstKeySym, nG);
1746            return 0;
1747        }
1748        if (nG > 0) {
1749            register int g, w;
1750
1751            for (g = w = 0; g < nG; g++) {
1752                if (wire->ktIndex[g] >= (unsigned) nTypes) {
1753                    *errorRtrn = _XkbErrCode4(0x15, i + req->firstKeySym, g,
1754                                              wire->ktIndex[g]);
1755                    return 0;
1756                }
1757                if (mapWidths[wire->ktIndex[g]] > w)
1758                    w = mapWidths[wire->ktIndex[g]];
1759            }
1760            if (wire->width != w) {
1761                *errorRtrn =
1762                    _XkbErrCode3(0x16, i + req->firstKeySym, wire->width);
1763                return 0;
1764            }
1765            w *= nG;
1766            symsPerKey[i + req->firstKeySym] = w;
1767            if (w != wire->nSyms) {
1768                *errorRtrn =
1769                    _XkbErrCode4(0x16, i + req->firstKeySym, wire->nSyms, w);
1770                return 0;
1771            }
1772        }
1773        else if (wire->nSyms != 0) {
1774            *errorRtrn = _XkbErrCode3(0x17, i + req->firstKeySym, wire->nSyms);
1775            return 0;
1776        }
1777        pSyms = (KeySym *) &wire[1];
1778        wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms];
1779    }
1780
1781    map = &xkb->map->key_sym_map[i];
1782    for (; i <= (unsigned) xkb->max_key_code; i++, map++) {
1783        register int g, nG, w;
1784
1785        nG = XkbKeyNumGroups(xkb, i);
1786        for (w = g = 0; g < nG; g++) {
1787            if (map->kt_index[g] >= (unsigned) nTypes) {
1788                *errorRtrn = _XkbErrCode4(0x18, i, g, map->kt_index[g]);
1789                return 0;
1790            }
1791            if (mapWidths[map->kt_index[g]] > w)
1792                w = mapWidths[map->kt_index[g]];
1793        }
1794        symsPerKey[i] = w * nG;
1795    }
1796    *wireRtrn = wire;
1797    return 1;
1798}
1799
1800static int
1801CheckKeyActions(XkbDescPtr xkb,
1802                xkbSetMapReq * req,
1803                int nTypes,
1804                CARD8 *mapWidths,
1805                CARD16 *symsPerKey, CARD8 **wireRtrn, int *nActsRtrn)
1806{
1807    int nActs;
1808    CARD8 *wire = *wireRtrn;
1809    register unsigned i;
1810
1811    if (!(XkbKeyActionsMask & req->present))
1812        return 1;
1813    CHK_REQ_KEY_RANGE2(0x21, req->firstKeyAct, req->nKeyActs, req, (*nActsRtrn),
1814                       0);
1815    for (nActs = i = 0; i < req->nKeyActs; i++) {
1816        if (wire[0] != 0) {
1817            if (wire[0] == symsPerKey[i + req->firstKeyAct])
1818                nActs += wire[0];
1819            else {
1820                *nActsRtrn = _XkbErrCode3(0x23, i + req->firstKeyAct, wire[0]);
1821                return 0;
1822            }
1823        }
1824        wire++;
1825    }
1826    if (req->nKeyActs % 4)
1827        wire += 4 - (req->nKeyActs % 4);
1828    *wireRtrn = (CARD8 *) (((XkbAnyAction *) wire) + nActs);
1829    *nActsRtrn = nActs;
1830    return 1;
1831}
1832
1833static int
1834CheckKeyBehaviors(XkbDescPtr xkb,
1835                  xkbSetMapReq * req,
1836                  xkbBehaviorWireDesc ** wireRtrn, int *errorRtrn)
1837{
1838    register xkbBehaviorWireDesc *wire = *wireRtrn;
1839    register XkbServerMapPtr server = xkb->server;
1840    register unsigned i;
1841    unsigned first, last;
1842
1843    if (((req->present & XkbKeyBehaviorsMask) == 0) || (req->nKeyBehaviors < 1)) {
1844        req->present &= ~XkbKeyBehaviorsMask;
1845        req->nKeyBehaviors = 0;
1846        return 1;
1847    }
1848    first = req->firstKeyBehavior;
1849    last = req->firstKeyBehavior + req->nKeyBehaviors - 1;
1850    if (first < req->minKeyCode) {
1851        *errorRtrn = _XkbErrCode3(0x31, first, req->minKeyCode);
1852        return 0;
1853    }
1854    if (last > req->maxKeyCode) {
1855        *errorRtrn = _XkbErrCode3(0x32, last, req->maxKeyCode);
1856        return 0;
1857    }
1858
1859    for (i = 0; i < req->totalKeyBehaviors; i++, wire++) {
1860        if ((wire->key < first) || (wire->key > last)) {
1861            *errorRtrn = _XkbErrCode4(0x33, first, last, wire->key);
1862            return 0;
1863        }
1864        if ((wire->type & XkbKB_Permanent) &&
1865            ((server->behaviors[wire->key].type != wire->type) ||
1866             (server->behaviors[wire->key].data != wire->data))) {
1867            *errorRtrn = _XkbErrCode3(0x33, wire->key, wire->type);
1868            return 0;
1869        }
1870        if ((wire->type == XkbKB_RadioGroup) &&
1871            ((wire->data & (~XkbKB_RGAllowNone)) > XkbMaxRadioGroups)) {
1872            *errorRtrn = _XkbErrCode4(0x34, wire->key, wire->data,
1873                                      XkbMaxRadioGroups);
1874            return 0;
1875        }
1876        if ((wire->type == XkbKB_Overlay1) || (wire->type == XkbKB_Overlay2)) {
1877            CHK_KEY_RANGE2(0x35, wire->key, 1, xkb, *errorRtrn, 0);
1878        }
1879    }
1880    *wireRtrn = wire;
1881    return 1;
1882}
1883
1884static int
1885CheckVirtualMods(XkbDescRec * xkb,
1886                 xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn)
1887{
1888    register CARD8 *wire = *wireRtrn;
1889    register unsigned i, nMods, bit;
1890
1891    if (((req->present & XkbVirtualModsMask) == 0) || (req->virtualMods == 0))
1892        return 1;
1893    for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
1894        if (req->virtualMods & bit)
1895            nMods++;
1896    }
1897    *wireRtrn = (wire + XkbPaddedSize(nMods));
1898    return 1;
1899}
1900
1901static int
1902CheckKeyExplicit(XkbDescPtr xkb,
1903                 xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn)
1904{
1905    register CARD8 *wire = *wireRtrn;
1906    CARD8 *start;
1907    register unsigned i;
1908    int first, last;
1909
1910    if (((req->present & XkbExplicitComponentsMask) == 0) ||
1911        (req->nKeyExplicit < 1)) {
1912        req->present &= ~XkbExplicitComponentsMask;
1913        req->nKeyExplicit = 0;
1914        return 1;
1915    }
1916    first = req->firstKeyExplicit;
1917    last = first + req->nKeyExplicit - 1;
1918    if (first < req->minKeyCode) {
1919        *errorRtrn = _XkbErrCode3(0x51, first, req->minKeyCode);
1920        return 0;
1921    }
1922    if (last > req->maxKeyCode) {
1923        *errorRtrn = _XkbErrCode3(0x52, last, req->maxKeyCode);
1924        return 0;
1925    }
1926    start = wire;
1927    for (i = 0; i < req->totalKeyExplicit; i++, wire += 2) {
1928        if ((wire[0] < first) || (wire[0] > last)) {
1929            *errorRtrn = _XkbErrCode4(0x53, first, last, wire[0]);
1930            return 0;
1931        }
1932        if (wire[1] & (~XkbAllExplicitMask)) {
1933            *errorRtrn = _XkbErrCode3(0x52, ~XkbAllExplicitMask, wire[1]);
1934            return 0;
1935        }
1936    }
1937    wire += XkbPaddedSize(wire - start) - (wire - start);
1938    *wireRtrn = wire;
1939    return 1;
1940}
1941
1942static int
1943CheckModifierMap(XkbDescPtr xkb, xkbSetMapReq * req, CARD8 **wireRtrn,
1944                 int *errRtrn)
1945{
1946    register CARD8 *wire = *wireRtrn;
1947    CARD8 *start;
1948    register unsigned i;
1949    int first, last;
1950
1951    if (((req->present & XkbModifierMapMask) == 0) || (req->nModMapKeys < 1)) {
1952        req->present &= ~XkbModifierMapMask;
1953        req->nModMapKeys = 0;
1954        return 1;
1955    }
1956    first = req->firstModMapKey;
1957    last = first + req->nModMapKeys - 1;
1958    if (first < req->minKeyCode) {
1959        *errRtrn = _XkbErrCode3(0x61, first, req->minKeyCode);
1960        return 0;
1961    }
1962    if (last > req->maxKeyCode) {
1963        *errRtrn = _XkbErrCode3(0x62, last, req->maxKeyCode);
1964        return 0;
1965    }
1966    start = wire;
1967    for (i = 0; i < req->totalModMapKeys; i++, wire += 2) {
1968        if ((wire[0] < first) || (wire[0] > last)) {
1969            *errRtrn = _XkbErrCode4(0x63, first, last, wire[0]);
1970            return 0;
1971        }
1972    }
1973    wire += XkbPaddedSize(wire - start) - (wire - start);
1974    *wireRtrn = wire;
1975    return 1;
1976}
1977
1978static int
1979CheckVirtualModMap(XkbDescPtr xkb,
1980                   xkbSetMapReq * req,
1981                   xkbVModMapWireDesc ** wireRtrn, int *errRtrn)
1982{
1983    register xkbVModMapWireDesc *wire = *wireRtrn;
1984    register unsigned i;
1985    int first, last;
1986
1987    if (((req->present & XkbVirtualModMapMask) == 0) || (req->nVModMapKeys < 1)) {
1988        req->present &= ~XkbVirtualModMapMask;
1989        req->nVModMapKeys = 0;
1990        return 1;
1991    }
1992    first = req->firstVModMapKey;
1993    last = first + req->nVModMapKeys - 1;
1994    if (first < req->minKeyCode) {
1995        *errRtrn = _XkbErrCode3(0x71, first, req->minKeyCode);
1996        return 0;
1997    }
1998    if (last > req->maxKeyCode) {
1999        *errRtrn = _XkbErrCode3(0x72, last, req->maxKeyCode);
2000        return 0;
2001    }
2002    for (i = 0; i < req->totalVModMapKeys; i++, wire++) {
2003        if ((wire->key < first) || (wire->key > last)) {
2004            *errRtrn = _XkbErrCode4(0x73, first, last, wire->key);
2005            return 0;
2006        }
2007    }
2008    *wireRtrn = wire;
2009    return 1;
2010}
2011
2012static char *
2013SetKeyTypes(XkbDescPtr xkb,
2014            xkbSetMapReq * req,
2015            xkbKeyTypeWireDesc * wire, XkbChangesPtr changes)
2016{
2017    register unsigned i;
2018    unsigned first, last;
2019    CARD8 *map;
2020
2021    if ((unsigned) (req->firstType + req->nTypes) > xkb->map->size_types) {
2022        i = req->firstType + req->nTypes;
2023        if (XkbAllocClientMap(xkb, XkbKeyTypesMask, i) != Success) {
2024            return NULL;
2025        }
2026    }
2027    if ((unsigned) (req->firstType + req->nTypes) > xkb->map->num_types)
2028        xkb->map->num_types = req->firstType + req->nTypes;
2029
2030    for (i = 0; i < req->nTypes; i++) {
2031        XkbKeyTypePtr pOld;
2032        register unsigned n;
2033
2034        if (XkbResizeKeyType(xkb, i + req->firstType, wire->nMapEntries,
2035                             wire->preserve, wire->numLevels) != Success) {
2036            return NULL;
2037        }
2038        pOld = &xkb->map->types[i + req->firstType];
2039        map = (CARD8 *) &wire[1];
2040
2041        pOld->mods.real_mods = wire->realMods;
2042        pOld->mods.vmods = wire->virtualMods;
2043        pOld->num_levels = wire->numLevels;
2044        pOld->map_count = wire->nMapEntries;
2045
2046        pOld->mods.mask = pOld->mods.real_mods |
2047            XkbMaskForVMask(xkb, pOld->mods.vmods);
2048
2049        if (wire->nMapEntries) {
2050            xkbKTSetMapEntryWireDesc *mapWire;
2051            xkbModsWireDesc *preWire;
2052            unsigned tmp;
2053
2054            mapWire = (xkbKTSetMapEntryWireDesc *) map;
2055            preWire = (xkbModsWireDesc *) &mapWire[wire->nMapEntries];
2056            for (n = 0; n < wire->nMapEntries; n++) {
2057                pOld->map[n].active = 1;
2058                pOld->map[n].mods.mask = mapWire[n].realMods;
2059                pOld->map[n].mods.real_mods = mapWire[n].realMods;
2060                pOld->map[n].mods.vmods = mapWire[n].virtualMods;
2061                pOld->map[n].level = mapWire[n].level;
2062                if (mapWire[n].virtualMods != 0) {
2063                    tmp = XkbMaskForVMask(xkb, mapWire[n].virtualMods);
2064                    pOld->map[n].active = (tmp != 0);
2065                    pOld->map[n].mods.mask |= tmp;
2066                }
2067                if (wire->preserve) {
2068                    pOld->preserve[n].real_mods = preWire[n].realMods;
2069                    pOld->preserve[n].vmods = preWire[n].virtualMods;
2070                    tmp = XkbMaskForVMask(xkb, preWire[n].virtualMods);
2071                    pOld->preserve[n].mask = preWire[n].realMods | tmp;
2072                }
2073            }
2074            if (wire->preserve)
2075                map = (CARD8 *) &preWire[wire->nMapEntries];
2076            else
2077                map = (CARD8 *) &mapWire[wire->nMapEntries];
2078        }
2079        else
2080            map = (CARD8 *) &wire[1];
2081        wire = (xkbKeyTypeWireDesc *) map;
2082    }
2083    first = req->firstType;
2084    last = first + req->nTypes - 1;     /* last changed type */
2085    if (changes->map.changed & XkbKeyTypesMask) {
2086        int oldLast;
2087
2088        oldLast = changes->map.first_type + changes->map.num_types - 1;
2089        if (changes->map.first_type < first)
2090            first = changes->map.first_type;
2091        if (oldLast > last)
2092            last = oldLast;
2093    }
2094    changes->map.changed |= XkbKeyTypesMask;
2095    changes->map.first_type = first;
2096    changes->map.num_types = (last - first) + 1;
2097    return (char *) wire;
2098}
2099
2100static char *
2101SetKeySyms(ClientPtr client,
2102           XkbDescPtr xkb,
2103           xkbSetMapReq * req,
2104           xkbSymMapWireDesc * wire, XkbChangesPtr changes, DeviceIntPtr dev)
2105{
2106    register unsigned i, s;
2107    XkbSymMapPtr oldMap;
2108    KeySym *newSyms;
2109    KeySym *pSyms;
2110    unsigned first, last;
2111
2112    oldMap = &xkb->map->key_sym_map[req->firstKeySym];
2113    for (i = 0; i < req->nKeySyms; i++, oldMap++) {
2114        pSyms = (KeySym *) &wire[1];
2115        if (wire->nSyms > 0) {
2116            newSyms = XkbResizeKeySyms(xkb, i + req->firstKeySym, wire->nSyms);
2117            for (s = 0; s < wire->nSyms; s++) {
2118                newSyms[s] = pSyms[s];
2119            }
2120            if (client->swapped) {
2121                for (s = 0; s < wire->nSyms; s++) {
2122                    swapl(&newSyms[s]);
2123                }
2124            }
2125        }
2126        if (XkbKeyHasActions(xkb, i + req->firstKeySym))
2127            XkbResizeKeyActions(xkb, i + req->firstKeySym,
2128                                XkbNumGroups(wire->groupInfo) * wire->width);
2129        oldMap->kt_index[0] = wire->ktIndex[0];
2130        oldMap->kt_index[1] = wire->ktIndex[1];
2131        oldMap->kt_index[2] = wire->ktIndex[2];
2132        oldMap->kt_index[3] = wire->ktIndex[3];
2133        oldMap->group_info = wire->groupInfo;
2134        oldMap->width = wire->width;
2135        wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms];
2136    }
2137    first = req->firstKeySym;
2138    last = first + req->nKeySyms - 1;
2139    if (changes->map.changed & XkbKeySymsMask) {
2140        int oldLast =
2141            (changes->map.first_key_sym + changes->map.num_key_syms - 1);
2142        if (changes->map.first_key_sym < first)
2143            first = changes->map.first_key_sym;
2144        if (oldLast > last)
2145            last = oldLast;
2146    }
2147    changes->map.changed |= XkbKeySymsMask;
2148    changes->map.first_key_sym = first;
2149    changes->map.num_key_syms = (last - first + 1);
2150
2151    s = 0;
2152    for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
2153        if (XkbKeyNumGroups(xkb, i) > s)
2154            s = XkbKeyNumGroups(xkb, i);
2155    }
2156    if (s != xkb->ctrls->num_groups) {
2157        xkbControlsNotify cn;
2158        XkbControlsRec old;
2159
2160        cn.keycode = 0;
2161        cn.eventType = 0;
2162        cn.requestMajor = XkbReqCode;
2163        cn.requestMinor = X_kbSetMap;
2164        old = *xkb->ctrls;
2165        xkb->ctrls->num_groups = s;
2166        if (XkbComputeControlsNotify(dev, &old, xkb->ctrls, &cn, FALSE))
2167            XkbSendControlsNotify(dev, &cn);
2168    }
2169    return (char *) wire;
2170}
2171
2172static char *
2173SetKeyActions(XkbDescPtr xkb,
2174              xkbSetMapReq * req, CARD8 *wire, XkbChangesPtr changes)
2175{
2176    register unsigned i, first, last;
2177    CARD8 *nActs = wire;
2178    XkbAction *newActs;
2179
2180    wire += XkbPaddedSize(req->nKeyActs);
2181    for (i = 0; i < req->nKeyActs; i++) {
2182        if (nActs[i] == 0)
2183            xkb->server->key_acts[i + req->firstKeyAct] = 0;
2184        else {
2185            newActs = XkbResizeKeyActions(xkb, i + req->firstKeyAct, nActs[i]);
2186            memcpy((char *) newActs, (char *) wire,
2187                   nActs[i] * SIZEOF(xkbActionWireDesc));
2188            wire += nActs[i] * SIZEOF(xkbActionWireDesc);
2189        }
2190    }
2191    first = req->firstKeyAct;
2192    last = (first + req->nKeyActs - 1);
2193    if (changes->map.changed & XkbKeyActionsMask) {
2194        int oldLast;
2195
2196        oldLast = changes->map.first_key_act + changes->map.num_key_acts - 1;
2197        if (changes->map.first_key_act < first)
2198            first = changes->map.first_key_act;
2199        if (oldLast > last)
2200            last = oldLast;
2201    }
2202    changes->map.changed |= XkbKeyActionsMask;
2203    changes->map.first_key_act = first;
2204    changes->map.num_key_acts = (last - first + 1);
2205    return (char *) wire;
2206}
2207
2208static char *
2209SetKeyBehaviors(XkbSrvInfoPtr xkbi,
2210                xkbSetMapReq * req,
2211                xkbBehaviorWireDesc * wire, XkbChangesPtr changes)
2212{
2213    register unsigned i;
2214    int maxRG = -1;
2215    XkbDescPtr xkb = xkbi->desc;
2216    XkbServerMapPtr server = xkb->server;
2217    unsigned first, last;
2218
2219    first = req->firstKeyBehavior;
2220    last = req->firstKeyBehavior + req->nKeyBehaviors - 1;
2221    memset(&server->behaviors[first], 0,
2222           req->nKeyBehaviors * sizeof(XkbBehavior));
2223    for (i = 0; i < req->totalKeyBehaviors; i++) {
2224        if ((server->behaviors[wire->key].type & XkbKB_Permanent) == 0) {
2225            server->behaviors[wire->key].type = wire->type;
2226            server->behaviors[wire->key].data = wire->data;
2227            if ((wire->type == XkbKB_RadioGroup) &&
2228                (((int) wire->data) > maxRG))
2229                maxRG = wire->data + 1;
2230        }
2231        wire++;
2232    }
2233
2234    if (maxRG > (int) xkbi->nRadioGroups) {
2235        if (xkbi->radioGroups)
2236            xkbi->radioGroups = reallocarray(xkbi->radioGroups, maxRG,
2237                                             sizeof(XkbRadioGroupRec));
2238        else
2239            xkbi->radioGroups = calloc(maxRG, sizeof(XkbRadioGroupRec));
2240        if (xkbi->radioGroups) {
2241            if (xkbi->nRadioGroups)
2242                memset(&xkbi->radioGroups[xkbi->nRadioGroups], 0,
2243                       (maxRG - xkbi->nRadioGroups) * sizeof(XkbRadioGroupRec));
2244            xkbi->nRadioGroups = maxRG;
2245        }
2246        else
2247            xkbi->nRadioGroups = 0;
2248        /* should compute members here */
2249    }
2250    if (changes->map.changed & XkbKeyBehaviorsMask) {
2251        unsigned oldLast;
2252
2253        oldLast = changes->map.first_key_behavior +
2254            changes->map.num_key_behaviors - 1;
2255        if (changes->map.first_key_behavior < req->firstKeyBehavior)
2256            first = changes->map.first_key_behavior;
2257        if (oldLast > last)
2258            last = oldLast;
2259    }
2260    changes->map.changed |= XkbKeyBehaviorsMask;
2261    changes->map.first_key_behavior = first;
2262    changes->map.num_key_behaviors = (last - first + 1);
2263    return (char *) wire;
2264}
2265
2266static char *
2267SetVirtualMods(XkbSrvInfoPtr xkbi, xkbSetMapReq * req, CARD8 *wire,
2268               XkbChangesPtr changes)
2269{
2270    register int i, bit, nMods;
2271    XkbServerMapPtr srv = xkbi->desc->server;
2272
2273    if (((req->present & XkbVirtualModsMask) == 0) || (req->virtualMods == 0))
2274        return (char *) wire;
2275    for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
2276        if (req->virtualMods & bit) {
2277            if (srv->vmods[i] != wire[nMods]) {
2278                changes->map.changed |= XkbVirtualModsMask;
2279                changes->map.vmods |= bit;
2280                srv->vmods[i] = wire[nMods];
2281            }
2282            nMods++;
2283        }
2284    }
2285    return (char *) (wire + XkbPaddedSize(nMods));
2286}
2287
2288static char *
2289SetKeyExplicit(XkbSrvInfoPtr xkbi, xkbSetMapReq * req, CARD8 *wire,
2290               XkbChangesPtr changes)
2291{
2292    register unsigned i, first, last;
2293    XkbServerMapPtr xkb = xkbi->desc->server;
2294    CARD8 *start;
2295
2296    start = wire;
2297    first = req->firstKeyExplicit;
2298    last = req->firstKeyExplicit + req->nKeyExplicit - 1;
2299    memset(&xkb->explicit[first], 0, req->nKeyExplicit);
2300    for (i = 0; i < req->totalKeyExplicit; i++, wire += 2) {
2301        xkb->explicit[wire[0]] = wire[1];
2302    }
2303    if (first > 0) {
2304        if (changes->map.changed & XkbExplicitComponentsMask) {
2305            int oldLast;
2306
2307            oldLast = changes->map.first_key_explicit +
2308                changes->map.num_key_explicit - 1;
2309            if (changes->map.first_key_explicit < first)
2310                first = changes->map.first_key_explicit;
2311            if (oldLast > last)
2312                last = oldLast;
2313        }
2314        changes->map.first_key_explicit = first;
2315        changes->map.num_key_explicit = (last - first) + 1;
2316    }
2317    wire += XkbPaddedSize(wire - start) - (wire - start);
2318    return (char *) wire;
2319}
2320
2321static char *
2322SetModifierMap(XkbSrvInfoPtr xkbi,
2323               xkbSetMapReq * req, CARD8 *wire, XkbChangesPtr changes)
2324{
2325    register unsigned i, first, last;
2326    XkbClientMapPtr xkb = xkbi->desc->map;
2327    CARD8 *start;
2328
2329    start = wire;
2330    first = req->firstModMapKey;
2331    last = req->firstModMapKey + req->nModMapKeys - 1;
2332    memset(&xkb->modmap[first], 0, req->nModMapKeys);
2333    for (i = 0; i < req->totalModMapKeys; i++, wire += 2) {
2334        xkb->modmap[wire[0]] = wire[1];
2335    }
2336    if (first > 0) {
2337        if (changes->map.changed & XkbModifierMapMask) {
2338            int oldLast;
2339
2340            oldLast = changes->map.first_modmap_key +
2341                changes->map.num_modmap_keys - 1;
2342            if (changes->map.first_modmap_key < first)
2343                first = changes->map.first_modmap_key;
2344            if (oldLast > last)
2345                last = oldLast;
2346        }
2347        changes->map.first_modmap_key = first;
2348        changes->map.num_modmap_keys = (last - first) + 1;
2349    }
2350    wire += XkbPaddedSize(wire - start) - (wire - start);
2351    return (char *) wire;
2352}
2353
2354static char *
2355SetVirtualModMap(XkbSrvInfoPtr xkbi,
2356                 xkbSetMapReq * req,
2357                 xkbVModMapWireDesc * wire, XkbChangesPtr changes)
2358{
2359    register unsigned i, first, last;
2360    XkbServerMapPtr srv = xkbi->desc->server;
2361
2362    first = req->firstVModMapKey;
2363    last = req->firstVModMapKey + req->nVModMapKeys - 1;
2364    memset(&srv->vmodmap[first], 0, req->nVModMapKeys * sizeof(unsigned short));
2365    for (i = 0; i < req->totalVModMapKeys; i++, wire++) {
2366        srv->vmodmap[wire->key] = wire->vmods;
2367    }
2368    if (first > 0) {
2369        if (changes->map.changed & XkbVirtualModMapMask) {
2370            int oldLast;
2371
2372            oldLast = changes->map.first_vmodmap_key +
2373                changes->map.num_vmodmap_keys - 1;
2374            if (changes->map.first_vmodmap_key < first)
2375                first = changes->map.first_vmodmap_key;
2376            if (oldLast > last)
2377                last = oldLast;
2378        }
2379        changes->map.first_vmodmap_key = first;
2380        changes->map.num_vmodmap_keys = (last - first) + 1;
2381    }
2382    return (char *) wire;
2383}
2384
2385#define _add_check_len(new) \
2386    if (len > UINT32_MAX - (new) || len > req_len - (new)) goto bad; \
2387    else len += new
2388
2389/**
2390 * Check the length of the SetMap request
2391 */
2392static int
2393_XkbSetMapCheckLength(xkbSetMapReq *req)
2394{
2395    size_t len = sz_xkbSetMapReq, req_len = req->length << 2;
2396    xkbKeyTypeWireDesc *keytype;
2397    xkbSymMapWireDesc *symmap;
2398    BOOL preserve;
2399    int i, map_count, nSyms;
2400
2401    if (req_len < len)
2402        goto bad;
2403    /* types */
2404    if (req->present & XkbKeyTypesMask) {
2405        keytype = (xkbKeyTypeWireDesc *)(req + 1);
2406        for (i = 0; i < req->nTypes; i++) {
2407            _add_check_len(XkbPaddedSize(sz_xkbKeyTypeWireDesc));
2408            _add_check_len(keytype->nMapEntries
2409                           * sz_xkbKTSetMapEntryWireDesc);
2410            preserve = keytype->preserve;
2411            map_count = keytype->nMapEntries;
2412            if (preserve) {
2413                _add_check_len(map_count * sz_xkbModsWireDesc);
2414            }
2415            keytype += 1;
2416            keytype = (xkbKeyTypeWireDesc *)
2417                      ((xkbKTSetMapEntryWireDesc *)keytype + map_count);
2418            if (preserve)
2419                keytype = (xkbKeyTypeWireDesc *)
2420                          ((xkbModsWireDesc *)keytype + map_count);
2421        }
2422    }
2423    /* syms */
2424    if (req->present & XkbKeySymsMask) {
2425        symmap = (xkbSymMapWireDesc *)((char *)req + len);
2426        for (i = 0; i < req->nKeySyms; i++) {
2427            _add_check_len(sz_xkbSymMapWireDesc);
2428            nSyms = symmap->nSyms;
2429            _add_check_len(nSyms*sizeof(CARD32));
2430            symmap += 1;
2431            symmap = (xkbSymMapWireDesc *)((CARD32 *)symmap + nSyms);
2432        }
2433    }
2434    /* actions */
2435    if (req->present & XkbKeyActionsMask) {
2436        _add_check_len(req->totalActs * sz_xkbActionWireDesc
2437                       + XkbPaddedSize(req->nKeyActs));
2438    }
2439    /* behaviours */
2440    if (req->present & XkbKeyBehaviorsMask) {
2441        _add_check_len(req->totalKeyBehaviors * sz_xkbBehaviorWireDesc);
2442    }
2443    /* vmods */
2444    if (req->present & XkbVirtualModsMask) {
2445        _add_check_len(XkbPaddedSize(Ones(req->virtualMods)));
2446    }
2447    /* explicit */
2448    if (req->present & XkbExplicitComponentsMask) {
2449        /* two bytes per non-zero explicit componen */
2450        _add_check_len(XkbPaddedSize(req->totalKeyExplicit * sizeof(CARD16)));
2451    }
2452    /* modmap */
2453    if (req->present & XkbModifierMapMask) {
2454         /* two bytes per non-zero modmap component */
2455        _add_check_len(XkbPaddedSize(req->totalModMapKeys * sizeof(CARD16)));
2456    }
2457    /* vmodmap */
2458    if (req->present & XkbVirtualModMapMask) {
2459        _add_check_len(req->totalVModMapKeys * sz_xkbVModMapWireDesc);
2460    }
2461    if (len == req_len)
2462        return Success;
2463bad:
2464    ErrorF("[xkb] BOGUS LENGTH in SetMap: expected %ld got %ld\n",
2465           len, req_len);
2466    return BadLength;
2467}
2468
2469
2470/**
2471 * Check if the given request can be applied to the given device but don't
2472 * actually do anything, except swap values when client->swapped and doswap are both true.
2473 */
2474static int
2475_XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req,
2476                 char *values, Bool doswap)
2477{
2478    XkbSrvInfoPtr xkbi;
2479    XkbDescPtr xkb;
2480    int error;
2481    int nTypes = 0, nActions;
2482    CARD8 mapWidths[XkbMaxLegalKeyCode + 1] = { 0 };
2483    CARD16 symsPerKey[XkbMaxLegalKeyCode + 1] = { 0 };
2484    XkbSymMapPtr map;
2485    int i;
2486
2487    if (!dev->key)
2488        return 0;
2489
2490    xkbi = dev->key->xkbInfo;
2491    xkb = xkbi->desc;
2492
2493    if ((xkb->min_key_code != req->minKeyCode) ||
2494        (xkb->max_key_code != req->maxKeyCode)) {
2495        if (client->xkbClientFlags & _XkbClientIsAncient) {
2496            /* pre 1.0 versions of Xlib have a bug */
2497            req->minKeyCode = xkb->min_key_code;
2498            req->maxKeyCode = xkb->max_key_code;
2499        }
2500        else {
2501            if (!XkbIsLegalKeycode(req->minKeyCode)) {
2502                client->errorValue =
2503                    _XkbErrCode3(2, req->minKeyCode, req->maxKeyCode);
2504                return BadValue;
2505            }
2506            if (req->minKeyCode > req->maxKeyCode) {
2507                client->errorValue =
2508                    _XkbErrCode3(3, req->minKeyCode, req->maxKeyCode);
2509                return BadMatch;
2510            }
2511        }
2512    }
2513
2514    if (!(req->present & XkbKeyTypesMask)) {
2515        nTypes = xkb->map->num_types;
2516    }
2517    else if (!CheckKeyTypes(client, xkb, req, (xkbKeyTypeWireDesc **) &values,
2518			       &nTypes, mapWidths, doswap)) {
2519	    client->errorValue = nTypes;
2520	    return BadValue;
2521    }
2522
2523    /* symsPerKey/mapWidths must be filled regardless of client-side flags */
2524    map = &xkb->map->key_sym_map[xkb->min_key_code];
2525    for (i = xkb->min_key_code; i < xkb->max_key_code; i++, map++) {
2526        register int g, ng, w;
2527
2528        ng = XkbNumGroups(map->group_info);
2529        for (w = g = 0; g < ng; g++) {
2530            if (map->kt_index[g] >= (unsigned) nTypes) {
2531                client->errorValue = _XkbErrCode4(0x13, i, g, map->kt_index[g]);
2532                return BadValue;
2533            }
2534            if (mapWidths[map->kt_index[g]] > w)
2535                w = mapWidths[map->kt_index[g]];
2536        }
2537        symsPerKey[i] = w * ng;
2538    }
2539
2540    if ((req->present & XkbKeySymsMask) &&
2541        (!CheckKeySyms(client, xkb, req, nTypes, mapWidths, symsPerKey,
2542                       (xkbSymMapWireDesc **) &values, &error, doswap))) {
2543        client->errorValue = error;
2544        return BadValue;
2545    }
2546
2547    if ((req->present & XkbKeyActionsMask) &&
2548        (!CheckKeyActions(xkb, req, nTypes, mapWidths, symsPerKey,
2549                          (CARD8 **) &values, &nActions))) {
2550        client->errorValue = nActions;
2551        return BadValue;
2552    }
2553
2554    if ((req->present & XkbKeyBehaviorsMask) &&
2555        (!CheckKeyBehaviors
2556         (xkb, req, (xkbBehaviorWireDesc **) &values, &error))) {
2557        client->errorValue = error;
2558        return BadValue;
2559    }
2560
2561    if ((req->present & XkbVirtualModsMask) &&
2562        (!CheckVirtualMods(xkb, req, (CARD8 **) &values, &error))) {
2563        client->errorValue = error;
2564        return BadValue;
2565    }
2566    if ((req->present & XkbExplicitComponentsMask) &&
2567        (!CheckKeyExplicit(xkb, req, (CARD8 **) &values, &error))) {
2568        client->errorValue = error;
2569        return BadValue;
2570    }
2571    if ((req->present & XkbModifierMapMask) &&
2572        (!CheckModifierMap(xkb, req, (CARD8 **) &values, &error))) {
2573        client->errorValue = error;
2574        return BadValue;
2575    }
2576    if ((req->present & XkbVirtualModMapMask) &&
2577        (!CheckVirtualModMap
2578         (xkb, req, (xkbVModMapWireDesc **) &values, &error))) {
2579        client->errorValue = error;
2580        return BadValue;
2581    }
2582
2583    if (((values - ((char *) req)) / 4) != req->length) {
2584        ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after check)\n");
2585        client->errorValue = values - ((char *) &req[1]);
2586        return BadLength;
2587    }
2588
2589    return Success;
2590}
2591
2592/**
2593 * Apply the given request on the given device.
2594 */
2595static int
2596_XkbSetMap(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req, char *values)
2597{
2598    XkbEventCauseRec cause;
2599    XkbChangesRec change;
2600    Bool sentNKN;
2601    XkbSrvInfoPtr xkbi;
2602    XkbDescPtr xkb;
2603
2604    if (!dev->key)
2605        return Success;
2606
2607    xkbi = dev->key->xkbInfo;
2608    xkb = xkbi->desc;
2609
2610    XkbSetCauseXkbReq(&cause, X_kbSetMap, client);
2611    memset(&change, 0, sizeof(change));
2612    sentNKN = FALSE;
2613    if ((xkb->min_key_code != req->minKeyCode) ||
2614        (xkb->max_key_code != req->maxKeyCode)) {
2615        Status status;
2616        xkbNewKeyboardNotify nkn;
2617
2618        nkn.deviceID = nkn.oldDeviceID = dev->id;
2619        nkn.oldMinKeyCode = xkb->min_key_code;
2620        nkn.oldMaxKeyCode = xkb->max_key_code;
2621        status = XkbChangeKeycodeRange(xkb, req->minKeyCode,
2622                                       req->maxKeyCode, &change);
2623        if (status != Success)
2624            return status;      /* oh-oh. what about the other keyboards? */
2625        nkn.minKeyCode = xkb->min_key_code;
2626        nkn.maxKeyCode = xkb->max_key_code;
2627        nkn.requestMajor = XkbReqCode;
2628        nkn.requestMinor = X_kbSetMap;
2629        nkn.changed = XkbNKN_KeycodesMask;
2630        XkbSendNewKeyboardNotify(dev, &nkn);
2631        sentNKN = TRUE;
2632    }
2633
2634    if (req->present & XkbKeyTypesMask) {
2635        values = SetKeyTypes(xkb, req, (xkbKeyTypeWireDesc *) values, &change);
2636        if (!values)
2637            goto allocFailure;
2638    }
2639    if (req->present & XkbKeySymsMask) {
2640        values =
2641            SetKeySyms(client, xkb, req, (xkbSymMapWireDesc *) values, &change,
2642                       dev);
2643        if (!values)
2644            goto allocFailure;
2645    }
2646    if (req->present & XkbKeyActionsMask) {
2647        values = SetKeyActions(xkb, req, (CARD8 *) values, &change);
2648        if (!values)
2649            goto allocFailure;
2650    }
2651    if (req->present & XkbKeyBehaviorsMask) {
2652        values =
2653            SetKeyBehaviors(xkbi, req, (xkbBehaviorWireDesc *) values, &change);
2654        if (!values)
2655            goto allocFailure;
2656    }
2657    if (req->present & XkbVirtualModsMask)
2658        values = SetVirtualMods(xkbi, req, (CARD8 *) values, &change);
2659    if (req->present & XkbExplicitComponentsMask)
2660        values = SetKeyExplicit(xkbi, req, (CARD8 *) values, &change);
2661    if (req->present & XkbModifierMapMask)
2662        values = SetModifierMap(xkbi, req, (CARD8 *) values, &change);
2663    if (req->present & XkbVirtualModMapMask)
2664        values =
2665            SetVirtualModMap(xkbi, req, (xkbVModMapWireDesc *) values, &change);
2666    if (((values - ((char *) req)) / 4) != req->length) {
2667        ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after set)\n");
2668        client->errorValue = values - ((char *) &req[1]);
2669        return BadLength;
2670    }
2671    if (req->flags & XkbSetMapRecomputeActions) {
2672        KeyCode first, last, firstMM, lastMM;
2673
2674        if (change.map.num_key_syms > 0) {
2675            first = change.map.first_key_sym;
2676            last = first + change.map.num_key_syms - 1;
2677        }
2678        else
2679            first = last = 0;
2680        if (change.map.num_modmap_keys > 0) {
2681            firstMM = change.map.first_modmap_key;
2682            lastMM = firstMM + change.map.num_modmap_keys - 1;
2683        }
2684        else
2685            firstMM = lastMM = 0;
2686        if ((last > 0) && (lastMM > 0)) {
2687            if (firstMM < first)
2688                first = firstMM;
2689            if (lastMM > last)
2690                last = lastMM;
2691        }
2692        else if (lastMM > 0) {
2693            first = firstMM;
2694            last = lastMM;
2695        }
2696        if (last > 0) {
2697            unsigned check = 0;
2698
2699            XkbUpdateActions(dev, first, (last - first + 1), &change, &check,
2700                             &cause);
2701            if (check)
2702                XkbCheckSecondaryEffects(xkbi, check, &change, &cause);
2703        }
2704    }
2705    if (!sentNKN)
2706        XkbSendNotification(dev, &change, &cause);
2707
2708    return Success;
2709 allocFailure:
2710    return BadAlloc;
2711}
2712
2713int
2714ProcXkbSetMap(ClientPtr client)
2715{
2716    DeviceIntPtr dev, master;
2717    char *tmp;
2718    int rc;
2719
2720    REQUEST(xkbSetMapReq);
2721    REQUEST_AT_LEAST_SIZE(xkbSetMapReq);
2722
2723    if (!(client->xkbClientFlags & _XkbClientInitialized))
2724        return BadAccess;
2725
2726    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
2727    CHK_MASK_LEGAL(0x01, stuff->present, XkbAllMapComponentsMask);
2728
2729    /* first verify the request length carefully */
2730    rc = _XkbSetMapCheckLength(stuff);
2731    if (rc != Success)
2732        return rc;
2733
2734    tmp = (char *) &stuff[1];
2735
2736    /* Check if we can to the SetMap on the requested device. If this
2737       succeeds, do the same thing for all extension devices (if needed).
2738       If any of them fails, fail.  */
2739    rc = _XkbSetMapChecks(client, dev, stuff, tmp, TRUE);
2740
2741    if (rc != Success)
2742        return rc;
2743
2744    master = GetMaster(dev, MASTER_KEYBOARD);
2745
2746    if (stuff->deviceSpec == XkbUseCoreKbd) {
2747        DeviceIntPtr other;
2748
2749        for (other = inputInfo.devices; other; other = other->next) {
2750            if ((other != dev) && other->key && !IsMaster(other) &&
2751                GetMaster(other, MASTER_KEYBOARD) == dev) {
2752                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
2753                              DixManageAccess);
2754                if (rc == Success) {
2755                    rc = _XkbSetMapChecks(client, other, stuff, tmp, FALSE);
2756                    if (rc != Success)
2757                        return rc;
2758                }
2759            }
2760        }
2761    } else {
2762        DeviceIntPtr other;
2763
2764        for (other = inputInfo.devices; other; other = other->next) {
2765            if (other != dev && GetMaster(other, MASTER_KEYBOARD) != dev &&
2766                (other != master || dev != master->lastSlave))
2767                continue;
2768
2769            rc = _XkbSetMapChecks(client, other, stuff, tmp, FALSE);
2770            if (rc != Success)
2771                return rc;
2772        }
2773    }
2774
2775    /* We know now that we will succeed with the SetMap. In theory anyway. */
2776    rc = _XkbSetMap(client, dev, stuff, tmp);
2777    if (rc != Success)
2778        return rc;
2779
2780    if (stuff->deviceSpec == XkbUseCoreKbd) {
2781        DeviceIntPtr other;
2782
2783        for (other = inputInfo.devices; other; other = other->next) {
2784            if ((other != dev) && other->key && !IsMaster(other) &&
2785                GetMaster(other, MASTER_KEYBOARD) == dev) {
2786                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
2787                              DixManageAccess);
2788                if (rc == Success)
2789                    _XkbSetMap(client, other, stuff, tmp);
2790                /* ignore rc. if the SetMap failed although the check above
2791                   reported true there isn't much we can do. we still need to
2792                   set all other devices, hoping that at least they stay in
2793                   sync. */
2794            }
2795        }
2796    } else {
2797        DeviceIntPtr other;
2798
2799        for (other = inputInfo.devices; other; other = other->next) {
2800            if (other != dev && GetMaster(other, MASTER_KEYBOARD) != dev &&
2801                (other != master || dev != master->lastSlave))
2802                continue;
2803
2804            _XkbSetMap(client, other, stuff, tmp); //ignore rc
2805        }
2806    }
2807
2808    return Success;
2809}
2810
2811/***====================================================================***/
2812
2813static Status
2814XkbComputeGetCompatMapReplySize(XkbCompatMapPtr compat,
2815                                xkbGetCompatMapReply * rep)
2816{
2817    unsigned size, nGroups;
2818
2819    nGroups = 0;
2820    if (rep->groups != 0) {
2821        register int i, bit;
2822
2823        for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
2824            if (rep->groups & bit)
2825                nGroups++;
2826        }
2827    }
2828    size = nGroups * SIZEOF(xkbModsWireDesc);
2829    size += (rep->nSI * SIZEOF(xkbSymInterpretWireDesc));
2830    rep->length = size / 4;
2831    return Success;
2832}
2833
2834static int
2835XkbSendCompatMap(ClientPtr client,
2836                 XkbCompatMapPtr compat, xkbGetCompatMapReply * rep)
2837{
2838    char *data;
2839    int size;
2840
2841    if (rep->length > 0) {
2842        data = xallocarray(rep->length, 4);
2843        if (data) {
2844            register unsigned i, bit;
2845            xkbModsWireDesc *grp;
2846            XkbSymInterpretPtr sym = &compat->sym_interpret[rep->firstSI];
2847            xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *) data;
2848
2849            size = rep->length * 4;
2850
2851            for (i = 0; i < rep->nSI; i++, sym++, wire++) {
2852                wire->sym = sym->sym;
2853                wire->mods = sym->mods;
2854                wire->match = sym->match;
2855                wire->virtualMod = sym->virtual_mod;
2856                wire->flags = sym->flags;
2857                memcpy((char *) &wire->act, (char *) &sym->act,
2858                       sz_xkbActionWireDesc);
2859                if (client->swapped) {
2860                    swapl(&wire->sym);
2861                }
2862            }
2863            if (rep->groups) {
2864                grp = (xkbModsWireDesc *) wire;
2865                for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
2866                    if (rep->groups & bit) {
2867                        grp->mask = compat->groups[i].mask;
2868                        grp->realMods = compat->groups[i].real_mods;
2869                        grp->virtualMods = compat->groups[i].vmods;
2870                        if (client->swapped) {
2871                            swaps(&grp->virtualMods);
2872                        }
2873                        grp++;
2874                    }
2875                }
2876                wire = (xkbSymInterpretWireDesc *) grp;
2877            }
2878        }
2879        else
2880            return BadAlloc;
2881    }
2882    else
2883        data = NULL;
2884
2885    if (client->swapped) {
2886        swaps(&rep->sequenceNumber);
2887        swapl(&rep->length);
2888        swaps(&rep->firstSI);
2889        swaps(&rep->nSI);
2890        swaps(&rep->nTotalSI);
2891    }
2892
2893    WriteToClient(client, SIZEOF(xkbGetCompatMapReply), rep);
2894    if (data) {
2895        WriteToClient(client, size, data);
2896        free((char *) data);
2897    }
2898    return Success;
2899}
2900
2901int
2902ProcXkbGetCompatMap(ClientPtr client)
2903{
2904    xkbGetCompatMapReply rep;
2905    DeviceIntPtr dev;
2906    XkbDescPtr xkb;
2907    XkbCompatMapPtr compat;
2908
2909    REQUEST(xkbGetCompatMapReq);
2910    REQUEST_SIZE_MATCH(xkbGetCompatMapReq);
2911
2912    if (!(client->xkbClientFlags & _XkbClientInitialized))
2913        return BadAccess;
2914
2915    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
2916
2917    xkb = dev->key->xkbInfo->desc;
2918    compat = xkb->compat;
2919
2920    rep = (xkbGetCompatMapReply) {
2921        .type = X_Reply,
2922        .sequenceNumber = client->sequence,
2923        .length = 0,
2924        .deviceID = dev->id,
2925        .firstSI = stuff->firstSI,
2926        .nSI = stuff->nSI
2927    };
2928    if (stuff->getAllSI) {
2929        rep.firstSI = 0;
2930        rep.nSI = compat->num_si;
2931    }
2932    else if ((((unsigned) stuff->nSI) > 0) &&
2933             ((unsigned) (stuff->firstSI + stuff->nSI - 1) >= compat->num_si)) {
2934        client->errorValue = _XkbErrCode2(0x05, compat->num_si);
2935        return BadValue;
2936    }
2937    rep.nTotalSI = compat->num_si;
2938    rep.groups = stuff->groups;
2939    XkbComputeGetCompatMapReplySize(compat, &rep);
2940    return XkbSendCompatMap(client, compat, &rep);
2941}
2942
2943/**
2944 * Apply the given request on the given device.
2945 * If dryRun is TRUE, then value checks are performed, but the device isn't
2946 * modified.
2947 */
2948static int
2949_XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev,
2950                 xkbSetCompatMapReq * req, char *data, BOOL dryRun)
2951{
2952    XkbSrvInfoPtr xkbi;
2953    XkbDescPtr xkb;
2954    XkbCompatMapPtr compat;
2955    int nGroups;
2956    unsigned i, bit;
2957
2958    xkbi = dev->key->xkbInfo;
2959    xkb = xkbi->desc;
2960    compat = xkb->compat;
2961
2962    if ((req->nSI > 0) || (req->truncateSI)) {
2963        xkbSymInterpretWireDesc *wire;
2964
2965        if (req->firstSI > compat->num_si) {
2966            client->errorValue = _XkbErrCode2(0x02, compat->num_si);
2967            return BadValue;
2968        }
2969        wire = (xkbSymInterpretWireDesc *) data;
2970        wire += req->nSI;
2971        data = (char *) wire;
2972    }
2973
2974    nGroups = 0;
2975    if (req->groups != 0) {
2976        for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
2977            if (req->groups & bit)
2978                nGroups++;
2979        }
2980    }
2981    data += nGroups * SIZEOF(xkbModsWireDesc);
2982    if (((data - ((char *) req)) / 4) != req->length) {
2983        return BadLength;
2984    }
2985
2986    /* Done all the checks we can do */
2987    if (dryRun)
2988        return Success;
2989
2990    data = (char *) &req[1];
2991    if (req->nSI > 0) {
2992        xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *) data;
2993        XkbSymInterpretPtr sym;
2994        unsigned int skipped = 0;
2995
2996        if ((unsigned) (req->firstSI + req->nSI) > compat->num_si) {
2997            compat->num_si = req->firstSI + req->nSI;
2998            compat->sym_interpret = reallocarray(compat->sym_interpret,
2999                                                 compat->num_si,
3000                                                 sizeof(XkbSymInterpretRec));
3001            if (!compat->sym_interpret) {
3002                compat->num_si = 0;
3003                return BadAlloc;
3004            }
3005        }
3006        else if (req->truncateSI) {
3007            compat->num_si = req->firstSI + req->nSI;
3008        }
3009        sym = &compat->sym_interpret[req->firstSI];
3010        for (i = 0; i < req->nSI; i++, wire++) {
3011            if (client->swapped) {
3012                swapl(&wire->sym);
3013            }
3014            if (wire->sym == NoSymbol && wire->match == XkbSI_AnyOfOrNone &&
3015                (wire->mods & 0xff) == 0xff &&
3016                wire->act.type == XkbSA_XFree86Private) {
3017                ErrorF("XKB: Skipping broken Any+AnyOfOrNone(All) -> Private "
3018                       "action from client\n");
3019                skipped++;
3020                continue;
3021            }
3022            sym->sym = wire->sym;
3023            sym->mods = wire->mods;
3024            sym->match = wire->match;
3025            sym->flags = wire->flags;
3026            sym->virtual_mod = wire->virtualMod;
3027            memcpy((char *) &sym->act, (char *) &wire->act,
3028                   SIZEOF(xkbActionWireDesc));
3029            sym++;
3030        }
3031        if (skipped) {
3032            if (req->firstSI + req->nSI < compat->num_si)
3033                memmove(sym, sym + skipped,
3034                        (compat->num_si - req->firstSI - req->nSI) *
3035                        sizeof(*sym));
3036            compat->num_si -= skipped;
3037        }
3038        data = (char *) wire;
3039    }
3040    else if (req->truncateSI) {
3041        compat->num_si = req->firstSI;
3042    }
3043
3044    if (req->groups != 0) {
3045        xkbModsWireDesc *wire = (xkbModsWireDesc *) data;
3046
3047        for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
3048            if (req->groups & bit) {
3049                if (client->swapped) {
3050                    swaps(&wire->virtualMods);
3051                }
3052                compat->groups[i].mask = wire->realMods;
3053                compat->groups[i].real_mods = wire->realMods;
3054                compat->groups[i].vmods = wire->virtualMods;
3055                if (wire->virtualMods != 0) {
3056                    unsigned tmp;
3057
3058                    tmp = XkbMaskForVMask(xkb, wire->virtualMods);
3059                    compat->groups[i].mask |= tmp;
3060                }
3061                data += SIZEOF(xkbModsWireDesc);
3062                wire = (xkbModsWireDesc *) data;
3063            }
3064        }
3065    }
3066    i = XkbPaddedSize((data - ((char *) req)));
3067    if ((i / 4) != req->length) {
3068        ErrorF("[xkb] Internal length error on read in _XkbSetCompatMap\n");
3069        return BadLength;
3070    }
3071
3072    if (dev->xkb_interest) {
3073        xkbCompatMapNotify ev;
3074
3075        ev.deviceID = dev->id;
3076        ev.changedGroups = req->groups;
3077        ev.firstSI = req->firstSI;
3078        ev.nSI = req->nSI;
3079        ev.nTotalSI = compat->num_si;
3080        XkbSendCompatMapNotify(dev, &ev);
3081    }
3082
3083    if (req->recomputeActions) {
3084        XkbChangesRec change;
3085        unsigned check;
3086        XkbEventCauseRec cause;
3087
3088        XkbSetCauseXkbReq(&cause, X_kbSetCompatMap, client);
3089        memset(&change, 0, sizeof(XkbChangesRec));
3090        XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &change,
3091                         &check, &cause);
3092        if (check)
3093            XkbCheckSecondaryEffects(xkbi, check, &change, &cause);
3094        XkbSendNotification(dev, &change, &cause);
3095    }
3096    return Success;
3097}
3098
3099int
3100ProcXkbSetCompatMap(ClientPtr client)
3101{
3102    DeviceIntPtr dev;
3103    char *data;
3104    int rc;
3105
3106    REQUEST(xkbSetCompatMapReq);
3107    REQUEST_AT_LEAST_SIZE(xkbSetCompatMapReq);
3108
3109    if (!(client->xkbClientFlags & _XkbClientInitialized))
3110        return BadAccess;
3111
3112    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
3113
3114    data = (char *) &stuff[1];
3115
3116    /* check first using a dry-run */
3117    rc = _XkbSetCompatMap(client, dev, stuff, data, TRUE);
3118    if (rc != Success)
3119        return rc;
3120    if (stuff->deviceSpec == XkbUseCoreKbd) {
3121        DeviceIntPtr other;
3122
3123        for (other = inputInfo.devices; other; other = other->next) {
3124            if ((other != dev) && other->key && !IsMaster(other) &&
3125                GetMaster(other, MASTER_KEYBOARD) == dev) {
3126                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
3127                              DixManageAccess);
3128                if (rc == Success) {
3129                    /* dry-run */
3130                    rc = _XkbSetCompatMap(client, other, stuff, data, TRUE);
3131                    if (rc != Success)
3132                        return rc;
3133                }
3134            }
3135        }
3136    }
3137
3138    /* Yay, the dry-runs succeed. Let's apply */
3139    rc = _XkbSetCompatMap(client, dev, stuff, data, FALSE);
3140    if (rc != Success)
3141        return rc;
3142    if (stuff->deviceSpec == XkbUseCoreKbd) {
3143        DeviceIntPtr other;
3144
3145        for (other = inputInfo.devices; other; other = other->next) {
3146            if ((other != dev) && other->key && !IsMaster(other) &&
3147                GetMaster(other, MASTER_KEYBOARD) == dev) {
3148                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
3149                              DixManageAccess);
3150                if (rc == Success) {
3151                    rc = _XkbSetCompatMap(client, other, stuff, data, FALSE);
3152                    if (rc != Success)
3153                        return rc;
3154                }
3155            }
3156        }
3157    }
3158
3159    return Success;
3160}
3161
3162/***====================================================================***/
3163
3164int
3165ProcXkbGetIndicatorState(ClientPtr client)
3166{
3167    xkbGetIndicatorStateReply rep;
3168    XkbSrvLedInfoPtr sli;
3169    DeviceIntPtr dev;
3170
3171    REQUEST(xkbGetIndicatorStateReq);
3172    REQUEST_SIZE_MATCH(xkbGetIndicatorStateReq);
3173
3174    if (!(client->xkbClientFlags & _XkbClientInitialized))
3175        return BadAccess;
3176
3177    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess);
3178
3179    sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId,
3180                            XkbXI_IndicatorStateMask);
3181    if (!sli)
3182        return BadAlloc;
3183
3184    rep = (xkbGetIndicatorStateReply) {
3185        .type = X_Reply,
3186        .deviceID = dev->id,
3187        .sequenceNumber = client->sequence,
3188        .length = 0,
3189        .state = sli->effectiveState
3190    };
3191
3192    if (client->swapped) {
3193        swaps(&rep.sequenceNumber);
3194        swapl(&rep.state);
3195    }
3196    WriteToClient(client, SIZEOF(xkbGetIndicatorStateReply), &rep);
3197    return Success;
3198}
3199
3200/***====================================================================***/
3201
3202static Status
3203XkbComputeGetIndicatorMapReplySize(XkbIndicatorPtr indicators,
3204                                   xkbGetIndicatorMapReply * rep)
3205{
3206    register int i, bit;
3207    int nIndicators;
3208
3209    rep->realIndicators = indicators->phys_indicators;
3210    for (i = nIndicators = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
3211        if (rep->which & bit)
3212            nIndicators++;
3213    }
3214    rep->length = (nIndicators * SIZEOF(xkbIndicatorMapWireDesc)) / 4;
3215    rep->nIndicators = nIndicators;
3216    return Success;
3217}
3218
3219static int
3220XkbSendIndicatorMap(ClientPtr client,
3221                    XkbIndicatorPtr indicators, xkbGetIndicatorMapReply * rep)
3222{
3223    int length;
3224    CARD8 *map;
3225    register int i;
3226    register unsigned bit;
3227
3228    if (rep->length > 0) {
3229        CARD8 *to;
3230
3231        to = map = xallocarray(rep->length, 4);
3232        if (map) {
3233            xkbIndicatorMapWireDesc *wire = (xkbIndicatorMapWireDesc *) to;
3234
3235            length = rep->length * 4;
3236
3237            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
3238                if (rep->which & bit) {
3239                    wire->flags = indicators->maps[i].flags;
3240                    wire->whichGroups = indicators->maps[i].which_groups;
3241                    wire->groups = indicators->maps[i].groups;
3242                    wire->whichMods = indicators->maps[i].which_mods;
3243                    wire->mods = indicators->maps[i].mods.mask;
3244                    wire->realMods = indicators->maps[i].mods.real_mods;
3245                    wire->virtualMods = indicators->maps[i].mods.vmods;
3246                    wire->ctrls = indicators->maps[i].ctrls;
3247                    if (client->swapped) {
3248                        swaps(&wire->virtualMods);
3249                        swapl(&wire->ctrls);
3250                    }
3251                    wire++;
3252                }
3253            }
3254            to = (CARD8 *) wire;
3255            if ((to - map) != length) {
3256                client->errorValue = _XkbErrCode2(0xff, length);
3257                free(map);
3258                return BadLength;
3259            }
3260        }
3261        else
3262            return BadAlloc;
3263    }
3264    else
3265        map = NULL;
3266    if (client->swapped) {
3267        swaps(&rep->sequenceNumber);
3268        swapl(&rep->length);
3269        swapl(&rep->which);
3270        swapl(&rep->realIndicators);
3271    }
3272    WriteToClient(client, SIZEOF(xkbGetIndicatorMapReply), rep);
3273    if (map) {
3274        WriteToClient(client, length, map);
3275        free((char *) map);
3276    }
3277    return Success;
3278}
3279
3280int
3281ProcXkbGetIndicatorMap(ClientPtr client)
3282{
3283    xkbGetIndicatorMapReply rep;
3284    DeviceIntPtr dev;
3285    XkbDescPtr xkb;
3286    XkbIndicatorPtr leds;
3287
3288    REQUEST(xkbGetIndicatorMapReq);
3289    REQUEST_SIZE_MATCH(xkbGetIndicatorMapReq);
3290
3291    if (!(client->xkbClientFlags & _XkbClientInitialized))
3292        return BadAccess;
3293
3294    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
3295
3296    xkb = dev->key->xkbInfo->desc;
3297    leds = xkb->indicators;
3298
3299    rep = (xkbGetIndicatorMapReply) {
3300        .type = X_Reply,
3301        .deviceID = dev->id,
3302        .sequenceNumber = client->sequence,
3303        .length = 0,
3304        .which = stuff->which
3305    };
3306    XkbComputeGetIndicatorMapReplySize(leds, &rep);
3307    return XkbSendIndicatorMap(client, leds, &rep);
3308}
3309
3310/**
3311 * Apply the given map to the given device. Which specifies which components
3312 * to apply.
3313 */
3314static int
3315_XkbSetIndicatorMap(ClientPtr client, DeviceIntPtr dev,
3316                    int which, xkbIndicatorMapWireDesc * desc)
3317{
3318    XkbSrvInfoPtr xkbi;
3319    XkbSrvLedInfoPtr sli;
3320    XkbEventCauseRec cause;
3321    int i, bit;
3322
3323    xkbi = dev->key->xkbInfo;
3324
3325    sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId,
3326                            XkbXI_IndicatorMapsMask);
3327    if (!sli)
3328        return BadAlloc;
3329
3330    for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
3331        if (which & bit) {
3332            sli->maps[i].flags = desc->flags;
3333            sli->maps[i].which_groups = desc->whichGroups;
3334            sli->maps[i].groups = desc->groups;
3335            sli->maps[i].which_mods = desc->whichMods;
3336            sli->maps[i].mods.mask = desc->mods;
3337            sli->maps[i].mods.real_mods = desc->mods;
3338            sli->maps[i].mods.vmods = desc->virtualMods;
3339            sli->maps[i].ctrls = desc->ctrls;
3340            if (desc->virtualMods != 0) {
3341                unsigned tmp;
3342
3343                tmp = XkbMaskForVMask(xkbi->desc, desc->virtualMods);
3344                sli->maps[i].mods.mask = desc->mods | tmp;
3345            }
3346            desc++;
3347        }
3348    }
3349
3350    XkbSetCauseXkbReq(&cause, X_kbSetIndicatorMap, client);
3351    XkbApplyLedMapChanges(dev, sli, which, NULL, NULL, &cause);
3352
3353    return Success;
3354}
3355
3356int
3357ProcXkbSetIndicatorMap(ClientPtr client)
3358{
3359    int i, bit;
3360    int nIndicators;
3361    DeviceIntPtr dev;
3362    xkbIndicatorMapWireDesc *from;
3363    int rc;
3364
3365    REQUEST(xkbSetIndicatorMapReq);
3366    REQUEST_AT_LEAST_SIZE(xkbSetIndicatorMapReq);
3367
3368    if (!(client->xkbClientFlags & _XkbClientInitialized))
3369        return BadAccess;
3370
3371    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
3372
3373    if (stuff->which == 0)
3374        return Success;
3375
3376    for (nIndicators = i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
3377        if (stuff->which & bit)
3378            nIndicators++;
3379    }
3380    if (stuff->length != ((SIZEOF(xkbSetIndicatorMapReq) +
3381                           (nIndicators * SIZEOF(xkbIndicatorMapWireDesc))) /
3382                          4)) {
3383        return BadLength;
3384    }
3385
3386    from = (xkbIndicatorMapWireDesc *) &stuff[1];
3387    for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
3388        if (stuff->which & bit) {
3389            if (client->swapped) {
3390                swaps(&from->virtualMods);
3391                swapl(&from->ctrls);
3392            }
3393            CHK_MASK_LEGAL(i, from->whichGroups, XkbIM_UseAnyGroup);
3394            CHK_MASK_LEGAL(i, from->whichMods, XkbIM_UseAnyMods);
3395            from++;
3396        }
3397    }
3398
3399    from = (xkbIndicatorMapWireDesc *) &stuff[1];
3400    rc = _XkbSetIndicatorMap(client, dev, stuff->which, from);
3401    if (rc != Success)
3402        return rc;
3403
3404    if (stuff->deviceSpec == XkbUseCoreKbd) {
3405        DeviceIntPtr other;
3406
3407        for (other = inputInfo.devices; other; other = other->next) {
3408            if ((other != dev) && other->key && !IsMaster(other) &&
3409                GetMaster(other, MASTER_KEYBOARD) == dev) {
3410                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
3411                              DixSetAttrAccess);
3412                if (rc == Success)
3413                    _XkbSetIndicatorMap(client, other, stuff->which, from);
3414            }
3415        }
3416    }
3417
3418    return Success;
3419}
3420
3421/***====================================================================***/
3422
3423int
3424ProcXkbGetNamedIndicator(ClientPtr client)
3425{
3426    DeviceIntPtr dev;
3427    xkbGetNamedIndicatorReply rep;
3428    register int i = 0;
3429    XkbSrvLedInfoPtr sli;
3430    XkbIndicatorMapPtr map = NULL;
3431
3432    REQUEST(xkbGetNamedIndicatorReq);
3433    REQUEST_SIZE_MATCH(xkbGetNamedIndicatorReq);
3434
3435    if (!(client->xkbClientFlags & _XkbClientInitialized))
3436        return BadAccess;
3437
3438    CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess);
3439    CHK_ATOM_ONLY(stuff->indicator);
3440
3441    sli = XkbFindSrvLedInfo(dev, stuff->ledClass, stuff->ledID, 0);
3442    if (!sli)
3443        return BadAlloc;
3444
3445    i = 0;
3446    map = NULL;
3447    if ((sli->names) && (sli->maps)) {
3448        for (i = 0; i < XkbNumIndicators; i++) {
3449            if (stuff->indicator == sli->names[i]) {
3450                map = &sli->maps[i];
3451                break;
3452            }
3453        }
3454    }
3455
3456    rep = (xkbGetNamedIndicatorReply) {
3457        .type = X_Reply,
3458        .sequenceNumber = client->sequence,
3459        .length = 0,
3460        .deviceID = dev->id,
3461        .indicator = stuff->indicator
3462    };
3463    if (map != NULL) {
3464        rep.found = TRUE;
3465        rep.on = ((sli->effectiveState & (1 << i)) != 0);
3466        rep.realIndicator = ((sli->physIndicators & (1 << i)) != 0);
3467        rep.ndx = i;
3468        rep.flags = map->flags;
3469        rep.whichGroups = map->which_groups;
3470        rep.groups = map->groups;
3471        rep.whichMods = map->which_mods;
3472        rep.mods = map->mods.mask;
3473        rep.realMods = map->mods.real_mods;
3474        rep.virtualMods = map->mods.vmods;
3475        rep.ctrls = map->ctrls;
3476        rep.supported = TRUE;
3477    }
3478    else {
3479        rep.found = FALSE;
3480        rep.on = FALSE;
3481        rep.realIndicator = FALSE;
3482        rep.ndx = XkbNoIndicator;
3483        rep.flags = 0;
3484        rep.whichGroups = 0;
3485        rep.groups = 0;
3486        rep.whichMods = 0;
3487        rep.mods = 0;
3488        rep.realMods = 0;
3489        rep.virtualMods = 0;
3490        rep.ctrls = 0;
3491        rep.supported = TRUE;
3492    }
3493    if (client->swapped) {
3494        swapl(&rep.length);
3495        swaps(&rep.sequenceNumber);
3496        swapl(&rep.indicator);
3497        swaps(&rep.virtualMods);
3498        swapl(&rep.ctrls);
3499    }
3500
3501    WriteToClient(client, SIZEOF(xkbGetNamedIndicatorReply), &rep);
3502    return Success;
3503}
3504
3505/**
3506 * Find the IM on the device.
3507 * Returns the map, or NULL if the map doesn't exist.
3508 * If the return value is NULL, led_return is undefined. Otherwise, led_return
3509 * is set to the led index of the map.
3510 */
3511static XkbIndicatorMapPtr
3512_XkbFindNamedIndicatorMap(XkbSrvLedInfoPtr sli, Atom indicator, int *led_return)
3513{
3514    XkbIndicatorMapPtr map;
3515
3516    /* search for the right indicator */
3517    map = NULL;
3518    if (sli->names && sli->maps) {
3519        int led;
3520
3521        for (led = 0; (led < XkbNumIndicators) && (map == NULL); led++) {
3522            if (sli->names[led] == indicator) {
3523                map = &sli->maps[led];
3524                *led_return = led;
3525                break;
3526            }
3527        }
3528    }
3529
3530    return map;
3531}
3532
3533/**
3534 * Creates an indicator map on the device. If dryRun is TRUE, it only checks
3535 * if creation is possible, but doesn't actually create it.
3536 */
3537static int
3538_XkbCreateIndicatorMap(DeviceIntPtr dev, Atom indicator,
3539                       int ledClass, int ledID,
3540                       XkbIndicatorMapPtr * map_return, int *led_return,
3541                       Bool dryRun)
3542{
3543    XkbSrvLedInfoPtr sli;
3544    XkbIndicatorMapPtr map;
3545    int led;
3546
3547    sli = XkbFindSrvLedInfo(dev, ledClass, ledID, XkbXI_IndicatorsMask);
3548    if (!sli)
3549        return BadAlloc;
3550
3551    map = _XkbFindNamedIndicatorMap(sli, indicator, &led);
3552
3553    if (!map) {
3554        /* find first unused indicator maps and assign the name to it */
3555        for (led = 0, map = NULL; (led < XkbNumIndicators) && (map == NULL);
3556             led++) {
3557            if ((sli->names) && (sli->maps) && (sli->names[led] == None) &&
3558                (!XkbIM_InUse(&sli->maps[led]))) {
3559                map = &sli->maps[led];
3560                if (!dryRun)
3561                    sli->names[led] = indicator;
3562                break;
3563            }
3564        }
3565    }
3566
3567    if (!map)
3568        return BadAlloc;
3569
3570    *led_return = led;
3571    *map_return = map;
3572    return Success;
3573}
3574
3575static int
3576_XkbSetNamedIndicator(ClientPtr client, DeviceIntPtr dev,
3577                      xkbSetNamedIndicatorReq * stuff)
3578{
3579    unsigned int extDevReason;
3580    unsigned int statec, namec, mapc;
3581    XkbSrvLedInfoPtr sli;
3582    int led = 0;
3583    XkbIndicatorMapPtr map;
3584    DeviceIntPtr kbd;
3585    XkbEventCauseRec cause;
3586    xkbExtensionDeviceNotify ed;
3587    XkbChangesRec changes;
3588    int rc;
3589
3590    rc = _XkbCreateIndicatorMap(dev, stuff->indicator, stuff->ledClass,
3591                                stuff->ledID, &map, &led, FALSE);
3592    if (rc != Success || !map)  /* oh-oh */
3593        return rc;
3594
3595    sli = XkbFindSrvLedInfo(dev, stuff->ledClass, stuff->ledID,
3596                            XkbXI_IndicatorsMask);
3597    if (!sli)
3598        return BadAlloc;
3599
3600    namec = mapc = statec = 0;
3601    extDevReason = 0;
3602
3603    namec |= (1 << led);
3604    sli->namesPresent |= ((stuff->indicator != None) ? (1 << led) : 0);
3605    extDevReason |= XkbXI_IndicatorNamesMask;
3606
3607    if (stuff->setMap) {
3608        map->flags = stuff->flags;
3609        map->which_groups = stuff->whichGroups;
3610        map->groups = stuff->groups;
3611        map->which_mods = stuff->whichMods;
3612        map->mods.mask = stuff->realMods;
3613        map->mods.real_mods = stuff->realMods;
3614        map->mods.vmods = stuff->virtualMods;
3615        map->ctrls = stuff->ctrls;
3616        mapc |= (1 << led);
3617    }
3618
3619    if ((stuff->setState) && ((map->flags & XkbIM_NoExplicit) == 0)) {
3620        if (stuff->on)
3621            sli->explicitState |= (1 << led);
3622        else
3623            sli->explicitState &= ~(1 << led);
3624        statec |= ((sli->effectiveState ^ sli->explicitState) & (1 << led));
3625    }
3626
3627    memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
3628    memset((char *) &changes, 0, sizeof(XkbChangesRec));
3629    XkbSetCauseXkbReq(&cause, X_kbSetNamedIndicator, client);
3630    if (namec)
3631        XkbApplyLedNameChanges(dev, sli, namec, &ed, &changes, &cause);
3632    if (mapc)
3633        XkbApplyLedMapChanges(dev, sli, mapc, &ed, &changes, &cause);
3634    if (statec)
3635        XkbApplyLedStateChanges(dev, sli, statec, &ed, &changes, &cause);
3636
3637    kbd = dev;
3638    if ((sli->flags & XkbSLI_HasOwnState) == 0)
3639        kbd = inputInfo.keyboard;
3640    XkbFlushLedEvents(dev, kbd, sli, &ed, &changes, &cause);
3641
3642    return Success;
3643}
3644
3645int
3646ProcXkbSetNamedIndicator(ClientPtr client)
3647{
3648    int rc;
3649    DeviceIntPtr dev;
3650    int led = 0;
3651    XkbIndicatorMapPtr map;
3652
3653    REQUEST(xkbSetNamedIndicatorReq);
3654    REQUEST_SIZE_MATCH(xkbSetNamedIndicatorReq);
3655
3656    if (!(client->xkbClientFlags & _XkbClientInitialized))
3657        return BadAccess;
3658
3659    CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
3660    CHK_ATOM_ONLY(stuff->indicator);
3661    CHK_MASK_LEGAL(0x10, stuff->whichGroups, XkbIM_UseAnyGroup);
3662    CHK_MASK_LEGAL(0x11, stuff->whichMods, XkbIM_UseAnyMods);
3663
3664    /* Dry-run for checks */
3665    rc = _XkbCreateIndicatorMap(dev, stuff->indicator,
3666                                stuff->ledClass, stuff->ledID,
3667                                &map, &led, TRUE);
3668    if (rc != Success || !map)  /* couldn't be created or didn't exist */
3669        return rc;
3670
3671    if (stuff->deviceSpec == XkbUseCoreKbd ||
3672        stuff->deviceSpec == XkbUseCorePtr) {
3673        DeviceIntPtr other;
3674
3675        for (other = inputInfo.devices; other; other = other->next) {
3676            if ((other != dev) && !IsMaster(other) &&
3677                GetMaster(other, MASTER_KEYBOARD) == dev && (other->kbdfeed ||
3678                                                             other->leds) &&
3679                (XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess)
3680                 == Success)) {
3681                rc = _XkbCreateIndicatorMap(other, stuff->indicator,
3682                                            stuff->ledClass, stuff->ledID, &map,
3683                                            &led, TRUE);
3684                if (rc != Success || !map)
3685                    return rc;
3686            }
3687        }
3688    }
3689
3690    /* All checks passed, let's do it */
3691    rc = _XkbSetNamedIndicator(client, dev, stuff);
3692    if (rc != Success)
3693        return rc;
3694
3695    if (stuff->deviceSpec == XkbUseCoreKbd ||
3696        stuff->deviceSpec == XkbUseCorePtr) {
3697        DeviceIntPtr other;
3698
3699        for (other = inputInfo.devices; other; other = other->next) {
3700            if ((other != dev) && !IsMaster(other) &&
3701                GetMaster(other, MASTER_KEYBOARD) == dev && (other->kbdfeed ||
3702                                                             other->leds) &&
3703                (XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess)
3704                 == Success)) {
3705                _XkbSetNamedIndicator(client, other, stuff);
3706            }
3707        }
3708    }
3709
3710    return Success;
3711}
3712
3713/***====================================================================***/
3714
3715static CARD32
3716_XkbCountAtoms(Atom *atoms, int maxAtoms, int *count)
3717{
3718    register unsigned int i, bit, nAtoms;
3719    register CARD32 atomsPresent;
3720
3721    for (i = nAtoms = atomsPresent = 0, bit = 1; i < maxAtoms; i++, bit <<= 1) {
3722        if (atoms[i] != None) {
3723            atomsPresent |= bit;
3724            nAtoms++;
3725        }
3726    }
3727    if (count)
3728        *count = nAtoms;
3729    return atomsPresent;
3730}
3731
3732static char *
3733_XkbWriteAtoms(char *wire, Atom *atoms, int maxAtoms, int swap)
3734{
3735    register unsigned int i;
3736    Atom *atm;
3737
3738    atm = (Atom *) wire;
3739    for (i = 0; i < maxAtoms; i++) {
3740        if (atoms[i] != None) {
3741            *atm = atoms[i];
3742            if (swap) {
3743                swapl(atm);
3744            }
3745            atm++;
3746        }
3747    }
3748    return (char *) atm;
3749}
3750
3751static Status
3752XkbComputeGetNamesReplySize(XkbDescPtr xkb, xkbGetNamesReply * rep)
3753{
3754    register unsigned which, length;
3755    register int i;
3756
3757    rep->minKeyCode = xkb->min_key_code;
3758    rep->maxKeyCode = xkb->max_key_code;
3759    which = rep->which;
3760    length = 0;
3761    if (xkb->names != NULL) {
3762        if (which & XkbKeycodesNameMask)
3763            length++;
3764        if (which & XkbGeometryNameMask)
3765            length++;
3766        if (which & XkbSymbolsNameMask)
3767            length++;
3768        if (which & XkbPhysSymbolsNameMask)
3769            length++;
3770        if (which & XkbTypesNameMask)
3771            length++;
3772        if (which & XkbCompatNameMask)
3773            length++;
3774    }
3775    else
3776        which &= ~XkbComponentNamesMask;
3777
3778    if (xkb->map != NULL) {
3779        if (which & XkbKeyTypeNamesMask)
3780            length += xkb->map->num_types;
3781        rep->nTypes = xkb->map->num_types;
3782        if (which & XkbKTLevelNamesMask) {
3783            XkbKeyTypePtr pType = xkb->map->types;
3784            int nKTLevels = 0;
3785
3786            length += XkbPaddedSize(xkb->map->num_types) / 4;
3787            for (i = 0; i < xkb->map->num_types; i++, pType++) {
3788                if (pType->level_names != NULL)
3789                    nKTLevels += pType->num_levels;
3790            }
3791            rep->nKTLevels = nKTLevels;
3792            length += nKTLevels;
3793        }
3794    }
3795    else {
3796        rep->nTypes = 0;
3797        rep->nKTLevels = 0;
3798        which &= ~(XkbKeyTypeNamesMask | XkbKTLevelNamesMask);
3799    }
3800
3801    rep->minKeyCode = xkb->min_key_code;
3802    rep->maxKeyCode = xkb->max_key_code;
3803    rep->indicators = 0;
3804    rep->virtualMods = 0;
3805    rep->groupNames = 0;
3806    if (xkb->names != NULL) {
3807        if (which & XkbIndicatorNamesMask) {
3808            int nLeds;
3809
3810            rep->indicators =
3811                _XkbCountAtoms(xkb->names->indicators, XkbNumIndicators,
3812                               &nLeds);
3813            length += nLeds;
3814            if (nLeds == 0)
3815                which &= ~XkbIndicatorNamesMask;
3816        }
3817
3818        if (which & XkbVirtualModNamesMask) {
3819            int nVMods;
3820
3821            rep->virtualMods =
3822                _XkbCountAtoms(xkb->names->vmods, XkbNumVirtualMods, &nVMods);
3823            length += nVMods;
3824            if (nVMods == 0)
3825                which &= ~XkbVirtualModNamesMask;
3826        }
3827
3828        if (which & XkbGroupNamesMask) {
3829            int nGroups;
3830
3831            rep->groupNames =
3832                _XkbCountAtoms(xkb->names->groups, XkbNumKbdGroups, &nGroups);
3833            length += nGroups;
3834            if (nGroups == 0)
3835                which &= ~XkbGroupNamesMask;
3836        }
3837
3838        if ((which & XkbKeyNamesMask) && (xkb->names->keys))
3839            length += rep->nKeys;
3840        else
3841            which &= ~XkbKeyNamesMask;
3842
3843        if ((which & XkbKeyAliasesMask) &&
3844            (xkb->names->key_aliases) && (xkb->names->num_key_aliases > 0)) {
3845            rep->nKeyAliases = xkb->names->num_key_aliases;
3846            length += rep->nKeyAliases * 2;
3847        }
3848        else {
3849            which &= ~XkbKeyAliasesMask;
3850            rep->nKeyAliases = 0;
3851        }
3852
3853        if ((which & XkbRGNamesMask) && (xkb->names->num_rg > 0))
3854            length += xkb->names->num_rg;
3855        else
3856            which &= ~XkbRGNamesMask;
3857    }
3858    else {
3859        which &= ~(XkbIndicatorNamesMask | XkbVirtualModNamesMask);
3860        which &= ~(XkbGroupNamesMask | XkbKeyNamesMask | XkbKeyAliasesMask);
3861        which &= ~XkbRGNamesMask;
3862    }
3863
3864    rep->length = length;
3865    rep->which = which;
3866    return Success;
3867}
3868
3869static int
3870XkbSendNames(ClientPtr client, XkbDescPtr xkb, xkbGetNamesReply * rep)
3871{
3872    register unsigned i, length, which;
3873    char *start;
3874    char *desc;
3875
3876    length = rep->length * 4;
3877    which = rep->which;
3878    if (client->swapped) {
3879        swaps(&rep->sequenceNumber);
3880        swapl(&rep->length);
3881        swapl(&rep->which);
3882        swaps(&rep->virtualMods);
3883        swapl(&rep->indicators);
3884    }
3885
3886    start = desc = calloc(1, length);
3887    if (!start)
3888        return BadAlloc;
3889    if (xkb->names) {
3890        if (which & XkbKeycodesNameMask) {
3891            *((CARD32 *) desc) = xkb->names->keycodes;
3892            if (client->swapped) {
3893                swapl((int *) desc);
3894            }
3895            desc += 4;
3896        }
3897        if (which & XkbGeometryNameMask) {
3898            *((CARD32 *) desc) = xkb->names->geometry;
3899            if (client->swapped) {
3900                swapl((int *) desc);
3901            }
3902            desc += 4;
3903        }
3904        if (which & XkbSymbolsNameMask) {
3905            *((CARD32 *) desc) = xkb->names->symbols;
3906            if (client->swapped) {
3907                swapl((int *) desc);
3908            }
3909            desc += 4;
3910        }
3911        if (which & XkbPhysSymbolsNameMask) {
3912            register CARD32 *atm = (CARD32 *) desc;
3913
3914            atm[0] = (CARD32) xkb->names->phys_symbols;
3915            if (client->swapped) {
3916                swapl(&atm[0]);
3917            }
3918            desc += 4;
3919        }
3920        if (which & XkbTypesNameMask) {
3921            *((CARD32 *) desc) = (CARD32) xkb->names->types;
3922            if (client->swapped) {
3923                swapl((int *) desc);
3924            }
3925            desc += 4;
3926        }
3927        if (which & XkbCompatNameMask) {
3928            *((CARD32 *) desc) = (CARD32) xkb->names->compat;
3929            if (client->swapped) {
3930                swapl((int *) desc);
3931            }
3932            desc += 4;
3933        }
3934        if (which & XkbKeyTypeNamesMask) {
3935            register CARD32 *atm = (CARD32 *) desc;
3936            register XkbKeyTypePtr type = xkb->map->types;
3937
3938            for (i = 0; i < xkb->map->num_types; i++, atm++, type++) {
3939                *atm = (CARD32) type->name;
3940                if (client->swapped) {
3941                    swapl(atm);
3942                }
3943            }
3944            desc = (char *) atm;
3945        }
3946        if (which & XkbKTLevelNamesMask && xkb->map) {
3947            XkbKeyTypePtr type = xkb->map->types;
3948            register CARD32 *atm;
3949
3950            for (i = 0; i < rep->nTypes; i++, type++) {
3951                *desc++ = type->num_levels;
3952            }
3953            desc += XkbPaddedSize(rep->nTypes) - rep->nTypes;
3954
3955            atm = (CARD32 *) desc;
3956            type = xkb->map->types;
3957            for (i = 0; i < xkb->map->num_types; i++, type++) {
3958                register unsigned l;
3959
3960                if (type->level_names) {
3961                    for (l = 0; l < type->num_levels; l++, atm++) {
3962                        *atm = type->level_names[l];
3963                        if (client->swapped) {
3964                            swapl(atm);
3965                        }
3966                    }
3967                    desc += type->num_levels * 4;
3968                }
3969            }
3970        }
3971        if (which & XkbIndicatorNamesMask) {
3972            desc =
3973                _XkbWriteAtoms(desc, xkb->names->indicators, XkbNumIndicators,
3974                               client->swapped);
3975        }
3976        if (which & XkbVirtualModNamesMask) {
3977            desc = _XkbWriteAtoms(desc, xkb->names->vmods, XkbNumVirtualMods,
3978                                  client->swapped);
3979        }
3980        if (which & XkbGroupNamesMask) {
3981            desc = _XkbWriteAtoms(desc, xkb->names->groups, XkbNumKbdGroups,
3982                                  client->swapped);
3983        }
3984        if (which & XkbKeyNamesMask) {
3985            for (i = 0; i < rep->nKeys; i++, desc += sizeof(XkbKeyNameRec)) {
3986                *((XkbKeyNamePtr) desc) = xkb->names->keys[i + rep->firstKey];
3987            }
3988        }
3989        if (which & XkbKeyAliasesMask) {
3990            XkbKeyAliasPtr pAl;
3991
3992            pAl = xkb->names->key_aliases;
3993            for (i = 0; i < rep->nKeyAliases;
3994                 i++, pAl++, desc += 2 * XkbKeyNameLength) {
3995                *((XkbKeyAliasPtr) desc) = *pAl;
3996            }
3997        }
3998        if ((which & XkbRGNamesMask) && (rep->nRadioGroups > 0)) {
3999            register CARD32 *atm = (CARD32 *) desc;
4000
4001            for (i = 0; i < rep->nRadioGroups; i++, atm++) {
4002                *atm = (CARD32) xkb->names->radio_groups[i];
4003                if (client->swapped) {
4004                    swapl(atm);
4005                }
4006            }
4007            desc += rep->nRadioGroups * 4;
4008        }
4009    }
4010
4011    if ((desc - start) != (length)) {
4012        ErrorF("[xkb] BOGUS LENGTH in write names, expected %d, got %ld\n",
4013               length, (unsigned long) (desc - start));
4014    }
4015    WriteToClient(client, SIZEOF(xkbGetNamesReply), rep);
4016    WriteToClient(client, length, start);
4017    free((char *) start);
4018    return Success;
4019}
4020
4021int
4022ProcXkbGetNames(ClientPtr client)
4023{
4024    DeviceIntPtr dev;
4025    XkbDescPtr xkb;
4026    xkbGetNamesReply rep;
4027
4028    REQUEST(xkbGetNamesReq);
4029    REQUEST_SIZE_MATCH(xkbGetNamesReq);
4030
4031    if (!(client->xkbClientFlags & _XkbClientInitialized))
4032        return BadAccess;
4033
4034    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
4035    CHK_MASK_LEGAL(0x01, stuff->which, XkbAllNamesMask);
4036
4037    xkb = dev->key->xkbInfo->desc;
4038    rep = (xkbGetNamesReply) {
4039        .type = X_Reply,
4040        .deviceID = dev->id,
4041        .sequenceNumber = client->sequence,
4042        .length = 0,
4043        .which = stuff->which,
4044        .nTypes = xkb->map->num_types,
4045        .firstKey = xkb->min_key_code,
4046        .nKeys = XkbNumKeys(xkb),
4047        .nKeyAliases = xkb->names ? xkb->names->num_key_aliases : 0,
4048        .nRadioGroups = xkb->names ? xkb->names->num_rg : 0
4049    };
4050    XkbComputeGetNamesReplySize(xkb, &rep);
4051    return XkbSendNames(client, xkb, &rep);
4052}
4053
4054/***====================================================================***/
4055
4056static CARD32 *
4057_XkbCheckAtoms(CARD32 *wire, int nAtoms, int swapped, Atom *pError)
4058{
4059    register int i;
4060
4061    for (i = 0; i < nAtoms; i++, wire++) {
4062        if (swapped) {
4063            swapl(wire);
4064        }
4065        if ((((Atom) *wire) != None) && (!ValidAtom((Atom) *wire))) {
4066            *pError = ((Atom) *wire);
4067            return NULL;
4068        }
4069    }
4070    return wire;
4071}
4072
4073static CARD32 *
4074_XkbCheckMaskedAtoms(CARD32 *wire, int nAtoms, CARD32 present, int swapped,
4075                     Atom *pError)
4076{
4077    register unsigned i, bit;
4078
4079    for (i = 0, bit = 1; (i < nAtoms) && (present); i++, bit <<= 1) {
4080        if ((present & bit) == 0)
4081            continue;
4082        if (swapped) {
4083            swapl(wire);
4084        }
4085        if ((((Atom) *wire) != None) && (!ValidAtom(((Atom) *wire)))) {
4086            *pError = (Atom) *wire;
4087            return NULL;
4088        }
4089        wire++;
4090    }
4091    return wire;
4092}
4093
4094static Atom *
4095_XkbCopyMaskedAtoms(Atom *wire, Atom *dest, int nAtoms, CARD32 present)
4096{
4097    register int i, bit;
4098
4099    for (i = 0, bit = 1; (i < nAtoms) && (present); i++, bit <<= 1) {
4100        if ((present & bit) == 0)
4101            continue;
4102        dest[i] = *wire++;
4103    }
4104    return wire;
4105}
4106
4107static Bool
4108_XkbCheckTypeName(Atom name, int typeNdx)
4109{
4110    const char *str;
4111
4112    str = NameForAtom(name);
4113    if ((strcmp(str, "ONE_LEVEL") == 0) || (strcmp(str, "TWO_LEVEL") == 0) ||
4114        (strcmp(str, "ALPHABETIC") == 0) || (strcmp(str, "KEYPAD") == 0))
4115        return FALSE;
4116    return TRUE;
4117}
4118
4119/**
4120 * Check the device-dependent data in the request against the device. Returns
4121 * Success, or the appropriate error code.
4122 */
4123static int
4124_XkbSetNamesCheck(ClientPtr client, DeviceIntPtr dev,
4125                  xkbSetNamesReq * stuff, CARD32 *data)
4126{
4127    XkbDescRec *xkb;
4128    CARD32 *tmp;
4129    Atom bad = None;
4130
4131    tmp = data;
4132    xkb = dev->key->xkbInfo->desc;
4133
4134    if (stuff->which & XkbKeyTypeNamesMask) {
4135        int i;
4136        CARD32 *old;
4137
4138        if (stuff->nTypes < 1) {
4139            client->errorValue = _XkbErrCode2(0x02, stuff->nTypes);
4140            return BadValue;
4141        }
4142        if ((unsigned) (stuff->firstType + stuff->nTypes - 1) >=
4143            xkb->map->num_types) {
4144            client->errorValue =
4145                _XkbErrCode4(0x03, stuff->firstType, stuff->nTypes,
4146                             xkb->map->num_types);
4147            return BadValue;
4148        }
4149        if (((unsigned) stuff->firstType) <= XkbLastRequiredType) {
4150            client->errorValue = _XkbErrCode2(0x04, stuff->firstType);
4151            return BadAccess;
4152        }
4153        if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + stuff->nTypes))
4154            return BadLength;
4155        old = tmp;
4156        tmp = _XkbCheckAtoms(tmp, stuff->nTypes, client->swapped, &bad);
4157        if (!tmp) {
4158            client->errorValue = bad;
4159            return BadAtom;
4160        }
4161        for (i = 0; i < stuff->nTypes; i++, old++) {
4162            if (!_XkbCheckTypeName((Atom) *old, stuff->firstType + i))
4163                client->errorValue = _XkbErrCode2(0x05, i);
4164        }
4165    }
4166    if (stuff->which & XkbKTLevelNamesMask) {
4167        unsigned i;
4168        XkbKeyTypePtr type;
4169        CARD8 *width;
4170
4171        if (stuff->nKTLevels < 1) {
4172            client->errorValue = _XkbErrCode2(0x05, stuff->nKTLevels);
4173            return BadValue;
4174        }
4175        if ((unsigned) (stuff->firstKTLevel + stuff->nKTLevels - 1) >=
4176            xkb->map->num_types) {
4177            client->errorValue = _XkbErrCode4(0x06, stuff->firstKTLevel,
4178                                              stuff->nKTLevels,
4179                                              xkb->map->num_types);
4180            return BadValue;
4181        }
4182        width = (CARD8 *) tmp;
4183        tmp = (CARD32 *) (((char *) tmp) + XkbPaddedSize(stuff->nKTLevels));
4184        if (!_XkbCheckRequestBounds(client, stuff, width, tmp))
4185            return BadLength;
4186        type = &xkb->map->types[stuff->firstKTLevel];
4187        for (i = 0; i < stuff->nKTLevels; i++, type++) {
4188            if (width[i] == 0)
4189                continue;
4190            else if (width[i] != type->num_levels) {
4191                client->errorValue = _XkbErrCode4(0x07, i + stuff->firstKTLevel,
4192                                                  type->num_levels, width[i]);
4193                return BadMatch;
4194            }
4195            if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + width[i]))
4196                return BadLength;
4197            tmp = _XkbCheckAtoms(tmp, width[i], client->swapped, &bad);
4198            if (!tmp) {
4199                client->errorValue = bad;
4200                return BadAtom;
4201            }
4202        }
4203    }
4204    if (stuff->which & XkbIndicatorNamesMask) {
4205        if (stuff->indicators == 0) {
4206            client->errorValue = 0x08;
4207            return BadMatch;
4208        }
4209        if (!_XkbCheckRequestBounds(client, stuff, tmp,
4210                                    tmp + Ones(stuff->indicators)))
4211            return BadLength;
4212        tmp = _XkbCheckMaskedAtoms(tmp, XkbNumIndicators, stuff->indicators,
4213                                   client->swapped, &bad);
4214        if (!tmp) {
4215            client->errorValue = bad;
4216            return BadAtom;
4217        }
4218    }
4219    if (stuff->which & XkbVirtualModNamesMask) {
4220        if (stuff->virtualMods == 0) {
4221            client->errorValue = 0x09;
4222            return BadMatch;
4223        }
4224        if (!_XkbCheckRequestBounds(client, stuff, tmp,
4225                                    tmp + Ones(stuff->virtualMods)))
4226            return BadLength;
4227        tmp = _XkbCheckMaskedAtoms(tmp, XkbNumVirtualMods,
4228                                   (CARD32) stuff->virtualMods,
4229                                   client->swapped, &bad);
4230        if (!tmp) {
4231            client->errorValue = bad;
4232            return BadAtom;
4233        }
4234    }
4235    if (stuff->which & XkbGroupNamesMask) {
4236        if (stuff->groupNames == 0) {
4237            client->errorValue = 0x0a;
4238            return BadMatch;
4239        }
4240        if (!_XkbCheckRequestBounds(client, stuff, tmp,
4241                                    tmp + Ones(stuff->groupNames)))
4242            return BadLength;
4243        tmp = _XkbCheckMaskedAtoms(tmp, XkbNumKbdGroups,
4244                                   (CARD32) stuff->groupNames,
4245                                   client->swapped, &bad);
4246        if (!tmp) {
4247            client->errorValue = bad;
4248            return BadAtom;
4249        }
4250    }
4251    if (stuff->which & XkbKeyNamesMask) {
4252        if (stuff->firstKey < (unsigned) xkb->min_key_code) {
4253            client->errorValue = _XkbErrCode3(0x0b, xkb->min_key_code,
4254                                              stuff->firstKey);
4255            return BadValue;
4256        }
4257        if (((unsigned) (stuff->firstKey + stuff->nKeys - 1) >
4258             xkb->max_key_code) || (stuff->nKeys < 1)) {
4259            client->errorValue =
4260                _XkbErrCode4(0x0c, xkb->max_key_code, stuff->firstKey,
4261                             stuff->nKeys);
4262            return BadValue;
4263        }
4264        if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + stuff->nKeys))
4265            return BadLength;
4266        tmp += stuff->nKeys;
4267    }
4268    if ((stuff->which & XkbKeyAliasesMask) && (stuff->nKeyAliases > 0)) {
4269        if (!_XkbCheckRequestBounds(client, stuff, tmp,
4270                                    tmp + (stuff->nKeyAliases * 2)))
4271            return BadLength;
4272        tmp += stuff->nKeyAliases * 2;
4273    }
4274    if (stuff->which & XkbRGNamesMask) {
4275        if (stuff->nRadioGroups < 1) {
4276            client->errorValue = _XkbErrCode2(0x0d, stuff->nRadioGroups);
4277            return BadValue;
4278        }
4279        if (!_XkbCheckRequestBounds(client, stuff, tmp,
4280                                    tmp + stuff->nRadioGroups))
4281            return BadLength;
4282        tmp = _XkbCheckAtoms(tmp, stuff->nRadioGroups, client->swapped, &bad);
4283        if (!tmp) {
4284            client->errorValue = bad;
4285            return BadAtom;
4286        }
4287    }
4288    if ((tmp - ((CARD32 *) stuff)) != stuff->length) {
4289        client->errorValue = stuff->length;
4290        return BadLength;
4291    }
4292
4293    return Success;
4294}
4295
4296static int
4297_XkbSetNames(ClientPtr client, DeviceIntPtr dev, xkbSetNamesReq * stuff)
4298{
4299    XkbDescRec *xkb;
4300    XkbNamesRec *names;
4301    CARD32 *tmp;
4302    xkbNamesNotify nn;
4303
4304    tmp = (CARD32 *) &stuff[1];
4305    xkb = dev->key->xkbInfo->desc;
4306    names = xkb->names;
4307
4308    if (XkbAllocNames(xkb, stuff->which, stuff->nRadioGroups,
4309                      stuff->nKeyAliases) != Success) {
4310        return BadAlloc;
4311    }
4312
4313    memset(&nn, 0, sizeof(xkbNamesNotify));
4314    nn.changed = stuff->which;
4315    tmp = (CARD32 *) &stuff[1];
4316    if (stuff->which & XkbKeycodesNameMask)
4317        names->keycodes = *tmp++;
4318    if (stuff->which & XkbGeometryNameMask)
4319        names->geometry = *tmp++;
4320    if (stuff->which & XkbSymbolsNameMask)
4321        names->symbols = *tmp++;
4322    if (stuff->which & XkbPhysSymbolsNameMask)
4323        names->phys_symbols = *tmp++;
4324    if (stuff->which & XkbTypesNameMask)
4325        names->types = *tmp++;
4326    if (stuff->which & XkbCompatNameMask)
4327        names->compat = *tmp++;
4328    if ((stuff->which & XkbKeyTypeNamesMask) && (stuff->nTypes > 0)) {
4329        register unsigned i;
4330        register XkbKeyTypePtr type;
4331
4332        type = &xkb->map->types[stuff->firstType];
4333        for (i = 0; i < stuff->nTypes; i++, type++) {
4334            type->name = *tmp++;
4335        }
4336        nn.firstType = stuff->firstType;
4337        nn.nTypes = stuff->nTypes;
4338    }
4339    if (stuff->which & XkbKTLevelNamesMask) {
4340        register XkbKeyTypePtr type;
4341        register unsigned i;
4342        CARD8 *width;
4343
4344        width = (CARD8 *) tmp;
4345        tmp = (CARD32 *) (((char *) tmp) + XkbPaddedSize(stuff->nKTLevels));
4346        type = &xkb->map->types[stuff->firstKTLevel];
4347        for (i = 0; i < stuff->nKTLevels; i++, type++) {
4348            if (width[i] > 0) {
4349                if (type->level_names) {
4350                    register unsigned n;
4351
4352                    for (n = 0; n < width[i]; n++) {
4353                        type->level_names[n] = tmp[n];
4354                    }
4355                }
4356                tmp += width[i];
4357            }
4358        }
4359        nn.firstLevelName = 0;
4360        nn.nLevelNames = stuff->nTypes;
4361    }
4362    if (stuff->which & XkbIndicatorNamesMask) {
4363        tmp = _XkbCopyMaskedAtoms(tmp, names->indicators, XkbNumIndicators,
4364                                  stuff->indicators);
4365        nn.changedIndicators = stuff->indicators;
4366    }
4367    if (stuff->which & XkbVirtualModNamesMask) {
4368        tmp = _XkbCopyMaskedAtoms(tmp, names->vmods, XkbNumVirtualMods,
4369                                  stuff->virtualMods);
4370        nn.changedVirtualMods = stuff->virtualMods;
4371    }
4372    if (stuff->which & XkbGroupNamesMask) {
4373        tmp = _XkbCopyMaskedAtoms(tmp, names->groups, XkbNumKbdGroups,
4374                                  stuff->groupNames);
4375        nn.changedVirtualMods = stuff->groupNames;
4376    }
4377    if (stuff->which & XkbKeyNamesMask) {
4378        memcpy((char *) &names->keys[stuff->firstKey], (char *) tmp,
4379               stuff->nKeys * XkbKeyNameLength);
4380        tmp += stuff->nKeys;
4381        nn.firstKey = stuff->firstKey;
4382        nn.nKeys = stuff->nKeys;
4383    }
4384    if (stuff->which & XkbKeyAliasesMask) {
4385        if (stuff->nKeyAliases > 0) {
4386            register int na = stuff->nKeyAliases;
4387
4388            if (XkbAllocNames(xkb, XkbKeyAliasesMask, 0, na) != Success)
4389                return BadAlloc;
4390            memcpy((char *) names->key_aliases, (char *) tmp,
4391                   stuff->nKeyAliases * sizeof(XkbKeyAliasRec));
4392            tmp += stuff->nKeyAliases * 2;
4393        }
4394        else if (names->key_aliases != NULL) {
4395            free(names->key_aliases);
4396            names->key_aliases = NULL;
4397            names->num_key_aliases = 0;
4398        }
4399        nn.nAliases = names->num_key_aliases;
4400    }
4401    if (stuff->which & XkbRGNamesMask) {
4402        if (stuff->nRadioGroups > 0) {
4403            register unsigned i, nrg;
4404
4405            nrg = stuff->nRadioGroups;
4406            if (XkbAllocNames(xkb, XkbRGNamesMask, nrg, 0) != Success)
4407                return BadAlloc;
4408
4409            for (i = 0; i < stuff->nRadioGroups; i++) {
4410                names->radio_groups[i] = tmp[i];
4411            }
4412            tmp += stuff->nRadioGroups;
4413        }
4414        else if (names->radio_groups) {
4415            free(names->radio_groups);
4416            names->radio_groups = NULL;
4417            names->num_rg = 0;
4418        }
4419        nn.nRadioGroups = names->num_rg;
4420    }
4421    if (nn.changed) {
4422        Bool needExtEvent;
4423
4424        needExtEvent = (nn.changed & XkbIndicatorNamesMask) != 0;
4425        XkbSendNamesNotify(dev, &nn);
4426        if (needExtEvent) {
4427            XkbSrvLedInfoPtr sli;
4428            xkbExtensionDeviceNotify edev;
4429            register int i;
4430            register unsigned bit;
4431
4432            sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId,
4433                                    XkbXI_IndicatorsMask);
4434            sli->namesPresent = 0;
4435            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
4436                if (names->indicators[i] != None)
4437                    sli->namesPresent |= bit;
4438            }
4439            memset(&edev, 0, sizeof(xkbExtensionDeviceNotify));
4440            edev.reason = XkbXI_IndicatorNamesMask;
4441            edev.ledClass = KbdFeedbackClass;
4442            edev.ledID = dev->kbdfeed->ctrl.id;
4443            edev.ledsDefined = sli->namesPresent | sli->mapsPresent;
4444            edev.ledState = sli->effectiveState;
4445            edev.firstBtn = 0;
4446            edev.nBtns = 0;
4447            edev.supported = XkbXI_AllFeaturesMask;
4448            edev.unsupported = 0;
4449            XkbSendExtensionDeviceNotify(dev, client, &edev);
4450        }
4451    }
4452    return Success;
4453}
4454
4455int
4456ProcXkbSetNames(ClientPtr client)
4457{
4458    DeviceIntPtr dev;
4459    CARD32 *tmp;
4460    Atom bad;
4461    int rc;
4462
4463    REQUEST(xkbSetNamesReq);
4464    REQUEST_AT_LEAST_SIZE(xkbSetNamesReq);
4465
4466    if (!(client->xkbClientFlags & _XkbClientInitialized))
4467        return BadAccess;
4468
4469    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
4470    CHK_MASK_LEGAL(0x01, stuff->which, XkbAllNamesMask);
4471
4472    /* check device-independent stuff */
4473    tmp = (CARD32 *) &stuff[1];
4474
4475    if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + 1))
4476        return BadLength;
4477    if (stuff->which & XkbKeycodesNameMask) {
4478        tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
4479        if (!tmp) {
4480            client->errorValue = bad;
4481            return BadAtom;
4482        }
4483    }
4484    if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + 1))
4485        return BadLength;
4486    if (stuff->which & XkbGeometryNameMask) {
4487        tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
4488        if (!tmp) {
4489            client->errorValue = bad;
4490            return BadAtom;
4491        }
4492    }
4493    if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + 1))
4494        return BadLength;
4495    if (stuff->which & XkbSymbolsNameMask) {
4496        tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
4497        if (!tmp) {
4498            client->errorValue = bad;
4499            return BadAtom;
4500        }
4501    }
4502    if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + 1))
4503        return BadLength;
4504    if (stuff->which & XkbPhysSymbolsNameMask) {
4505        tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
4506        if (!tmp) {
4507            client->errorValue = bad;
4508            return BadAtom;
4509        }
4510    }
4511    if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + 1))
4512        return BadLength;
4513    if (stuff->which & XkbTypesNameMask) {
4514        tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
4515        if (!tmp) {
4516            client->errorValue = bad;
4517            return BadAtom;
4518        }
4519    }
4520    if (!_XkbCheckRequestBounds(client, stuff, tmp, tmp + 1))
4521        return BadLength;
4522    if (stuff->which & XkbCompatNameMask) {
4523        tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
4524        if (!tmp) {
4525            client->errorValue = bad;
4526            return BadAtom;
4527        }
4528    }
4529
4530    /* start of device-dependent tests */
4531    rc = _XkbSetNamesCheck(client, dev, stuff, tmp);
4532    if (rc != Success)
4533        return rc;
4534
4535    if (stuff->deviceSpec == XkbUseCoreKbd) {
4536        DeviceIntPtr other;
4537
4538        for (other = inputInfo.devices; other; other = other->next) {
4539            if ((other != dev) && other->key && !IsMaster(other) &&
4540                GetMaster(other, MASTER_KEYBOARD) == dev) {
4541
4542                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
4543                              DixManageAccess);
4544                if (rc == Success) {
4545                    rc = _XkbSetNamesCheck(client, other, stuff, tmp);
4546                    if (rc != Success)
4547                        return rc;
4548                }
4549            }
4550        }
4551    }
4552
4553    /* everything is okay -- update names */
4554
4555    rc = _XkbSetNames(client, dev, stuff);
4556    if (rc != Success)
4557        return rc;
4558
4559    if (stuff->deviceSpec == XkbUseCoreKbd) {
4560        DeviceIntPtr other;
4561
4562        for (other = inputInfo.devices; other; other = other->next) {
4563            if ((other != dev) && other->key && !IsMaster(other) &&
4564                GetMaster(other, MASTER_KEYBOARD) == dev) {
4565
4566                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
4567                              DixManageAccess);
4568                if (rc == Success)
4569                    _XkbSetNames(client, other, stuff);
4570            }
4571        }
4572    }
4573
4574    /* everything is okay -- update names */
4575
4576    return Success;
4577}
4578
4579/***====================================================================***/
4580
4581#include "xkbgeom.h"
4582
4583#define	XkbSizeCountedString(s)  ((s)?((((2+strlen(s))+3)/4)*4):4)
4584
4585/**
4586 * Write the zero-terminated string str into wire as a pascal string with a
4587 * 16-bit length field prefixed before the actual string.
4588 *
4589 * @param wire The destination array, usually the wire struct
4590 * @param str The source string as zero-terminated C string
4591 * @param swap If TRUE, the length field is swapped.
4592 *
4593 * @return The input string in the format <string length><string> with a
4594 * (swapped) 16 bit string length, non-zero terminated.
4595 */
4596static char *
4597XkbWriteCountedString(char *wire, const char *str, Bool swap)
4598{
4599    CARD16 len, *pLen, paddedLen;
4600
4601    if (!str)
4602        return wire;
4603
4604    len = strlen(str);
4605    pLen = (CARD16 *) wire;
4606    *pLen = len;
4607    if (swap) {
4608        swaps(pLen);
4609    }
4610    paddedLen = pad_to_int32(sizeof(len) + len) - sizeof(len);
4611    strncpy(&wire[sizeof(len)], str, paddedLen);
4612    wire += sizeof(len) + paddedLen;
4613    return wire;
4614}
4615
4616static int
4617XkbSizeGeomProperties(XkbGeometryPtr geom)
4618{
4619    register int i, size;
4620    XkbPropertyPtr prop;
4621
4622    for (size = i = 0, prop = geom->properties; i < geom->num_properties;
4623         i++, prop++) {
4624        size += XkbSizeCountedString(prop->name);
4625        size += XkbSizeCountedString(prop->value);
4626    }
4627    return size;
4628}
4629
4630static char *
4631XkbWriteGeomProperties(char *wire, XkbGeometryPtr geom, Bool swap)
4632{
4633    register int i;
4634    register XkbPropertyPtr prop;
4635
4636    for (i = 0, prop = geom->properties; i < geom->num_properties; i++, prop++) {
4637        wire = XkbWriteCountedString(wire, prop->name, swap);
4638        wire = XkbWriteCountedString(wire, prop->value, swap);
4639    }
4640    return wire;
4641}
4642
4643static int
4644XkbSizeGeomKeyAliases(XkbGeometryPtr geom)
4645{
4646    return geom->num_key_aliases * (2 * XkbKeyNameLength);
4647}
4648
4649static char *
4650XkbWriteGeomKeyAliases(char *wire, XkbGeometryPtr geom, Bool swap)
4651{
4652    register int sz;
4653
4654    sz = geom->num_key_aliases * (XkbKeyNameLength * 2);
4655    if (sz > 0) {
4656        memcpy(wire, (char *) geom->key_aliases, sz);
4657        wire += sz;
4658    }
4659    return wire;
4660}
4661
4662static int
4663XkbSizeGeomColors(XkbGeometryPtr geom)
4664{
4665    register int i, size;
4666    register XkbColorPtr color;
4667
4668    for (i = size = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
4669        size += XkbSizeCountedString(color->spec);
4670    }
4671    return size;
4672}
4673
4674static char *
4675XkbWriteGeomColors(char *wire, XkbGeometryPtr geom, Bool swap)
4676{
4677    register int i;
4678    register XkbColorPtr color;
4679
4680    for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
4681        wire = XkbWriteCountedString(wire, color->spec, swap);
4682    }
4683    return wire;
4684}
4685
4686static int
4687XkbSizeGeomShapes(XkbGeometryPtr geom)
4688{
4689    register int i, size;
4690    register XkbShapePtr shape;
4691
4692    for (i = size = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
4693        register int n;
4694        register XkbOutlinePtr ol;
4695
4696        size += SIZEOF(xkbShapeWireDesc);
4697        for (n = 0, ol = shape->outlines; n < shape->num_outlines; n++, ol++) {
4698            size += SIZEOF(xkbOutlineWireDesc);
4699            size += ol->num_points * SIZEOF(xkbPointWireDesc);
4700        }
4701    }
4702    return size;
4703}
4704
4705static char *
4706XkbWriteGeomShapes(char *wire, XkbGeometryPtr geom, Bool swap)
4707{
4708    int i;
4709    XkbShapePtr shape;
4710    xkbShapeWireDesc *shapeWire;
4711
4712    for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
4713        register int o;
4714        XkbOutlinePtr ol;
4715        xkbOutlineWireDesc *olWire;
4716
4717        shapeWire = (xkbShapeWireDesc *) wire;
4718        shapeWire->name = shape->name;
4719        shapeWire->nOutlines = shape->num_outlines;
4720        if (shape->primary != NULL)
4721            shapeWire->primaryNdx = XkbOutlineIndex(shape, shape->primary);
4722        else
4723            shapeWire->primaryNdx = XkbNoShape;
4724        if (shape->approx != NULL)
4725            shapeWire->approxNdx = XkbOutlineIndex(shape, shape->approx);
4726        else
4727            shapeWire->approxNdx = XkbNoShape;
4728        shapeWire->pad = 0;
4729        if (swap) {
4730            swapl(&shapeWire->name);
4731        }
4732        wire = (char *) &shapeWire[1];
4733        for (o = 0, ol = shape->outlines; o < shape->num_outlines; o++, ol++) {
4734            register int p;
4735            XkbPointPtr pt;
4736            xkbPointWireDesc *ptWire;
4737
4738            olWire = (xkbOutlineWireDesc *) wire;
4739            olWire->nPoints = ol->num_points;
4740            olWire->cornerRadius = ol->corner_radius;
4741            olWire->pad = 0;
4742            wire = (char *) &olWire[1];
4743            ptWire = (xkbPointWireDesc *) wire;
4744            for (p = 0, pt = ol->points; p < ol->num_points; p++, pt++) {
4745                ptWire[p].x = pt->x;
4746                ptWire[p].y = pt->y;
4747                if (swap) {
4748                    swaps(&ptWire[p].x);
4749                    swaps(&ptWire[p].y);
4750                }
4751            }
4752            wire = (char *) &ptWire[ol->num_points];
4753        }
4754    }
4755    return wire;
4756}
4757
4758static int
4759XkbSizeGeomDoodads(int num_doodads, XkbDoodadPtr doodad)
4760{
4761    register int i, size;
4762
4763    for (i = size = 0; i < num_doodads; i++, doodad++) {
4764        size += SIZEOF(xkbAnyDoodadWireDesc);
4765        if (doodad->any.type == XkbTextDoodad) {
4766            size += XkbSizeCountedString(doodad->text.text);
4767            size += XkbSizeCountedString(doodad->text.font);
4768        }
4769        else if (doodad->any.type == XkbLogoDoodad) {
4770            size += XkbSizeCountedString(doodad->logo.logo_name);
4771        }
4772    }
4773    return size;
4774}
4775
4776static char *
4777XkbWriteGeomDoodads(char *wire, int num_doodads, XkbDoodadPtr doodad, Bool swap)
4778{
4779    register int i;
4780    xkbDoodadWireDesc *doodadWire;
4781
4782    for (i = 0; i < num_doodads; i++, doodad++) {
4783        doodadWire = (xkbDoodadWireDesc *) wire;
4784        wire = (char *) &doodadWire[1];
4785        memset(doodadWire, 0, SIZEOF(xkbDoodadWireDesc));
4786        doodadWire->any.name = doodad->any.name;
4787        doodadWire->any.type = doodad->any.type;
4788        doodadWire->any.priority = doodad->any.priority;
4789        doodadWire->any.top = doodad->any.top;
4790        doodadWire->any.left = doodad->any.left;
4791        if (swap) {
4792            swapl(&doodadWire->any.name);
4793            swaps(&doodadWire->any.top);
4794            swaps(&doodadWire->any.left);
4795        }
4796        switch (doodad->any.type) {
4797        case XkbOutlineDoodad:
4798        case XkbSolidDoodad:
4799            doodadWire->shape.angle = doodad->shape.angle;
4800            doodadWire->shape.colorNdx = doodad->shape.color_ndx;
4801            doodadWire->shape.shapeNdx = doodad->shape.shape_ndx;
4802            if (swap) {
4803                swaps(&doodadWire->shape.angle);
4804            }
4805            break;
4806        case XkbTextDoodad:
4807            doodadWire->text.angle = doodad->text.angle;
4808            doodadWire->text.width = doodad->text.width;
4809            doodadWire->text.height = doodad->text.height;
4810            doodadWire->text.colorNdx = doodad->text.color_ndx;
4811            if (swap) {
4812                swaps(&doodadWire->text.angle);
4813                swaps(&doodadWire->text.width);
4814                swaps(&doodadWire->text.height);
4815            }
4816            wire = XkbWriteCountedString(wire, doodad->text.text, swap);
4817            wire = XkbWriteCountedString(wire, doodad->text.font, swap);
4818            break;
4819        case XkbIndicatorDoodad:
4820            doodadWire->indicator.shapeNdx = doodad->indicator.shape_ndx;
4821            doodadWire->indicator.onColorNdx = doodad->indicator.on_color_ndx;
4822            doodadWire->indicator.offColorNdx = doodad->indicator.off_color_ndx;
4823            break;
4824        case XkbLogoDoodad:
4825            doodadWire->logo.angle = doodad->logo.angle;
4826            doodadWire->logo.colorNdx = doodad->logo.color_ndx;
4827            doodadWire->logo.shapeNdx = doodad->logo.shape_ndx;
4828            wire = XkbWriteCountedString(wire, doodad->logo.logo_name, swap);
4829            break;
4830        default:
4831            ErrorF("[xkb] Unknown doodad type %d in XkbWriteGeomDoodads\n",
4832                   doodad->any.type);
4833            ErrorF("[xkb] Ignored\n");
4834            break;
4835        }
4836    }
4837    return wire;
4838}
4839
4840static char *
4841XkbWriteGeomOverlay(char *wire, XkbOverlayPtr ol, Bool swap)
4842{
4843    register int r;
4844    XkbOverlayRowPtr row;
4845    xkbOverlayWireDesc *olWire;
4846
4847    olWire = (xkbOverlayWireDesc *) wire;
4848    olWire->name = ol->name;
4849    olWire->nRows = ol->num_rows;
4850    olWire->pad1 = 0;
4851    olWire->pad2 = 0;
4852    if (swap) {
4853        swapl(&olWire->name);
4854    }
4855    wire = (char *) &olWire[1];
4856    for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
4857        unsigned int k;
4858        XkbOverlayKeyPtr key;
4859        xkbOverlayRowWireDesc *rowWire;
4860
4861        rowWire = (xkbOverlayRowWireDesc *) wire;
4862        rowWire->rowUnder = row->row_under;
4863        rowWire->nKeys = row->num_keys;
4864        rowWire->pad1 = 0;
4865        wire = (char *) &rowWire[1];
4866        for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
4867            xkbOverlayKeyWireDesc *keyWire;
4868
4869            keyWire = (xkbOverlayKeyWireDesc *) wire;
4870            memcpy(keyWire->over, key->over.name, XkbKeyNameLength);
4871            memcpy(keyWire->under, key->under.name, XkbKeyNameLength);
4872            wire = (char *) &keyWire[1];
4873        }
4874    }
4875    return wire;
4876}
4877
4878static int
4879XkbSizeGeomSections(XkbGeometryPtr geom)
4880{
4881    register int i, size;
4882    XkbSectionPtr section;
4883
4884    for (i = size = 0, section = geom->sections; i < geom->num_sections;
4885         i++, section++) {
4886        size += SIZEOF(xkbSectionWireDesc);
4887        if (section->rows) {
4888            int r;
4889            XkbRowPtr row;
4890
4891            for (r = 0, row = section->rows; r < section->num_rows; row++, r++) {
4892                size += SIZEOF(xkbRowWireDesc);
4893                size += row->num_keys * SIZEOF(xkbKeyWireDesc);
4894            }
4895        }
4896        if (section->doodads)
4897            size += XkbSizeGeomDoodads(section->num_doodads, section->doodads);
4898        if (section->overlays) {
4899            int o;
4900            XkbOverlayPtr ol;
4901
4902            for (o = 0, ol = section->overlays; o < section->num_overlays;
4903                 o++, ol++) {
4904                int r;
4905                XkbOverlayRowPtr row;
4906
4907                size += SIZEOF(xkbOverlayWireDesc);
4908                for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
4909                    size += SIZEOF(xkbOverlayRowWireDesc);
4910                    size += row->num_keys * SIZEOF(xkbOverlayKeyWireDesc);
4911                }
4912            }
4913        }
4914    }
4915    return size;
4916}
4917
4918static char *
4919XkbWriteGeomSections(char *wire, XkbGeometryPtr geom, Bool swap)
4920{
4921    register int i;
4922    XkbSectionPtr section;
4923    xkbSectionWireDesc *sectionWire;
4924
4925    for (i = 0, section = geom->sections; i < geom->num_sections;
4926         i++, section++) {
4927        sectionWire = (xkbSectionWireDesc *) wire;
4928        sectionWire->name = section->name;
4929        sectionWire->top = section->top;
4930        sectionWire->left = section->left;
4931        sectionWire->width = section->width;
4932        sectionWire->height = section->height;
4933        sectionWire->angle = section->angle;
4934        sectionWire->priority = section->priority;
4935        sectionWire->nRows = section->num_rows;
4936        sectionWire->nDoodads = section->num_doodads;
4937        sectionWire->nOverlays = section->num_overlays;
4938        sectionWire->pad = 0;
4939        if (swap) {
4940            swapl(&sectionWire->name);
4941            swaps(&sectionWire->top);
4942            swaps(&sectionWire->left);
4943            swaps(&sectionWire->width);
4944            swaps(&sectionWire->height);
4945            swaps(&sectionWire->angle);
4946        }
4947        wire = (char *) &sectionWire[1];
4948        if (section->rows) {
4949            int r;
4950            XkbRowPtr row;
4951            xkbRowWireDesc *rowWire;
4952
4953            for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
4954                rowWire = (xkbRowWireDesc *) wire;
4955                rowWire->top = row->top;
4956                rowWire->left = row->left;
4957                rowWire->nKeys = row->num_keys;
4958                rowWire->vertical = row->vertical;
4959                rowWire->pad = 0;
4960                if (swap) {
4961                    swaps(&rowWire->top);
4962                    swaps(&rowWire->left);
4963                }
4964                wire = (char *) &rowWire[1];
4965                if (row->keys) {
4966                    int k;
4967                    XkbKeyPtr key;
4968                    xkbKeyWireDesc *keyWire;
4969
4970                    keyWire = (xkbKeyWireDesc *) wire;
4971                    for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
4972                        memcpy(keyWire[k].name, key->name.name,
4973                               XkbKeyNameLength);
4974                        keyWire[k].gap = key->gap;
4975                        keyWire[k].shapeNdx = key->shape_ndx;
4976                        keyWire[k].colorNdx = key->color_ndx;
4977                        if (swap) {
4978                            swaps(&keyWire[k].gap);
4979                        }
4980                    }
4981                    wire = (char *) &keyWire[row->num_keys];
4982                }
4983            }
4984        }
4985        if (section->doodads) {
4986            wire = XkbWriteGeomDoodads(wire,
4987                                       section->num_doodads, section->doodads,
4988                                       swap);
4989        }
4990        if (section->overlays) {
4991            register int o;
4992
4993            for (o = 0; o < section->num_overlays; o++) {
4994                wire = XkbWriteGeomOverlay(wire, &section->overlays[o], swap);
4995            }
4996        }
4997    }
4998    return wire;
4999}
5000
5001static Status
5002XkbComputeGetGeometryReplySize(XkbGeometryPtr geom,
5003                               xkbGetGeometryReply * rep, Atom name)
5004{
5005    int len;
5006
5007    if (geom != NULL) {
5008        len = XkbSizeCountedString(geom->label_font);
5009        len += XkbSizeGeomProperties(geom);
5010        len += XkbSizeGeomColors(geom);
5011        len += XkbSizeGeomShapes(geom);
5012        len += XkbSizeGeomSections(geom);
5013        len += XkbSizeGeomDoodads(geom->num_doodads, geom->doodads);
5014        len += XkbSizeGeomKeyAliases(geom);
5015        rep->length = len / 4;
5016        rep->found = TRUE;
5017        rep->name = geom->name;
5018        rep->widthMM = geom->width_mm;
5019        rep->heightMM = geom->height_mm;
5020        rep->nProperties = geom->num_properties;
5021        rep->nColors = geom->num_colors;
5022        rep->nShapes = geom->num_shapes;
5023        rep->nSections = geom->num_sections;
5024        rep->nDoodads = geom->num_doodads;
5025        rep->nKeyAliases = geom->num_key_aliases;
5026        rep->baseColorNdx = XkbGeomColorIndex(geom, geom->base_color);
5027        rep->labelColorNdx = XkbGeomColorIndex(geom, geom->label_color);
5028    }
5029    else {
5030        rep->length = 0;
5031        rep->found = FALSE;
5032        rep->name = name;
5033        rep->widthMM = rep->heightMM = 0;
5034        rep->nProperties = rep->nColors = rep->nShapes = 0;
5035        rep->nSections = rep->nDoodads = 0;
5036        rep->nKeyAliases = 0;
5037        rep->labelColorNdx = rep->baseColorNdx = 0;
5038    }
5039    return Success;
5040}
5041static int
5042XkbSendGeometry(ClientPtr client,
5043                XkbGeometryPtr geom, xkbGetGeometryReply * rep, Bool freeGeom)
5044{
5045    char *desc, *start;
5046    int len;
5047
5048    if (geom != NULL) {
5049        start = desc = xallocarray(rep->length, 4);
5050        if (!start)
5051            return BadAlloc;
5052        len = rep->length * 4;
5053        desc = XkbWriteCountedString(desc, geom->label_font, client->swapped);
5054        if (rep->nProperties > 0)
5055            desc = XkbWriteGeomProperties(desc, geom, client->swapped);
5056        if (rep->nColors > 0)
5057            desc = XkbWriteGeomColors(desc, geom, client->swapped);
5058        if (rep->nShapes > 0)
5059            desc = XkbWriteGeomShapes(desc, geom, client->swapped);
5060        if (rep->nSections > 0)
5061            desc = XkbWriteGeomSections(desc, geom, client->swapped);
5062        if (rep->nDoodads > 0)
5063            desc = XkbWriteGeomDoodads(desc, geom->num_doodads, geom->doodads,
5064                                       client->swapped);
5065        if (rep->nKeyAliases > 0)
5066            desc = XkbWriteGeomKeyAliases(desc, geom, client->swapped);
5067        if ((desc - start) != (len)) {
5068            ErrorF
5069                ("[xkb] BOGUS LENGTH in XkbSendGeometry, expected %d, got %ld\n",
5070                 len, (unsigned long) (desc - start));
5071        }
5072    }
5073    else {
5074        len = 0;
5075        start = NULL;
5076    }
5077    if (client->swapped) {
5078        swaps(&rep->sequenceNumber);
5079        swapl(&rep->length);
5080        swapl(&rep->name);
5081        swaps(&rep->widthMM);
5082        swaps(&rep->heightMM);
5083        swaps(&rep->nProperties);
5084        swaps(&rep->nColors);
5085        swaps(&rep->nShapes);
5086        swaps(&rep->nSections);
5087        swaps(&rep->nDoodads);
5088        swaps(&rep->nKeyAliases);
5089    }
5090    WriteToClient(client, SIZEOF(xkbGetGeometryReply), rep);
5091    if (len > 0)
5092        WriteToClient(client, len, start);
5093    if (start != NULL)
5094        free((char *) start);
5095    if (freeGeom)
5096        XkbFreeGeometry(geom, XkbGeomAllMask, TRUE);
5097    return Success;
5098}
5099
5100int
5101ProcXkbGetGeometry(ClientPtr client)
5102{
5103    DeviceIntPtr dev;
5104    xkbGetGeometryReply rep;
5105    XkbGeometryPtr geom;
5106    Bool shouldFree;
5107    Status status;
5108
5109    REQUEST(xkbGetGeometryReq);
5110    REQUEST_SIZE_MATCH(xkbGetGeometryReq);
5111
5112    if (!(client->xkbClientFlags & _XkbClientInitialized))
5113        return BadAccess;
5114
5115    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
5116    CHK_ATOM_OR_NONE(stuff->name);
5117
5118    geom = XkbLookupNamedGeometry(dev, stuff->name, &shouldFree);
5119    rep = (xkbGetGeometryReply) {
5120        .type = X_Reply,
5121        .deviceID = dev->id,
5122        .sequenceNumber = client->sequence,
5123        .length = 0
5124    };
5125    status = XkbComputeGetGeometryReplySize(geom, &rep, stuff->name);
5126    if (status != Success)
5127        return status;
5128    else
5129        return XkbSendGeometry(client, geom, &rep, shouldFree);
5130}
5131
5132/***====================================================================***/
5133
5134static Status
5135_GetCountedString(char **wire_inout, ClientPtr client, char **str)
5136{
5137    char *wire, *next;
5138    CARD16 len;
5139
5140    wire = *wire_inout;
5141    len = *(CARD16 *) wire;
5142    if (client->swapped) {
5143        swaps(&len);
5144    }
5145    next = wire + XkbPaddedSize(len + 2);
5146    /* Check we're still within the size of the request */
5147    if (client->req_len <
5148        bytes_to_int32(next - (char *) client->requestBuffer))
5149        return BadValue;
5150    *str = malloc(len + 1);
5151    if (!*str)
5152        return BadAlloc;
5153    memcpy(*str, &wire[2], len);
5154    *(*str + len) = '\0';
5155    *wire_inout = next;
5156    return Success;
5157}
5158
5159static Status
5160_CheckSetDoodad(char **wire_inout,
5161                XkbGeometryPtr geom, XkbSectionPtr section, ClientPtr client)
5162{
5163    char *wire;
5164    xkbDoodadWireDesc *dWire;
5165    xkbAnyDoodadWireDesc any;
5166    xkbTextDoodadWireDesc text;
5167    XkbDoodadPtr doodad;
5168    Status status;
5169
5170    dWire = (xkbDoodadWireDesc *) (*wire_inout);
5171    any = dWire->any;
5172    wire = (char *) &dWire[1];
5173    if (client->swapped) {
5174        swapl(&any.name);
5175        swaps(&any.top);
5176        swaps(&any.left);
5177        swaps(&any.angle);
5178    }
5179    CHK_ATOM_ONLY(dWire->any.name);
5180    doodad = XkbAddGeomDoodad(geom, section, any.name);
5181    if (!doodad)
5182        return BadAlloc;
5183    doodad->any.type = dWire->any.type;
5184    doodad->any.priority = dWire->any.priority;
5185    doodad->any.top = any.top;
5186    doodad->any.left = any.left;
5187    doodad->any.angle = any.angle;
5188    switch (doodad->any.type) {
5189    case XkbOutlineDoodad:
5190    case XkbSolidDoodad:
5191        if (dWire->shape.colorNdx >= geom->num_colors) {
5192            client->errorValue = _XkbErrCode3(0x40, geom->num_colors,
5193                                              dWire->shape.colorNdx);
5194            return BadMatch;
5195        }
5196        if (dWire->shape.shapeNdx >= geom->num_shapes) {
5197            client->errorValue = _XkbErrCode3(0x41, geom->num_shapes,
5198                                              dWire->shape.shapeNdx);
5199            return BadMatch;
5200        }
5201        doodad->shape.color_ndx = dWire->shape.colorNdx;
5202        doodad->shape.shape_ndx = dWire->shape.shapeNdx;
5203        break;
5204    case XkbTextDoodad:
5205        if (dWire->text.colorNdx >= geom->num_colors) {
5206            client->errorValue = _XkbErrCode3(0x42, geom->num_colors,
5207                                              dWire->text.colorNdx);
5208            return BadMatch;
5209        }
5210        text = dWire->text;
5211        if (client->swapped) {
5212            swaps(&text.width);
5213            swaps(&text.height);
5214        }
5215        doodad->text.width = text.width;
5216        doodad->text.height = text.height;
5217        doodad->text.color_ndx = dWire->text.colorNdx;
5218        status = _GetCountedString(&wire, client, &doodad->text.text);
5219        if (status != Success)
5220            return status;
5221        status = _GetCountedString(&wire, client, &doodad->text.font);
5222        if (status != Success) {
5223            free (doodad->text.text);
5224            return status;
5225        }
5226        break;
5227    case XkbIndicatorDoodad:
5228        if (dWire->indicator.onColorNdx >= geom->num_colors) {
5229            client->errorValue = _XkbErrCode3(0x43, geom->num_colors,
5230                                              dWire->indicator.onColorNdx);
5231            return BadMatch;
5232        }
5233        if (dWire->indicator.offColorNdx >= geom->num_colors) {
5234            client->errorValue = _XkbErrCode3(0x44, geom->num_colors,
5235                                              dWire->indicator.offColorNdx);
5236            return BadMatch;
5237        }
5238        if (dWire->indicator.shapeNdx >= geom->num_shapes) {
5239            client->errorValue = _XkbErrCode3(0x45, geom->num_shapes,
5240                                              dWire->indicator.shapeNdx);
5241            return BadMatch;
5242        }
5243        doodad->indicator.shape_ndx = dWire->indicator.shapeNdx;
5244        doodad->indicator.on_color_ndx = dWire->indicator.onColorNdx;
5245        doodad->indicator.off_color_ndx = dWire->indicator.offColorNdx;
5246        break;
5247    case XkbLogoDoodad:
5248        if (dWire->logo.colorNdx >= geom->num_colors) {
5249            client->errorValue = _XkbErrCode3(0x46, geom->num_colors,
5250                                              dWire->logo.colorNdx);
5251            return BadMatch;
5252        }
5253        if (dWire->logo.shapeNdx >= geom->num_shapes) {
5254            client->errorValue = _XkbErrCode3(0x47, geom->num_shapes,
5255                                              dWire->logo.shapeNdx);
5256            return BadMatch;
5257        }
5258        doodad->logo.color_ndx = dWire->logo.colorNdx;
5259        doodad->logo.shape_ndx = dWire->logo.shapeNdx;
5260        status = _GetCountedString(&wire, client, &doodad->logo.logo_name);
5261        if (status != Success)
5262            return status;
5263        break;
5264    default:
5265        client->errorValue = _XkbErrCode2(0x4F, dWire->any.type);
5266        return BadValue;
5267    }
5268    *wire_inout = wire;
5269    return Success;
5270}
5271
5272static Status
5273_CheckSetOverlay(char **wire_inout,
5274                 XkbGeometryPtr geom, XkbSectionPtr section, ClientPtr client)
5275{
5276    register int r;
5277    char *wire;
5278    XkbOverlayPtr ol;
5279    xkbOverlayWireDesc *olWire;
5280    xkbOverlayRowWireDesc *rWire;
5281
5282    wire = *wire_inout;
5283    olWire = (xkbOverlayWireDesc *) wire;
5284    if (client->swapped) {
5285        swapl(&olWire->name);
5286    }
5287    CHK_ATOM_ONLY(olWire->name);
5288    ol = XkbAddGeomOverlay(section, olWire->name, olWire->nRows);
5289    rWire = (xkbOverlayRowWireDesc *) &olWire[1];
5290    for (r = 0; r < olWire->nRows; r++) {
5291        register int k;
5292        xkbOverlayKeyWireDesc *kWire;
5293        XkbOverlayRowPtr row;
5294
5295        if (rWire->rowUnder > section->num_rows) {
5296            client->errorValue = _XkbErrCode4(0x20, r, section->num_rows,
5297                                              rWire->rowUnder);
5298            return BadMatch;
5299        }
5300        row = XkbAddGeomOverlayRow(ol, rWire->rowUnder, rWire->nKeys);
5301        kWire = (xkbOverlayKeyWireDesc *) &rWire[1];
5302        for (k = 0; k < rWire->nKeys; k++, kWire++) {
5303            if (XkbAddGeomOverlayKey(ol, row,
5304                                     (char *) kWire->over,
5305                                     (char *) kWire->under) == NULL) {
5306                client->errorValue = _XkbErrCode3(0x21, r, k);
5307                return BadMatch;
5308            }
5309        }
5310        rWire = (xkbOverlayRowWireDesc *) kWire;
5311    }
5312    olWire = (xkbOverlayWireDesc *) rWire;
5313    wire = (char *) olWire;
5314    *wire_inout = wire;
5315    return Success;
5316}
5317
5318static Status
5319_CheckSetSections(XkbGeometryPtr geom,
5320                  xkbSetGeometryReq * req, char **wire_inout, ClientPtr client)
5321{
5322    Status status;
5323    register int s;
5324    char *wire;
5325    xkbSectionWireDesc *sWire;
5326    XkbSectionPtr section;
5327
5328    wire = *wire_inout;
5329    if (req->nSections < 1)
5330        return Success;
5331    sWire = (xkbSectionWireDesc *) wire;
5332    for (s = 0; s < req->nSections; s++) {
5333        register int r;
5334        xkbRowWireDesc *rWire;
5335
5336        if (client->swapped) {
5337            swapl(&sWire->name);
5338            swaps(&sWire->top);
5339            swaps(&sWire->left);
5340            swaps(&sWire->width);
5341            swaps(&sWire->height);
5342            swaps(&sWire->angle);
5343        }
5344        CHK_ATOM_ONLY(sWire->name);
5345        section = XkbAddGeomSection(geom, sWire->name, sWire->nRows,
5346                                    sWire->nDoodads, sWire->nOverlays);
5347        if (!section)
5348            return BadAlloc;
5349        section->priority = sWire->priority;
5350        section->top = sWire->top;
5351        section->left = sWire->left;
5352        section->width = sWire->width;
5353        section->height = sWire->height;
5354        section->angle = sWire->angle;
5355        rWire = (xkbRowWireDesc *) &sWire[1];
5356        for (r = 0; r < sWire->nRows; r++) {
5357            register int k;
5358            XkbRowPtr row;
5359            xkbKeyWireDesc *kWire;
5360
5361            if (client->swapped) {
5362                swaps(&rWire->top);
5363                swaps(&rWire->left);
5364            }
5365            row = XkbAddGeomRow(section, rWire->nKeys);
5366            if (!row)
5367                return BadAlloc;
5368            row->top = rWire->top;
5369            row->left = rWire->left;
5370            row->vertical = rWire->vertical;
5371            kWire = (xkbKeyWireDesc *) &rWire[1];
5372            for (k = 0; k < rWire->nKeys; k++) {
5373                XkbKeyPtr key;
5374
5375                key = XkbAddGeomKey(row);
5376                if (!key)
5377                    return BadAlloc;
5378                memcpy(key->name.name, kWire[k].name, XkbKeyNameLength);
5379                key->gap = kWire[k].gap;
5380                key->shape_ndx = kWire[k].shapeNdx;
5381                key->color_ndx = kWire[k].colorNdx;
5382                if (key->shape_ndx >= geom->num_shapes) {
5383                    client->errorValue = _XkbErrCode3(0x10, key->shape_ndx,
5384                                                      geom->num_shapes);
5385                    return BadMatch;
5386                }
5387                if (key->color_ndx >= geom->num_colors) {
5388                    client->errorValue = _XkbErrCode3(0x11, key->color_ndx,
5389                                                      geom->num_colors);
5390                    return BadMatch;
5391                }
5392            }
5393            rWire = (xkbRowWireDesc *) &kWire[rWire->nKeys];
5394        }
5395        wire = (char *) rWire;
5396        if (sWire->nDoodads > 0) {
5397            register int d;
5398
5399            for (d = 0; d < sWire->nDoodads; d++) {
5400                status = _CheckSetDoodad(&wire, geom, section, client);
5401                if (status != Success)
5402                    return status;
5403            }
5404        }
5405        if (sWire->nOverlays > 0) {
5406            register int o;
5407
5408            for (o = 0; o < sWire->nOverlays; o++) {
5409                status = _CheckSetOverlay(&wire, geom, section, client);
5410                if (status != Success)
5411                    return status;
5412            }
5413        }
5414        sWire = (xkbSectionWireDesc *) wire;
5415    }
5416    wire = (char *) sWire;
5417    *wire_inout = wire;
5418    return Success;
5419}
5420
5421static Status
5422_CheckSetShapes(XkbGeometryPtr geom,
5423                xkbSetGeometryReq * req, char **wire_inout, ClientPtr client)
5424{
5425    register int i;
5426    char *wire;
5427
5428    wire = *wire_inout;
5429    if (req->nShapes < 1) {
5430        client->errorValue = _XkbErrCode2(0x06, req->nShapes);
5431        return BadValue;
5432    }
5433    else {
5434        xkbShapeWireDesc *shapeWire;
5435        XkbShapePtr shape;
5436        register int o;
5437
5438        shapeWire = (xkbShapeWireDesc *) wire;
5439        for (i = 0; i < req->nShapes; i++) {
5440            xkbOutlineWireDesc *olWire;
5441            XkbOutlinePtr ol;
5442
5443            shape =
5444                XkbAddGeomShape(geom, shapeWire->name, shapeWire->nOutlines);
5445            if (!shape)
5446                return BadAlloc;
5447            olWire = (xkbOutlineWireDesc *) (&shapeWire[1]);
5448            for (o = 0; o < shapeWire->nOutlines; o++) {
5449                register int p;
5450                XkbPointPtr pt;
5451                xkbPointWireDesc *ptWire;
5452
5453                ol = XkbAddGeomOutline(shape, olWire->nPoints);
5454                if (!ol)
5455                    return BadAlloc;
5456                ol->corner_radius = olWire->cornerRadius;
5457                ptWire = (xkbPointWireDesc *) &olWire[1];
5458                for (p = 0, pt = ol->points; p < olWire->nPoints; p++, pt++) {
5459                    pt->x = ptWire[p].x;
5460                    pt->y = ptWire[p].y;
5461                    if (client->swapped) {
5462                        swaps(&pt->x);
5463                        swaps(&pt->y);
5464                    }
5465                }
5466                ol->num_points = olWire->nPoints;
5467                olWire = (xkbOutlineWireDesc *) (&ptWire[olWire->nPoints]);
5468            }
5469            if (shapeWire->primaryNdx != XkbNoShape)
5470                shape->primary = &shape->outlines[shapeWire->primaryNdx];
5471            if (shapeWire->approxNdx != XkbNoShape)
5472                shape->approx = &shape->outlines[shapeWire->approxNdx];
5473            shapeWire = (xkbShapeWireDesc *) olWire;
5474        }
5475        wire = (char *) shapeWire;
5476    }
5477    if (geom->num_shapes != req->nShapes) {
5478        client->errorValue = _XkbErrCode3(0x07, geom->num_shapes, req->nShapes);
5479        return BadMatch;
5480    }
5481
5482    *wire_inout = wire;
5483    return Success;
5484}
5485
5486static Status
5487_CheckSetGeom(XkbGeometryPtr geom, xkbSetGeometryReq * req, ClientPtr client)
5488{
5489    register int i;
5490    Status status;
5491    char *wire;
5492
5493    wire = (char *) &req[1];
5494    status = _GetCountedString(&wire, client, &geom->label_font);
5495    if (status != Success)
5496        return status;
5497
5498    for (i = 0; i < req->nProperties; i++) {
5499        char *name, *val;
5500
5501        status = _GetCountedString(&wire, client, &name);
5502        if (status != Success)
5503            return status;
5504        status = _GetCountedString(&wire, client, &val);
5505        if (status != Success) {
5506            free(name);
5507            return status;
5508        }
5509        if (XkbAddGeomProperty(geom, name, val) == NULL) {
5510            free(name);
5511            free(val);
5512            return BadAlloc;
5513        }
5514        free(name);
5515        free(val);
5516    }
5517
5518    if (req->nColors < 2) {
5519        client->errorValue = _XkbErrCode3(0x01, 2, req->nColors);
5520        return BadValue;
5521    }
5522    if (req->baseColorNdx > req->nColors) {
5523        client->errorValue =
5524            _XkbErrCode3(0x03, req->nColors, req->baseColorNdx);
5525        return BadMatch;
5526    }
5527    if (req->labelColorNdx > req->nColors) {
5528        client->errorValue =
5529            _XkbErrCode3(0x03, req->nColors, req->labelColorNdx);
5530        return BadMatch;
5531    }
5532    if (req->labelColorNdx == req->baseColorNdx) {
5533        client->errorValue = _XkbErrCode3(0x04, req->baseColorNdx,
5534                                          req->labelColorNdx);
5535        return BadMatch;
5536    }
5537
5538    for (i = 0; i < req->nColors; i++) {
5539        char *name;
5540
5541        status = _GetCountedString(&wire, client, &name);
5542        if (status != Success)
5543            return status;
5544        if (!XkbAddGeomColor(geom, name, geom->num_colors)) {
5545            free(name);
5546            return BadAlloc;
5547        }
5548        free(name);
5549    }
5550    if (req->nColors != geom->num_colors) {
5551        client->errorValue = _XkbErrCode3(0x05, req->nColors, geom->num_colors);
5552        return BadMatch;
5553    }
5554    geom->label_color = &geom->colors[req->labelColorNdx];
5555    geom->base_color = &geom->colors[req->baseColorNdx];
5556
5557    if ((status = _CheckSetShapes(geom, req, &wire, client)) != Success)
5558        return status;
5559
5560    if ((status = _CheckSetSections(geom, req, &wire, client)) != Success)
5561        return status;
5562
5563    for (i = 0; i < req->nDoodads; i++) {
5564        status = _CheckSetDoodad(&wire, geom, NULL, client);
5565        if (status != Success)
5566            return status;
5567    }
5568
5569    for (i = 0; i < req->nKeyAliases; i++) {
5570        if (XkbAddGeomKeyAlias(geom, &wire[XkbKeyNameLength], wire) == NULL)
5571            return BadAlloc;
5572        wire += 2 * XkbKeyNameLength;
5573    }
5574    return Success;
5575}
5576
5577static int
5578_XkbSetGeometry(ClientPtr client, DeviceIntPtr dev, xkbSetGeometryReq * stuff)
5579{
5580    XkbDescPtr xkb;
5581    Bool new_name;
5582    xkbNewKeyboardNotify nkn;
5583    XkbGeometryPtr geom, old;
5584    XkbGeometrySizesRec sizes;
5585    Status status;
5586
5587    xkb = dev->key->xkbInfo->desc;
5588    old = xkb->geom;
5589    xkb->geom = NULL;
5590
5591    sizes.which = XkbGeomAllMask;
5592    sizes.num_properties = stuff->nProperties;
5593    sizes.num_colors = stuff->nColors;
5594    sizes.num_shapes = stuff->nShapes;
5595    sizes.num_sections = stuff->nSections;
5596    sizes.num_doodads = stuff->nDoodads;
5597    sizes.num_key_aliases = stuff->nKeyAliases;
5598    if ((status = XkbAllocGeometry(xkb, &sizes)) != Success) {
5599        xkb->geom = old;
5600        return status;
5601    }
5602    geom = xkb->geom;
5603    geom->name = stuff->name;
5604    geom->width_mm = stuff->widthMM;
5605    geom->height_mm = stuff->heightMM;
5606    if ((status = _CheckSetGeom(geom, stuff, client)) != Success) {
5607        XkbFreeGeometry(geom, XkbGeomAllMask, TRUE);
5608        xkb->geom = old;
5609        return status;
5610    }
5611    new_name = (xkb->names->geometry != geom->name);
5612    xkb->names->geometry = geom->name;
5613    if (old)
5614        XkbFreeGeometry(old, XkbGeomAllMask, TRUE);
5615    if (new_name) {
5616        xkbNamesNotify nn;
5617
5618        memset(&nn, 0, sizeof(xkbNamesNotify));
5619        nn.changed = XkbGeometryNameMask;
5620        XkbSendNamesNotify(dev, &nn);
5621    }
5622    nkn.deviceID = nkn.oldDeviceID = dev->id;
5623    nkn.minKeyCode = nkn.oldMinKeyCode = xkb->min_key_code;
5624    nkn.maxKeyCode = nkn.oldMaxKeyCode = xkb->max_key_code;
5625    nkn.requestMajor = XkbReqCode;
5626    nkn.requestMinor = X_kbSetGeometry;
5627    nkn.changed = XkbNKN_GeometryMask;
5628    XkbSendNewKeyboardNotify(dev, &nkn);
5629    return Success;
5630}
5631
5632int
5633ProcXkbSetGeometry(ClientPtr client)
5634{
5635    DeviceIntPtr dev;
5636    int rc;
5637
5638    REQUEST(xkbSetGeometryReq);
5639    REQUEST_AT_LEAST_SIZE(xkbSetGeometryReq);
5640
5641    if (!(client->xkbClientFlags & _XkbClientInitialized))
5642        return BadAccess;
5643
5644    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
5645    CHK_ATOM_OR_NONE(stuff->name);
5646
5647    rc = _XkbSetGeometry(client, dev, stuff);
5648    if (rc != Success)
5649        return rc;
5650
5651    if (stuff->deviceSpec == XkbUseCoreKbd) {
5652        DeviceIntPtr other;
5653
5654        for (other = inputInfo.devices; other; other = other->next) {
5655            if ((other != dev) && other->key && !IsMaster(other) &&
5656                GetMaster(other, MASTER_KEYBOARD) == dev) {
5657                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
5658                              DixManageAccess);
5659                if (rc == Success)
5660                    _XkbSetGeometry(client, other, stuff);
5661            }
5662        }
5663    }
5664
5665    return Success;
5666}
5667
5668/***====================================================================***/
5669
5670int
5671ProcXkbPerClientFlags(ClientPtr client)
5672{
5673    DeviceIntPtr dev;
5674    xkbPerClientFlagsReply rep;
5675    XkbInterestPtr interest;
5676    Mask access_mode = DixGetAttrAccess | DixSetAttrAccess;
5677
5678    REQUEST(xkbPerClientFlagsReq);
5679    REQUEST_SIZE_MATCH(xkbPerClientFlagsReq);
5680
5681    if (!(client->xkbClientFlags & _XkbClientInitialized))
5682        return BadAccess;
5683
5684    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode);
5685    CHK_MASK_LEGAL(0x01, stuff->change, XkbPCF_AllFlagsMask);
5686    CHK_MASK_MATCH(0x02, stuff->change, stuff->value);
5687
5688    interest = XkbFindClientResource((DevicePtr) dev, client);
5689    if (stuff->change) {
5690        client->xkbClientFlags &= ~stuff->change;
5691        client->xkbClientFlags |= stuff->value;
5692    }
5693    if (stuff->change & XkbPCF_AutoResetControlsMask) {
5694        Bool want;
5695
5696        want = stuff->value & XkbPCF_AutoResetControlsMask;
5697        if (interest && !want) {
5698            interest->autoCtrls = interest->autoCtrlValues = 0;
5699        }
5700        else if (want && (!interest)) {
5701            XID id = FakeClientID(client->index);
5702
5703            if (!AddResource(id, RT_XKBCLIENT, dev))
5704                return BadAlloc;
5705            interest = XkbAddClientResource((DevicePtr) dev, client, id);
5706            if (!interest)
5707                return BadAlloc;
5708        }
5709        if (interest && want) {
5710            register unsigned affect;
5711
5712            affect = stuff->ctrlsToChange;
5713
5714            CHK_MASK_LEGAL(0x03, affect, XkbAllBooleanCtrlsMask);
5715            CHK_MASK_MATCH(0x04, affect, stuff->autoCtrls);
5716            CHK_MASK_MATCH(0x05, stuff->autoCtrls, stuff->autoCtrlValues);
5717
5718            interest->autoCtrls &= ~affect;
5719            interest->autoCtrlValues &= ~affect;
5720            interest->autoCtrls |= stuff->autoCtrls & affect;
5721            interest->autoCtrlValues |= stuff->autoCtrlValues & affect;
5722        }
5723    }
5724
5725    rep = (xkbPerClientFlagsReply) {
5726        .type = X_Reply,
5727        .sequenceNumber = client->sequence,
5728        .length = 0,
5729        .supported = XkbPCF_AllFlagsMask,
5730        .value = client->xkbClientFlags & XkbPCF_AllFlagsMask,
5731        .autoCtrls = interest ? interest->autoCtrls : 0,
5732        .autoCtrlValues =  interest ? interest->autoCtrlValues : 0,
5733    };
5734    if (client->swapped) {
5735        swaps(&rep.sequenceNumber);
5736        swapl(&rep.supported);
5737        swapl(&rep.value);
5738        swapl(&rep.autoCtrls);
5739        swapl(&rep.autoCtrlValues);
5740    }
5741    WriteToClient(client, SIZEOF(xkbPerClientFlagsReply), &rep);
5742    return Success;
5743}
5744
5745/***====================================================================***/
5746
5747/* all latin-1 alphanumerics, plus parens, minus, underscore, slash */
5748/* and wildcards */
5749static unsigned char componentSpecLegal[] = {
5750    0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x87,
5751    0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
5752    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5753    0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
5754};
5755
5756/* same as above but accepts percent, plus and bar too */
5757static unsigned char componentExprLegal[] = {
5758    0x00, 0x00, 0x00, 0x00, 0x20, 0xaf, 0xff, 0x87,
5759    0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x17,
5760    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5761    0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
5762};
5763
5764static char *
5765GetComponentSpec(unsigned char **pWire, Bool allowExpr, int *errRtrn)
5766{
5767    int len;
5768    register int i;
5769    unsigned char *wire, *str, *tmp, *legal;
5770
5771    if (allowExpr)
5772        legal = &componentExprLegal[0];
5773    else
5774        legal = &componentSpecLegal[0];
5775
5776    wire = *pWire;
5777    len = (*(unsigned char *) wire++);
5778    if (len > 0) {
5779        str = calloc(1, len + 1);
5780        if (str) {
5781            tmp = str;
5782            for (i = 0; i < len; i++) {
5783                if (legal[(*wire) / 8] & (1 << ((*wire) % 8)))
5784                    *tmp++ = *wire++;
5785                else
5786                    wire++;
5787            }
5788            if (tmp != str)
5789                *tmp++ = '\0';
5790            else {
5791                free(str);
5792                str = NULL;
5793            }
5794        }
5795        else {
5796            *errRtrn = BadAlloc;
5797        }
5798    }
5799    else {
5800        str = NULL;
5801    }
5802    *pWire = wire;
5803    return (char *) str;
5804}
5805
5806/***====================================================================***/
5807
5808int
5809ProcXkbListComponents(ClientPtr client)
5810{
5811    DeviceIntPtr dev;
5812    xkbListComponentsReply rep;
5813    unsigned len;
5814    unsigned char *str;
5815    uint8_t size;
5816    int i;
5817
5818    REQUEST(xkbListComponentsReq);
5819    REQUEST_AT_LEAST_SIZE(xkbListComponentsReq);
5820
5821    if (!(client->xkbClientFlags & _XkbClientInitialized))
5822        return BadAccess;
5823
5824    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
5825
5826    /* The request is followed by six Pascal strings (i.e. size in characters
5827     * followed by a string pattern) describing what the client wants us to
5828     * list.  We don't care, but might as well check they haven't got the
5829     * length wrong. */
5830    str = (unsigned char *) &stuff[1];
5831    for (i = 0; i < 6; i++) {
5832        size = *((uint8_t *)str);
5833        len = (str + size + 1) - ((unsigned char *) stuff);
5834        if ((XkbPaddedSize(len) / 4) > stuff->length)
5835            return BadLength;
5836        str += (size + 1);
5837    }
5838    if ((XkbPaddedSize(len) / 4) != stuff->length)
5839        return BadLength;
5840    rep = (xkbListComponentsReply) {
5841        .type = X_Reply,
5842        .deviceID = dev->id,
5843        .sequenceNumber = client->sequence,
5844        .length = 0,
5845        .nKeymaps = 0,
5846        .nKeycodes = 0,
5847        .nTypes = 0,
5848        .nCompatMaps = 0,
5849        .nSymbols = 0,
5850        .nGeometries = 0,
5851        .extra = 0
5852    };
5853    if (client->swapped) {
5854        swaps(&rep.sequenceNumber);
5855        swapl(&rep.length);
5856        swaps(&rep.nKeymaps);
5857        swaps(&rep.nKeycodes);
5858        swaps(&rep.nTypes);
5859        swaps(&rep.nCompatMaps);
5860        swaps(&rep.nSymbols);
5861        swaps(&rep.nGeometries);
5862        swaps(&rep.extra);
5863    }
5864    WriteToClient(client, SIZEOF(xkbListComponentsReply), &rep);
5865    return Success;
5866}
5867
5868/***====================================================================***/
5869int
5870ProcXkbGetKbdByName(ClientPtr client)
5871{
5872    DeviceIntPtr dev;
5873    DeviceIntPtr tmpd;
5874    DeviceIntPtr master;
5875    xkbGetKbdByNameReply rep = { 0 };
5876    xkbGetMapReply mrep = { 0 };
5877    xkbGetCompatMapReply crep = { 0 };
5878    xkbGetIndicatorMapReply irep = { 0 };
5879    xkbGetNamesReply nrep = { 0 };
5880    xkbGetGeometryReply grep = { 0 };
5881    XkbComponentNamesRec names = { 0 };
5882    XkbDescPtr xkb, new;
5883    XkbEventCauseRec cause;
5884    unsigned char *str;
5885    char mapFile[PATH_MAX];
5886    unsigned len;
5887    unsigned fwant, fneed, reported;
5888    int status;
5889    Bool geom_changed;
5890    XkbSrvLedInfoPtr old_sli;
5891    XkbSrvLedInfoPtr sli;
5892    Mask access_mode = DixGetAttrAccess | DixManageAccess;
5893
5894    REQUEST(xkbGetKbdByNameReq);
5895    REQUEST_AT_LEAST_SIZE(xkbGetKbdByNameReq);
5896
5897    if (!(client->xkbClientFlags & _XkbClientInitialized))
5898        return BadAccess;
5899
5900    CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode);
5901    master = GetMaster(dev, MASTER_KEYBOARD);
5902
5903    xkb = dev->key->xkbInfo->desc;
5904    status = Success;
5905    str = (unsigned char *) &stuff[1];
5906    if (GetComponentSpec(&str, TRUE, &status))  /* keymap, unsupported */
5907        return BadMatch;
5908    names.keycodes = GetComponentSpec(&str, TRUE, &status);
5909    names.types = GetComponentSpec(&str, TRUE, &status);
5910    names.compat = GetComponentSpec(&str, TRUE, &status);
5911    names.symbols = GetComponentSpec(&str, TRUE, &status);
5912    names.geometry = GetComponentSpec(&str, TRUE, &status);
5913    if (status != Success)
5914        return status;
5915    len = str - ((unsigned char *) stuff);
5916    if ((XkbPaddedSize(len) / 4) != stuff->length)
5917        return BadLength;
5918
5919    CHK_MASK_LEGAL(0x01, stuff->want, XkbGBN_AllComponentsMask);
5920    CHK_MASK_LEGAL(0x02, stuff->need, XkbGBN_AllComponentsMask);
5921
5922    if (stuff->load)
5923        fwant = XkbGBN_AllComponentsMask;
5924    else
5925        fwant = stuff->want | stuff->need;
5926    if ((!names.compat) &&
5927        (fwant & (XkbGBN_CompatMapMask | XkbGBN_IndicatorMapMask))) {
5928        names.compat = Xstrdup("%");
5929    }
5930    if ((!names.types) && (fwant & (XkbGBN_TypesMask))) {
5931        names.types = Xstrdup("%");
5932    }
5933    if ((!names.symbols) && (fwant & XkbGBN_SymbolsMask)) {
5934        names.symbols = Xstrdup("%");
5935    }
5936    geom_changed = ((names.geometry != NULL) &&
5937                    (strcmp(names.geometry, "%") != 0));
5938    if ((!names.geometry) && (fwant & XkbGBN_GeometryMask)) {
5939        names.geometry = Xstrdup("%");
5940        geom_changed = FALSE;
5941    }
5942
5943    memset(mapFile, 0, PATH_MAX);
5944    rep.type = X_Reply;
5945    rep.deviceID = dev->id;
5946    rep.sequenceNumber = client->sequence;
5947    rep.length = 0;
5948    rep.minKeyCode = xkb->min_key_code;
5949    rep.maxKeyCode = xkb->max_key_code;
5950    rep.loaded = FALSE;
5951    fwant =
5952        XkbConvertGetByNameComponents(TRUE, stuff->want) | XkmVirtualModsMask;
5953    fneed = XkbConvertGetByNameComponents(TRUE, stuff->need);
5954    rep.reported = XkbConvertGetByNameComponents(FALSE, fwant | fneed);
5955    if (stuff->load) {
5956        fneed |= XkmKeymapRequired;
5957        fwant |= XkmKeymapLegal;
5958    }
5959    if ((fwant | fneed) & XkmSymbolsMask) {
5960        fneed |= XkmKeyNamesIndex | XkmTypesIndex;
5961        fwant |= XkmIndicatorsIndex;
5962    }
5963
5964    /* We pass dev in here so we can get the old names out if needed. */
5965    rep.found = XkbDDXLoadKeymapByNames(dev, &names, fwant, fneed, &new,
5966                                        mapFile, PATH_MAX);
5967    rep.newKeyboard = FALSE;
5968    rep.pad1 = rep.pad2 = rep.pad3 = rep.pad4 = 0;
5969
5970    stuff->want |= stuff->need;
5971    if (new == NULL)
5972        rep.reported = 0;
5973    else {
5974        if (stuff->load)
5975            rep.loaded = TRUE;
5976        if (stuff->load ||
5977            ((rep.reported & XkbGBN_SymbolsMask) && (new->compat))) {
5978            XkbChangesRec changes;
5979
5980            memset(&changes, 0, sizeof(changes));
5981            XkbUpdateDescActions(new,
5982                                 new->min_key_code, XkbNumKeys(new), &changes);
5983        }
5984
5985        if (new->map == NULL)
5986            rep.reported &= ~(XkbGBN_SymbolsMask | XkbGBN_TypesMask);
5987        else if (rep.reported & (XkbGBN_SymbolsMask | XkbGBN_TypesMask)) {
5988            mrep.type = X_Reply;
5989            mrep.deviceID = dev->id;
5990            mrep.sequenceNumber = client->sequence;
5991            mrep.length =
5992                ((SIZEOF(xkbGetMapReply) - SIZEOF(xGenericReply)) >> 2);
5993            mrep.minKeyCode = new->min_key_code;
5994            mrep.maxKeyCode = new->max_key_code;
5995            mrep.present = 0;
5996            mrep.totalSyms = mrep.totalActs =
5997                mrep.totalKeyBehaviors = mrep.totalKeyExplicit =
5998                mrep.totalModMapKeys = mrep.totalVModMapKeys = 0;
5999            if (rep.reported & (XkbGBN_TypesMask | XkbGBN_ClientSymbolsMask)) {
6000                mrep.present |= XkbKeyTypesMask;
6001                mrep.firstType = 0;
6002                mrep.nTypes = mrep.totalTypes = new->map->num_types;
6003            }
6004            else {
6005                mrep.firstType = mrep.nTypes = 0;
6006                mrep.totalTypes = 0;
6007            }
6008            if (rep.reported & XkbGBN_ClientSymbolsMask) {
6009                mrep.present |= (XkbKeySymsMask | XkbModifierMapMask);
6010                mrep.firstKeySym = mrep.firstModMapKey = new->min_key_code;
6011                mrep.nKeySyms = mrep.nModMapKeys = XkbNumKeys(new);
6012            }
6013            else {
6014                mrep.firstKeySym = mrep.firstModMapKey = 0;
6015                mrep.nKeySyms = mrep.nModMapKeys = 0;
6016            }
6017            if (rep.reported & XkbGBN_ServerSymbolsMask) {
6018                mrep.present |= XkbAllServerInfoMask;
6019                mrep.virtualMods = ~0;
6020                mrep.firstKeyAct = mrep.firstKeyBehavior =
6021                    mrep.firstKeyExplicit = new->min_key_code;
6022                mrep.nKeyActs = mrep.nKeyBehaviors =
6023                    mrep.nKeyExplicit = XkbNumKeys(new);
6024                mrep.firstVModMapKey = new->min_key_code;
6025                mrep.nVModMapKeys = XkbNumKeys(new);
6026            }
6027            else {
6028                mrep.virtualMods = 0;
6029                mrep.firstKeyAct = mrep.firstKeyBehavior =
6030                    mrep.firstKeyExplicit = 0;
6031                mrep.nKeyActs = mrep.nKeyBehaviors = mrep.nKeyExplicit = 0;
6032            }
6033            XkbComputeGetMapReplySize(new, &mrep);
6034            rep.length += SIZEOF(xGenericReply) / 4 + mrep.length;
6035        }
6036        if (new->compat == NULL)
6037            rep.reported &= ~XkbGBN_CompatMapMask;
6038        else if (rep.reported & XkbGBN_CompatMapMask) {
6039            crep.type = X_Reply;
6040            crep.deviceID = dev->id;
6041            crep.sequenceNumber = client->sequence;
6042            crep.length = 0;
6043            crep.groups = XkbAllGroupsMask;
6044            crep.firstSI = 0;
6045            crep.nSI = crep.nTotalSI = new->compat->num_si;
6046            XkbComputeGetCompatMapReplySize(new->compat, &crep);
6047            rep.length += SIZEOF(xGenericReply) / 4 + crep.length;
6048        }
6049        if (new->indicators == NULL)
6050            rep.reported &= ~XkbGBN_IndicatorMapMask;
6051        else if (rep.reported & XkbGBN_IndicatorMapMask) {
6052            irep.type = X_Reply;
6053            irep.deviceID = dev->id;
6054            irep.sequenceNumber = client->sequence;
6055            irep.length = 0;
6056            irep.which = XkbAllIndicatorsMask;
6057            XkbComputeGetIndicatorMapReplySize(new->indicators, &irep);
6058            rep.length += SIZEOF(xGenericReply) / 4 + irep.length;
6059        }
6060        if (new->names == NULL)
6061            rep.reported &= ~(XkbGBN_OtherNamesMask | XkbGBN_KeyNamesMask);
6062        else if (rep.reported & (XkbGBN_OtherNamesMask | XkbGBN_KeyNamesMask)) {
6063            nrep.type = X_Reply;
6064            nrep.deviceID = dev->id;
6065            nrep.sequenceNumber = client->sequence;
6066            nrep.length = 0;
6067            nrep.minKeyCode = new->min_key_code;
6068            nrep.maxKeyCode = new->max_key_code;
6069            if (rep.reported & XkbGBN_OtherNamesMask) {
6070                nrep.which = XkbAllNamesMask;
6071                if (new->map != NULL)
6072                    nrep.nTypes = new->map->num_types;
6073                else
6074                    nrep.nTypes = 0;
6075                nrep.nKTLevels = 0;
6076                nrep.groupNames = XkbAllGroupsMask;
6077                nrep.virtualMods = XkbAllVirtualModsMask;
6078                nrep.indicators = XkbAllIndicatorsMask;
6079                nrep.nRadioGroups = new->names->num_rg;
6080            }
6081            else {
6082                nrep.which = 0;
6083                nrep.nTypes = 0;
6084                nrep.nKTLevels = 0;
6085                nrep.groupNames = 0;
6086                nrep.virtualMods = 0;
6087                nrep.indicators = 0;
6088                nrep.nRadioGroups = 0;
6089            }
6090            if (rep.reported & XkbGBN_KeyNamesMask) {
6091                nrep.which |= XkbKeyNamesMask;
6092                nrep.firstKey = new->min_key_code;
6093                nrep.nKeys = XkbNumKeys(new);
6094                nrep.nKeyAliases = new->names->num_key_aliases;
6095                if (nrep.nKeyAliases)
6096                    nrep.which |= XkbKeyAliasesMask;
6097            }
6098            else {
6099                nrep.which &= ~(XkbKeyNamesMask | XkbKeyAliasesMask);
6100                nrep.firstKey = nrep.nKeys = 0;
6101                nrep.nKeyAliases = 0;
6102            }
6103            XkbComputeGetNamesReplySize(new, &nrep);
6104            rep.length += SIZEOF(xGenericReply) / 4 + nrep.length;
6105        }
6106        if (new->geom == NULL)
6107            rep.reported &= ~XkbGBN_GeometryMask;
6108        else if (rep.reported & XkbGBN_GeometryMask) {
6109            grep.type = X_Reply;
6110            grep.deviceID = dev->id;
6111            grep.sequenceNumber = client->sequence;
6112            grep.length = 0;
6113            grep.found = TRUE;
6114            grep.pad = 0;
6115            grep.widthMM = grep.heightMM = 0;
6116            grep.nProperties = grep.nColors = grep.nShapes = 0;
6117            grep.nSections = grep.nDoodads = 0;
6118            grep.baseColorNdx = grep.labelColorNdx = 0;
6119            XkbComputeGetGeometryReplySize(new->geom, &grep, None);
6120            rep.length += SIZEOF(xGenericReply) / 4 + grep.length;
6121        }
6122    }
6123
6124    reported = rep.reported;
6125    if (client->swapped) {
6126        swaps(&rep.sequenceNumber);
6127        swapl(&rep.length);
6128        swaps(&rep.found);
6129        swaps(&rep.reported);
6130    }
6131    WriteToClient(client, SIZEOF(xkbGetKbdByNameReply), &rep);
6132    if (reported & (XkbGBN_SymbolsMask | XkbGBN_TypesMask))
6133        XkbSendMap(client, new, &mrep);
6134    if (reported & XkbGBN_CompatMapMask)
6135        XkbSendCompatMap(client, new->compat, &crep);
6136    if (reported & XkbGBN_IndicatorMapMask)
6137        XkbSendIndicatorMap(client, new->indicators, &irep);
6138    if (reported & (XkbGBN_KeyNamesMask | XkbGBN_OtherNamesMask))
6139        XkbSendNames(client, new, &nrep);
6140    if (reported & XkbGBN_GeometryMask)
6141        XkbSendGeometry(client, new->geom, &grep, FALSE);
6142    if (rep.loaded) {
6143        XkbDescPtr old_xkb;
6144        xkbNewKeyboardNotify nkn;
6145
6146        old_xkb = xkb;
6147        xkb = new;
6148        dev->key->xkbInfo->desc = xkb;
6149        new = old_xkb;          /* so it'll get freed automatically */
6150
6151        XkbCopyControls(xkb, old_xkb);
6152
6153        nkn.deviceID = nkn.oldDeviceID = dev->id;
6154        nkn.minKeyCode = new->min_key_code;
6155        nkn.maxKeyCode = new->max_key_code;
6156        nkn.oldMinKeyCode = xkb->min_key_code;
6157        nkn.oldMaxKeyCode = xkb->max_key_code;
6158        nkn.requestMajor = XkbReqCode;
6159        nkn.requestMinor = X_kbGetKbdByName;
6160        nkn.changed = XkbNKN_KeycodesMask;
6161        if (geom_changed)
6162            nkn.changed |= XkbNKN_GeometryMask;
6163        XkbSendNewKeyboardNotify(dev, &nkn);
6164
6165        /* Update the map and LED info on the device itself, as well as
6166         * any slaves if it's an MD, or its MD if it's an SD and was the
6167         * last device used on that MD. */
6168        for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
6169            if (tmpd != dev && GetMaster(tmpd, MASTER_KEYBOARD) != dev &&
6170                (tmpd != master || dev != master->lastSlave))
6171                continue;
6172
6173            if (tmpd != dev)
6174                XkbDeviceApplyKeymap(tmpd, xkb);
6175
6176            if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) {
6177                old_sli = tmpd->kbdfeed->xkb_sli;
6178                tmpd->kbdfeed->xkb_sli = NULL;
6179                sli = XkbAllocSrvLedInfo(tmpd, tmpd->kbdfeed, NULL, 0);
6180                if (sli) {
6181                    sli->explicitState = old_sli->explicitState;
6182                    sli->effectiveState = old_sli->effectiveState;
6183                }
6184                tmpd->kbdfeed->xkb_sli = sli;
6185                XkbFreeSrvLedInfo(old_sli);
6186            }
6187        }
6188    }
6189    if ((new != NULL) && (new != xkb)) {
6190        XkbFreeKeyboard(new, XkbAllComponentsMask, TRUE);
6191        new = NULL;
6192    }
6193    XkbFreeComponentNames(&names, FALSE);
6194    XkbSetCauseXkbReq(&cause, X_kbGetKbdByName, client);
6195    XkbUpdateAllDeviceIndicators(NULL, &cause);
6196
6197    return Success;
6198}
6199
6200/***====================================================================***/
6201
6202static int
6203ComputeDeviceLedInfoSize(DeviceIntPtr dev,
6204                         unsigned int what, XkbSrvLedInfoPtr sli)
6205{
6206    int nNames, nMaps;
6207    register unsigned n, bit;
6208
6209    if (sli == NULL)
6210        return 0;
6211    nNames = nMaps = 0;
6212    if ((what & XkbXI_IndicatorNamesMask) == 0)
6213        sli->namesPresent = 0;
6214    if ((what & XkbXI_IndicatorMapsMask) == 0)
6215        sli->mapsPresent = 0;
6216
6217    for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
6218        if (sli->names && sli->names[n] != None) {
6219            sli->namesPresent |= bit;
6220            nNames++;
6221        }
6222        if (sli->maps && XkbIM_InUse(&sli->maps[n])) {
6223            sli->mapsPresent |= bit;
6224            nMaps++;
6225        }
6226    }
6227    return (nNames * 4) + (nMaps * SIZEOF(xkbIndicatorMapWireDesc));
6228}
6229
6230static int
6231CheckDeviceLedFBs(DeviceIntPtr dev,
6232                  int class,
6233                  int id, xkbGetDeviceInfoReply * rep, ClientPtr client)
6234{
6235    int nFBs = 0;
6236    int length = 0;
6237    Bool classOk;
6238
6239    if (class == XkbDfltXIClass) {
6240        if (dev->kbdfeed)
6241            class = KbdFeedbackClass;
6242        else if (dev->leds)
6243            class = LedFeedbackClass;
6244        else {
6245            client->errorValue = _XkbErrCode2(XkbErr_BadClass, class);
6246            return XkbKeyboardErrorCode;
6247        }
6248    }
6249    classOk = FALSE;
6250    if ((dev->kbdfeed) &&
6251        ((class == KbdFeedbackClass) || (class == XkbAllXIClasses))) {
6252        KbdFeedbackPtr kf;
6253
6254        classOk = TRUE;
6255        for (kf = dev->kbdfeed; (kf); kf = kf->next) {
6256            if ((id != XkbAllXIIds) && (id != XkbDfltXIId) &&
6257                (id != kf->ctrl.id))
6258                continue;
6259            nFBs++;
6260            length += SIZEOF(xkbDeviceLedsWireDesc);
6261            if (!kf->xkb_sli)
6262                kf->xkb_sli = XkbAllocSrvLedInfo(dev, kf, NULL, 0);
6263            length += ComputeDeviceLedInfoSize(dev, rep->present, kf->xkb_sli);
6264            if (id != XkbAllXIIds)
6265                break;
6266        }
6267    }
6268    if ((dev->leds) &&
6269        ((class == LedFeedbackClass) || (class == XkbAllXIClasses))) {
6270        LedFeedbackPtr lf;
6271
6272        classOk = TRUE;
6273        for (lf = dev->leds; (lf); lf = lf->next) {
6274            if ((id != XkbAllXIIds) && (id != XkbDfltXIId) &&
6275                (id != lf->ctrl.id))
6276                continue;
6277            nFBs++;
6278            length += SIZEOF(xkbDeviceLedsWireDesc);
6279            if (!lf->xkb_sli)
6280                lf->xkb_sli = XkbAllocSrvLedInfo(dev, NULL, lf, 0);
6281            length += ComputeDeviceLedInfoSize(dev, rep->present, lf->xkb_sli);
6282            if (id != XkbAllXIIds)
6283                break;
6284        }
6285    }
6286    if (nFBs > 0) {
6287        rep->nDeviceLedFBs = nFBs;
6288        rep->length += (length / 4);
6289        return Success;
6290    }
6291    if (classOk)
6292        client->errorValue = _XkbErrCode2(XkbErr_BadId, id);
6293    else
6294        client->errorValue = _XkbErrCode2(XkbErr_BadClass, class);
6295    return XkbKeyboardErrorCode;
6296}
6297
6298static int
6299SendDeviceLedInfo(XkbSrvLedInfoPtr sli, ClientPtr client)
6300{
6301    xkbDeviceLedsWireDesc wire;
6302    int length;
6303
6304    length = 0;
6305    wire.ledClass = sli->class;
6306    wire.ledID = sli->id;
6307    wire.namesPresent = sli->namesPresent;
6308    wire.mapsPresent = sli->mapsPresent;
6309    wire.physIndicators = sli->physIndicators;
6310    wire.state = sli->effectiveState;
6311    if (client->swapped) {
6312        swaps(&wire.ledClass);
6313        swaps(&wire.ledID);
6314        swapl(&wire.namesPresent);
6315        swapl(&wire.mapsPresent);
6316        swapl(&wire.physIndicators);
6317        swapl(&wire.state);
6318    }
6319    WriteToClient(client, SIZEOF(xkbDeviceLedsWireDesc), &wire);
6320    length += SIZEOF(xkbDeviceLedsWireDesc);
6321    if (sli->namesPresent | sli->mapsPresent) {
6322        register unsigned i, bit;
6323
6324        if (sli->namesPresent) {
6325            CARD32 awire;
6326
6327            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
6328                if (sli->namesPresent & bit) {
6329                    awire = (CARD32) sli->names[i];
6330                    if (client->swapped) {
6331                        swapl(&awire);
6332                    }
6333                    WriteToClient(client, 4, &awire);
6334                    length += 4;
6335                }
6336            }
6337        }
6338        if (sli->mapsPresent) {
6339            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
6340                xkbIndicatorMapWireDesc iwire;
6341
6342                if (sli->mapsPresent & bit) {
6343                    iwire.flags = sli->maps[i].flags;
6344                    iwire.whichGroups = sli->maps[i].which_groups;
6345                    iwire.groups = sli->maps[i].groups;
6346                    iwire.whichMods = sli->maps[i].which_mods;
6347                    iwire.mods = sli->maps[i].mods.mask;
6348                    iwire.realMods = sli->maps[i].mods.real_mods;
6349                    iwire.virtualMods = sli->maps[i].mods.vmods;
6350                    iwire.ctrls = sli->maps[i].ctrls;
6351                    if (client->swapped) {
6352                        swaps(&iwire.virtualMods);
6353                        swapl(&iwire.ctrls);
6354                    }
6355                    WriteToClient(client, SIZEOF(xkbIndicatorMapWireDesc),
6356                                  &iwire);
6357                    length += SIZEOF(xkbIndicatorMapWireDesc);
6358                }
6359            }
6360        }
6361    }
6362    return length;
6363}
6364
6365static int
6366SendDeviceLedFBs(DeviceIntPtr dev,
6367                 int class, int id, unsigned wantLength, ClientPtr client)
6368{
6369    int length = 0;
6370
6371    if (class == XkbDfltXIClass) {
6372        if (dev->kbdfeed)
6373            class = KbdFeedbackClass;
6374        else if (dev->leds)
6375            class = LedFeedbackClass;
6376    }
6377    if ((dev->kbdfeed) &&
6378        ((class == KbdFeedbackClass) || (class == XkbAllXIClasses))) {
6379        KbdFeedbackPtr kf;
6380
6381        for (kf = dev->kbdfeed; (kf); kf = kf->next) {
6382            if ((id == XkbAllXIIds) || (id == XkbDfltXIId) ||
6383                (id == kf->ctrl.id)) {
6384                length += SendDeviceLedInfo(kf->xkb_sli, client);
6385                if (id != XkbAllXIIds)
6386                    break;
6387            }
6388        }
6389    }
6390    if ((dev->leds) &&
6391        ((class == LedFeedbackClass) || (class == XkbAllXIClasses))) {
6392        LedFeedbackPtr lf;
6393
6394        for (lf = dev->leds; (lf); lf = lf->next) {
6395            if ((id == XkbAllXIIds) || (id == XkbDfltXIId) ||
6396                (id == lf->ctrl.id)) {
6397                length += SendDeviceLedInfo(lf->xkb_sli, client);
6398                if (id != XkbAllXIIds)
6399                    break;
6400            }
6401        }
6402    }
6403    if (length == wantLength)
6404        return Success;
6405    else
6406        return BadLength;
6407}
6408
6409int
6410ProcXkbGetDeviceInfo(ClientPtr client)
6411{
6412    DeviceIntPtr dev;
6413    xkbGetDeviceInfoReply rep;
6414    int status, nDeviceLedFBs;
6415    unsigned length, nameLen;
6416    CARD16 ledClass, ledID;
6417    unsigned wanted;
6418    char *str;
6419
6420    REQUEST(xkbGetDeviceInfoReq);
6421    REQUEST_SIZE_MATCH(xkbGetDeviceInfoReq);
6422
6423    if (!(client->xkbClientFlags & _XkbClientInitialized))
6424        return BadAccess;
6425
6426    wanted = stuff->wanted;
6427
6428    CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
6429    CHK_MASK_LEGAL(0x01, wanted, XkbXI_AllDeviceFeaturesMask);
6430
6431    if ((!dev->button) || ((stuff->nBtns < 1) && (!stuff->allBtns)))
6432        wanted &= ~XkbXI_ButtonActionsMask;
6433    if ((!dev->kbdfeed) && (!dev->leds))
6434        wanted &= ~XkbXI_IndicatorsMask;
6435
6436    nameLen = XkbSizeCountedString(dev->name);
6437    rep = (xkbGetDeviceInfoReply) {
6438        .type = X_Reply,
6439        .deviceID = dev->id,
6440        .sequenceNumber = client->sequence,
6441        .length = nameLen / 4,
6442        .present = wanted,
6443        .supported = XkbXI_AllDeviceFeaturesMask,
6444        .unsupported = 0,
6445        .nDeviceLedFBs = 0,
6446        .firstBtnWanted = 0,
6447        .nBtnsWanted = 0,
6448        .firstBtnRtrn = 0,
6449        .nBtnsRtrn = 0,
6450        .totalBtns = dev->button ? dev->button->numButtons : 0,
6451        .hasOwnState = (dev->key && dev->key->xkbInfo),
6452        .dfltKbdFB = dev->kbdfeed ? dev->kbdfeed->ctrl.id : XkbXINone,
6453        .dfltLedFB = dev->leds ? dev->leds->ctrl.id : XkbXINone,
6454        .devType = dev->xinput_type
6455    };
6456
6457    ledClass = stuff->ledClass;
6458    ledID = stuff->ledID;
6459
6460    if (wanted & XkbXI_ButtonActionsMask) {
6461        if (stuff->allBtns) {
6462            stuff->firstBtn = 0;
6463            stuff->nBtns = dev->button->numButtons;
6464        }
6465
6466        if ((stuff->firstBtn + stuff->nBtns) > dev->button->numButtons) {
6467            client->errorValue = _XkbErrCode4(0x02, dev->button->numButtons,
6468                                              stuff->firstBtn, stuff->nBtns);
6469            return BadValue;
6470        }
6471        else {
6472            rep.firstBtnWanted = stuff->firstBtn;
6473            rep.nBtnsWanted = stuff->nBtns;
6474            if (dev->button->xkb_acts != NULL) {
6475                XkbAction *act;
6476                register int i;
6477
6478                rep.firstBtnRtrn = stuff->firstBtn;
6479                rep.nBtnsRtrn = stuff->nBtns;
6480                act = &dev->button->xkb_acts[rep.firstBtnWanted];
6481                for (i = 0; i < rep.nBtnsRtrn; i++, act++) {
6482                    if (act->type != XkbSA_NoAction)
6483                        break;
6484                }
6485                rep.firstBtnRtrn += i;
6486                rep.nBtnsRtrn -= i;
6487                act =
6488                    &dev->button->xkb_acts[rep.firstBtnRtrn + rep.nBtnsRtrn -
6489                                           1];
6490                for (i = 0; i < rep.nBtnsRtrn; i++, act--) {
6491                    if (act->type != XkbSA_NoAction)
6492                        break;
6493                }
6494                rep.nBtnsRtrn -= i;
6495            }
6496            rep.length += (rep.nBtnsRtrn * SIZEOF(xkbActionWireDesc)) / 4;
6497        }
6498    }
6499
6500    if (wanted & XkbXI_IndicatorsMask) {
6501        status = CheckDeviceLedFBs(dev, ledClass, ledID, &rep, client);
6502        if (status != Success)
6503            return status;
6504    }
6505    length = rep.length * 4;
6506    nDeviceLedFBs = rep.nDeviceLedFBs;
6507    if (client->swapped) {
6508        swaps(&rep.sequenceNumber);
6509        swapl(&rep.length);
6510        swaps(&rep.present);
6511        swaps(&rep.supported);
6512        swaps(&rep.unsupported);
6513        swaps(&rep.nDeviceLedFBs);
6514        swaps(&rep.dfltKbdFB);
6515        swaps(&rep.dfltLedFB);
6516        swapl(&rep.devType);
6517    }
6518    WriteToClient(client, SIZEOF(xkbGetDeviceInfoReply), &rep);
6519
6520    str = malloc(nameLen);
6521    if (!str)
6522        return BadAlloc;
6523    XkbWriteCountedString(str, dev->name, client->swapped);
6524    WriteToClient(client, nameLen, str);
6525    free(str);
6526    length -= nameLen;
6527
6528    if (rep.nBtnsRtrn > 0) {
6529        int sz;
6530        xkbActionWireDesc *awire;
6531
6532        sz = rep.nBtnsRtrn * SIZEOF(xkbActionWireDesc);
6533        awire = (xkbActionWireDesc *) &dev->button->xkb_acts[rep.firstBtnRtrn];
6534        WriteToClient(client, sz, awire);
6535        length -= sz;
6536    }
6537    if (nDeviceLedFBs > 0) {
6538        status = SendDeviceLedFBs(dev, ledClass, ledID, length, client);
6539        if (status != Success)
6540            return status;
6541    }
6542    else if (length != 0) {
6543        ErrorF("[xkb] Internal Error!  BadLength in ProcXkbGetDeviceInfo\n");
6544        ErrorF("[xkb]                  Wrote %d fewer bytes than expected\n",
6545               length);
6546        return BadLength;
6547    }
6548    return Success;
6549}
6550
6551static char *
6552CheckSetDeviceIndicators(char *wire,
6553                         DeviceIntPtr dev,
6554                         int num, int *status_rtrn, ClientPtr client)
6555{
6556    xkbDeviceLedsWireDesc *ledWire;
6557    int i;
6558    XkbSrvLedInfoPtr sli;
6559
6560    ledWire = (xkbDeviceLedsWireDesc *) wire;
6561    for (i = 0; i < num; i++) {
6562        if (client->swapped) {
6563            swaps(&ledWire->ledClass);
6564            swaps(&ledWire->ledID);
6565            swapl(&ledWire->namesPresent);
6566            swapl(&ledWire->mapsPresent);
6567            swapl(&ledWire->physIndicators);
6568        }
6569
6570        sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID,
6571                                XkbXI_IndicatorsMask);
6572        if (sli != NULL) {
6573            register int n;
6574            register unsigned bit;
6575            int nMaps, nNames;
6576            CARD32 *atomWire;
6577            xkbIndicatorMapWireDesc *mapWire;
6578
6579            nMaps = nNames = 0;
6580            for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
6581                if (ledWire->namesPresent & bit)
6582                    nNames++;
6583                if (ledWire->mapsPresent & bit)
6584                    nMaps++;
6585            }
6586            atomWire = (CARD32 *) &ledWire[1];
6587            if (nNames > 0) {
6588                for (n = 0; n < nNames; n++) {
6589                    if (client->swapped) {
6590                        swapl(atomWire);
6591                    }
6592                    CHK_ATOM_OR_NONE3(((Atom) (*atomWire)), client->errorValue,
6593                                      *status_rtrn, NULL);
6594                    atomWire++;
6595                }
6596            }
6597            mapWire = (xkbIndicatorMapWireDesc *) atomWire;
6598            if (nMaps > 0) {
6599                for (n = 0; n < nMaps; n++) {
6600                    if (client->swapped) {
6601                        swaps(&mapWire->virtualMods);
6602                        swapl(&mapWire->ctrls);
6603                    }
6604                    CHK_MASK_LEGAL3(0x21, mapWire->whichGroups,
6605                                    XkbIM_UseAnyGroup,
6606                                    client->errorValue, *status_rtrn, NULL);
6607                    CHK_MASK_LEGAL3(0x22, mapWire->whichMods, XkbIM_UseAnyMods,
6608                                    client->errorValue, *status_rtrn, NULL);
6609                    mapWire++;
6610                }
6611            }
6612            ledWire = (xkbDeviceLedsWireDesc *) mapWire;
6613        }
6614        else {
6615            /* SHOULD NEVER HAPPEN */
6616            return (char *) ledWire;
6617        }
6618    }
6619    return (char *) ledWire;
6620}
6621
6622static char *
6623SetDeviceIndicators(char *wire,
6624                    DeviceIntPtr dev,
6625                    unsigned changed,
6626                    int num,
6627                    int *status_rtrn,
6628                    ClientPtr client,
6629                    xkbExtensionDeviceNotify * ev,
6630                    xkbSetDeviceInfoReq * stuff)
6631{
6632    xkbDeviceLedsWireDesc *ledWire;
6633    int i;
6634    XkbEventCauseRec cause;
6635    unsigned namec, mapc, statec;
6636    xkbExtensionDeviceNotify ed;
6637    XkbChangesRec changes;
6638    DeviceIntPtr kbd;
6639
6640    memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
6641    memset((char *) &changes, 0, sizeof(XkbChangesRec));
6642    XkbSetCauseXkbReq(&cause, X_kbSetDeviceInfo, client);
6643    ledWire = (xkbDeviceLedsWireDesc *) wire;
6644    for (i = 0; i < num; i++) {
6645        register int n;
6646        register unsigned bit;
6647        CARD32 *atomWire;
6648        xkbIndicatorMapWireDesc *mapWire;
6649        XkbSrvLedInfoPtr sli;
6650
6651        if (!_XkbCheckRequestBounds(client, stuff, ledWire, ledWire + 1)) {
6652            *status_rtrn = BadLength;
6653            return (char *) ledWire;
6654        }
6655
6656        namec = mapc = statec = 0;
6657        sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID,
6658                                XkbXI_IndicatorMapsMask);
6659        if (!sli) {
6660            /* SHOULD NEVER HAPPEN!! */
6661            return (char *) ledWire;
6662        }
6663
6664        atomWire = (CARD32 *) &ledWire[1];
6665        if (changed & XkbXI_IndicatorNamesMask) {
6666            namec = sli->namesPresent | ledWire->namesPresent;
6667            memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom));
6668        }
6669        if (ledWire->namesPresent) {
6670            sli->namesPresent = ledWire->namesPresent;
6671            memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom));
6672            for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
6673                if (ledWire->namesPresent & bit) {
6674                    if (!_XkbCheckRequestBounds(client, stuff, atomWire, atomWire + 1)) {
6675                        *status_rtrn = BadLength;
6676                        return (char *) atomWire;
6677                    }
6678                    sli->names[n] = (Atom) *atomWire;
6679                    if (sli->names[n] == None)
6680                        ledWire->namesPresent &= ~bit;
6681                    atomWire++;
6682                }
6683            }
6684        }
6685        mapWire = (xkbIndicatorMapWireDesc *) atomWire;
6686        if (changed & XkbXI_IndicatorMapsMask) {
6687            mapc = sli->mapsPresent | ledWire->mapsPresent;
6688            sli->mapsPresent = ledWire->mapsPresent;
6689            memset((char *) sli->maps, 0,
6690                   XkbNumIndicators * sizeof(XkbIndicatorMapRec));
6691        }
6692        if (ledWire->mapsPresent) {
6693            for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
6694                if (ledWire->mapsPresent & bit) {
6695                    if (!_XkbCheckRequestBounds(client, stuff, mapWire, mapWire + 1)) {
6696                        *status_rtrn = BadLength;
6697                        return (char *) mapWire;
6698                    }
6699                    sli->maps[n].flags = mapWire->flags;
6700                    sli->maps[n].which_groups = mapWire->whichGroups;
6701                    sli->maps[n].groups = mapWire->groups;
6702                    sli->maps[n].which_mods = mapWire->whichMods;
6703                    sli->maps[n].mods.mask = mapWire->mods;
6704                    sli->maps[n].mods.real_mods = mapWire->realMods;
6705                    sli->maps[n].mods.vmods = mapWire->virtualMods;
6706                    sli->maps[n].ctrls = mapWire->ctrls;
6707                    mapWire++;
6708                }
6709            }
6710        }
6711        if (changed & XkbXI_IndicatorStateMask) {
6712            statec = sli->effectiveState ^ ledWire->state;
6713            sli->explicitState &= ~statec;
6714            sli->explicitState |= (ledWire->state & statec);
6715        }
6716        if (namec)
6717            XkbApplyLedNameChanges(dev, sli, namec, &ed, &changes, &cause);
6718        if (mapc)
6719            XkbApplyLedMapChanges(dev, sli, mapc, &ed, &changes, &cause);
6720        if (statec)
6721            XkbApplyLedStateChanges(dev, sli, statec, &ed, &changes, &cause);
6722
6723        kbd = dev;
6724        if ((sli->flags & XkbSLI_HasOwnState) == 0)
6725            kbd = inputInfo.keyboard;
6726
6727        XkbFlushLedEvents(dev, kbd, sli, &ed, &changes, &cause);
6728        ledWire = (xkbDeviceLedsWireDesc *) mapWire;
6729    }
6730    return (char *) ledWire;
6731}
6732
6733static int
6734_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
6735                  xkbSetDeviceInfoReq * stuff)
6736{
6737    char *wire;
6738
6739    wire = (char *) &stuff[1];
6740    if (stuff->change & XkbXI_ButtonActionsMask) {
6741        if (!dev->button) {
6742            client->errorValue = _XkbErrCode2(XkbErr_BadClass, ButtonClass);
6743            return XkbKeyboardErrorCode;
6744        }
6745        if ((stuff->firstBtn + stuff->nBtns) > dev->button->numButtons) {
6746            client->errorValue =
6747                _XkbErrCode4(0x02, stuff->firstBtn, stuff->nBtns,
6748                             dev->button->numButtons);
6749            return BadMatch;
6750        }
6751        wire += (stuff->nBtns * SIZEOF(xkbActionWireDesc));
6752    }
6753    if (stuff->change & XkbXI_IndicatorsMask) {
6754        int status = Success;
6755
6756        wire = CheckSetDeviceIndicators(wire, dev, stuff->nDeviceLedFBs,
6757                                        &status, client);
6758        if (status != Success)
6759            return status;
6760    }
6761    if (((wire - ((char *) stuff)) / 4) != stuff->length)
6762        return BadLength;
6763
6764    return Success;
6765}
6766
6767static int
6768_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
6769                       xkbSetDeviceInfoReq * stuff)
6770{
6771    char *wire;
6772    xkbExtensionDeviceNotify ed;
6773
6774    memset((char *) &ed, 0, SIZEOF(xkbExtensionDeviceNotify));
6775    ed.deviceID = dev->id;
6776    wire = (char *) &stuff[1];
6777    if (stuff->change & XkbXI_ButtonActionsMask) {
6778	int nBtns, sz, i;
6779        XkbAction *acts;
6780        DeviceIntPtr kbd;
6781
6782        nBtns = dev->button->numButtons;
6783        acts = dev->button->xkb_acts;
6784        if (acts == NULL) {
6785            acts = calloc(nBtns, sizeof(XkbAction));
6786            if (!acts)
6787                return BadAlloc;
6788            dev->button->xkb_acts = acts;
6789        }
6790        if (stuff->firstBtn + stuff->nBtns > nBtns)
6791            return BadValue;
6792        sz = stuff->nBtns * SIZEOF(xkbActionWireDesc);
6793        if (!_XkbCheckRequestBounds(client, stuff, wire, (char *) wire + sz))
6794            return BadLength;
6795        memcpy((char *) &acts[stuff->firstBtn], (char *) wire, sz);
6796        wire += sz;
6797        ed.reason |= XkbXI_ButtonActionsMask;
6798        ed.firstBtn = stuff->firstBtn;
6799        ed.nBtns = stuff->nBtns;
6800
6801        if (dev->key)
6802            kbd = dev;
6803        else
6804            kbd = inputInfo.keyboard;
6805        acts = &dev->button->xkb_acts[stuff->firstBtn];
6806        for (i = 0; i < stuff->nBtns; i++, acts++) {
6807            if (acts->type != XkbSA_NoAction)
6808                XkbSetActionKeyMods(kbd->key->xkbInfo->desc, acts, 0);
6809        }
6810    }
6811    if (stuff->change & XkbXI_IndicatorsMask) {
6812        int status = Success;
6813
6814        wire = SetDeviceIndicators(wire, dev, stuff->change,
6815                                   stuff->nDeviceLedFBs, &status, client, &ed,
6816                                   stuff);
6817        if (status != Success)
6818            return status;
6819    }
6820    if ((stuff->change) && (ed.reason))
6821        XkbSendExtensionDeviceNotify(dev, client, &ed);
6822    return Success;
6823}
6824
6825int
6826ProcXkbSetDeviceInfo(ClientPtr client)
6827{
6828    DeviceIntPtr dev;
6829    int rc;
6830
6831    REQUEST(xkbSetDeviceInfoReq);
6832    REQUEST_AT_LEAST_SIZE(xkbSetDeviceInfoReq);
6833
6834    if (!(client->xkbClientFlags & _XkbClientInitialized))
6835        return BadAccess;
6836
6837    CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
6838    CHK_MASK_LEGAL(0x01, stuff->change, XkbXI_AllFeaturesMask);
6839
6840    rc = _XkbSetDeviceInfoCheck(client, dev, stuff);
6841
6842    if (rc != Success)
6843        return rc;
6844
6845    if (stuff->deviceSpec == XkbUseCoreKbd ||
6846        stuff->deviceSpec == XkbUseCorePtr) {
6847        DeviceIntPtr other;
6848
6849        for (other = inputInfo.devices; other; other = other->next) {
6850            if (((other != dev) && !IsMaster(other) &&
6851                 GetMaster(other, MASTER_KEYBOARD) == dev) &&
6852                ((stuff->deviceSpec == XkbUseCoreKbd && other->key) ||
6853                 (stuff->deviceSpec == XkbUseCorePtr && other->button))) {
6854                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
6855                              DixManageAccess);
6856                if (rc == Success) {
6857                    rc = _XkbSetDeviceInfoCheck(client, other, stuff);
6858                    if (rc != Success)
6859                        return rc;
6860                }
6861            }
6862        }
6863    }
6864
6865    /* checks done, apply */
6866    rc = _XkbSetDeviceInfo(client, dev, stuff);
6867    if (rc != Success)
6868        return rc;
6869
6870    if (stuff->deviceSpec == XkbUseCoreKbd ||
6871        stuff->deviceSpec == XkbUseCorePtr) {
6872        DeviceIntPtr other;
6873
6874        for (other = inputInfo.devices; other; other = other->next) {
6875            if (((other != dev) && !IsMaster(other) &&
6876                 GetMaster(other, MASTER_KEYBOARD) == dev) &&
6877                ((stuff->deviceSpec == XkbUseCoreKbd && other->key) ||
6878                 (stuff->deviceSpec == XkbUseCorePtr && other->button))) {
6879                rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
6880                              DixManageAccess);
6881                if (rc == Success) {
6882                    rc = _XkbSetDeviceInfo(client, other, stuff);
6883                    if (rc != Success)
6884                        return rc;
6885                }
6886            }
6887        }
6888    }
6889
6890    return Success;
6891}
6892
6893/***====================================================================***/
6894
6895int
6896ProcXkbSetDebuggingFlags(ClientPtr client)
6897{
6898    CARD32 newFlags, newCtrls, extraLength;
6899    xkbSetDebuggingFlagsReply rep;
6900    int rc;
6901
6902    REQUEST(xkbSetDebuggingFlagsReq);
6903    REQUEST_AT_LEAST_SIZE(xkbSetDebuggingFlagsReq);
6904
6905    rc = XaceHook(XACE_SERVER_ACCESS, client, DixDebugAccess);
6906    if (rc != Success)
6907        return rc;
6908
6909    newFlags = xkbDebugFlags & (~stuff->affectFlags);
6910    newFlags |= (stuff->flags & stuff->affectFlags);
6911    newCtrls = xkbDebugCtrls & (~stuff->affectCtrls);
6912    newCtrls |= (stuff->ctrls & stuff->affectCtrls);
6913    if (xkbDebugFlags || newFlags || stuff->msgLength) {
6914        ErrorF("[xkb] XkbDebug: Setting debug flags to 0x%lx\n",
6915               (long) newFlags);
6916        if (newCtrls != xkbDebugCtrls)
6917            ErrorF("[xkb] XkbDebug: Setting debug controls to 0x%lx\n",
6918                   (long) newCtrls);
6919    }
6920    extraLength = (stuff->length << 2) - sz_xkbSetDebuggingFlagsReq;
6921    if (stuff->msgLength > 0) {
6922        char *msg;
6923
6924        if (extraLength < XkbPaddedSize(stuff->msgLength)) {
6925            ErrorF
6926                ("[xkb] XkbDebug: msgLength= %d, length= %ld (should be %d)\n",
6927                 stuff->msgLength, (long) extraLength,
6928                 XkbPaddedSize(stuff->msgLength));
6929            return BadLength;
6930        }
6931        msg = (char *) &stuff[1];
6932        if (msg[stuff->msgLength - 1] != '\0') {
6933            ErrorF("[xkb] XkbDebug: message not null-terminated\n");
6934            return BadValue;
6935        }
6936        ErrorF("[xkb] XkbDebug: %s\n", msg);
6937    }
6938    xkbDebugFlags = newFlags;
6939    xkbDebugCtrls = newCtrls;
6940
6941    rep = (xkbSetDebuggingFlagsReply) {
6942        .type = X_Reply,
6943        .sequenceNumber = client->sequence,
6944        .length = 0,
6945        .currentFlags = newFlags,
6946        .currentCtrls = newCtrls,
6947        .supportedFlags = ~0,
6948        .supportedCtrls = ~0
6949    };
6950    if (client->swapped) {
6951        swaps(&rep.sequenceNumber);
6952        swapl(&rep.currentFlags);
6953        swapl(&rep.currentCtrls);
6954        swapl(&rep.supportedFlags);
6955        swapl(&rep.supportedCtrls);
6956    }
6957    WriteToClient(client, SIZEOF(xkbSetDebuggingFlagsReply), &rep);
6958    return Success;
6959}
6960
6961/***====================================================================***/
6962
6963static int
6964ProcXkbDispatch(ClientPtr client)
6965{
6966    REQUEST(xReq);
6967    switch (stuff->data) {
6968    case X_kbUseExtension:
6969        return ProcXkbUseExtension(client);
6970    case X_kbSelectEvents:
6971        return ProcXkbSelectEvents(client);
6972    case X_kbBell:
6973        return ProcXkbBell(client);
6974    case X_kbGetState:
6975        return ProcXkbGetState(client);
6976    case X_kbLatchLockState:
6977        return ProcXkbLatchLockState(client);
6978    case X_kbGetControls:
6979        return ProcXkbGetControls(client);
6980    case X_kbSetControls:
6981        return ProcXkbSetControls(client);
6982    case X_kbGetMap:
6983        return ProcXkbGetMap(client);
6984    case X_kbSetMap:
6985        return ProcXkbSetMap(client);
6986    case X_kbGetCompatMap:
6987        return ProcXkbGetCompatMap(client);
6988    case X_kbSetCompatMap:
6989        return ProcXkbSetCompatMap(client);
6990    case X_kbGetIndicatorState:
6991        return ProcXkbGetIndicatorState(client);
6992    case X_kbGetIndicatorMap:
6993        return ProcXkbGetIndicatorMap(client);
6994    case X_kbSetIndicatorMap:
6995        return ProcXkbSetIndicatorMap(client);
6996    case X_kbGetNamedIndicator:
6997        return ProcXkbGetNamedIndicator(client);
6998    case X_kbSetNamedIndicator:
6999        return ProcXkbSetNamedIndicator(client);
7000    case X_kbGetNames:
7001        return ProcXkbGetNames(client);
7002    case X_kbSetNames:
7003        return ProcXkbSetNames(client);
7004    case X_kbGetGeometry:
7005        return ProcXkbGetGeometry(client);
7006    case X_kbSetGeometry:
7007        return ProcXkbSetGeometry(client);
7008    case X_kbPerClientFlags:
7009        return ProcXkbPerClientFlags(client);
7010    case X_kbListComponents:
7011        return ProcXkbListComponents(client);
7012    case X_kbGetKbdByName:
7013        return ProcXkbGetKbdByName(client);
7014    case X_kbGetDeviceInfo:
7015        return ProcXkbGetDeviceInfo(client);
7016    case X_kbSetDeviceInfo:
7017        return ProcXkbSetDeviceInfo(client);
7018    case X_kbSetDebuggingFlags:
7019        return ProcXkbSetDebuggingFlags(client);
7020    default:
7021        return BadRequest;
7022    }
7023}
7024
7025static int
7026XkbClientGone(void *data, XID id)
7027{
7028    DevicePtr pXDev = (DevicePtr) data;
7029
7030    if (!XkbRemoveResourceClient(pXDev, id)) {
7031        ErrorF
7032            ("[xkb] Internal Error! bad RemoveResourceClient in XkbClientGone\n");
7033    }
7034    return 1;
7035}
7036
7037void
7038XkbExtensionInit(void)
7039{
7040    ExtensionEntry *extEntry;
7041
7042    RT_XKBCLIENT = CreateNewResourceType(XkbClientGone, "XkbClient");
7043    if (!RT_XKBCLIENT)
7044        return;
7045
7046    if (!XkbInitPrivates())
7047        return;
7048
7049    if ((extEntry = AddExtension(XkbName, XkbNumberEvents, XkbNumberErrors,
7050                                 ProcXkbDispatch, SProcXkbDispatch,
7051                                 NULL, StandardMinorOpcode))) {
7052        XkbReqCode = (unsigned char) extEntry->base;
7053        XkbEventBase = (unsigned char) extEntry->eventBase;
7054        XkbErrorBase = (unsigned char) extEntry->errorBase;
7055        XkbKeyboardErrorCode = XkbErrorBase + XkbKeyboard;
7056    }
7057    return;
7058}
7059