1/************************************************************
2Copyright (c) 1995 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_CONFIG_H
28#include <config.h>
29#endif
30#include <stdio.h>
31#define	NEED_MAP_READERS
32#include "Xlibint.h"
33#include <X11/extensions/XKBproto.h>
34#include "XKBlibint.h"
35#include <X11/extensions/XI.h>
36
37/***====================================================================***/
38
39void
40XkbNoteDeviceChanges(XkbDeviceChangesPtr old,
41                     XkbExtensionDeviceNotifyEvent *new,
42                     unsigned int wanted)
43{
44    if ((!old) || (!new) || (!wanted) || ((new->reason & wanted) == 0))
45        return;
46    if ((wanted & new->reason) & XkbXI_ButtonActionsMask) {
47        if (old->changed & XkbXI_ButtonActionsMask) {
48            int first, last, newLast;
49
50            if (new->first_btn < old->first_btn)
51                first = new->first_btn;
52            else
53                first = old->first_btn;
54            last = old->first_btn + old->num_btns - 1;
55            newLast = new->first_btn + new->num_btns - 1;
56            if (newLast > last)
57                last = newLast;
58            old->first_btn = first;
59            old->num_btns = (last - first) + 1;
60        }
61        else {
62            old->changed |= XkbXI_ButtonActionsMask;
63            old->first_btn = new->first_btn;
64            old->num_btns = new->num_btns;
65        }
66    }
67    if ((wanted & new->reason) & XkbXI_IndicatorsMask) {
68        XkbDeviceLedChangesPtr this;
69
70        if (old->changed & XkbXI_IndicatorsMask) {
71            XkbDeviceLedChangesPtr found = NULL;
72
73            for (this = &old->leds; this && (!found); this = this->next) {
74                if ((this->led_class == new->led_class) &&
75                    (this->led_id == new->led_id)) {
76                    found = this;
77                }
78            }
79            if (!found) {
80                found = _XkbTypedCalloc(1, XkbDeviceLedChangesRec);
81                if (!found)
82                    return;
83                found->next = old->leds.next;
84                found->led_class = new->led_class;
85                found->led_id = new->led_id;
86                old->leds.next = found;
87            }
88            if ((wanted & new->reason) & XkbXI_IndicatorNamesMask)
89                found->defined = new->leds_defined;
90        }
91        else {
92            old->changed |= ((wanted & new->reason) & XkbXI_IndicatorsMask);
93            old->leds.led_class = new->led_class;
94            old->leds.led_id = new->led_id;
95            old->leds.defined = new->leds_defined;
96            if (old->leds.next) {
97                XkbDeviceLedChangesPtr next;
98
99                for (this = old->leds.next; this; this = next) {
100                    next = this->next;
101                    _XkbFree(this);
102                }
103                old->leds.next = NULL;
104            }
105        }
106    }
107    return;
108}
109
110/***====================================================================***/
111
112static Status
113_XkbReadDeviceLedInfo(XkbReadBufferPtr buf,
114                      unsigned present,
115                      XkbDeviceInfoPtr devi)
116{
117    register unsigned i, bit;
118    XkbDeviceLedInfoPtr devli;
119    xkbDeviceLedsWireDesc *wireli;
120
121    wireli = _XkbGetTypedRdBufPtr(buf, 1, xkbDeviceLedsWireDesc);
122    if (!wireli)
123        return BadLength;
124    devli = XkbAddDeviceLedInfo(devi, wireli->ledClass, wireli->ledID);
125    if (!devli)
126        return BadAlloc;
127    devli->phys_indicators = wireli->physIndicators;
128
129    if (present & XkbXI_IndicatorStateMask)
130        devli->state = wireli->state;
131
132    if (present & XkbXI_IndicatorNamesMask) {
133        devli->names_present = wireli->namesPresent;
134        if (devli->names_present) {
135            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
136                if (wireli->namesPresent & bit) {
137                    if (!_XkbCopyFromReadBuffer(buf,
138                                                (char *) &devli->names[i], 4))
139                        return BadLength;
140                }
141            }
142        }
143    }
144
145    if (present & XkbXI_IndicatorMapsMask) {
146        devli->maps_present = wireli->mapsPresent;
147        if (devli->maps_present) {
148            XkbIndicatorMapPtr im;
149            xkbIndicatorMapWireDesc *wireim;
150
151            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
152                if (wireli->mapsPresent & bit) {
153                    wireim =
154                        _XkbGetTypedRdBufPtr(buf, 1, xkbIndicatorMapWireDesc);
155                    if (!wireim)
156                        return BadAlloc;
157                    im = &devli->maps[i];
158                    im->flags = wireim->flags;
159                    im->which_groups = wireim->whichGroups;
160                    im->groups = wireim->groups;
161                    im->which_mods = wireim->whichMods;
162                    im->mods.mask = wireim->mods;
163                    im->mods.real_mods = wireim->realMods;
164                    im->mods.vmods = wireim->virtualMods;
165                    im->ctrls = wireim->ctrls;
166                }
167            }
168        }
169    }
170    return Success;
171}
172
173static Status
174_XkbReadGetDeviceInfoReply(Display *dpy,
175                           xkbGetDeviceInfoReply *rep,
176                           XkbDeviceInfoPtr devi)
177{
178    XkbReadBufferRec buf;
179    XkbAction *act;
180    int tmp;
181
182    if (!_XkbInitReadBuffer(dpy, &buf, (int) rep->length * 4))
183        return BadAlloc;
184
185    if ((rep->totalBtns > 0) && (rep->totalBtns != devi->num_btns)) {
186        tmp = XkbResizeDeviceButtonActions(devi, rep->totalBtns);
187        if (tmp != Success)
188            return tmp;
189    }
190    if (rep->nBtnsWanted > 0) {
191        if (((unsigned short) rep->firstBtnWanted + rep->nBtnsWanted) > devi->num_btns)
192            goto BAILOUT;
193        act = &devi->btn_acts[rep->firstBtnWanted];
194        bzero((char *) act, (rep->nBtnsWanted * sizeof(XkbAction)));
195    }
196
197    _XkbFree(devi->name);
198    if (!_XkbGetReadBufferCountedString(&buf, &devi->name))
199        goto BAILOUT;
200    if (rep->nBtnsRtrn > 0) {
201        int size;
202
203        if (((unsigned short) rep->firstBtnRtrn + rep->nBtnsRtrn) > devi->num_btns)
204            goto BAILOUT;
205        act = &devi->btn_acts[rep->firstBtnRtrn];
206        size = rep->nBtnsRtrn * SIZEOF(xkbActionWireDesc);
207        if (!_XkbCopyFromReadBuffer(&buf, (char *) act, size))
208            goto BAILOUT;
209    }
210    if (rep->nDeviceLedFBs > 0) {
211        register int i;
212
213        for (i = 0; i < rep->nDeviceLedFBs; i++) {
214            if ((tmp = _XkbReadDeviceLedInfo(&buf, rep->present, devi))
215                != Success)
216                return tmp;
217        }
218    }
219    tmp = _XkbFreeReadBuffer(&buf);
220    if (tmp)
221        fprintf(stderr, "GetDeviceInfo! Bad length (%d extra bytes)\n", tmp);
222    if (tmp || buf.error)
223        return BadLength;
224    return Success;
225 BAILOUT:
226    _XkbFreeReadBuffer(&buf);
227    return BadLength;
228}
229
230XkbDeviceInfoPtr
231XkbGetDeviceInfo(Display *dpy,
232                 unsigned which,
233                 unsigned deviceSpec,
234                 unsigned class,
235                 unsigned id)
236{
237    register xkbGetDeviceInfoReq *req;
238    xkbGetDeviceInfoReply rep;
239    Status status;
240    XkbDeviceInfoPtr devi;
241
242    if ((dpy->flags & XlibDisplayNoXkb) ||
243        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
244        return NULL;
245    LockDisplay(dpy);
246    GetReq(kbGetDeviceInfo, req);
247    req->reqType = dpy->xkb_info->codes->major_opcode;
248    req->xkbReqType = X_kbGetDeviceInfo;
249    req->deviceSpec = deviceSpec;
250    req->wanted = which;
251    req->allBtns = ((which & XkbXI_ButtonActionsMask) != 0);
252    req->firstBtn = req->nBtns = 0;
253    req->ledClass = class;
254    req->ledID = id;
255    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
256        UnlockDisplay(dpy);
257        SyncHandle();
258        return NULL;
259    }
260    devi = XkbAllocDeviceInfo(rep.deviceID, rep.totalBtns, rep.nDeviceLedFBs);
261    if (devi) {
262        devi->supported = rep.supported;
263        devi->unsupported = rep.unsupported;
264        devi->type = rep.devType;
265        devi->has_own_state = rep.hasOwnState;
266        devi->dflt_kbd_fb = rep.dfltKbdFB;
267        devi->dflt_led_fb = rep.dfltLedFB;
268        status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
269        if (status != Success) {
270            XkbFreeDeviceInfo(devi, XkbXI_AllDeviceFeaturesMask, True);
271            devi = NULL;
272        }
273    }
274    UnlockDisplay(dpy);
275    SyncHandle();
276    return devi;
277}
278
279Status
280XkbGetDeviceInfoChanges(Display *dpy,
281                        XkbDeviceInfoPtr devi,
282                        XkbDeviceChangesPtr changes)
283{
284    register xkbGetDeviceInfoReq *req;
285    xkbGetDeviceInfoReply rep;
286    Status status;
287
288    if ((dpy->flags & XlibDisplayNoXkb) ||
289        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
290        return BadMatch;
291    if ((changes->changed & XkbXI_AllDeviceFeaturesMask) == 0)
292        return Success;
293    changes->changed &= ~XkbXI_AllDeviceFeaturesMask;
294    status = Success;
295    LockDisplay(dpy);
296    while ((changes->changed) && (status == Success)) {
297        GetReq(kbGetDeviceInfo, req);
298        req->reqType = dpy->xkb_info->codes->major_opcode;
299        req->xkbReqType = X_kbGetDeviceInfo;
300        req->deviceSpec = devi->device_spec;
301        req->wanted = changes->changed;
302        req->allBtns = False;
303        if (changes->changed & XkbXI_ButtonActionsMask) {
304            req->firstBtn = changes->first_btn;
305            req->nBtns = changes->num_btns;
306            changes->changed &= ~XkbXI_ButtonActionsMask;
307        }
308        else
309            req->firstBtn = req->nBtns = 0;
310        if (changes->changed & XkbXI_IndicatorsMask) {
311            req->ledClass = changes->leds.led_class;
312            req->ledID = changes->leds.led_id;
313            if (changes->leds.next == NULL)
314                changes->changed &= ~XkbXI_IndicatorsMask;
315            else {
316                XkbDeviceLedChangesPtr next;
317
318                next = changes->leds.next;
319                changes->leds = *next;
320                _XkbFree(next);
321            }
322        }
323        else {
324            req->ledClass = XkbDfltXIClass;
325            req->ledID = XkbDfltXIId;
326        }
327        if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
328            status = BadLength;
329            break;
330        }
331        devi->supported |= rep.supported;
332        devi->unsupported |= rep.unsupported;
333        devi->type = rep.devType;
334        status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
335    }
336    UnlockDisplay(dpy);
337    SyncHandle();
338    return status;
339}
340
341Status
342XkbGetDeviceButtonActions(Display *dpy,
343                          XkbDeviceInfoPtr devi,
344                          Bool all,
345                          unsigned int first,
346                          unsigned int num)
347{
348    register xkbGetDeviceInfoReq *req;
349    xkbGetDeviceInfoReply rep;
350    Status status;
351
352    if ((dpy->flags & XlibDisplayNoXkb) ||
353        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
354        return BadMatch;
355    if (!devi)
356        return BadValue;
357    LockDisplay(dpy);
358    GetReq(kbGetDeviceInfo, req);
359    req->reqType = dpy->xkb_info->codes->major_opcode;
360    req->xkbReqType = X_kbGetDeviceInfo;
361    req->deviceSpec = devi->device_spec;
362    req->wanted = XkbXI_ButtonActionsMask;
363    req->allBtns = all;
364    req->firstBtn = first;
365    req->nBtns = num;
366    req->ledClass = XkbDfltXIClass;
367    req->ledID = XkbDfltXIId;
368    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
369        UnlockDisplay(dpy);
370        SyncHandle();
371        return BadLength;
372    }
373    devi->type = rep.devType;
374    devi->supported = rep.supported;
375    devi->unsupported = rep.unsupported;
376    status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
377    UnlockDisplay(dpy);
378    SyncHandle();
379    return status;
380}
381
382Status
383XkbGetDeviceLedInfo(Display *dpy,
384                    XkbDeviceInfoPtr devi,
385                    unsigned int ledClass,
386                    unsigned int ledId,
387                    unsigned int which)
388{
389    register xkbGetDeviceInfoReq *req;
390    xkbGetDeviceInfoReply rep;
391    Status status;
392
393    if ((dpy->flags & XlibDisplayNoXkb) ||
394        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
395        return BadMatch;
396    if (((which & XkbXI_IndicatorsMask) == 0) ||
397        (which & (~XkbXI_IndicatorsMask)))
398        return BadMatch;
399    if (!devi)
400        return BadValue;
401    LockDisplay(dpy);
402    GetReq(kbGetDeviceInfo, req);
403    req->reqType = dpy->xkb_info->codes->major_opcode;
404    req->xkbReqType = X_kbGetDeviceInfo;
405    req->deviceSpec = devi->device_spec;
406    req->wanted = which;
407    req->allBtns = False;
408    req->firstBtn = req->nBtns = 0;
409    req->ledClass = ledClass;
410    req->ledID = ledId;
411    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
412        UnlockDisplay(dpy);
413        SyncHandle();
414        return BadLength;
415    }
416    devi->type = rep.devType;
417    devi->supported = rep.supported;
418    devi->unsupported = rep.unsupported;
419    status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
420    UnlockDisplay(dpy);
421    SyncHandle();
422    return status;
423}
424
425/***====================================================================***/
426
427typedef struct _LedInfoStuff {
428    Bool used;
429    XkbDeviceLedInfoPtr devli;
430} LedInfoStuff;
431
432typedef struct _SetLedStuff {
433    unsigned wanted;
434    int num_info;
435    int dflt_class;
436    LedInfoStuff *dflt_kbd_fb;
437    LedInfoStuff *dflt_led_fb;
438    LedInfoStuff *info;
439} SetLedStuff;
440
441static void
442_InitLedStuff(SetLedStuff *stuff, unsigned wanted, XkbDeviceInfoPtr devi)
443{
444    int i;
445    register XkbDeviceLedInfoPtr devli;
446
447    bzero(stuff, sizeof(SetLedStuff));
448    stuff->wanted = wanted;
449    stuff->dflt_class = XkbXINone;
450    if ((devi->num_leds < 1) || ((wanted & XkbXI_IndicatorsMask) == 0))
451        return;
452    stuff->info = _XkbTypedCalloc(devi->num_leds, LedInfoStuff);
453    if (!stuff->info)
454        return;
455    stuff->num_info = devi->num_leds;
456    for (devli = &devi->leds[0], i = 0; i < devi->num_leds; i++, devli++) {
457        stuff->info[i].devli = devli;
458        if (devli->led_class == KbdFeedbackClass) {
459            stuff->dflt_class = KbdFeedbackClass;
460            if (stuff->dflt_kbd_fb == NULL)
461                stuff->dflt_kbd_fb = &stuff->info[i];
462        }
463        else if (devli->led_class == LedFeedbackClass) {
464            if (stuff->dflt_class == XkbXINone)
465                stuff->dflt_class = LedFeedbackClass;
466            if (stuff->dflt_led_fb == NULL)
467                stuff->dflt_led_fb = &stuff->info[i];
468        }
469    }
470    return;
471}
472
473static void
474_FreeLedStuff(SetLedStuff * stuff)
475{
476    if (stuff->num_info > 0)
477        _XkbFree(stuff->info);
478    bzero(stuff, sizeof(SetLedStuff));
479    return;
480}
481
482static int
483_XkbSizeLedInfo(unsigned changed, XkbDeviceLedInfoPtr devli)
484{
485    register int i, size;
486    register unsigned bit, namesNeeded, mapsNeeded;
487
488    size = SIZEOF(xkbDeviceLedsWireDesc);
489    namesNeeded = mapsNeeded = 0;
490    if (changed & XkbXI_IndicatorNamesMask)
491        namesNeeded = devli->names_present;
492    if (changed & XkbXI_IndicatorMapsMask)
493        mapsNeeded = devli->maps_present;
494    if ((namesNeeded) || (mapsNeeded)) {
495        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
496            if (namesNeeded & bit)
497                size += 4;      /* atoms are 4 bytes on the wire */
498            if (mapsNeeded & bit)
499                size += SIZEOF(xkbIndicatorMapWireDesc);
500        }
501    }
502    return size;
503}
504
505static Bool
506_SizeMatches(SetLedStuff *stuff,
507             XkbDeviceLedChangesPtr changes,
508             int *sz_rtrn,
509             int *nleds_rtrn)
510{
511    int i, nMatch, class, id;
512    LedInfoStuff *linfo;
513    Bool match;
514
515    nMatch = 0;
516    class = changes->led_class;
517    id = changes->led_id;
518    if (class == XkbDfltXIClass)
519        class = stuff->dflt_class;
520    for (i = 0, linfo = &stuff->info[0]; i < stuff->num_info; i++, linfo++) {
521        XkbDeviceLedInfoPtr devli;
522        LedInfoStuff *dflt;
523
524        devli = linfo->devli;
525        match = ((class == devli->led_class) || (class == XkbAllXIClasses));
526        if (devli->led_class == KbdFeedbackClass)
527            dflt = stuff->dflt_kbd_fb;
528        else
529            dflt = stuff->dflt_led_fb;
530        match = (match && (id == devli->led_id)) ||
531            (id == XkbAllXIIds) ||
532            ((id == XkbDfltXIId) && (linfo == dflt));
533        if (match) {
534            if (!linfo->used) {
535                *sz_rtrn += _XkbSizeLedInfo(stuff->wanted, devli);
536                *nleds_rtrn += 1;
537                linfo->used = True;
538                if ((class != XkbAllXIClasses) && (id != XkbAllXIIds))
539                    return True;
540            }
541            nMatch++;
542            linfo->used = True;
543        }
544    }
545    return (nMatch > 0);
546}
547
548/***====================================================================***/
549
550
551static Status
552_XkbSetDeviceInfoSize(XkbDeviceInfoPtr devi,
553                      XkbDeviceChangesPtr changes,
554                      SetLedStuff *stuff,
555                      int *sz_rtrn,
556                      int *num_leds_rtrn)
557{
558    *sz_rtrn = 0;
559    if ((changes->changed & XkbXI_ButtonActionsMask) && (changes->num_btns > 0)) {
560        if (!XkbXI_LegalDevBtn
561            (devi, (changes->first_btn + changes->num_btns - 1)))
562            return BadMatch;
563        *sz_rtrn += changes->num_btns * SIZEOF(xkbActionWireDesc);
564    }
565    else {
566        changes->changed &= ~XkbXI_ButtonActionsMask;
567        changes->first_btn = changes->num_btns = 0;
568    }
569    if ((changes->changed & XkbXI_IndicatorsMask) &&
570        XkbLegalXILedClass(changes->leds.led_class)) {
571        XkbDeviceLedChangesPtr leds;
572
573        for (leds = &changes->leds; leds != NULL; leds = leds->next) {
574            if (!_SizeMatches(stuff, leds, sz_rtrn, num_leds_rtrn))
575                return BadMatch;
576        }
577    }
578    else {
579        changes->changed &= ~XkbXI_IndicatorsMask;
580        *num_leds_rtrn = 0;
581    }
582    return Success;
583}
584
585static char *
586_XkbWriteLedInfo(char *wire, unsigned changed, XkbDeviceLedInfoPtr devli)
587{
588    register int i;
589    register unsigned bit, namesNeeded, mapsNeeded;
590    xkbDeviceLedsWireDesc *lwire;
591
592    namesNeeded = mapsNeeded = 0;
593    if (changed & XkbXI_IndicatorNamesMask)
594        namesNeeded = devli->names_present;
595    if (changed & XkbXI_IndicatorMapsMask)
596        mapsNeeded = devli->maps_present;
597
598    lwire = (xkbDeviceLedsWireDesc *) wire;
599    lwire->ledClass = devli->led_class;
600    lwire->ledID = devli->led_id;
601    lwire->namesPresent = namesNeeded;
602    lwire->mapsPresent = mapsNeeded;
603    lwire->physIndicators = devli->phys_indicators;
604    lwire->state = devli->state;
605    wire = (char *) &lwire[1];
606    if (namesNeeded) {
607        CARD32 *awire = (CARD32 *) wire;
608
609        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
610            if (namesNeeded & bit) {
611                *awire = (CARD32) devli->names[i];
612                awire++;
613            }
614        }
615        wire = (char *) awire;
616    }
617    if (mapsNeeded) {
618        xkbIndicatorMapWireDesc *mwire = (xkbIndicatorMapWireDesc *) wire;
619
620        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
621            if (mapsNeeded & bit) {
622                XkbIndicatorMapPtr map = &devli->maps[i];
623
624                mwire->flags = map->flags;
625                mwire->whichGroups = map->which_groups;
626                mwire->groups = map->groups;
627                mwire->whichMods = map->which_mods;
628                mwire->mods = map->mods.mask;
629                mwire->realMods = map->mods.real_mods;
630                mwire->virtualMods = map->mods.vmods;
631                mwire->ctrls = map->ctrls;
632                mwire++;
633            }
634        }
635        wire = (char *) mwire;
636    }
637    return wire;
638}
639
640
641static int
642_XkbWriteSetDeviceInfo(char *wire,
643                       XkbDeviceChangesPtr changes,
644                       SetLedStuff *stuff,
645                       XkbDeviceInfoPtr devi)
646{
647    char *start = wire;
648
649    if (changes->changed & XkbXI_ButtonActionsMask) {
650        int size = changes->num_btns * SIZEOF(xkbActionWireDesc);
651
652        memcpy(wire, (char *) &devi->btn_acts[changes->first_btn], (size_t) size);
653        wire += size;
654    }
655    if (changes->changed & XkbXI_IndicatorsMask) {
656        register int i;
657        register LedInfoStuff *linfo;
658
659        for (i = 0, linfo = &stuff->info[0]; i < stuff->num_info; i++, linfo++) {
660            if (linfo->used) {
661                register char *new_wire;
662
663                new_wire = _XkbWriteLedInfo(wire, stuff->wanted, linfo->devli);
664                if (!new_wire)
665                    return wire - start;
666                wire = new_wire;
667            }
668        }
669    }
670    return wire - start;
671}
672
673Bool
674XkbSetDeviceInfo(Display *dpy, unsigned which, XkbDeviceInfoPtr devi)
675{
676    register xkbSetDeviceInfoReq *req;
677    Status ok = 0;
678    int size, nLeds;
679    XkbInfoPtr xkbi;
680    XkbDeviceChangesRec changes;
681    SetLedStuff lstuff;
682
683    if ((dpy->flags & XlibDisplayNoXkb) ||
684        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
685        return False;
686    if ((!devi) || (which & (~XkbXI_AllDeviceFeaturesMask)) ||
687        ((which & XkbXI_ButtonActionsMask) && (!XkbXI_DevHasBtnActs(devi))) ||
688        ((which & XkbXI_IndicatorsMask) && (!XkbXI_DevHasLeds(devi))))
689        return False;
690
691    bzero((char *) &changes, sizeof(XkbDeviceChangesRec));
692    changes.changed = which;
693    changes.first_btn = 0;
694    changes.num_btns = devi->num_btns;
695    changes.leds.led_class = XkbAllXIClasses;
696    changes.leds.led_id = XkbAllXIIds;
697    changes.leds.defined = 0;
698    size = nLeds = 0;
699    _InitLedStuff(&lstuff, changes.changed, devi);
700    if (_XkbSetDeviceInfoSize(devi, &changes, &lstuff, &size, &nLeds) !=
701        Success)
702        return False;
703    LockDisplay(dpy);
704    xkbi = dpy->xkb_info;
705    GetReq(kbSetDeviceInfo, req);
706    req->length += size / 4;
707    req->reqType = xkbi->codes->major_opcode;
708    req->xkbReqType = X_kbSetDeviceInfo;
709    req->deviceSpec = devi->device_spec;
710    req->firstBtn = changes.first_btn;
711    req->nBtns = changes.num_btns;
712    req->change = changes.changed;
713    req->nDeviceLedFBs = nLeds;
714    if (size > 0) {
715        char *wire;
716
717        BufAlloc(char *, wire, size);
718        ok = (wire != NULL) &&
719            (_XkbWriteSetDeviceInfo(wire, &changes, &lstuff, devi) == size);
720    }
721    UnlockDisplay(dpy);
722    SyncHandle();
723    _FreeLedStuff(&lstuff);
724    /* 12/11/95 (ef) -- XXX!! should clear changes here */
725    return ok;
726}
727
728Bool
729XkbChangeDeviceInfo(Display *dpy,
730                    XkbDeviceInfoPtr devi,
731                    XkbDeviceChangesPtr changes)
732{
733    register xkbSetDeviceInfoReq *req;
734    Status ok = 0;
735    int size, nLeds;
736    XkbInfoPtr xkbi;
737    SetLedStuff lstuff;
738
739    if ((dpy->flags & XlibDisplayNoXkb) ||
740        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
741        return False;
742    if ((!devi) || (changes->changed & (~XkbXI_AllDeviceFeaturesMask)) ||
743        ((changes->changed & XkbXI_ButtonActionsMask) &&
744         (!XkbXI_DevHasBtnActs(devi))) ||
745        ((changes->changed & XkbXI_IndicatorsMask) &&
746         (!XkbXI_DevHasLeds(devi))))
747        return False;
748
749    size = nLeds = 0;
750    _InitLedStuff(&lstuff, changes->changed, devi);
751    if (_XkbSetDeviceInfoSize(devi, changes, &lstuff, &size, &nLeds) != Success)
752        return False;
753    LockDisplay(dpy);
754    xkbi = dpy->xkb_info;
755    GetReq(kbSetDeviceInfo, req);
756    req->length += size / 4;
757    req->reqType = xkbi->codes->major_opcode;
758    req->xkbReqType = X_kbSetDeviceInfo;
759    req->deviceSpec = devi->device_spec;
760    req->firstBtn = changes->first_btn;
761    req->nBtns = changes->num_btns;
762    req->change = changes->changed;
763    req->nDeviceLedFBs = nLeds;
764    if (size > 0) {
765        char *wire;
766
767        BufAlloc(char *, wire, size);
768        ok = (wire != NULL) &&
769            (_XkbWriteSetDeviceInfo(wire, changes, &lstuff, devi) == size);
770    }
771    UnlockDisplay(dpy);
772    SyncHandle();
773    _FreeLedStuff(&lstuff);
774    /* 12/11/95 (ef) -- XXX!! should clear changes here */
775    return ok;
776}
777
778Bool
779XkbSetDeviceLedInfo(Display *dpy,
780                    XkbDeviceInfoPtr devi,
781                    unsigned ledClass,
782                    unsigned ledID,
783                    unsigned which)
784{
785    return False;
786}
787
788Bool
789XkbSetDeviceButtonActions(Display *dpy,
790                          XkbDeviceInfoPtr devi,
791                          unsigned int first,
792                          unsigned int nBtns)
793{
794    register xkbSetDeviceInfoReq *req;
795    Status ok = 0;
796    int size, nLeds;
797    XkbInfoPtr xkbi;
798    XkbDeviceChangesRec changes;
799    SetLedStuff lstuff;
800
801    if ((dpy->flags & XlibDisplayNoXkb) ||
802        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
803        return False;
804    if ((!devi) || (!XkbXI_DevHasBtnActs(devi)) ||
805        (first + nBtns > devi->num_btns))
806        return False;
807    if (nBtns == 0)
808        return True;
809
810    bzero((char *) &changes, sizeof(XkbDeviceChangesRec));
811    changes.changed = XkbXI_ButtonActionsMask;
812    changes.first_btn = first;
813    changes.num_btns = nBtns;
814    changes.leds.led_class = XkbXINone;
815    changes.leds.led_id = XkbXINone;
816    changes.leds.defined = 0;
817    size = nLeds = 0;
818    if (_XkbSetDeviceInfoSize(devi, &changes, NULL, &size, &nLeds) != Success)
819        return False;
820    LockDisplay(dpy);
821    xkbi = dpy->xkb_info;
822    GetReq(kbSetDeviceInfo, req);
823    req->length += size / 4;
824    req->reqType = xkbi->codes->major_opcode;
825    req->xkbReqType = X_kbSetDeviceInfo;
826    req->deviceSpec = devi->device_spec;
827    req->firstBtn = changes.first_btn;
828    req->nBtns = changes.num_btns;
829    req->change = changes.changed;
830    req->nDeviceLedFBs = nLeds;
831    if (size > 0) {
832        char *wire;
833
834        BufAlloc(char *, wire, size);
835        ok = (wire != NULL) &&
836            (_XkbWriteSetDeviceInfo(wire, &changes, &lstuff, devi) == size);
837    }
838    UnlockDisplay(dpy);
839    SyncHandle();
840    return ok;
841}
842