11ab64890Smrg/************************************************************
21ab64890SmrgCopyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
31ab64890Smrg
41ab64890SmrgPermission to use, copy, modify, and distribute this
51ab64890Smrgsoftware and its documentation for any purpose and without
61ab64890Smrgfee is hereby granted, provided that the above copyright
71ab64890Smrgnotice appear in all copies and that both that copyright
81ab64890Smrgnotice and this permission notice appear in supporting
961b2299dSmrgdocumentation, and that the name of Silicon Graphics not be
1061b2299dSmrgused in advertising or publicity pertaining to distribution
111ab64890Smrgof the software without specific prior written permission.
1261b2299dSmrgSilicon Graphics makes no representation about the suitability
131ab64890Smrgof this software for any purpose. It is provided "as is"
141ab64890Smrgwithout any express or implied warranty.
151ab64890Smrg
1661b2299dSmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1761b2299dSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
181ab64890SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1961b2299dSmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2061b2299dSmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2161b2299dSmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
221ab64890SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
231ab64890SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
241ab64890Smrg
251ab64890Smrg********************************************************/
261ab64890Smrg
271ab64890Smrg#ifdef HAVE_CONFIG_H
281ab64890Smrg#include <config.h>
291ab64890Smrg#endif
301ab64890Smrg#include <stdio.h>
311ab64890Smrg#define	NEED_MAP_READERS
321ab64890Smrg#include "Xlibint.h"
331ab64890Smrg#include <X11/extensions/XKBproto.h>
341ab64890Smrg#include "XKBlibint.h"
351ab64890Smrg#include <X11/extensions/XI.h>
361ab64890Smrg
371ab64890Smrg/***====================================================================***/
381ab64890Smrg
393233502eSmrgvoid
40818534a1SmrgXkbNoteDeviceChanges(XkbDeviceChangesPtr old,
41818534a1Smrg                     XkbExtensionDeviceNotifyEvent *new,
42818534a1Smrg                     unsigned int wanted)
431ab64890Smrg{
44818534a1Smrg    if ((!old) || (!new) || (!wanted) || ((new->reason & wanted) == 0))
45818534a1Smrg        return;
46818534a1Smrg    if ((wanted & new->reason) & XkbXI_ButtonActionsMask) {
47818534a1Smrg        if (old->changed & XkbXI_ButtonActionsMask) {
48818534a1Smrg            int first, last, newLast;
49818534a1Smrg
50818534a1Smrg            if (new->first_btn < old->first_btn)
51818534a1Smrg                first = new->first_btn;
52818534a1Smrg            else
53818534a1Smrg                first = old->first_btn;
54818534a1Smrg            last = old->first_btn + old->num_btns - 1;
55818534a1Smrg            newLast = new->first_btn + new->num_btns - 1;
56818534a1Smrg            if (newLast > last)
57818534a1Smrg                last = newLast;
58818534a1Smrg            old->first_btn = first;
59818534a1Smrg            old->num_btns = (last - first) + 1;
60818534a1Smrg        }
61818534a1Smrg        else {
62818534a1Smrg            old->changed |= XkbXI_ButtonActionsMask;
63818534a1Smrg            old->first_btn = new->first_btn;
64818534a1Smrg            old->num_btns = new->num_btns;
65818534a1Smrg        }
661ab64890Smrg    }
67818534a1Smrg    if ((wanted & new->reason) & XkbXI_IndicatorsMask) {
68818534a1Smrg        XkbDeviceLedChangesPtr this;
69818534a1Smrg
70818534a1Smrg        if (old->changed & XkbXI_IndicatorsMask) {
71818534a1Smrg            XkbDeviceLedChangesPtr found = NULL;
72818534a1Smrg
73818534a1Smrg            for (this = &old->leds; this && (!found); this = this->next) {
74818534a1Smrg                if ((this->led_class == new->led_class) &&
75818534a1Smrg                    (this->led_id == new->led_id)) {
76818534a1Smrg                    found = this;
77818534a1Smrg                }
78818534a1Smrg            }
79818534a1Smrg            if (!found) {
80818534a1Smrg                found = _XkbTypedCalloc(1, XkbDeviceLedChangesRec);
81818534a1Smrg                if (!found)
82818534a1Smrg                    return;
83818534a1Smrg                found->next = old->leds.next;
84818534a1Smrg                found->led_class = new->led_class;
85818534a1Smrg                found->led_id = new->led_id;
86818534a1Smrg                old->leds.next = found;
87818534a1Smrg            }
88818534a1Smrg            if ((wanted & new->reason) & XkbXI_IndicatorNamesMask)
89818534a1Smrg                found->defined = new->leds_defined;
90818534a1Smrg        }
91818534a1Smrg        else {
92818534a1Smrg            old->changed |= ((wanted & new->reason) & XkbXI_IndicatorsMask);
93818534a1Smrg            old->leds.led_class = new->led_class;
94818534a1Smrg            old->leds.led_id = new->led_id;
95818534a1Smrg            old->leds.defined = new->leds_defined;
96818534a1Smrg            if (old->leds.next) {
97818534a1Smrg                XkbDeviceLedChangesPtr next;
98818534a1Smrg
99818534a1Smrg                for (this = old->leds.next; this; this = next) {
100818534a1Smrg                    next = this->next;
101818534a1Smrg                    _XkbFree(this);
102818534a1Smrg                }
103818534a1Smrg                old->leds.next = NULL;
104818534a1Smrg            }
105818534a1Smrg        }
1061ab64890Smrg    }
1071ab64890Smrg    return;
1081ab64890Smrg}
1091ab64890Smrg
1101ab64890Smrg/***====================================================================***/
1111ab64890Smrg
1121ab64890Smrgstatic Status
113818534a1Smrg_XkbReadDeviceLedInfo(XkbReadBufferPtr buf,
114818534a1Smrg                      unsigned present,
115818534a1Smrg                      XkbDeviceInfoPtr devi)
1161ab64890Smrg{
117818534a1Smrg    register unsigned i, bit;
118818534a1Smrg    XkbDeviceLedInfoPtr devli;
119818534a1Smrg    xkbDeviceLedsWireDesc *wireli;
1201ab64890Smrg
121818534a1Smrg    wireli = _XkbGetTypedRdBufPtr(buf, 1, xkbDeviceLedsWireDesc);
1221ab64890Smrg    if (!wireli)
123818534a1Smrg        return BadLength;
124818534a1Smrg    devli = XkbAddDeviceLedInfo(devi, wireli->ledClass, wireli->ledID);
1251ab64890Smrg    if (!devli)
126818534a1Smrg        return BadAlloc;
127818534a1Smrg    devli->phys_indicators = wireli->physIndicators;
128818534a1Smrg
129818534a1Smrg    if (present & XkbXI_IndicatorStateMask)
130818534a1Smrg        devli->state = wireli->state;
131818534a1Smrg
132818534a1Smrg    if (present & XkbXI_IndicatorNamesMask) {
133818534a1Smrg        devli->names_present = wireli->namesPresent;
134818534a1Smrg        if (devli->names_present) {
135818534a1Smrg            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
136818534a1Smrg                if (wireli->namesPresent & bit) {
137818534a1Smrg                    if (!_XkbCopyFromReadBuffer(buf,
138818534a1Smrg                                                (char *) &devli->names[i], 4))
139818534a1Smrg                        return BadLength;
140818534a1Smrg                }
141818534a1Smrg            }
142818534a1Smrg        }
1431ab64890Smrg    }
1441ab64890Smrg
145818534a1Smrg    if (present & XkbXI_IndicatorMapsMask) {
146818534a1Smrg        devli->maps_present = wireli->mapsPresent;
147818534a1Smrg        if (devli->maps_present) {
148818534a1Smrg            XkbIndicatorMapPtr im;
149818534a1Smrg            xkbIndicatorMapWireDesc *wireim;
150818534a1Smrg
151818534a1Smrg            for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
152818534a1Smrg                if (wireli->mapsPresent & bit) {
153818534a1Smrg                    wireim =
154818534a1Smrg                        _XkbGetTypedRdBufPtr(buf, 1, xkbIndicatorMapWireDesc);
155818534a1Smrg                    if (!wireim)
156818534a1Smrg                        return BadAlloc;
157818534a1Smrg                    im = &devli->maps[i];
158818534a1Smrg                    im->flags = wireim->flags;
159818534a1Smrg                    im->which_groups = wireim->whichGroups;
160818534a1Smrg                    im->groups = wireim->groups;
161818534a1Smrg                    im->which_mods = wireim->whichMods;
162818534a1Smrg                    im->mods.mask = wireim->mods;
163818534a1Smrg                    im->mods.real_mods = wireim->realMods;
164818534a1Smrg                    im->mods.vmods = wireim->virtualMods;
165818534a1Smrg                    im->ctrls = wireim->ctrls;
166818534a1Smrg                }
167818534a1Smrg            }
168818534a1Smrg        }
1691ab64890Smrg    }
1701ab64890Smrg    return Success;
1711ab64890Smrg}
1721ab64890Smrg
1731ab64890Smrgstatic Status
174818534a1Smrg_XkbReadGetDeviceInfoReply(Display *dpy,
175818534a1Smrg                           xkbGetDeviceInfoReply *rep,
176818534a1Smrg                           XkbDeviceInfoPtr devi)
1771ab64890Smrg{
178818534a1Smrg    XkbReadBufferRec buf;
179818534a1Smrg    XkbAction *act;
180818534a1Smrg    int tmp;
1811ab64890Smrg
182818534a1Smrg    if (!_XkbInitReadBuffer(dpy, &buf, (int) rep->length * 4))
183818534a1Smrg        return BadAlloc;
1841ab64890Smrg
185818534a1Smrg    if ((rep->totalBtns > 0) && (rep->totalBtns != devi->num_btns)) {
186818534a1Smrg        tmp = XkbResizeDeviceButtonActions(devi, rep->totalBtns);
187818534a1Smrg        if (tmp != Success)
188818534a1Smrg            return tmp;
1891ab64890Smrg    }
190818534a1Smrg    if (rep->nBtnsWanted > 0) {
191ebe525bcSmrg        if (((unsigned short) rep->firstBtnWanted + rep->nBtnsWanted) > devi->num_btns)
192818534a1Smrg            goto BAILOUT;
193818534a1Smrg        act = &devi->btn_acts[rep->firstBtnWanted];
194818534a1Smrg        bzero((char *) act, (rep->nBtnsWanted * sizeof(XkbAction)));
1951ab64890Smrg    }
1960f8248bfSmrg
1970f8248bfSmrg    _XkbFree(devi->name);
198818534a1Smrg    if (!_XkbGetReadBufferCountedString(&buf, &devi->name))
199818534a1Smrg        goto BAILOUT;
200818534a1Smrg    if (rep->nBtnsRtrn > 0) {
201818534a1Smrg        int size;
202818534a1Smrg
203ebe525bcSmrg        if (((unsigned short) rep->firstBtnRtrn + rep->nBtnsRtrn) > devi->num_btns)
204818534a1Smrg            goto BAILOUT;
205818534a1Smrg        act = &devi->btn_acts[rep->firstBtnRtrn];
206818534a1Smrg        size = rep->nBtnsRtrn * SIZEOF(xkbActionWireDesc);
207818534a1Smrg        if (!_XkbCopyFromReadBuffer(&buf, (char *) act, size))
208818534a1Smrg            goto BAILOUT;
2091ab64890Smrg    }
210818534a1Smrg    if (rep->nDeviceLedFBs > 0) {
211818534a1Smrg        register int i;
212818534a1Smrg
213818534a1Smrg        for (i = 0; i < rep->nDeviceLedFBs; i++) {
214818534a1Smrg            if ((tmp = _XkbReadDeviceLedInfo(&buf, rep->present, devi))
215818534a1Smrg                != Success)
216818534a1Smrg                return tmp;
217818534a1Smrg        }
2181ab64890Smrg    }
219818534a1Smrg    tmp = _XkbFreeReadBuffer(&buf);
22061b2299dSmrg    if (tmp)
221818534a1Smrg        fprintf(stderr, "GetDeviceInfo! Bad length (%d extra bytes)\n", tmp);
2221ab64890Smrg    if (tmp || buf.error)
223818534a1Smrg        return BadLength;
2241ab64890Smrg    return Success;
225818534a1Smrg BAILOUT:
2261ab64890Smrg    _XkbFreeReadBuffer(&buf);
2271ab64890Smrg    return BadLength;
2281ab64890Smrg}
2291ab64890Smrg
2301ab64890SmrgXkbDeviceInfoPtr
231818534a1SmrgXkbGetDeviceInfo(Display *dpy,
232818534a1Smrg                 unsigned which,
233818534a1Smrg                 unsigned deviceSpec,
234818534a1Smrg                 unsigned class,
235818534a1Smrg                 unsigned id)
2361ab64890Smrg{
237818534a1Smrg    register xkbGetDeviceInfoReq *req;
238818534a1Smrg    xkbGetDeviceInfoReply rep;
239818534a1Smrg    Status status;
240818534a1Smrg    XkbDeviceInfoPtr devi;
2411ab64890Smrg
2421ab64890Smrg    if ((dpy->flags & XlibDisplayNoXkb) ||
243818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
244818534a1Smrg        return NULL;
2451ab64890Smrg    LockDisplay(dpy);
2461ab64890Smrg    GetReq(kbGetDeviceInfo, req);
2471ab64890Smrg    req->reqType = dpy->xkb_info->codes->major_opcode;
2481ab64890Smrg    req->xkbReqType = X_kbGetDeviceInfo;
2491ab64890Smrg    req->deviceSpec = deviceSpec;
250818534a1Smrg    req->wanted = which;
251818534a1Smrg    req->allBtns = ((which & XkbXI_ButtonActionsMask) != 0);
252818534a1Smrg    req->firstBtn = req->nBtns = 0;
253818534a1Smrg    req->ledClass = class;
254818534a1Smrg    req->ledID = id;
255818534a1Smrg    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
256818534a1Smrg        UnlockDisplay(dpy);
257818534a1Smrg        SyncHandle();
258818534a1Smrg        return NULL;
2591ab64890Smrg    }
260818534a1Smrg    devi = XkbAllocDeviceInfo(rep.deviceID, rep.totalBtns, rep.nDeviceLedFBs);
2611ab64890Smrg    if (devi) {
262818534a1Smrg        devi->supported = rep.supported;
263818534a1Smrg        devi->unsupported = rep.unsupported;
264818534a1Smrg        devi->type = rep.devType;
265818534a1Smrg        devi->has_own_state = rep.hasOwnState;
266818534a1Smrg        devi->dflt_kbd_fb = rep.dfltKbdFB;
267818534a1Smrg        devi->dflt_led_fb = rep.dfltLedFB;
268818534a1Smrg        status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
269818534a1Smrg        if (status != Success) {
270818534a1Smrg            XkbFreeDeviceInfo(devi, XkbXI_AllDeviceFeaturesMask, True);
271818534a1Smrg            devi = NULL;
272818534a1Smrg        }
2731ab64890Smrg    }
2741ab64890Smrg    UnlockDisplay(dpy);
2751ab64890Smrg    SyncHandle();
2761ab64890Smrg    return devi;
2771ab64890Smrg}
2781ab64890Smrg
2791ab64890SmrgStatus
280818534a1SmrgXkbGetDeviceInfoChanges(Display *dpy,
281818534a1Smrg                        XkbDeviceInfoPtr devi,
282818534a1Smrg                        XkbDeviceChangesPtr changes)
2831ab64890Smrg{
284818534a1Smrg    register xkbGetDeviceInfoReq *req;
285818534a1Smrg    xkbGetDeviceInfoReply rep;
286818534a1Smrg    Status status;
2871ab64890Smrg
2881ab64890Smrg    if ((dpy->flags & XlibDisplayNoXkb) ||
289818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
290818534a1Smrg        return BadMatch;
291818534a1Smrg    if ((changes->changed & XkbXI_AllDeviceFeaturesMask) == 0)
292818534a1Smrg        return Success;
293818534a1Smrg    changes->changed &= ~XkbXI_AllDeviceFeaturesMask;
294818534a1Smrg    status = Success;
2951ab64890Smrg    LockDisplay(dpy);
296818534a1Smrg    while ((changes->changed) && (status == Success)) {
297818534a1Smrg        GetReq(kbGetDeviceInfo, req);
298818534a1Smrg        req->reqType = dpy->xkb_info->codes->major_opcode;
299818534a1Smrg        req->xkbReqType = X_kbGetDeviceInfo;
300818534a1Smrg        req->deviceSpec = devi->device_spec;
301818534a1Smrg        req->wanted = changes->changed;
302818534a1Smrg        req->allBtns = False;
303818534a1Smrg        if (changes->changed & XkbXI_ButtonActionsMask) {
304818534a1Smrg            req->firstBtn = changes->first_btn;
305818534a1Smrg            req->nBtns = changes->num_btns;
306818534a1Smrg            changes->changed &= ~XkbXI_ButtonActionsMask;
307818534a1Smrg        }
308818534a1Smrg        else
309818534a1Smrg            req->firstBtn = req->nBtns = 0;
310818534a1Smrg        if (changes->changed & XkbXI_IndicatorsMask) {
311818534a1Smrg            req->ledClass = changes->leds.led_class;
312818534a1Smrg            req->ledID = changes->leds.led_id;
313818534a1Smrg            if (changes->leds.next == NULL)
314818534a1Smrg                changes->changed &= ~XkbXI_IndicatorsMask;
315818534a1Smrg            else {
316818534a1Smrg                XkbDeviceLedChangesPtr next;
317818534a1Smrg
318818534a1Smrg                next = changes->leds.next;
319818534a1Smrg                changes->leds = *next;
320818534a1Smrg                _XkbFree(next);
321818534a1Smrg            }
322818534a1Smrg        }
323818534a1Smrg        else {
324818534a1Smrg            req->ledClass = XkbDfltXIClass;
325818534a1Smrg            req->ledID = XkbDfltXIId;
326818534a1Smrg        }
327818534a1Smrg        if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
328818534a1Smrg            status = BadLength;
329818534a1Smrg            break;
330818534a1Smrg        }
331818534a1Smrg        devi->supported |= rep.supported;
332818534a1Smrg        devi->unsupported |= rep.unsupported;
333818534a1Smrg        devi->type = rep.devType;
334818534a1Smrg        status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
3351ab64890Smrg    }
3361ab64890Smrg    UnlockDisplay(dpy);
3371ab64890Smrg    SyncHandle();
3381ab64890Smrg    return status;
3391ab64890Smrg}
3401ab64890Smrg
3411ab64890SmrgStatus
342818534a1SmrgXkbGetDeviceButtonActions(Display *dpy,
343818534a1Smrg                          XkbDeviceInfoPtr devi,
344818534a1Smrg                          Bool all,
345818534a1Smrg                          unsigned int first,
346818534a1Smrg                          unsigned int num)
3471ab64890Smrg{
348818534a1Smrg    register xkbGetDeviceInfoReq *req;
349818534a1Smrg    xkbGetDeviceInfoReply rep;
350818534a1Smrg    Status status;
3511ab64890Smrg
35261b2299dSmrg    if ((dpy->flags & XlibDisplayNoXkb) ||
353818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
354818534a1Smrg        return BadMatch;
3551ab64890Smrg    if (!devi)
356818534a1Smrg        return BadValue;
3571ab64890Smrg    LockDisplay(dpy);
3581ab64890Smrg    GetReq(kbGetDeviceInfo, req);
3591ab64890Smrg    req->reqType = dpy->xkb_info->codes->major_opcode;
3601ab64890Smrg    req->xkbReqType = X_kbGetDeviceInfo;
3611ab64890Smrg    req->deviceSpec = devi->device_spec;
362818534a1Smrg    req->wanted = XkbXI_ButtonActionsMask;
363818534a1Smrg    req->allBtns = all;
364818534a1Smrg    req->firstBtn = first;
365818534a1Smrg    req->nBtns = num;
366818534a1Smrg    req->ledClass = XkbDfltXIClass;
367818534a1Smrg    req->ledID = XkbDfltXIId;
368818534a1Smrg    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
369818534a1Smrg        UnlockDisplay(dpy);
370818534a1Smrg        SyncHandle();
371818534a1Smrg        return BadLength;
3721ab64890Smrg    }
373818534a1Smrg    devi->type = rep.devType;
374818534a1Smrg    devi->supported = rep.supported;
375818534a1Smrg    devi->unsupported = rep.unsupported;
376818534a1Smrg    status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
3771ab64890Smrg    UnlockDisplay(dpy);
3781ab64890Smrg    SyncHandle();
3791ab64890Smrg    return status;
3801ab64890Smrg}
3811ab64890Smrg
3821ab64890SmrgStatus
383818534a1SmrgXkbGetDeviceLedInfo(Display *dpy,
384818534a1Smrg                    XkbDeviceInfoPtr devi,
385818534a1Smrg                    unsigned int ledClass,
386818534a1Smrg                    unsigned int ledId,
387818534a1Smrg                    unsigned int which)
3881ab64890Smrg{
389818534a1Smrg    register xkbGetDeviceInfoReq *req;
390818534a1Smrg    xkbGetDeviceInfoReply rep;
391818534a1Smrg    Status status;
3921ab64890Smrg
39361b2299dSmrg    if ((dpy->flags & XlibDisplayNoXkb) ||
394818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
395818534a1Smrg        return BadMatch;
396818534a1Smrg    if (((which & XkbXI_IndicatorsMask) == 0) ||
397818534a1Smrg        (which & (~XkbXI_IndicatorsMask)))
398818534a1Smrg        return BadMatch;
3991ab64890Smrg    if (!devi)
400818534a1Smrg        return BadValue;
4011ab64890Smrg    LockDisplay(dpy);
4021ab64890Smrg    GetReq(kbGetDeviceInfo, req);
4031ab64890Smrg    req->reqType = dpy->xkb_info->codes->major_opcode;
4041ab64890Smrg    req->xkbReqType = X_kbGetDeviceInfo;
4051ab64890Smrg    req->deviceSpec = devi->device_spec;
406818534a1Smrg    req->wanted = which;
407818534a1Smrg    req->allBtns = False;
408818534a1Smrg    req->firstBtn = req->nBtns = 0;
409818534a1Smrg    req->ledClass = ledClass;
410818534a1Smrg    req->ledID = ledId;
411818534a1Smrg    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
412818534a1Smrg        UnlockDisplay(dpy);
413818534a1Smrg        SyncHandle();
414818534a1Smrg        return BadLength;
41561b2299dSmrg    }
416818534a1Smrg    devi->type = rep.devType;
417818534a1Smrg    devi->supported = rep.supported;
418818534a1Smrg    devi->unsupported = rep.unsupported;
419818534a1Smrg    status = _XkbReadGetDeviceInfoReply(dpy, &rep, devi);
4201ab64890Smrg    UnlockDisplay(dpy);
4211ab64890Smrg    SyncHandle();
4221ab64890Smrg    return status;
4231ab64890Smrg}
4241ab64890Smrg
4251ab64890Smrg/***====================================================================***/
4261ab64890Smrg
4271ab64890Smrgtypedef struct _LedInfoStuff {
428818534a1Smrg    Bool used;
429818534a1Smrg    XkbDeviceLedInfoPtr devli;
4301ab64890Smrg} LedInfoStuff;
4311ab64890Smrg
4321ab64890Smrgtypedef struct _SetLedStuff {
433818534a1Smrg    unsigned wanted;
434818534a1Smrg    int num_info;
435818534a1Smrg    int dflt_class;
436818534a1Smrg    LedInfoStuff *dflt_kbd_fb;
437818534a1Smrg    LedInfoStuff *dflt_led_fb;
438818534a1Smrg    LedInfoStuff *info;
4391ab64890Smrg} SetLedStuff;
4401ab64890Smrg
4411ab64890Smrgstatic void
442818534a1Smrg_InitLedStuff(SetLedStuff *stuff, unsigned wanted, XkbDeviceInfoPtr devi)
4431ab64890Smrg{
444818534a1Smrg    int i;
445818534a1Smrg    register XkbDeviceLedInfoPtr devli;
446818534a1Smrg
447818534a1Smrg    bzero(stuff, sizeof(SetLedStuff));
448818534a1Smrg    stuff->wanted = wanted;
449818534a1Smrg    stuff->dflt_class = XkbXINone;
450818534a1Smrg    if ((devi->num_leds < 1) || ((wanted & XkbXI_IndicatorsMask) == 0))
451818534a1Smrg        return;
452818534a1Smrg    stuff->info = _XkbTypedCalloc(devi->num_leds, LedInfoStuff);
4531ab64890Smrg    if (!stuff->info)
454818534a1Smrg        return;
455818534a1Smrg    stuff->num_info = devi->num_leds;
456818534a1Smrg    for (devli = &devi->leds[0], i = 0; i < devi->num_leds; i++, devli++) {
457818534a1Smrg        stuff->info[i].devli = devli;
458818534a1Smrg        if (devli->led_class == KbdFeedbackClass) {
459818534a1Smrg            stuff->dflt_class = KbdFeedbackClass;
460818534a1Smrg            if (stuff->dflt_kbd_fb == NULL)
461818534a1Smrg                stuff->dflt_kbd_fb = &stuff->info[i];
462818534a1Smrg        }
463818534a1Smrg        else if (devli->led_class == LedFeedbackClass) {
464818534a1Smrg            if (stuff->dflt_class == XkbXINone)
465818534a1Smrg                stuff->dflt_class = LedFeedbackClass;
466818534a1Smrg            if (stuff->dflt_led_fb == NULL)
467818534a1Smrg                stuff->dflt_led_fb = &stuff->info[i];
468818534a1Smrg        }
4691ab64890Smrg    }
4701ab64890Smrg    return;
4711ab64890Smrg}
4721ab64890Smrg
4731ab64890Smrgstatic void
474818534a1Smrg_FreeLedStuff(SetLedStuff * stuff)
4751ab64890Smrg{
4760f8248bfSmrg    if (stuff->num_info > 0)
477818534a1Smrg        _XkbFree(stuff->info);
478818534a1Smrg    bzero(stuff, sizeof(SetLedStuff));
4791ab64890Smrg    return;
4801ab64890Smrg}
4811ab64890Smrg
4821ab64890Smrgstatic int
483818534a1Smrg_XkbSizeLedInfo(unsigned changed, XkbDeviceLedInfoPtr devli)
4841ab64890Smrg{
485818534a1Smrg    register int i, size;
486818534a1Smrg    register unsigned bit, namesNeeded, mapsNeeded;
487818534a1Smrg
488818534a1Smrg    size = SIZEOF(xkbDeviceLedsWireDesc);
489818534a1Smrg    namesNeeded = mapsNeeded = 0;
490818534a1Smrg    if (changed & XkbXI_IndicatorNamesMask)
491818534a1Smrg        namesNeeded = devli->names_present;
492818534a1Smrg    if (changed & XkbXI_IndicatorMapsMask)
493818534a1Smrg        mapsNeeded = devli->maps_present;
494818534a1Smrg    if ((namesNeeded) || (mapsNeeded)) {
495818534a1Smrg        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
496818534a1Smrg            if (namesNeeded & bit)
497818534a1Smrg                size += 4;      /* atoms are 4 bytes on the wire */
498818534a1Smrg            if (mapsNeeded & bit)
499818534a1Smrg                size += SIZEOF(xkbIndicatorMapWireDesc);
500818534a1Smrg        }
5011ab64890Smrg    }
5021ab64890Smrg    return size;
5031ab64890Smrg}
5041ab64890Smrg
5051ab64890Smrgstatic Bool
506818534a1Smrg_SizeMatches(SetLedStuff *stuff,
507818534a1Smrg             XkbDeviceLedChangesPtr changes,
508818534a1Smrg             int *sz_rtrn,
509818534a1Smrg             int *nleds_rtrn)
5101ab64890Smrg{
511818534a1Smrg    int i, nMatch, class, id;
512818534a1Smrg    LedInfoStuff *linfo;
513818534a1Smrg    Bool match;
514818534a1Smrg
515818534a1Smrg    nMatch = 0;
516818534a1Smrg    class = changes->led_class;
517818534a1Smrg    id = changes->led_id;
518818534a1Smrg    if (class == XkbDfltXIClass)
519818534a1Smrg        class = stuff->dflt_class;
520818534a1Smrg    for (i = 0, linfo = &stuff->info[0]; i < stuff->num_info; i++, linfo++) {
521818534a1Smrg        XkbDeviceLedInfoPtr devli;
522818534a1Smrg        LedInfoStuff *dflt;
523818534a1Smrg
524818534a1Smrg        devli = linfo->devli;
525818534a1Smrg        match = ((class == devli->led_class) || (class == XkbAllXIClasses));
526818534a1Smrg        if (devli->led_class == KbdFeedbackClass)
527818534a1Smrg            dflt = stuff->dflt_kbd_fb;
528818534a1Smrg        else
529818534a1Smrg            dflt = stuff->dflt_led_fb;
530818534a1Smrg        match = (match && (id == devli->led_id)) ||
531818534a1Smrg            (id == XkbAllXIIds) ||
532818534a1Smrg            ((id == XkbDfltXIId) && (linfo == dflt));
533818534a1Smrg        if (match) {
534818534a1Smrg            if (!linfo->used) {
535818534a1Smrg                *sz_rtrn += _XkbSizeLedInfo(stuff->wanted, devli);
536818534a1Smrg                *nleds_rtrn += 1;
537818534a1Smrg                linfo->used = True;
538818534a1Smrg                if ((class != XkbAllXIClasses) && (id != XkbAllXIIds))
539818534a1Smrg                    return True;
540818534a1Smrg            }
541818534a1Smrg            nMatch++;
542818534a1Smrg            linfo->used = True;
543818534a1Smrg        }
5441ab64890Smrg    }
545818534a1Smrg    return (nMatch > 0);
5461ab64890Smrg}
5471ab64890Smrg
5481ab64890Smrg/***====================================================================***/
5491ab64890Smrg
5501ab64890Smrg
5511ab64890Smrgstatic Status
552818534a1Smrg_XkbSetDeviceInfoSize(XkbDeviceInfoPtr devi,
553818534a1Smrg                      XkbDeviceChangesPtr changes,
554818534a1Smrg                      SetLedStuff *stuff,
555818534a1Smrg                      int *sz_rtrn,
556818534a1Smrg                      int *num_leds_rtrn)
5571ab64890Smrg{
558818534a1Smrg    *sz_rtrn = 0;
559818534a1Smrg    if ((changes->changed & XkbXI_ButtonActionsMask) && (changes->num_btns > 0)) {
560818534a1Smrg        if (!XkbXI_LegalDevBtn
561818534a1Smrg            (devi, (changes->first_btn + changes->num_btns - 1)))
562818534a1Smrg            return BadMatch;
563818534a1Smrg        *sz_rtrn += changes->num_btns * SIZEOF(xkbActionWireDesc);
5641ab64890Smrg    }
5651ab64890Smrg    else {
566818534a1Smrg        changes->changed &= ~XkbXI_ButtonActionsMask;
567818534a1Smrg        changes->first_btn = changes->num_btns = 0;
5681ab64890Smrg    }
569818534a1Smrg    if ((changes->changed & XkbXI_IndicatorsMask) &&
570818534a1Smrg        XkbLegalXILedClass(changes->leds.led_class)) {
571818534a1Smrg        XkbDeviceLedChangesPtr leds;
572818534a1Smrg
573818534a1Smrg        for (leds = &changes->leds; leds != NULL; leds = leds->next) {
574818534a1Smrg            if (!_SizeMatches(stuff, leds, sz_rtrn, num_leds_rtrn))
575818534a1Smrg                return BadMatch;
576818534a1Smrg        }
5771ab64890Smrg    }
5781ab64890Smrg    else {
579818534a1Smrg        changes->changed &= ~XkbXI_IndicatorsMask;
580818534a1Smrg        *num_leds_rtrn = 0;
5811ab64890Smrg    }
5821ab64890Smrg    return Success;
5831ab64890Smrg}
5841ab64890Smrg
5851ab64890Smrgstatic char *
586818534a1Smrg_XkbWriteLedInfo(char *wire, unsigned changed, XkbDeviceLedInfoPtr devli)
5871ab64890Smrg{
588818534a1Smrg    register int i;
589818534a1Smrg    register unsigned bit, namesNeeded, mapsNeeded;
590818534a1Smrg    xkbDeviceLedsWireDesc *lwire;
591818534a1Smrg
592818534a1Smrg    namesNeeded = mapsNeeded = 0;
593818534a1Smrg    if (changed & XkbXI_IndicatorNamesMask)
594818534a1Smrg        namesNeeded = devli->names_present;
595818534a1Smrg    if (changed & XkbXI_IndicatorMapsMask)
596818534a1Smrg        mapsNeeded = devli->maps_present;
597818534a1Smrg
598818534a1Smrg    lwire = (xkbDeviceLedsWireDesc *) wire;
599818534a1Smrg    lwire->ledClass = devli->led_class;
600818534a1Smrg    lwire->ledID = devli->led_id;
601818534a1Smrg    lwire->namesPresent = namesNeeded;
602818534a1Smrg    lwire->mapsPresent = mapsNeeded;
603818534a1Smrg    lwire->physIndicators = devli->phys_indicators;
604818534a1Smrg    lwire->state = devli->state;
605818534a1Smrg    wire = (char *) &lwire[1];
6061ab64890Smrg    if (namesNeeded) {
607818534a1Smrg        CARD32 *awire = (CARD32 *) wire;
608818534a1Smrg
609818534a1Smrg        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
610818534a1Smrg            if (namesNeeded & bit) {
611818534a1Smrg                *awire = (CARD32) devli->names[i];
612818534a1Smrg                awire++;
613818534a1Smrg            }
614818534a1Smrg        }
615818534a1Smrg        wire = (char *) awire;
6161ab64890Smrg    }
6171ab64890Smrg    if (mapsNeeded) {
618818534a1Smrg        xkbIndicatorMapWireDesc *mwire = (xkbIndicatorMapWireDesc *) wire;
619818534a1Smrg
620818534a1Smrg        for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
621818534a1Smrg            if (mapsNeeded & bit) {
622818534a1Smrg                XkbIndicatorMapPtr map = &devli->maps[i];
623818534a1Smrg
624818534a1Smrg                mwire->flags = map->flags;
625818534a1Smrg                mwire->whichGroups = map->which_groups;
626818534a1Smrg                mwire->groups = map->groups;
627818534a1Smrg                mwire->whichMods = map->which_mods;
628818534a1Smrg                mwire->mods = map->mods.mask;
629818534a1Smrg                mwire->realMods = map->mods.real_mods;
630818534a1Smrg                mwire->virtualMods = map->mods.vmods;
631818534a1Smrg                mwire->ctrls = map->ctrls;
632818534a1Smrg                mwire++;
633818534a1Smrg            }
634818534a1Smrg        }
635818534a1Smrg        wire = (char *) mwire;
6361ab64890Smrg    }
6371ab64890Smrg    return wire;
6381ab64890Smrg}
6391ab64890Smrg
6401ab64890Smrg
6411ab64890Smrgstatic int
642818534a1Smrg_XkbWriteSetDeviceInfo(char *wire,
643818534a1Smrg                       XkbDeviceChangesPtr changes,
644818534a1Smrg                       SetLedStuff *stuff,
645818534a1Smrg                       XkbDeviceInfoPtr devi)
6461ab64890Smrg{
647818534a1Smrg    char *start = wire;
648818534a1Smrg
649818534a1Smrg    if (changes->changed & XkbXI_ButtonActionsMask) {
650818534a1Smrg        int size = changes->num_btns * SIZEOF(xkbActionWireDesc);
651818534a1Smrg
6529c019ec5Smaya        memcpy(wire, (char *) &devi->btn_acts[changes->first_btn], (size_t) size);
653818534a1Smrg        wire += size;
6541ab64890Smrg    }
655818534a1Smrg    if (changes->changed & XkbXI_IndicatorsMask) {
656818534a1Smrg        register int i;
657818534a1Smrg        register LedInfoStuff *linfo;
658818534a1Smrg
659818534a1Smrg        for (i = 0, linfo = &stuff->info[0]; i < stuff->num_info; i++, linfo++) {
660818534a1Smrg            if (linfo->used) {
661818534a1Smrg                register char *new_wire;
662818534a1Smrg
663818534a1Smrg                new_wire = _XkbWriteLedInfo(wire, stuff->wanted, linfo->devli);
664818534a1Smrg                if (!new_wire)
665818534a1Smrg                    return wire - start;
666818534a1Smrg                wire = new_wire;
667818534a1Smrg            }
668818534a1Smrg        }
6691ab64890Smrg    }
670818534a1Smrg    return wire - start;
6711ab64890Smrg}
6721ab64890Smrg
6731ab64890SmrgBool
674818534a1SmrgXkbSetDeviceInfo(Display *dpy, unsigned which, XkbDeviceInfoPtr devi)
6751ab64890Smrg{
6761ab64890Smrg    register xkbSetDeviceInfoReq *req;
677818534a1Smrg    Status ok = 0;
678818534a1Smrg    int size, nLeds;
679818534a1Smrg    XkbInfoPtr xkbi;
680818534a1Smrg    XkbDeviceChangesRec changes;
681818534a1Smrg    SetLedStuff lstuff;
6821ab64890Smrg
6831ab64890Smrg    if ((dpy->flags & XlibDisplayNoXkb) ||
684818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
685818534a1Smrg        return False;
686818534a1Smrg    if ((!devi) || (which & (~XkbXI_AllDeviceFeaturesMask)) ||
687818534a1Smrg        ((which & XkbXI_ButtonActionsMask) && (!XkbXI_DevHasBtnActs(devi))) ||
688818534a1Smrg        ((which & XkbXI_IndicatorsMask) && (!XkbXI_DevHasLeds(devi))))
689818534a1Smrg        return False;
690818534a1Smrg
691818534a1Smrg    bzero((char *) &changes, sizeof(XkbDeviceChangesRec));
692818534a1Smrg    changes.changed = which;
693818534a1Smrg    changes.first_btn = 0;
694818534a1Smrg    changes.num_btns = devi->num_btns;
695818534a1Smrg    changes.leds.led_class = XkbAllXIClasses;
696818534a1Smrg    changes.leds.led_id = XkbAllXIIds;
697818534a1Smrg    changes.leds.defined = 0;
698818534a1Smrg    size = nLeds = 0;
699818534a1Smrg    _InitLedStuff(&lstuff, changes.changed, devi);
700818534a1Smrg    if (_XkbSetDeviceInfoSize(devi, &changes, &lstuff, &size, &nLeds) !=
701818534a1Smrg        Success)
702818534a1Smrg        return False;
7031ab64890Smrg    LockDisplay(dpy);
7041ab64890Smrg    xkbi = dpy->xkb_info;
7051ab64890Smrg    GetReq(kbSetDeviceInfo, req);
706818534a1Smrg    req->length += size / 4;
707818534a1Smrg    req->reqType = xkbi->codes->major_opcode;
708818534a1Smrg    req->xkbReqType = X_kbSetDeviceInfo;
709818534a1Smrg    req->deviceSpec = devi->device_spec;
710818534a1Smrg    req->firstBtn = changes.first_btn;
711818534a1Smrg    req->nBtns = changes.num_btns;
712818534a1Smrg    req->change = changes.changed;
713818534a1Smrg    req->nDeviceLedFBs = nLeds;
714818534a1Smrg    if (size > 0) {
715818534a1Smrg        char *wire;
716818534a1Smrg
717818534a1Smrg        BufAlloc(char *, wire, size);
718818534a1Smrg        ok = (wire != NULL) &&
719818534a1Smrg            (_XkbWriteSetDeviceInfo(wire, &changes, &lstuff, devi) == size);
7201ab64890Smrg    }
7211ab64890Smrg    UnlockDisplay(dpy);
7221ab64890Smrg    SyncHandle();
7231ab64890Smrg    _FreeLedStuff(&lstuff);
7241ab64890Smrg    /* 12/11/95 (ef) -- XXX!! should clear changes here */
7251ab64890Smrg    return ok;
7261ab64890Smrg}
7271ab64890Smrg
7281ab64890SmrgBool
729818534a1SmrgXkbChangeDeviceInfo(Display *dpy,
730818534a1Smrg                    XkbDeviceInfoPtr devi,
731818534a1Smrg                    XkbDeviceChangesPtr changes)
7321ab64890Smrg{
7331ab64890Smrg    register xkbSetDeviceInfoReq *req;
734818534a1Smrg    Status ok = 0;
735818534a1Smrg    int size, nLeds;
736818534a1Smrg    XkbInfoPtr xkbi;
737818534a1Smrg    SetLedStuff lstuff;
7381ab64890Smrg
7391ab64890Smrg    if ((dpy->flags & XlibDisplayNoXkb) ||
740818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
741818534a1Smrg        return False;
742818534a1Smrg    if ((!devi) || (changes->changed & (~XkbXI_AllDeviceFeaturesMask)) ||
743818534a1Smrg        ((changes->changed & XkbXI_ButtonActionsMask) &&
744818534a1Smrg         (!XkbXI_DevHasBtnActs(devi))) ||
745818534a1Smrg        ((changes->changed & XkbXI_IndicatorsMask) &&
746818534a1Smrg         (!XkbXI_DevHasLeds(devi))))
747818534a1Smrg        return False;
748818534a1Smrg
749818534a1Smrg    size = nLeds = 0;
750818534a1Smrg    _InitLedStuff(&lstuff, changes->changed, devi);
751818534a1Smrg    if (_XkbSetDeviceInfoSize(devi, changes, &lstuff, &size, &nLeds) != Success)
752818534a1Smrg        return False;
7531ab64890Smrg    LockDisplay(dpy);
7541ab64890Smrg    xkbi = dpy->xkb_info;
7551ab64890Smrg    GetReq(kbSetDeviceInfo, req);
756818534a1Smrg    req->length += size / 4;
757818534a1Smrg    req->reqType = xkbi->codes->major_opcode;
758818534a1Smrg    req->xkbReqType = X_kbSetDeviceInfo;
759818534a1Smrg    req->deviceSpec = devi->device_spec;
760818534a1Smrg    req->firstBtn = changes->first_btn;
761818534a1Smrg    req->nBtns = changes->num_btns;
762818534a1Smrg    req->change = changes->changed;
763818534a1Smrg    req->nDeviceLedFBs = nLeds;
764818534a1Smrg    if (size > 0) {
765818534a1Smrg        char *wire;
766818534a1Smrg
767818534a1Smrg        BufAlloc(char *, wire, size);
768818534a1Smrg        ok = (wire != NULL) &&
769818534a1Smrg            (_XkbWriteSetDeviceInfo(wire, changes, &lstuff, devi) == size);
7701ab64890Smrg    }
7711ab64890Smrg    UnlockDisplay(dpy);
7721ab64890Smrg    SyncHandle();
7731ab64890Smrg    _FreeLedStuff(&lstuff);
7741ab64890Smrg    /* 12/11/95 (ef) -- XXX!! should clear changes here */
7751ab64890Smrg    return ok;
7761ab64890Smrg}
7771ab64890Smrg
77861b2299dSmrgBool
779818534a1SmrgXkbSetDeviceLedInfo(Display *dpy,
780818534a1Smrg                    XkbDeviceInfoPtr devi,
781818534a1Smrg                    unsigned ledClass,
782818534a1Smrg                    unsigned ledID,
783818534a1Smrg                    unsigned which)
7841ab64890Smrg{
7851ab64890Smrg    return False;
7861ab64890Smrg}
7871ab64890Smrg
78861b2299dSmrgBool
789818534a1SmrgXkbSetDeviceButtonActions(Display *dpy,
790818534a1Smrg                          XkbDeviceInfoPtr devi,
791818534a1Smrg                          unsigned int first,
792818534a1Smrg                          unsigned int nBtns)
7931ab64890Smrg{
7941ab64890Smrg    register xkbSetDeviceInfoReq *req;
795818534a1Smrg    Status ok = 0;
796818534a1Smrg    int size, nLeds;
797818534a1Smrg    XkbInfoPtr xkbi;
798818534a1Smrg    XkbDeviceChangesRec changes;
799818534a1Smrg    SetLedStuff lstuff;
8001ab64890Smrg
8011ab64890Smrg    if ((dpy->flags & XlibDisplayNoXkb) ||
802818534a1Smrg        (!dpy->xkb_info && !XkbUseExtension(dpy, NULL, NULL)))
803818534a1Smrg        return False;
804818534a1Smrg    if ((!devi) || (!XkbXI_DevHasBtnActs(devi)) ||
805818534a1Smrg        (first + nBtns > devi->num_btns))
806818534a1Smrg        return False;
807818534a1Smrg    if (nBtns == 0)
808818534a1Smrg        return True;
809818534a1Smrg
810818534a1Smrg    bzero((char *) &changes, sizeof(XkbDeviceChangesRec));
811818534a1Smrg    changes.changed = XkbXI_ButtonActionsMask;
812818534a1Smrg    changes.first_btn = first;
813818534a1Smrg    changes.num_btns = nBtns;
814818534a1Smrg    changes.leds.led_class = XkbXINone;
815818534a1Smrg    changes.leds.led_id = XkbXINone;
816818534a1Smrg    changes.leds.defined = 0;
817818534a1Smrg    size = nLeds = 0;
818818534a1Smrg    if (_XkbSetDeviceInfoSize(devi, &changes, NULL, &size, &nLeds) != Success)
819818534a1Smrg        return False;
8201ab64890Smrg    LockDisplay(dpy);
8211ab64890Smrg    xkbi = dpy->xkb_info;
8221ab64890Smrg    GetReq(kbSetDeviceInfo, req);
823818534a1Smrg    req->length += size / 4;
824818534a1Smrg    req->reqType = xkbi->codes->major_opcode;
825818534a1Smrg    req->xkbReqType = X_kbSetDeviceInfo;
826818534a1Smrg    req->deviceSpec = devi->device_spec;
827818534a1Smrg    req->firstBtn = changes.first_btn;
828818534a1Smrg    req->nBtns = changes.num_btns;
829818534a1Smrg    req->change = changes.changed;
830818534a1Smrg    req->nDeviceLedFBs = nLeds;
831818534a1Smrg    if (size > 0) {
832818534a1Smrg        char *wire;
833818534a1Smrg
834818534a1Smrg        BufAlloc(char *, wire, size);
835818534a1Smrg        ok = (wire != NULL) &&
836818534a1Smrg            (_XkbWriteSetDeviceInfo(wire, &changes, &lstuff, devi) == size);
8371ab64890Smrg    }
8381ab64890Smrg    UnlockDisplay(dpy);
8391ab64890Smrg    SyncHandle();
8401ab64890Smrg    return ok;
8411ab64890Smrg}
842