5b19f6d757
Contains fix for CVE-2015-0255. ok dcoppa@
6862 lines
219 KiB
C
6862 lines
219 KiB
C
/************************************************************
|
|
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
|
|
|
|
Permission to use, copy, modify, and distribute this
|
|
software and its documentation for any purpose and without
|
|
fee is hereby granted, provided that the above copyright
|
|
notice appear in all copies and that both that copyright
|
|
notice and this permission notice appear in supporting
|
|
documentation, and that the name of Silicon Graphics not be
|
|
used in advertising or publicity pertaining to distribution
|
|
of the software without specific prior written permission.
|
|
Silicon Graphics makes no representation about the suitability
|
|
of this software for any purpose. It is provided "as is"
|
|
without any express or implied warranty.
|
|
|
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
|
|
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
|
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
|
|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
********************************************************/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include "misc.h"
|
|
#include "inputstr.h"
|
|
#define XKBSRV_NEED_FILE_FUNCS
|
|
#include <xkbsrv.h>
|
|
#include "extnsionst.h"
|
|
#include "extinit.h"
|
|
#include "xace.h"
|
|
#include "xkb.h"
|
|
#include "protocol-versions.h"
|
|
|
|
#include <X11/extensions/XI.h>
|
|
#include <X11/extensions/XKMformat.h>
|
|
|
|
int XkbEventBase;
|
|
static int XkbErrorBase;
|
|
int XkbReqCode;
|
|
int XkbKeyboardErrorCode;
|
|
CARD32 xkbDebugFlags = 0;
|
|
static CARD32 xkbDebugCtrls = 0;
|
|
|
|
static RESTYPE RT_XKBCLIENT;
|
|
|
|
/***====================================================================***/
|
|
|
|
#define CHK_DEVICE(dev, id, client, access_mode, lf) {\
|
|
int why;\
|
|
int tmprc = lf(&(dev), id, client, access_mode, &why);\
|
|
if (tmprc != Success) {\
|
|
client->errorValue = _XkbErrCode2(why, id);\
|
|
return tmprc;\
|
|
}\
|
|
}
|
|
|
|
#define CHK_KBD_DEVICE(dev, id, client, mode) \
|
|
CHK_DEVICE(dev, id, client, mode, _XkbLookupKeyboard)
|
|
#define CHK_LED_DEVICE(dev, id, client, mode) \
|
|
CHK_DEVICE(dev, id, client, mode, _XkbLookupLedDevice)
|
|
#define CHK_BELL_DEVICE(dev, id, client, mode) \
|
|
CHK_DEVICE(dev, id, client, mode, _XkbLookupBellDevice)
|
|
#define CHK_ANY_DEVICE(dev, id, client, mode) \
|
|
CHK_DEVICE(dev, id, client, mode, _XkbLookupAnyDevice)
|
|
|
|
#define CHK_ATOM_ONLY2(a,ev,er) {\
|
|
if (((a)==None)||(!ValidAtom((a)))) {\
|
|
(ev)= (XID)(a);\
|
|
return er;\
|
|
}\
|
|
}
|
|
#define CHK_ATOM_ONLY(a) \
|
|
CHK_ATOM_ONLY2(a,client->errorValue,BadAtom)
|
|
|
|
#define CHK_ATOM_OR_NONE3(a,ev,er,ret) {\
|
|
if (((a)!=None)&&(!ValidAtom((a)))) {\
|
|
(ev)= (XID)(a);\
|
|
(er)= BadAtom;\
|
|
return ret;\
|
|
}\
|
|
}
|
|
#define CHK_ATOM_OR_NONE2(a,ev,er) {\
|
|
if (((a)!=None)&&(!ValidAtom((a)))) {\
|
|
(ev)= (XID)(a);\
|
|
return er;\
|
|
}\
|
|
}
|
|
#define CHK_ATOM_OR_NONE(a) \
|
|
CHK_ATOM_OR_NONE2(a,client->errorValue,BadAtom)
|
|
|
|
#define CHK_MASK_LEGAL3(err,mask,legal,ev,er,ret) {\
|
|
if ((mask)&(~(legal))) { \
|
|
(ev)= _XkbErrCode2((err),((mask)&(~(legal))));\
|
|
(er)= BadValue;\
|
|
return ret;\
|
|
}\
|
|
}
|
|
#define CHK_MASK_LEGAL2(err,mask,legal,ev,er) {\
|
|
if ((mask)&(~(legal))) { \
|
|
(ev)= _XkbErrCode2((err),((mask)&(~(legal))));\
|
|
return er;\
|
|
}\
|
|
}
|
|
#define CHK_MASK_LEGAL(err,mask,legal) \
|
|
CHK_MASK_LEGAL2(err,mask,legal,client->errorValue,BadValue)
|
|
|
|
#define CHK_MASK_MATCH(err,affect,value) {\
|
|
if ((value)&(~(affect))) { \
|
|
client->errorValue= _XkbErrCode2((err),((value)&(~(affect))));\
|
|
return BadMatch;\
|
|
}\
|
|
}
|
|
#define CHK_MASK_OVERLAP(err,m1,m2) {\
|
|
if ((m1)&(m2)) { \
|
|
client->errorValue= _XkbErrCode2((err),((m1)&(m2)));\
|
|
return BadMatch;\
|
|
}\
|
|
}
|
|
#define CHK_KEY_RANGE2(err,first,num,x,ev,er) {\
|
|
if (((unsigned)(first)+(num)-1)>(x)->max_key_code) {\
|
|
(ev)=_XkbErrCode4(err,(first),(num),(x)->max_key_code);\
|
|
return er;\
|
|
}\
|
|
else if ( (first)<(x)->min_key_code ) {\
|
|
(ev)=_XkbErrCode3(err+1,(first),xkb->min_key_code);\
|
|
return er;\
|
|
}\
|
|
}
|
|
#define CHK_KEY_RANGE(err,first,num,x) \
|
|
CHK_KEY_RANGE2(err,first,num,x,client->errorValue,BadValue)
|
|
|
|
#define CHK_REQ_KEY_RANGE2(err,first,num,r,ev,er) {\
|
|
if (((unsigned)(first)+(num)-1)>(r)->maxKeyCode) {\
|
|
(ev)=_XkbErrCode4(err,(first),(num),(r)->maxKeyCode);\
|
|
return er;\
|
|
}\
|
|
else if ( (first)<(r)->minKeyCode ) {\
|
|
(ev)=_XkbErrCode3(err+1,(first),(r)->minKeyCode);\
|
|
return er;\
|
|
}\
|
|
}
|
|
#define CHK_REQ_KEY_RANGE(err,first,num,r) \
|
|
CHK_REQ_KEY_RANGE2(err,first,num,r,client->errorValue,BadValue)
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbUseExtension(ClientPtr client)
|
|
{
|
|
REQUEST(xkbUseExtensionReq);
|
|
xkbUseExtensionReply rep;
|
|
int supported;
|
|
|
|
REQUEST_SIZE_MATCH(xkbUseExtensionReq);
|
|
if (stuff->wantedMajor != SERVER_XKB_MAJOR_VERSION) {
|
|
/* pre-release version 0.65 is compatible with 1.00 */
|
|
supported = ((SERVER_XKB_MAJOR_VERSION == 1) &&
|
|
(stuff->wantedMajor == 0) && (stuff->wantedMinor == 65));
|
|
}
|
|
else
|
|
supported = 1;
|
|
|
|
if ((supported) && (!(client->xkbClientFlags & _XkbClientInitialized))) {
|
|
client->xkbClientFlags = _XkbClientInitialized;
|
|
client->vMajor = stuff->wantedMajor;
|
|
client->vMinor = stuff->wantedMinor;
|
|
}
|
|
else if (xkbDebugFlags & 0x1) {
|
|
ErrorF
|
|
("[xkb] Rejecting client %d (0x%lx) (wants %d.%02d, have %d.%02d)\n",
|
|
client->index, (long) client->clientAsMask, stuff->wantedMajor,
|
|
stuff->wantedMinor, SERVER_XKB_MAJOR_VERSION,
|
|
SERVER_XKB_MINOR_VERSION);
|
|
}
|
|
rep = (xkbUseExtensionReply) {
|
|
.type = X_Reply,
|
|
.supported = supported,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.serverMajor = SERVER_XKB_MAJOR_VERSION,
|
|
.serverMinor = SERVER_XKB_MINOR_VERSION
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swaps(&rep.serverMajor);
|
|
swaps(&rep.serverMinor);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbUseExtensionReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbSelectEvents(ClientPtr client)
|
|
{
|
|
unsigned legal;
|
|
DeviceIntPtr dev;
|
|
XkbInterestPtr masks;
|
|
|
|
REQUEST(xkbSelectEventsReq);
|
|
|
|
REQUEST_AT_LEAST_SIZE(xkbSelectEventsReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixUseAccess);
|
|
|
|
if (((stuff->affectWhich & XkbMapNotifyMask) != 0) && (stuff->affectMap)) {
|
|
client->mapNotifyMask &= ~stuff->affectMap;
|
|
client->mapNotifyMask |= (stuff->affectMap & stuff->map);
|
|
}
|
|
if ((stuff->affectWhich & (~XkbMapNotifyMask)) == 0)
|
|
return Success;
|
|
|
|
masks = XkbFindClientResource((DevicePtr) dev, client);
|
|
if (!masks) {
|
|
XID id = FakeClientID(client->index);
|
|
|
|
if (!AddResource(id, RT_XKBCLIENT, dev))
|
|
return BadAlloc;
|
|
masks = XkbAddClientResource((DevicePtr) dev, client, id);
|
|
}
|
|
if (masks) {
|
|
union {
|
|
CARD8 *c8;
|
|
CARD16 *c16;
|
|
CARD32 *c32;
|
|
} from, to;
|
|
register unsigned bit, ndx, maskLeft, dataLeft, size;
|
|
|
|
from.c8 = (CARD8 *) &stuff[1];
|
|
dataLeft = (stuff->length * 4) - SIZEOF(xkbSelectEventsReq);
|
|
maskLeft = (stuff->affectWhich & (~XkbMapNotifyMask));
|
|
for (ndx = 0, bit = 1; (maskLeft != 0); ndx++, bit <<= 1) {
|
|
if ((bit & maskLeft) == 0)
|
|
continue;
|
|
maskLeft &= ~bit;
|
|
switch (ndx) {
|
|
case XkbNewKeyboardNotify:
|
|
to.c16 = &client->newKeyboardNotifyMask;
|
|
legal = XkbAllNewKeyboardEventsMask;
|
|
size = 2;
|
|
break;
|
|
case XkbStateNotify:
|
|
to.c16 = &masks->stateNotifyMask;
|
|
legal = XkbAllStateEventsMask;
|
|
size = 2;
|
|
break;
|
|
case XkbControlsNotify:
|
|
to.c32 = &masks->ctrlsNotifyMask;
|
|
legal = XkbAllControlEventsMask;
|
|
size = 4;
|
|
break;
|
|
case XkbIndicatorStateNotify:
|
|
to.c32 = &masks->iStateNotifyMask;
|
|
legal = XkbAllIndicatorEventsMask;
|
|
size = 4;
|
|
break;
|
|
case XkbIndicatorMapNotify:
|
|
to.c32 = &masks->iMapNotifyMask;
|
|
legal = XkbAllIndicatorEventsMask;
|
|
size = 4;
|
|
break;
|
|
case XkbNamesNotify:
|
|
to.c16 = &masks->namesNotifyMask;
|
|
legal = XkbAllNameEventsMask;
|
|
size = 2;
|
|
break;
|
|
case XkbCompatMapNotify:
|
|
to.c8 = &masks->compatNotifyMask;
|
|
legal = XkbAllCompatMapEventsMask;
|
|
size = 1;
|
|
break;
|
|
case XkbBellNotify:
|
|
to.c8 = &masks->bellNotifyMask;
|
|
legal = XkbAllBellEventsMask;
|
|
size = 1;
|
|
break;
|
|
case XkbActionMessage:
|
|
to.c8 = &masks->actionMessageMask;
|
|
legal = XkbAllActionMessagesMask;
|
|
size = 1;
|
|
break;
|
|
case XkbAccessXNotify:
|
|
to.c16 = &masks->accessXNotifyMask;
|
|
legal = XkbAllAccessXEventsMask;
|
|
size = 2;
|
|
break;
|
|
case XkbExtensionDeviceNotify:
|
|
to.c16 = &masks->extDevNotifyMask;
|
|
legal = XkbAllExtensionDeviceEventsMask;
|
|
size = 2;
|
|
break;
|
|
default:
|
|
client->errorValue = _XkbErrCode2(33, bit);
|
|
return BadValue;
|
|
}
|
|
|
|
if (stuff->clear & bit) {
|
|
if (size == 2)
|
|
to.c16[0] = 0;
|
|
else if (size == 4)
|
|
to.c32[0] = 0;
|
|
else
|
|
to.c8[0] = 0;
|
|
}
|
|
else if (stuff->selectAll & bit) {
|
|
if (size == 2)
|
|
to.c16[0] = ~0;
|
|
else if (size == 4)
|
|
to.c32[0] = ~0;
|
|
else
|
|
to.c8[0] = ~0;
|
|
}
|
|
else {
|
|
if (dataLeft < (size * 2))
|
|
return BadLength;
|
|
if (size == 2) {
|
|
CHK_MASK_MATCH(ndx, from.c16[0], from.c16[1]);
|
|
CHK_MASK_LEGAL(ndx, from.c16[0], legal);
|
|
to.c16[0] &= ~from.c16[0];
|
|
to.c16[0] |= (from.c16[0] & from.c16[1]);
|
|
}
|
|
else if (size == 4) {
|
|
CHK_MASK_MATCH(ndx, from.c32[0], from.c32[1]);
|
|
CHK_MASK_LEGAL(ndx, from.c32[0], legal);
|
|
to.c32[0] &= ~from.c32[0];
|
|
to.c32[0] |= (from.c32[0] & from.c32[1]);
|
|
}
|
|
else {
|
|
CHK_MASK_MATCH(ndx, from.c8[0], from.c8[1]);
|
|
CHK_MASK_LEGAL(ndx, from.c8[0], legal);
|
|
to.c8[0] &= ~from.c8[0];
|
|
to.c8[0] |= (from.c8[0] & from.c8[1]);
|
|
size = 2;
|
|
}
|
|
from.c8 += (size * 2);
|
|
dataLeft -= (size * 2);
|
|
}
|
|
}
|
|
if (dataLeft > 2) {
|
|
ErrorF("[xkb] Extra data (%d bytes) after SelectEvents\n",
|
|
dataLeft);
|
|
return BadLength;
|
|
}
|
|
return Success;
|
|
}
|
|
return BadAlloc;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
/**
|
|
* Ring a bell on the given device for the given client.
|
|
*/
|
|
static int
|
|
_XkbBell(ClientPtr client, DeviceIntPtr dev, WindowPtr pWin,
|
|
int bellClass, int bellID, int pitch, int duration,
|
|
int percent, int forceSound, int eventOnly, Atom name)
|
|
{
|
|
int base;
|
|
void *ctrl;
|
|
int oldPitch, oldDuration;
|
|
int newPercent;
|
|
|
|
if (bellClass == KbdFeedbackClass) {
|
|
KbdFeedbackPtr k;
|
|
|
|
if (bellID == XkbDfltXIId)
|
|
k = dev->kbdfeed;
|
|
else {
|
|
for (k = dev->kbdfeed; k; k = k->next) {
|
|
if (k->ctrl.id == bellID)
|
|
break;
|
|
}
|
|
}
|
|
if (!k) {
|
|
client->errorValue = _XkbErrCode2(0x5, bellID);
|
|
return BadValue;
|
|
}
|
|
base = k->ctrl.bell;
|
|
ctrl = (void *) &(k->ctrl);
|
|
oldPitch = k->ctrl.bell_pitch;
|
|
oldDuration = k->ctrl.bell_duration;
|
|
if (pitch != 0) {
|
|
if (pitch == -1)
|
|
k->ctrl.bell_pitch = defaultKeyboardControl.bell_pitch;
|
|
else
|
|
k->ctrl.bell_pitch = pitch;
|
|
}
|
|
if (duration != 0) {
|
|
if (duration == -1)
|
|
k->ctrl.bell_duration = defaultKeyboardControl.bell_duration;
|
|
else
|
|
k->ctrl.bell_duration = duration;
|
|
}
|
|
}
|
|
else if (bellClass == BellFeedbackClass) {
|
|
BellFeedbackPtr b;
|
|
|
|
if (bellID == XkbDfltXIId)
|
|
b = dev->bell;
|
|
else {
|
|
for (b = dev->bell; b; b = b->next) {
|
|
if (b->ctrl.id == bellID)
|
|
break;
|
|
}
|
|
}
|
|
if (!b) {
|
|
client->errorValue = _XkbErrCode2(0x6, bellID);
|
|
return BadValue;
|
|
}
|
|
base = b->ctrl.percent;
|
|
ctrl = (void *) &(b->ctrl);
|
|
oldPitch = b->ctrl.pitch;
|
|
oldDuration = b->ctrl.duration;
|
|
if (pitch != 0) {
|
|
if (pitch == -1)
|
|
b->ctrl.pitch = defaultKeyboardControl.bell_pitch;
|
|
else
|
|
b->ctrl.pitch = pitch;
|
|
}
|
|
if (duration != 0) {
|
|
if (duration == -1)
|
|
b->ctrl.duration = defaultKeyboardControl.bell_duration;
|
|
else
|
|
b->ctrl.duration = duration;
|
|
}
|
|
}
|
|
else {
|
|
client->errorValue = _XkbErrCode2(0x7, bellClass);
|
|
return BadValue;
|
|
}
|
|
|
|
newPercent = (base * percent) / 100;
|
|
if (percent < 0)
|
|
newPercent = base + newPercent;
|
|
else
|
|
newPercent = base - newPercent + percent;
|
|
|
|
XkbHandleBell(forceSound, eventOnly,
|
|
dev, newPercent, ctrl, bellClass, name, pWin, client);
|
|
if ((pitch != 0) || (duration != 0)) {
|
|
if (bellClass == KbdFeedbackClass) {
|
|
KbdFeedbackPtr k;
|
|
|
|
k = (KbdFeedbackPtr) ctrl;
|
|
if (pitch != 0)
|
|
k->ctrl.bell_pitch = oldPitch;
|
|
if (duration != 0)
|
|
k->ctrl.bell_duration = oldDuration;
|
|
}
|
|
else {
|
|
BellFeedbackPtr b;
|
|
|
|
b = (BellFeedbackPtr) ctrl;
|
|
if (pitch != 0)
|
|
b->ctrl.pitch = oldPitch;
|
|
if (duration != 0)
|
|
b->ctrl.duration = oldDuration;
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbBell(ClientPtr client)
|
|
{
|
|
REQUEST(xkbBellReq);
|
|
DeviceIntPtr dev;
|
|
WindowPtr pWin;
|
|
int rc;
|
|
|
|
REQUEST_SIZE_MATCH(xkbBellReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_BELL_DEVICE(dev, stuff->deviceSpec, client, DixBellAccess);
|
|
CHK_ATOM_OR_NONE(stuff->name);
|
|
|
|
/* device-independent checks request for sane values */
|
|
if ((stuff->forceSound) && (stuff->eventOnly)) {
|
|
client->errorValue =
|
|
_XkbErrCode3(0x1, stuff->forceSound, stuff->eventOnly);
|
|
return BadMatch;
|
|
}
|
|
if (stuff->percent < -100 || stuff->percent > 100) {
|
|
client->errorValue = _XkbErrCode2(0x2, stuff->percent);
|
|
return BadValue;
|
|
}
|
|
if (stuff->duration < -1) {
|
|
client->errorValue = _XkbErrCode2(0x3, stuff->duration);
|
|
return BadValue;
|
|
}
|
|
if (stuff->pitch < -1) {
|
|
client->errorValue = _XkbErrCode2(0x4, stuff->pitch);
|
|
return BadValue;
|
|
}
|
|
|
|
if (stuff->bellClass == XkbDfltXIClass) {
|
|
if (dev->kbdfeed != NULL)
|
|
stuff->bellClass = KbdFeedbackClass;
|
|
else
|
|
stuff->bellClass = BellFeedbackClass;
|
|
}
|
|
|
|
if (stuff->window != None) {
|
|
rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess);
|
|
if (rc != Success) {
|
|
client->errorValue = stuff->window;
|
|
return rc;
|
|
}
|
|
}
|
|
else
|
|
pWin = NULL;
|
|
|
|
/* Client wants to ring a bell on the core keyboard?
|
|
Ring the bell on the core keyboard (which does nothing, but if that
|
|
fails the client is screwed anyway), and then on all extension devices.
|
|
Fail if the core keyboard fails but not the extension devices. this
|
|
may cause some keyboards to ding and others to stay silent. Fix
|
|
your client to use explicit keyboards to avoid this.
|
|
|
|
dev is the device the client requested.
|
|
*/
|
|
rc = _XkbBell(client, dev, pWin, stuff->bellClass, stuff->bellID,
|
|
stuff->pitch, stuff->duration, stuff->percent,
|
|
stuff->forceSound, stuff->eventOnly, stuff->name);
|
|
|
|
if ((rc == Success) && ((stuff->deviceSpec == XkbUseCoreKbd) ||
|
|
(stuff->deviceSpec == XkbUseCorePtr))) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixBellAccess);
|
|
if (rc == Success)
|
|
_XkbBell(client, other, pWin, stuff->bellClass,
|
|
stuff->bellID, stuff->pitch, stuff->duration,
|
|
stuff->percent, stuff->forceSound,
|
|
stuff->eventOnly, stuff->name);
|
|
}
|
|
}
|
|
rc = Success; /* reset to success, that's what we got for the VCK */
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbGetState(ClientPtr client)
|
|
{
|
|
REQUEST(xkbGetStateReq);
|
|
DeviceIntPtr dev;
|
|
xkbGetStateReply rep;
|
|
XkbStateRec *xkb;
|
|
|
|
REQUEST_SIZE_MATCH(xkbGetStateReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
|
|
xkb = &dev->key->xkbInfo->state;
|
|
rep = (xkbGetStateReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.mods = XkbStateFieldFromRec(xkb) & 0xff,
|
|
.baseMods = xkb->base_mods,
|
|
.latchedMods = xkb->latched_mods,
|
|
.lockedMods = xkb->locked_mods,
|
|
.group = xkb->group,
|
|
.lockedGroup = xkb->locked_group,
|
|
.baseGroup = xkb->base_group,
|
|
.latchedGroup = xkb->latched_group,
|
|
.compatState = xkb->compat_state,
|
|
.ptrBtnState = xkb->ptr_buttons
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swaps(&rep.ptrBtnState);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetStateReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbLatchLockState(ClientPtr client)
|
|
{
|
|
int status;
|
|
DeviceIntPtr dev, tmpd;
|
|
XkbStateRec oldState, *newState;
|
|
CARD16 changed;
|
|
xkbStateNotify sn;
|
|
XkbEventCauseRec cause;
|
|
|
|
REQUEST(xkbLatchLockStateReq);
|
|
REQUEST_SIZE_MATCH(xkbLatchLockStateReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
|
|
CHK_MASK_MATCH(0x01, stuff->affectModLocks, stuff->modLocks);
|
|
CHK_MASK_MATCH(0x01, stuff->affectModLatches, stuff->modLatches);
|
|
|
|
status = Success;
|
|
|
|
for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
|
|
if ((tmpd == dev) ||
|
|
(!IsMaster(tmpd) && GetMaster(tmpd, MASTER_KEYBOARD) == dev)) {
|
|
if (!tmpd->key || !tmpd->key->xkbInfo)
|
|
continue;
|
|
|
|
oldState = tmpd->key->xkbInfo->state;
|
|
newState = &tmpd->key->xkbInfo->state;
|
|
if (stuff->affectModLocks) {
|
|
newState->locked_mods &= ~stuff->affectModLocks;
|
|
newState->locked_mods |=
|
|
(stuff->affectModLocks & stuff->modLocks);
|
|
}
|
|
if (status == Success && stuff->lockGroup)
|
|
newState->locked_group = stuff->groupLock;
|
|
if (status == Success && stuff->affectModLatches)
|
|
status = XkbLatchModifiers(tmpd, stuff->affectModLatches,
|
|
stuff->modLatches);
|
|
if (status == Success && stuff->latchGroup)
|
|
status = XkbLatchGroup(tmpd, stuff->groupLatch);
|
|
|
|
if (status != Success)
|
|
return status;
|
|
|
|
XkbComputeDerivedState(tmpd->key->xkbInfo);
|
|
|
|
changed = XkbStateChangedFlags(&oldState, newState);
|
|
if (changed) {
|
|
sn.keycode = 0;
|
|
sn.eventType = 0;
|
|
sn.requestMajor = XkbReqCode;
|
|
sn.requestMinor = X_kbLatchLockState;
|
|
sn.changed = changed;
|
|
XkbSendStateNotify(tmpd, &sn);
|
|
changed = XkbIndicatorsToUpdate(tmpd, changed, FALSE);
|
|
if (changed) {
|
|
XkbSetCauseXkbReq(&cause, X_kbLatchLockState, client);
|
|
XkbUpdateIndicators(tmpd, changed, TRUE, NULL, &cause);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbGetControls(ClientPtr client)
|
|
{
|
|
xkbGetControlsReply rep;
|
|
XkbControlsPtr xkb;
|
|
DeviceIntPtr dev;
|
|
|
|
REQUEST(xkbGetControlsReq);
|
|
REQUEST_SIZE_MATCH(xkbGetControlsReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
|
|
xkb = dev->key->xkbInfo->desc->ctrls;
|
|
rep = (xkbGetControlsReply) {
|
|
.type = X_Reply,
|
|
.deviceID = ((DeviceIntPtr) dev)->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = bytes_to_int32(SIZEOF(xkbGetControlsReply) -
|
|
SIZEOF(xGenericReply)),
|
|
.mkDfltBtn = xkb->mk_dflt_btn,
|
|
.numGroups = xkb->num_groups,
|
|
.groupsWrap = xkb->groups_wrap,
|
|
.internalMods = xkb->internal.mask,
|
|
.ignoreLockMods = xkb->ignore_lock.mask,
|
|
.internalRealMods = xkb->internal.real_mods,
|
|
.ignoreLockRealMods = xkb->ignore_lock.real_mods,
|
|
.internalVMods = xkb->internal.vmods,
|
|
.ignoreLockVMods = xkb->ignore_lock.vmods,
|
|
.repeatDelay = xkb->repeat_delay,
|
|
.repeatInterval = xkb->repeat_interval,
|
|
.slowKeysDelay = xkb->slow_keys_delay,
|
|
.debounceDelay = xkb->debounce_delay,
|
|
.mkDelay = xkb->mk_delay,
|
|
.mkInterval = xkb->mk_interval,
|
|
.mkTimeToMax = xkb->mk_time_to_max,
|
|
.mkMaxSpeed = xkb->mk_max_speed,
|
|
.mkCurve = xkb->mk_curve,
|
|
.axOptions = xkb->ax_options,
|
|
.axTimeout = xkb->ax_timeout,
|
|
.axtOptsMask = xkb->axt_opts_mask,
|
|
.axtOptsValues = xkb->axt_opts_values,
|
|
.axtCtrlsMask = xkb->axt_ctrls_mask,
|
|
.axtCtrlsValues = xkb->axt_ctrls_values,
|
|
.enabledCtrls = xkb->enabled_ctrls,
|
|
};
|
|
memcpy(rep.perKeyRepeat, xkb->per_key_repeat, XkbPerKeyBitArraySize);
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swaps(&rep.internalVMods);
|
|
swaps(&rep.ignoreLockVMods);
|
|
swapl(&rep.enabledCtrls);
|
|
swaps(&rep.repeatDelay);
|
|
swaps(&rep.repeatInterval);
|
|
swaps(&rep.slowKeysDelay);
|
|
swaps(&rep.debounceDelay);
|
|
swaps(&rep.mkDelay);
|
|
swaps(&rep.mkInterval);
|
|
swaps(&rep.mkTimeToMax);
|
|
swaps(&rep.mkMaxSpeed);
|
|
swaps(&rep.mkCurve);
|
|
swaps(&rep.axTimeout);
|
|
swapl(&rep.axtCtrlsMask);
|
|
swapl(&rep.axtCtrlsValues);
|
|
swaps(&rep.axtOptsMask);
|
|
swaps(&rep.axtOptsValues);
|
|
swaps(&rep.axOptions);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetControlsReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetControls(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev, tmpd;
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbControlsPtr ctrl;
|
|
XkbControlsRec new, old;
|
|
xkbControlsNotify cn;
|
|
XkbEventCauseRec cause;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
REQUEST(xkbSetControlsReq);
|
|
REQUEST_SIZE_MATCH(xkbSetControlsReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
CHK_MASK_LEGAL(0x01, stuff->changeCtrls, XkbAllControlsMask);
|
|
|
|
for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
|
|
if (!tmpd->key || !tmpd->key->xkbInfo)
|
|
continue;
|
|
if ((tmpd == dev) ||
|
|
(!IsMaster(tmpd) && GetMaster(tmpd, MASTER_KEYBOARD) == dev)) {
|
|
xkbi = tmpd->key->xkbInfo;
|
|
ctrl = xkbi->desc->ctrls;
|
|
new = *ctrl;
|
|
XkbSetCauseXkbReq(&cause, X_kbSetControls, client);
|
|
|
|
if (stuff->changeCtrls & XkbInternalModsMask) {
|
|
CHK_MASK_MATCH(0x02, stuff->affectInternalMods,
|
|
stuff->internalMods);
|
|
CHK_MASK_MATCH(0x03, stuff->affectInternalVMods,
|
|
stuff->internalVMods);
|
|
|
|
new.internal.real_mods &= ~(stuff->affectInternalMods);
|
|
new.internal.real_mods |= (stuff->affectInternalMods &
|
|
stuff->internalMods);
|
|
new.internal.vmods &= ~(stuff->affectInternalVMods);
|
|
new.internal.vmods |= (stuff->affectInternalVMods &
|
|
stuff->internalVMods);
|
|
new.internal.mask = new.internal.real_mods |
|
|
XkbMaskForVMask(xkbi->desc, new.internal.vmods);
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbIgnoreLockModsMask) {
|
|
CHK_MASK_MATCH(0x4, stuff->affectIgnoreLockMods,
|
|
stuff->ignoreLockMods);
|
|
CHK_MASK_MATCH(0x5, stuff->affectIgnoreLockVMods,
|
|
stuff->ignoreLockVMods);
|
|
|
|
new.ignore_lock.real_mods &= ~(stuff->affectIgnoreLockMods);
|
|
new.ignore_lock.real_mods |= (stuff->affectIgnoreLockMods &
|
|
stuff->ignoreLockMods);
|
|
new.ignore_lock.vmods &= ~(stuff->affectIgnoreLockVMods);
|
|
new.ignore_lock.vmods |= (stuff->affectIgnoreLockVMods &
|
|
stuff->ignoreLockVMods);
|
|
new.ignore_lock.mask = new.ignore_lock.real_mods |
|
|
XkbMaskForVMask(xkbi->desc, new.ignore_lock.vmods);
|
|
}
|
|
|
|
CHK_MASK_MATCH(0x06, stuff->affectEnabledCtrls,
|
|
stuff->enabledCtrls);
|
|
if (stuff->affectEnabledCtrls) {
|
|
CHK_MASK_LEGAL(0x07, stuff->affectEnabledCtrls,
|
|
XkbAllBooleanCtrlsMask);
|
|
|
|
new.enabled_ctrls &= ~(stuff->affectEnabledCtrls);
|
|
new.enabled_ctrls |= (stuff->affectEnabledCtrls &
|
|
stuff->enabledCtrls);
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbRepeatKeysMask) {
|
|
if (stuff->repeatDelay < 1 || stuff->repeatInterval < 1) {
|
|
client->errorValue = _XkbErrCode3(0x08, stuff->repeatDelay,
|
|
stuff->repeatInterval);
|
|
return BadValue;
|
|
}
|
|
|
|
new.repeat_delay = stuff->repeatDelay;
|
|
new.repeat_interval = stuff->repeatInterval;
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbSlowKeysMask) {
|
|
if (stuff->slowKeysDelay < 1) {
|
|
client->errorValue = _XkbErrCode2(0x09,
|
|
stuff->slowKeysDelay);
|
|
return BadValue;
|
|
}
|
|
|
|
new.slow_keys_delay = stuff->slowKeysDelay;
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbBounceKeysMask) {
|
|
if (stuff->debounceDelay < 1) {
|
|
client->errorValue = _XkbErrCode2(0x0A,
|
|
stuff->debounceDelay);
|
|
return BadValue;
|
|
}
|
|
|
|
new.debounce_delay = stuff->debounceDelay;
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbMouseKeysMask) {
|
|
if (stuff->mkDfltBtn > XkbMaxMouseKeysBtn) {
|
|
client->errorValue = _XkbErrCode2(0x0B, stuff->mkDfltBtn);
|
|
return BadValue;
|
|
}
|
|
|
|
new.mk_dflt_btn = stuff->mkDfltBtn;
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbMouseKeysAccelMask) {
|
|
if (stuff->mkDelay < 1 || stuff->mkInterval < 1 ||
|
|
stuff->mkTimeToMax < 1 || stuff->mkMaxSpeed < 1 ||
|
|
stuff->mkCurve < -1000) {
|
|
client->errorValue = _XkbErrCode2(0x0C, 0);
|
|
return BadValue;
|
|
}
|
|
|
|
new.mk_delay = stuff->mkDelay;
|
|
new.mk_interval = stuff->mkInterval;
|
|
new.mk_time_to_max = stuff->mkTimeToMax;
|
|
new.mk_max_speed = stuff->mkMaxSpeed;
|
|
new.mk_curve = stuff->mkCurve;
|
|
AccessXComputeCurveFactor(xkbi, &new);
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbGroupsWrapMask) {
|
|
unsigned act, num;
|
|
|
|
act = XkbOutOfRangeGroupAction(stuff->groupsWrap);
|
|
switch (act) {
|
|
case XkbRedirectIntoRange:
|
|
num = XkbOutOfRangeGroupNumber(stuff->groupsWrap);
|
|
if (num >= new.num_groups) {
|
|
client->errorValue = _XkbErrCode3(0x0D, new.num_groups,
|
|
num);
|
|
return BadValue;
|
|
}
|
|
case XkbWrapIntoRange:
|
|
case XkbClampIntoRange:
|
|
break;
|
|
default:
|
|
client->errorValue = _XkbErrCode2(0x0E, act);
|
|
return BadValue;
|
|
}
|
|
|
|
new.groups_wrap = stuff->groupsWrap;
|
|
}
|
|
|
|
CHK_MASK_LEGAL(0x0F, stuff->axOptions, XkbAX_AllOptionsMask);
|
|
if (stuff->changeCtrls & XkbAccessXKeysMask) {
|
|
new.ax_options = stuff->axOptions & XkbAX_AllOptionsMask;
|
|
}
|
|
else {
|
|
if (stuff->changeCtrls & XkbStickyKeysMask) {
|
|
new.ax_options &= ~(XkbAX_SKOptionsMask);
|
|
new.ax_options |= (stuff->axOptions & XkbAX_SKOptionsMask);
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbAccessXFeedbackMask) {
|
|
new.ax_options &= ~(XkbAX_FBOptionsMask);
|
|
new.ax_options |= (stuff->axOptions & XkbAX_FBOptionsMask);
|
|
}
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbAccessXTimeoutMask) {
|
|
if (stuff->axTimeout < 1) {
|
|
client->errorValue = _XkbErrCode2(0x10, stuff->axTimeout);
|
|
return BadValue;
|
|
}
|
|
CHK_MASK_MATCH(0x11, stuff->axtCtrlsMask,
|
|
stuff->axtCtrlsValues);
|
|
CHK_MASK_LEGAL(0x12, stuff->axtCtrlsMask,
|
|
XkbAllBooleanCtrlsMask);
|
|
CHK_MASK_MATCH(0x13, stuff->axtOptsMask, stuff->axtOptsValues);
|
|
CHK_MASK_LEGAL(0x14, stuff->axtOptsMask, XkbAX_AllOptionsMask);
|
|
new.ax_timeout = stuff->axTimeout;
|
|
new.axt_ctrls_mask = stuff->axtCtrlsMask;
|
|
new.axt_ctrls_values = (stuff->axtCtrlsValues &
|
|
stuff->axtCtrlsMask);
|
|
new.axt_opts_mask = stuff->axtOptsMask;
|
|
new.axt_opts_values = (stuff->axtOptsValues &
|
|
stuff->axtOptsMask);
|
|
}
|
|
|
|
if (stuff->changeCtrls & XkbPerKeyRepeatMask) {
|
|
memcpy(new.per_key_repeat, stuff->perKeyRepeat,
|
|
XkbPerKeyBitArraySize);
|
|
if (xkbi->repeatKey &&
|
|
!BitIsOn(new.per_key_repeat, xkbi->repeatKey)) {
|
|
AccessXCancelRepeatKey(xkbi, xkbi->repeatKey);
|
|
}
|
|
}
|
|
|
|
old = *ctrl;
|
|
*ctrl = new;
|
|
XkbDDXChangeControls(tmpd, &old, ctrl);
|
|
|
|
if (XkbComputeControlsNotify(tmpd, &old, ctrl, &cn, FALSE)) {
|
|
cn.keycode = 0;
|
|
cn.eventType = 0;
|
|
cn.requestMajor = XkbReqCode;
|
|
cn.requestMinor = X_kbSetControls;
|
|
XkbSendControlsNotify(tmpd, &cn);
|
|
}
|
|
|
|
sli = XkbFindSrvLedInfo(tmpd, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
if (sli)
|
|
XkbUpdateIndicators(tmpd, sli->usesControls, TRUE, NULL,
|
|
&cause);
|
|
|
|
/* If sticky keys were disabled, clear all locks and latches */
|
|
if ((old.enabled_ctrls & XkbStickyKeysMask) &&
|
|
!(ctrl->enabled_ctrls & XkbStickyKeysMask))
|
|
XkbClearAllLatchesAndLocks(tmpd, xkbi, TRUE, &cause);
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static int
|
|
XkbSizeKeyTypes(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
XkbKeyTypeRec *type;
|
|
unsigned i, len;
|
|
|
|
len = 0;
|
|
if (((rep->present & XkbKeyTypesMask) == 0) || (rep->nTypes < 1) ||
|
|
(!xkb) || (!xkb->map) || (!xkb->map->types)) {
|
|
rep->present &= ~XkbKeyTypesMask;
|
|
rep->firstType = rep->nTypes = 0;
|
|
return 0;
|
|
}
|
|
type = &xkb->map->types[rep->firstType];
|
|
for (i = 0; i < rep->nTypes; i++, type++) {
|
|
len += SIZEOF(xkbKeyTypeWireDesc);
|
|
if (type->map_count > 0) {
|
|
len += (type->map_count * SIZEOF(xkbKTMapEntryWireDesc));
|
|
if (type->preserve)
|
|
len += (type->map_count * SIZEOF(xkbModsWireDesc));
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteKeyTypes(XkbDescPtr xkb,
|
|
xkbGetMapReply * rep, char *buf, ClientPtr client)
|
|
{
|
|
XkbKeyTypePtr type;
|
|
unsigned i;
|
|
xkbKeyTypeWireDesc *wire;
|
|
|
|
type = &xkb->map->types[rep->firstType];
|
|
for (i = 0; i < rep->nTypes; i++, type++) {
|
|
register unsigned n;
|
|
|
|
wire = (xkbKeyTypeWireDesc *) buf;
|
|
wire->mask = type->mods.mask;
|
|
wire->realMods = type->mods.real_mods;
|
|
wire->virtualMods = type->mods.vmods;
|
|
wire->numLevels = type->num_levels;
|
|
wire->nMapEntries = type->map_count;
|
|
wire->preserve = (type->preserve != NULL);
|
|
if (client->swapped) {
|
|
swaps(&wire->virtualMods);
|
|
}
|
|
|
|
buf = (char *) &wire[1];
|
|
if (wire->nMapEntries > 0) {
|
|
xkbKTMapEntryWireDesc *ewire;
|
|
XkbKTMapEntryPtr entry;
|
|
|
|
ewire = (xkbKTMapEntryWireDesc *) buf;
|
|
entry = type->map;
|
|
for (n = 0; n < type->map_count; n++, ewire++, entry++) {
|
|
ewire->active = entry->active;
|
|
ewire->mask = entry->mods.mask;
|
|
ewire->level = entry->level;
|
|
ewire->realMods = entry->mods.real_mods;
|
|
ewire->virtualMods = entry->mods.vmods;
|
|
if (client->swapped) {
|
|
swaps(&ewire->virtualMods);
|
|
}
|
|
}
|
|
buf = (char *) ewire;
|
|
if (type->preserve != NULL) {
|
|
xkbModsWireDesc *pwire;
|
|
XkbModsPtr preserve;
|
|
|
|
pwire = (xkbModsWireDesc *) buf;
|
|
preserve = type->preserve;
|
|
for (n = 0; n < type->map_count; n++, pwire++, preserve++) {
|
|
pwire->mask = preserve->mask;
|
|
pwire->realMods = preserve->real_mods;
|
|
pwire->virtualMods = preserve->vmods;
|
|
if (client->swapped) {
|
|
swaps(&pwire->virtualMods);
|
|
}
|
|
}
|
|
buf = (char *) pwire;
|
|
}
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static int
|
|
XkbSizeKeySyms(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
XkbSymMapPtr symMap;
|
|
unsigned i, len;
|
|
unsigned nSyms, nSymsThisKey;
|
|
|
|
if (((rep->present & XkbKeySymsMask) == 0) || (rep->nKeySyms < 1) ||
|
|
(!xkb) || (!xkb->map) || (!xkb->map->key_sym_map)) {
|
|
rep->present &= ~XkbKeySymsMask;
|
|
rep->firstKeySym = rep->nKeySyms = 0;
|
|
rep->totalSyms = 0;
|
|
return 0;
|
|
}
|
|
len = rep->nKeySyms * SIZEOF(xkbSymMapWireDesc);
|
|
symMap = &xkb->map->key_sym_map[rep->firstKeySym];
|
|
for (i = nSyms = 0; i < rep->nKeySyms; i++, symMap++) {
|
|
if (symMap->offset != 0) {
|
|
nSymsThisKey = XkbNumGroups(symMap->group_info) * symMap->width;
|
|
nSyms += nSymsThisKey;
|
|
}
|
|
}
|
|
len += nSyms * 4;
|
|
rep->totalSyms = nSyms;
|
|
return len;
|
|
}
|
|
|
|
static int
|
|
XkbSizeVirtualMods(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
register unsigned i, nMods, bit;
|
|
|
|
if (((rep->present & XkbVirtualModsMask) == 0) || (rep->virtualMods == 0) ||
|
|
(!xkb) || (!xkb->server)) {
|
|
rep->present &= ~XkbVirtualModsMask;
|
|
rep->virtualMods = 0;
|
|
return 0;
|
|
}
|
|
for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
|
|
if (rep->virtualMods & bit)
|
|
nMods++;
|
|
}
|
|
return XkbPaddedSize(nMods);
|
|
}
|
|
|
|
static char *
|
|
XkbWriteKeySyms(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
|
|
ClientPtr client)
|
|
{
|
|
register KeySym *pSym;
|
|
XkbSymMapPtr symMap;
|
|
xkbSymMapWireDesc *outMap;
|
|
register unsigned i;
|
|
|
|
symMap = &xkb->map->key_sym_map[rep->firstKeySym];
|
|
for (i = 0; i < rep->nKeySyms; i++, symMap++) {
|
|
outMap = (xkbSymMapWireDesc *) buf;
|
|
outMap->ktIndex[0] = symMap->kt_index[0];
|
|
outMap->ktIndex[1] = symMap->kt_index[1];
|
|
outMap->ktIndex[2] = symMap->kt_index[2];
|
|
outMap->ktIndex[3] = symMap->kt_index[3];
|
|
outMap->groupInfo = symMap->group_info;
|
|
outMap->width = symMap->width;
|
|
outMap->nSyms = symMap->width * XkbNumGroups(symMap->group_info);
|
|
buf = (char *) &outMap[1];
|
|
if (outMap->nSyms == 0)
|
|
continue;
|
|
|
|
pSym = &xkb->map->syms[symMap->offset];
|
|
memcpy((char *) buf, (char *) pSym, outMap->nSyms * 4);
|
|
if (client->swapped) {
|
|
register int nSyms = outMap->nSyms;
|
|
|
|
swaps(&outMap->nSyms);
|
|
while (nSyms-- > 0) {
|
|
swapl((int *) buf);
|
|
buf += 4;
|
|
}
|
|
}
|
|
else
|
|
buf += outMap->nSyms * 4;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static int
|
|
XkbSizeKeyActions(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
unsigned i, len, nActs;
|
|
register KeyCode firstKey;
|
|
|
|
if (((rep->present & XkbKeyActionsMask) == 0) || (rep->nKeyActs < 1) ||
|
|
(!xkb) || (!xkb->server) || (!xkb->server->key_acts)) {
|
|
rep->present &= ~XkbKeyActionsMask;
|
|
rep->firstKeyAct = rep->nKeyActs = 0;
|
|
rep->totalActs = 0;
|
|
return 0;
|
|
}
|
|
firstKey = rep->firstKeyAct;
|
|
for (nActs = i = 0; i < rep->nKeyActs; i++) {
|
|
if (xkb->server->key_acts[i + firstKey] != 0)
|
|
nActs += XkbKeyNumActions(xkb, i + firstKey);
|
|
}
|
|
len = XkbPaddedSize(rep->nKeyActs) + (nActs * SIZEOF(xkbActionWireDesc));
|
|
rep->totalActs = nActs;
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteKeyActions(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
|
|
ClientPtr client)
|
|
{
|
|
unsigned i;
|
|
CARD8 *numDesc;
|
|
XkbAnyAction *actDesc;
|
|
|
|
numDesc = (CARD8 *) buf;
|
|
for (i = 0; i < rep->nKeyActs; i++) {
|
|
if (xkb->server->key_acts[i + rep->firstKeyAct] == 0)
|
|
numDesc[i] = 0;
|
|
else
|
|
numDesc[i] = XkbKeyNumActions(xkb, (i + rep->firstKeyAct));
|
|
}
|
|
buf += XkbPaddedSize(rep->nKeyActs);
|
|
|
|
actDesc = (XkbAnyAction *) buf;
|
|
for (i = 0; i < rep->nKeyActs; i++) {
|
|
if (xkb->server->key_acts[i + rep->firstKeyAct] != 0) {
|
|
unsigned int num;
|
|
|
|
num = XkbKeyNumActions(xkb, (i + rep->firstKeyAct));
|
|
memcpy((char *) actDesc,
|
|
(char *) XkbKeyActionsPtr(xkb, (i + rep->firstKeyAct)),
|
|
num * SIZEOF(xkbActionWireDesc));
|
|
actDesc += num;
|
|
}
|
|
}
|
|
buf = (char *) actDesc;
|
|
return buf;
|
|
}
|
|
|
|
static int
|
|
XkbSizeKeyBehaviors(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
unsigned i, len, nBhvr;
|
|
XkbBehavior *bhv;
|
|
|
|
if (((rep->present & XkbKeyBehaviorsMask) == 0) || (rep->nKeyBehaviors < 1)
|
|
|| (!xkb) || (!xkb->server) || (!xkb->server->behaviors)) {
|
|
rep->present &= ~XkbKeyBehaviorsMask;
|
|
rep->firstKeyBehavior = rep->nKeyBehaviors = 0;
|
|
rep->totalKeyBehaviors = 0;
|
|
return 0;
|
|
}
|
|
bhv = &xkb->server->behaviors[rep->firstKeyBehavior];
|
|
for (nBhvr = i = 0; i < rep->nKeyBehaviors; i++, bhv++) {
|
|
if (bhv->type != XkbKB_Default)
|
|
nBhvr++;
|
|
}
|
|
len = nBhvr * SIZEOF(xkbBehaviorWireDesc);
|
|
rep->totalKeyBehaviors = nBhvr;
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteKeyBehaviors(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
|
|
ClientPtr client)
|
|
{
|
|
unsigned i;
|
|
xkbBehaviorWireDesc *wire;
|
|
XkbBehavior *pBhvr;
|
|
|
|
wire = (xkbBehaviorWireDesc *) buf;
|
|
pBhvr = &xkb->server->behaviors[rep->firstKeyBehavior];
|
|
for (i = 0; i < rep->nKeyBehaviors; i++, pBhvr++) {
|
|
if (pBhvr->type != XkbKB_Default) {
|
|
wire->key = i + rep->firstKeyBehavior;
|
|
wire->type = pBhvr->type;
|
|
wire->data = pBhvr->data;
|
|
wire++;
|
|
}
|
|
}
|
|
buf = (char *) wire;
|
|
return buf;
|
|
}
|
|
|
|
static int
|
|
XkbSizeExplicit(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
unsigned i, len, nRtrn;
|
|
|
|
if (((rep->present & XkbExplicitComponentsMask) == 0) ||
|
|
(rep->nKeyExplicit < 1) || (!xkb) || (!xkb->server) ||
|
|
(!xkb->server->explicit)) {
|
|
rep->present &= ~XkbExplicitComponentsMask;
|
|
rep->firstKeyExplicit = rep->nKeyExplicit = 0;
|
|
rep->totalKeyExplicit = 0;
|
|
return 0;
|
|
}
|
|
for (nRtrn = i = 0; i < rep->nKeyExplicit; i++) {
|
|
if (xkb->server->explicit[i + rep->firstKeyExplicit] != 0)
|
|
nRtrn++;
|
|
}
|
|
rep->totalKeyExplicit = nRtrn;
|
|
len = XkbPaddedSize(nRtrn * 2); /* two bytes per non-zero explicit component */
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteExplicit(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
|
|
ClientPtr client)
|
|
{
|
|
unsigned i;
|
|
char *start;
|
|
unsigned char *pExp;
|
|
|
|
start = buf;
|
|
pExp = &xkb->server->explicit[rep->firstKeyExplicit];
|
|
for (i = 0; i < rep->nKeyExplicit; i++, pExp++) {
|
|
if (*pExp != 0) {
|
|
*buf++ = i + rep->firstKeyExplicit;
|
|
*buf++ = *pExp;
|
|
}
|
|
}
|
|
i = XkbPaddedSize(buf - start) - (buf - start); /* pad to word boundary */
|
|
return buf + i;
|
|
}
|
|
|
|
static int
|
|
XkbSizeModifierMap(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
unsigned i, len, nRtrn;
|
|
|
|
if (((rep->present & XkbModifierMapMask) == 0) || (rep->nModMapKeys < 1) ||
|
|
(!xkb) || (!xkb->map) || (!xkb->map->modmap)) {
|
|
rep->present &= ~XkbModifierMapMask;
|
|
rep->firstModMapKey = rep->nModMapKeys = 0;
|
|
rep->totalModMapKeys = 0;
|
|
return 0;
|
|
}
|
|
for (nRtrn = i = 0; i < rep->nModMapKeys; i++) {
|
|
if (xkb->map->modmap[i + rep->firstModMapKey] != 0)
|
|
nRtrn++;
|
|
}
|
|
rep->totalModMapKeys = nRtrn;
|
|
len = XkbPaddedSize(nRtrn * 2); /* two bytes per non-zero modmap component */
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteModifierMap(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
|
|
ClientPtr client)
|
|
{
|
|
unsigned i;
|
|
char *start;
|
|
unsigned char *pMap;
|
|
|
|
start = buf;
|
|
pMap = &xkb->map->modmap[rep->firstModMapKey];
|
|
for (i = 0; i < rep->nModMapKeys; i++, pMap++) {
|
|
if (*pMap != 0) {
|
|
*buf++ = i + rep->firstModMapKey;
|
|
*buf++ = *pMap;
|
|
}
|
|
}
|
|
i = XkbPaddedSize(buf - start) - (buf - start); /* pad to word boundary */
|
|
return buf + i;
|
|
}
|
|
|
|
static int
|
|
XkbSizeVirtualModMap(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
unsigned i, len, nRtrn;
|
|
|
|
if (((rep->present & XkbVirtualModMapMask) == 0) || (rep->nVModMapKeys < 1)
|
|
|| (!xkb) || (!xkb->server) || (!xkb->server->vmodmap)) {
|
|
rep->present &= ~XkbVirtualModMapMask;
|
|
rep->firstVModMapKey = rep->nVModMapKeys = 0;
|
|
rep->totalVModMapKeys = 0;
|
|
return 0;
|
|
}
|
|
for (nRtrn = i = 0; i < rep->nVModMapKeys; i++) {
|
|
if (xkb->server->vmodmap[i + rep->firstVModMapKey] != 0)
|
|
nRtrn++;
|
|
}
|
|
rep->totalVModMapKeys = nRtrn;
|
|
len = nRtrn * SIZEOF(xkbVModMapWireDesc);
|
|
return len;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteVirtualModMap(XkbDescPtr xkb, xkbGetMapReply * rep, char *buf,
|
|
ClientPtr client)
|
|
{
|
|
unsigned i;
|
|
xkbVModMapWireDesc *wire;
|
|
unsigned short *pMap;
|
|
|
|
wire = (xkbVModMapWireDesc *) buf;
|
|
pMap = &xkb->server->vmodmap[rep->firstVModMapKey];
|
|
for (i = 0; i < rep->nVModMapKeys; i++, pMap++) {
|
|
if (*pMap != 0) {
|
|
wire->key = i + rep->firstVModMapKey;
|
|
wire->vmods = *pMap;
|
|
wire++;
|
|
}
|
|
}
|
|
return (char *) wire;
|
|
}
|
|
|
|
static Status
|
|
XkbComputeGetMapReplySize(XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
int len;
|
|
|
|
rep->minKeyCode = xkb->min_key_code;
|
|
rep->maxKeyCode = xkb->max_key_code;
|
|
len = XkbSizeKeyTypes(xkb, rep);
|
|
len += XkbSizeKeySyms(xkb, rep);
|
|
len += XkbSizeKeyActions(xkb, rep);
|
|
len += XkbSizeKeyBehaviors(xkb, rep);
|
|
len += XkbSizeVirtualMods(xkb, rep);
|
|
len += XkbSizeExplicit(xkb, rep);
|
|
len += XkbSizeModifierMap(xkb, rep);
|
|
len += XkbSizeVirtualModMap(xkb, rep);
|
|
rep->length += (len / 4);
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
XkbSendMap(ClientPtr client, XkbDescPtr xkb, xkbGetMapReply * rep)
|
|
{
|
|
unsigned i, len;
|
|
char *desc, *start;
|
|
|
|
len = (rep->length * 4) - (SIZEOF(xkbGetMapReply) - SIZEOF(xGenericReply));
|
|
start = desc = calloc(1, len);
|
|
if (!start)
|
|
return BadAlloc;
|
|
if (rep->nTypes > 0)
|
|
desc = XkbWriteKeyTypes(xkb, rep, desc, client);
|
|
if (rep->nKeySyms > 0)
|
|
desc = XkbWriteKeySyms(xkb, rep, desc, client);
|
|
if (rep->nKeyActs > 0)
|
|
desc = XkbWriteKeyActions(xkb, rep, desc, client);
|
|
if (rep->totalKeyBehaviors > 0)
|
|
desc = XkbWriteKeyBehaviors(xkb, rep, desc, client);
|
|
if (rep->virtualMods) {
|
|
register int sz, bit;
|
|
|
|
for (i = sz = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
|
|
if (rep->virtualMods & bit) {
|
|
desc[sz++] = xkb->server->vmods[i];
|
|
}
|
|
}
|
|
desc += XkbPaddedSize(sz);
|
|
}
|
|
if (rep->totalKeyExplicit > 0)
|
|
desc = XkbWriteExplicit(xkb, rep, desc, client);
|
|
if (rep->totalModMapKeys > 0)
|
|
desc = XkbWriteModifierMap(xkb, rep, desc, client);
|
|
if (rep->totalVModMapKeys > 0)
|
|
desc = XkbWriteVirtualModMap(xkb, rep, desc, client);
|
|
if ((desc - start) != (len)) {
|
|
ErrorF
|
|
("[xkb] BOGUS LENGTH in write keyboard desc, expected %d, got %ld\n",
|
|
len, (unsigned long) (desc - start));
|
|
}
|
|
if (client->swapped) {
|
|
swaps(&rep->sequenceNumber);
|
|
swapl(&rep->length);
|
|
swaps(&rep->present);
|
|
swaps(&rep->totalSyms);
|
|
swaps(&rep->totalActs);
|
|
}
|
|
WriteToClient(client, (i = SIZEOF(xkbGetMapReply)), rep);
|
|
WriteToClient(client, len, start);
|
|
free((char *) start);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbGetMap(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
xkbGetMapReply rep;
|
|
XkbDescRec *xkb;
|
|
int n, status;
|
|
|
|
REQUEST(xkbGetMapReq);
|
|
REQUEST_SIZE_MATCH(xkbGetMapReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
CHK_MASK_OVERLAP(0x01, stuff->full, stuff->partial);
|
|
CHK_MASK_LEGAL(0x02, stuff->full, XkbAllMapComponentsMask);
|
|
CHK_MASK_LEGAL(0x03, stuff->partial, XkbAllMapComponentsMask);
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
rep = (xkbGetMapReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = (SIZEOF(xkbGetMapReply) - SIZEOF(xGenericReply)) >> 2,
|
|
.present = stuff->partial | stuff->full,
|
|
.minKeyCode = xkb->min_key_code,
|
|
.maxKeyCode = xkb->max_key_code
|
|
};
|
|
|
|
if (stuff->full & XkbKeyTypesMask) {
|
|
rep.firstType = 0;
|
|
rep.nTypes = xkb->map->num_types;
|
|
}
|
|
else if (stuff->partial & XkbKeyTypesMask) {
|
|
if (((unsigned) stuff->firstType + stuff->nTypes) > xkb->map->num_types) {
|
|
client->errorValue = _XkbErrCode4(0x04, xkb->map->num_types,
|
|
stuff->firstType, stuff->nTypes);
|
|
return BadValue;
|
|
}
|
|
rep.firstType = stuff->firstType;
|
|
rep.nTypes = stuff->nTypes;
|
|
}
|
|
else
|
|
rep.nTypes = 0;
|
|
rep.totalTypes = xkb->map->num_types;
|
|
|
|
n = XkbNumKeys(xkb);
|
|
if (stuff->full & XkbKeySymsMask) {
|
|
rep.firstKeySym = xkb->min_key_code;
|
|
rep.nKeySyms = n;
|
|
}
|
|
else if (stuff->partial & XkbKeySymsMask) {
|
|
CHK_KEY_RANGE(0x05, stuff->firstKeySym, stuff->nKeySyms, xkb);
|
|
rep.firstKeySym = stuff->firstKeySym;
|
|
rep.nKeySyms = stuff->nKeySyms;
|
|
}
|
|
else
|
|
rep.nKeySyms = 0;
|
|
rep.totalSyms = 0;
|
|
|
|
if (stuff->full & XkbKeyActionsMask) {
|
|
rep.firstKeyAct = xkb->min_key_code;
|
|
rep.nKeyActs = n;
|
|
}
|
|
else if (stuff->partial & XkbKeyActionsMask) {
|
|
CHK_KEY_RANGE(0x07, stuff->firstKeyAct, stuff->nKeyActs, xkb);
|
|
rep.firstKeyAct = stuff->firstKeyAct;
|
|
rep.nKeyActs = stuff->nKeyActs;
|
|
}
|
|
else
|
|
rep.nKeyActs = 0;
|
|
rep.totalActs = 0;
|
|
|
|
if (stuff->full & XkbKeyBehaviorsMask) {
|
|
rep.firstKeyBehavior = xkb->min_key_code;
|
|
rep.nKeyBehaviors = n;
|
|
}
|
|
else if (stuff->partial & XkbKeyBehaviorsMask) {
|
|
CHK_KEY_RANGE(0x09, stuff->firstKeyBehavior, stuff->nKeyBehaviors, xkb);
|
|
rep.firstKeyBehavior = stuff->firstKeyBehavior;
|
|
rep.nKeyBehaviors = stuff->nKeyBehaviors;
|
|
}
|
|
else
|
|
rep.nKeyBehaviors = 0;
|
|
rep.totalKeyBehaviors = 0;
|
|
|
|
if (stuff->full & XkbVirtualModsMask)
|
|
rep.virtualMods = ~0;
|
|
else if (stuff->partial & XkbVirtualModsMask)
|
|
rep.virtualMods = stuff->virtualMods;
|
|
|
|
if (stuff->full & XkbExplicitComponentsMask) {
|
|
rep.firstKeyExplicit = xkb->min_key_code;
|
|
rep.nKeyExplicit = n;
|
|
}
|
|
else if (stuff->partial & XkbExplicitComponentsMask) {
|
|
CHK_KEY_RANGE(0x0B, stuff->firstKeyExplicit, stuff->nKeyExplicit, xkb);
|
|
rep.firstKeyExplicit = stuff->firstKeyExplicit;
|
|
rep.nKeyExplicit = stuff->nKeyExplicit;
|
|
}
|
|
else
|
|
rep.nKeyExplicit = 0;
|
|
rep.totalKeyExplicit = 0;
|
|
|
|
if (stuff->full & XkbModifierMapMask) {
|
|
rep.firstModMapKey = xkb->min_key_code;
|
|
rep.nModMapKeys = n;
|
|
}
|
|
else if (stuff->partial & XkbModifierMapMask) {
|
|
CHK_KEY_RANGE(0x0D, stuff->firstModMapKey, stuff->nModMapKeys, xkb);
|
|
rep.firstModMapKey = stuff->firstModMapKey;
|
|
rep.nModMapKeys = stuff->nModMapKeys;
|
|
}
|
|
else
|
|
rep.nModMapKeys = 0;
|
|
rep.totalModMapKeys = 0;
|
|
|
|
if (stuff->full & XkbVirtualModMapMask) {
|
|
rep.firstVModMapKey = xkb->min_key_code;
|
|
rep.nVModMapKeys = n;
|
|
}
|
|
else if (stuff->partial & XkbVirtualModMapMask) {
|
|
CHK_KEY_RANGE(0x0F, stuff->firstVModMapKey, stuff->nVModMapKeys, xkb);
|
|
rep.firstVModMapKey = stuff->firstVModMapKey;
|
|
rep.nVModMapKeys = stuff->nVModMapKeys;
|
|
}
|
|
else
|
|
rep.nVModMapKeys = 0;
|
|
rep.totalVModMapKeys = 0;
|
|
|
|
if ((status = XkbComputeGetMapReplySize(xkb, &rep)) != Success)
|
|
return status;
|
|
return XkbSendMap(client, xkb, &rep);
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static int
|
|
CheckKeyTypes(ClientPtr client,
|
|
XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
xkbKeyTypeWireDesc ** wireRtrn,
|
|
int *nMapsRtrn, CARD8 *mapWidthRtrn)
|
|
{
|
|
unsigned nMaps;
|
|
register unsigned i, n;
|
|
register CARD8 *map;
|
|
register xkbKeyTypeWireDesc *wire = *wireRtrn;
|
|
|
|
if (req->firstType > ((unsigned) xkb->map->num_types)) {
|
|
*nMapsRtrn = _XkbErrCode3(0x01, req->firstType, xkb->map->num_types);
|
|
return 0;
|
|
}
|
|
if (req->flags & XkbSetMapResizeTypes) {
|
|
nMaps = req->firstType + req->nTypes;
|
|
if (nMaps < XkbNumRequiredTypes) { /* canonical types must be there */
|
|
*nMapsRtrn = _XkbErrCode4(0x02, req->firstType, req->nTypes, 4);
|
|
return 0;
|
|
}
|
|
}
|
|
else if (req->present & XkbKeyTypesMask) {
|
|
nMaps = xkb->map->num_types;
|
|
if ((req->firstType + req->nTypes) > nMaps) {
|
|
*nMapsRtrn = req->firstType + req->nTypes;
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
*nMapsRtrn = xkb->map->num_types;
|
|
for (i = 0; i < xkb->map->num_types; i++) {
|
|
mapWidthRtrn[i] = xkb->map->types[i].num_levels;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < req->firstType; i++) {
|
|
mapWidthRtrn[i] = xkb->map->types[i].num_levels;
|
|
}
|
|
for (i = 0; i < req->nTypes; i++) {
|
|
unsigned width;
|
|
|
|
if (client->swapped) {
|
|
swaps(&wire->virtualMods);
|
|
}
|
|
n = i + req->firstType;
|
|
width = wire->numLevels;
|
|
if (width < 1) {
|
|
*nMapsRtrn = _XkbErrCode3(0x04, n, width);
|
|
return 0;
|
|
}
|
|
else if ((n == XkbOneLevelIndex) && (width != 1)) { /* must be width 1 */
|
|
*nMapsRtrn = _XkbErrCode3(0x05, n, width);
|
|
return 0;
|
|
}
|
|
else if ((width != 2) &&
|
|
((n == XkbTwoLevelIndex) || (n == XkbKeypadIndex) ||
|
|
(n == XkbAlphabeticIndex))) {
|
|
/* TWO_LEVEL, ALPHABETIC and KEYPAD must be width 2 */
|
|
*nMapsRtrn = _XkbErrCode3(0x05, n, width);
|
|
return 0;
|
|
}
|
|
if (wire->nMapEntries > 0) {
|
|
xkbKTSetMapEntryWireDesc *mapWire;
|
|
xkbModsWireDesc *preWire;
|
|
|
|
mapWire = (xkbKTSetMapEntryWireDesc *) &wire[1];
|
|
preWire = (xkbModsWireDesc *) &mapWire[wire->nMapEntries];
|
|
for (n = 0; n < wire->nMapEntries; n++) {
|
|
if (client->swapped) {
|
|
swaps(&mapWire[n].virtualMods);
|
|
}
|
|
if (mapWire[n].realMods & (~wire->realMods)) {
|
|
*nMapsRtrn = _XkbErrCode4(0x06, n, mapWire[n].realMods,
|
|
wire->realMods);
|
|
return 0;
|
|
}
|
|
if (mapWire[n].virtualMods & (~wire->virtualMods)) {
|
|
*nMapsRtrn = _XkbErrCode3(0x07, n, mapWire[n].virtualMods);
|
|
return 0;
|
|
}
|
|
if (mapWire[n].level >= wire->numLevels) {
|
|
*nMapsRtrn = _XkbErrCode4(0x08, n, wire->numLevels,
|
|
mapWire[n].level);
|
|
return 0;
|
|
}
|
|
if (wire->preserve) {
|
|
if (client->swapped) {
|
|
swaps(&preWire[n].virtualMods);
|
|
}
|
|
if (preWire[n].realMods & (~mapWire[n].realMods)) {
|
|
*nMapsRtrn = _XkbErrCode4(0x09, n, preWire[n].realMods,
|
|
mapWire[n].realMods);
|
|
return 0;
|
|
}
|
|
if (preWire[n].virtualMods & (~mapWire[n].virtualMods)) {
|
|
*nMapsRtrn =
|
|
_XkbErrCode3(0x0a, n, preWire[n].virtualMods);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (wire->preserve)
|
|
map = (CARD8 *) &preWire[wire->nMapEntries];
|
|
else
|
|
map = (CARD8 *) &mapWire[wire->nMapEntries];
|
|
}
|
|
else
|
|
map = (CARD8 *) &wire[1];
|
|
mapWidthRtrn[i + req->firstType] = wire->numLevels;
|
|
wire = (xkbKeyTypeWireDesc *) map;
|
|
}
|
|
for (i = req->firstType + req->nTypes; i < nMaps; i++) {
|
|
mapWidthRtrn[i] = xkb->map->types[i].num_levels;
|
|
}
|
|
*nMapsRtrn = nMaps;
|
|
*wireRtrn = wire;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckKeySyms(ClientPtr client,
|
|
XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
int nTypes,
|
|
CARD8 *mapWidths,
|
|
CARD16 *symsPerKey, xkbSymMapWireDesc ** wireRtrn, int *errorRtrn)
|
|
{
|
|
register unsigned i;
|
|
XkbSymMapPtr map;
|
|
xkbSymMapWireDesc *wire = *wireRtrn;
|
|
|
|
if (!(XkbKeySymsMask & req->present))
|
|
return 1;
|
|
CHK_REQ_KEY_RANGE2(0x11, req->firstKeySym, req->nKeySyms, req, (*errorRtrn),
|
|
0);
|
|
for (i = 0; i < req->nKeySyms; i++) {
|
|
KeySym *pSyms;
|
|
register unsigned nG;
|
|
|
|
if (client->swapped) {
|
|
swaps(&wire->nSyms);
|
|
}
|
|
nG = XkbNumGroups(wire->groupInfo);
|
|
if (nG > XkbNumKbdGroups) {
|
|
*errorRtrn = _XkbErrCode3(0x14, i + req->firstKeySym, nG);
|
|
return 0;
|
|
}
|
|
if (nG > 0) {
|
|
register int g, w;
|
|
|
|
for (g = w = 0; g < nG; g++) {
|
|
if (wire->ktIndex[g] >= (unsigned) nTypes) {
|
|
*errorRtrn = _XkbErrCode4(0x15, i + req->firstKeySym, g,
|
|
wire->ktIndex[g]);
|
|
return 0;
|
|
}
|
|
if (mapWidths[wire->ktIndex[g]] > w)
|
|
w = mapWidths[wire->ktIndex[g]];
|
|
}
|
|
if (wire->width != w) {
|
|
*errorRtrn =
|
|
_XkbErrCode3(0x16, i + req->firstKeySym, wire->width);
|
|
return 0;
|
|
}
|
|
w *= nG;
|
|
symsPerKey[i + req->firstKeySym] = w;
|
|
if (w != wire->nSyms) {
|
|
*errorRtrn =
|
|
_XkbErrCode4(0x16, i + req->firstKeySym, wire->nSyms, w);
|
|
return 0;
|
|
}
|
|
}
|
|
else if (wire->nSyms != 0) {
|
|
*errorRtrn = _XkbErrCode3(0x17, i + req->firstKeySym, wire->nSyms);
|
|
return 0;
|
|
}
|
|
pSyms = (KeySym *) &wire[1];
|
|
wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms];
|
|
}
|
|
|
|
map = &xkb->map->key_sym_map[i];
|
|
for (; i <= (unsigned) xkb->max_key_code; i++, map++) {
|
|
register int g, nG, w;
|
|
|
|
nG = XkbKeyNumGroups(xkb, i);
|
|
for (w = g = 0; g < nG; g++) {
|
|
if (map->kt_index[g] >= (unsigned) nTypes) {
|
|
*errorRtrn = _XkbErrCode4(0x18, i, g, map->kt_index[g]);
|
|
return 0;
|
|
}
|
|
if (mapWidths[map->kt_index[g]] > w)
|
|
w = mapWidths[map->kt_index[g]];
|
|
}
|
|
symsPerKey[i] = w * nG;
|
|
}
|
|
*wireRtrn = wire;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckKeyActions(XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
int nTypes,
|
|
CARD8 *mapWidths,
|
|
CARD16 *symsPerKey, CARD8 **wireRtrn, int *nActsRtrn)
|
|
{
|
|
int nActs;
|
|
CARD8 *wire = *wireRtrn;
|
|
register unsigned i;
|
|
|
|
if (!(XkbKeyActionsMask & req->present))
|
|
return 1;
|
|
CHK_REQ_KEY_RANGE2(0x21, req->firstKeyAct, req->nKeyActs, req, (*nActsRtrn),
|
|
0);
|
|
for (nActs = i = 0; i < req->nKeyActs; i++) {
|
|
if (wire[0] != 0) {
|
|
if (wire[0] == symsPerKey[i + req->firstKeyAct])
|
|
nActs += wire[0];
|
|
else {
|
|
*nActsRtrn = _XkbErrCode3(0x23, i + req->firstKeyAct, wire[0]);
|
|
return 0;
|
|
}
|
|
}
|
|
wire++;
|
|
}
|
|
if (req->nKeyActs % 4)
|
|
wire += 4 - (req->nKeyActs % 4);
|
|
*wireRtrn = (CARD8 *) (((XkbAnyAction *) wire) + nActs);
|
|
*nActsRtrn = nActs;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckKeyBehaviors(XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
xkbBehaviorWireDesc ** wireRtrn, int *errorRtrn)
|
|
{
|
|
register xkbBehaviorWireDesc *wire = *wireRtrn;
|
|
register XkbServerMapPtr server = xkb->server;
|
|
register unsigned i;
|
|
unsigned first, last;
|
|
|
|
if (((req->present & XkbKeyBehaviorsMask) == 0) || (req->nKeyBehaviors < 1)) {
|
|
req->present &= ~XkbKeyBehaviorsMask;
|
|
req->nKeyBehaviors = 0;
|
|
return 1;
|
|
}
|
|
first = req->firstKeyBehavior;
|
|
last = req->firstKeyBehavior + req->nKeyBehaviors - 1;
|
|
if (first < req->minKeyCode) {
|
|
*errorRtrn = _XkbErrCode3(0x31, first, req->minKeyCode);
|
|
return 0;
|
|
}
|
|
if (last > req->maxKeyCode) {
|
|
*errorRtrn = _XkbErrCode3(0x32, last, req->maxKeyCode);
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < req->totalKeyBehaviors; i++, wire++) {
|
|
if ((wire->key < first) || (wire->key > last)) {
|
|
*errorRtrn = _XkbErrCode4(0x33, first, last, wire->key);
|
|
return 0;
|
|
}
|
|
if ((wire->type & XkbKB_Permanent) &&
|
|
((server->behaviors[wire->key].type != wire->type) ||
|
|
(server->behaviors[wire->key].data != wire->data))) {
|
|
*errorRtrn = _XkbErrCode3(0x33, wire->key, wire->type);
|
|
return 0;
|
|
}
|
|
if ((wire->type == XkbKB_RadioGroup) &&
|
|
((wire->data & (~XkbKB_RGAllowNone)) > XkbMaxRadioGroups)) {
|
|
*errorRtrn = _XkbErrCode4(0x34, wire->key, wire->data,
|
|
XkbMaxRadioGroups);
|
|
return 0;
|
|
}
|
|
if ((wire->type == XkbKB_Overlay1) || (wire->type == XkbKB_Overlay2)) {
|
|
CHK_KEY_RANGE2(0x35, wire->key, 1, xkb, *errorRtrn, 0);
|
|
}
|
|
}
|
|
*wireRtrn = wire;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckVirtualMods(XkbDescRec * xkb,
|
|
xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn)
|
|
{
|
|
register CARD8 *wire = *wireRtrn;
|
|
register unsigned i, nMods, bit;
|
|
|
|
if (((req->present & XkbVirtualModsMask) == 0) || (req->virtualMods == 0))
|
|
return 1;
|
|
for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
|
|
if (req->virtualMods & bit)
|
|
nMods++;
|
|
}
|
|
*wireRtrn = (wire + XkbPaddedSize(nMods));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckKeyExplicit(XkbDescPtr xkb,
|
|
xkbSetMapReq * req, CARD8 **wireRtrn, int *errorRtrn)
|
|
{
|
|
register CARD8 *wire = *wireRtrn;
|
|
CARD8 *start;
|
|
register unsigned i;
|
|
int first, last;
|
|
|
|
if (((req->present & XkbExplicitComponentsMask) == 0) ||
|
|
(req->nKeyExplicit < 1)) {
|
|
req->present &= ~XkbExplicitComponentsMask;
|
|
req->nKeyExplicit = 0;
|
|
return 1;
|
|
}
|
|
first = req->firstKeyExplicit;
|
|
last = first + req->nKeyExplicit - 1;
|
|
if (first < req->minKeyCode) {
|
|
*errorRtrn = _XkbErrCode3(0x51, first, req->minKeyCode);
|
|
return 0;
|
|
}
|
|
if (last > req->maxKeyCode) {
|
|
*errorRtrn = _XkbErrCode3(0x52, last, req->maxKeyCode);
|
|
return 0;
|
|
}
|
|
start = wire;
|
|
for (i = 0; i < req->totalKeyExplicit; i++, wire += 2) {
|
|
if ((wire[0] < first) || (wire[0] > last)) {
|
|
*errorRtrn = _XkbErrCode4(0x53, first, last, wire[0]);
|
|
return 0;
|
|
}
|
|
if (wire[1] & (~XkbAllExplicitMask)) {
|
|
*errorRtrn = _XkbErrCode3(0x52, ~XkbAllExplicitMask, wire[1]);
|
|
return 0;
|
|
}
|
|
}
|
|
wire += XkbPaddedSize(wire - start) - (wire - start);
|
|
*wireRtrn = wire;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckModifierMap(XkbDescPtr xkb, xkbSetMapReq * req, CARD8 **wireRtrn,
|
|
int *errRtrn)
|
|
{
|
|
register CARD8 *wire = *wireRtrn;
|
|
CARD8 *start;
|
|
register unsigned i;
|
|
int first, last;
|
|
|
|
if (((req->present & XkbModifierMapMask) == 0) || (req->nModMapKeys < 1)) {
|
|
req->present &= ~XkbModifierMapMask;
|
|
req->nModMapKeys = 0;
|
|
return 1;
|
|
}
|
|
first = req->firstModMapKey;
|
|
last = first + req->nModMapKeys - 1;
|
|
if (first < req->minKeyCode) {
|
|
*errRtrn = _XkbErrCode3(0x61, first, req->minKeyCode);
|
|
return 0;
|
|
}
|
|
if (last > req->maxKeyCode) {
|
|
*errRtrn = _XkbErrCode3(0x62, last, req->maxKeyCode);
|
|
return 0;
|
|
}
|
|
start = wire;
|
|
for (i = 0; i < req->totalModMapKeys; i++, wire += 2) {
|
|
if ((wire[0] < first) || (wire[0] > last)) {
|
|
*errRtrn = _XkbErrCode4(0x63, first, last, wire[0]);
|
|
return 0;
|
|
}
|
|
}
|
|
wire += XkbPaddedSize(wire - start) - (wire - start);
|
|
*wireRtrn = wire;
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
CheckVirtualModMap(XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
xkbVModMapWireDesc ** wireRtrn, int *errRtrn)
|
|
{
|
|
register xkbVModMapWireDesc *wire = *wireRtrn;
|
|
register unsigned i;
|
|
int first, last;
|
|
|
|
if (((req->present & XkbVirtualModMapMask) == 0) || (req->nVModMapKeys < 1)) {
|
|
req->present &= ~XkbVirtualModMapMask;
|
|
req->nVModMapKeys = 0;
|
|
return 1;
|
|
}
|
|
first = req->firstVModMapKey;
|
|
last = first + req->nVModMapKeys - 1;
|
|
if (first < req->minKeyCode) {
|
|
*errRtrn = _XkbErrCode3(0x71, first, req->minKeyCode);
|
|
return 0;
|
|
}
|
|
if (last > req->maxKeyCode) {
|
|
*errRtrn = _XkbErrCode3(0x72, last, req->maxKeyCode);
|
|
return 0;
|
|
}
|
|
for (i = 0; i < req->totalVModMapKeys; i++, wire++) {
|
|
if ((wire->key < first) || (wire->key > last)) {
|
|
*errRtrn = _XkbErrCode4(0x73, first, last, wire->key);
|
|
return 0;
|
|
}
|
|
}
|
|
*wireRtrn = wire;
|
|
return 1;
|
|
}
|
|
|
|
static char *
|
|
SetKeyTypes(XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
xkbKeyTypeWireDesc * wire, XkbChangesPtr changes)
|
|
{
|
|
register unsigned i;
|
|
unsigned first, last;
|
|
CARD8 *map;
|
|
|
|
if ((unsigned) (req->firstType + req->nTypes) > xkb->map->size_types) {
|
|
i = req->firstType + req->nTypes;
|
|
if (XkbAllocClientMap(xkb, XkbKeyTypesMask, i) != Success) {
|
|
return NULL;
|
|
}
|
|
}
|
|
if ((unsigned) (req->firstType + req->nTypes) > xkb->map->num_types)
|
|
xkb->map->num_types = req->firstType + req->nTypes;
|
|
|
|
for (i = 0; i < req->nTypes; i++) {
|
|
XkbKeyTypePtr pOld;
|
|
register unsigned n;
|
|
|
|
if (XkbResizeKeyType(xkb, i + req->firstType, wire->nMapEntries,
|
|
wire->preserve, wire->numLevels) != Success) {
|
|
return NULL;
|
|
}
|
|
pOld = &xkb->map->types[i + req->firstType];
|
|
map = (CARD8 *) &wire[1];
|
|
|
|
pOld->mods.real_mods = wire->realMods;
|
|
pOld->mods.vmods = wire->virtualMods;
|
|
pOld->num_levels = wire->numLevels;
|
|
pOld->map_count = wire->nMapEntries;
|
|
|
|
pOld->mods.mask = pOld->mods.real_mods |
|
|
XkbMaskForVMask(xkb, pOld->mods.vmods);
|
|
|
|
if (wire->nMapEntries) {
|
|
xkbKTSetMapEntryWireDesc *mapWire;
|
|
xkbModsWireDesc *preWire;
|
|
unsigned tmp;
|
|
|
|
mapWire = (xkbKTSetMapEntryWireDesc *) map;
|
|
preWire = (xkbModsWireDesc *) &mapWire[wire->nMapEntries];
|
|
for (n = 0; n < wire->nMapEntries; n++) {
|
|
pOld->map[n].active = 1;
|
|
pOld->map[n].mods.mask = mapWire[n].realMods;
|
|
pOld->map[n].mods.real_mods = mapWire[n].realMods;
|
|
pOld->map[n].mods.vmods = mapWire[n].virtualMods;
|
|
pOld->map[n].level = mapWire[n].level;
|
|
if (mapWire[n].virtualMods != 0) {
|
|
tmp = XkbMaskForVMask(xkb, mapWire[n].virtualMods);
|
|
pOld->map[n].active = (tmp != 0);
|
|
pOld->map[n].mods.mask |= tmp;
|
|
}
|
|
if (wire->preserve) {
|
|
pOld->preserve[n].real_mods = preWire[n].realMods;
|
|
pOld->preserve[n].vmods = preWire[n].virtualMods;
|
|
tmp = XkbMaskForVMask(xkb, preWire[n].virtualMods);
|
|
pOld->preserve[n].mask = preWire[n].realMods | tmp;
|
|
}
|
|
}
|
|
if (wire->preserve)
|
|
map = (CARD8 *) &preWire[wire->nMapEntries];
|
|
else
|
|
map = (CARD8 *) &mapWire[wire->nMapEntries];
|
|
}
|
|
else
|
|
map = (CARD8 *) &wire[1];
|
|
wire = (xkbKeyTypeWireDesc *) map;
|
|
}
|
|
first = req->firstType;
|
|
last = first + req->nTypes - 1; /* last changed type */
|
|
if (changes->map.changed & XkbKeyTypesMask) {
|
|
int oldLast;
|
|
|
|
oldLast = changes->map.first_type + changes->map.num_types - 1;
|
|
if (changes->map.first_type < first)
|
|
first = changes->map.first_type;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.changed |= XkbKeyTypesMask;
|
|
changes->map.first_type = first;
|
|
changes->map.num_types = (last - first) + 1;
|
|
return (char *) wire;
|
|
}
|
|
|
|
static char *
|
|
SetKeySyms(ClientPtr client,
|
|
XkbDescPtr xkb,
|
|
xkbSetMapReq * req,
|
|
xkbSymMapWireDesc * wire, XkbChangesPtr changes, DeviceIntPtr dev)
|
|
{
|
|
register unsigned i, s;
|
|
XkbSymMapPtr oldMap;
|
|
KeySym *newSyms;
|
|
KeySym *pSyms;
|
|
unsigned first, last;
|
|
|
|
oldMap = &xkb->map->key_sym_map[req->firstKeySym];
|
|
for (i = 0; i < req->nKeySyms; i++, oldMap++) {
|
|
pSyms = (KeySym *) &wire[1];
|
|
if (wire->nSyms > 0) {
|
|
newSyms = XkbResizeKeySyms(xkb, i + req->firstKeySym, wire->nSyms);
|
|
for (s = 0; s < wire->nSyms; s++) {
|
|
newSyms[s] = pSyms[s];
|
|
}
|
|
if (client->swapped) {
|
|
for (s = 0; s < wire->nSyms; s++) {
|
|
swapl(&newSyms[s]);
|
|
}
|
|
}
|
|
}
|
|
oldMap->kt_index[0] = wire->ktIndex[0];
|
|
oldMap->kt_index[1] = wire->ktIndex[1];
|
|
oldMap->kt_index[2] = wire->ktIndex[2];
|
|
oldMap->kt_index[3] = wire->ktIndex[3];
|
|
oldMap->group_info = wire->groupInfo;
|
|
oldMap->width = wire->width;
|
|
wire = (xkbSymMapWireDesc *) &pSyms[wire->nSyms];
|
|
}
|
|
first = req->firstKeySym;
|
|
last = first + req->nKeySyms - 1;
|
|
if (changes->map.changed & XkbKeySymsMask) {
|
|
int oldLast =
|
|
(changes->map.first_key_sym + changes->map.num_key_syms - 1);
|
|
if (changes->map.first_key_sym < first)
|
|
first = changes->map.first_key_sym;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.changed |= XkbKeySymsMask;
|
|
changes->map.first_key_sym = first;
|
|
changes->map.num_key_syms = (last - first + 1);
|
|
|
|
s = 0;
|
|
for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
|
|
if (XkbKeyNumGroups(xkb, i) > s)
|
|
s = XkbKeyNumGroups(xkb, i);
|
|
}
|
|
if (s != xkb->ctrls->num_groups) {
|
|
xkbControlsNotify cn;
|
|
XkbControlsRec old;
|
|
|
|
cn.keycode = 0;
|
|
cn.eventType = 0;
|
|
cn.requestMajor = XkbReqCode;
|
|
cn.requestMinor = X_kbSetMap;
|
|
old = *xkb->ctrls;
|
|
xkb->ctrls->num_groups = s;
|
|
if (XkbComputeControlsNotify(dev, &old, xkb->ctrls, &cn, FALSE))
|
|
XkbSendControlsNotify(dev, &cn);
|
|
}
|
|
return (char *) wire;
|
|
}
|
|
|
|
static char *
|
|
SetKeyActions(XkbDescPtr xkb,
|
|
xkbSetMapReq * req, CARD8 *wire, XkbChangesPtr changes)
|
|
{
|
|
register unsigned i, first, last;
|
|
CARD8 *nActs = wire;
|
|
XkbAction *newActs;
|
|
|
|
wire += XkbPaddedSize(req->nKeyActs);
|
|
for (i = 0; i < req->nKeyActs; i++) {
|
|
if (nActs[i] == 0)
|
|
xkb->server->key_acts[i + req->firstKeyAct] = 0;
|
|
else {
|
|
newActs = XkbResizeKeyActions(xkb, i + req->firstKeyAct, nActs[i]);
|
|
memcpy((char *) newActs, (char *) wire,
|
|
nActs[i] * SIZEOF(xkbActionWireDesc));
|
|
wire += nActs[i] * SIZEOF(xkbActionWireDesc);
|
|
}
|
|
}
|
|
first = req->firstKeyAct;
|
|
last = (first + req->nKeyActs - 1);
|
|
if (changes->map.changed & XkbKeyActionsMask) {
|
|
int oldLast;
|
|
|
|
oldLast = changes->map.first_key_act + changes->map.num_key_acts - 1;
|
|
if (changes->map.first_key_act < first)
|
|
first = changes->map.first_key_act;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.changed |= XkbKeyActionsMask;
|
|
changes->map.first_key_act = first;
|
|
changes->map.num_key_acts = (last - first + 1);
|
|
return (char *) wire;
|
|
}
|
|
|
|
static char *
|
|
SetKeyBehaviors(XkbSrvInfoPtr xkbi,
|
|
xkbSetMapReq * req,
|
|
xkbBehaviorWireDesc * wire, XkbChangesPtr changes)
|
|
{
|
|
register unsigned i;
|
|
int maxRG = -1;
|
|
XkbDescPtr xkb = xkbi->desc;
|
|
XkbServerMapPtr server = xkb->server;
|
|
unsigned first, last;
|
|
|
|
first = req->firstKeyBehavior;
|
|
last = req->firstKeyBehavior + req->nKeyBehaviors - 1;
|
|
memset(&server->behaviors[first], 0,
|
|
req->nKeyBehaviors * sizeof(XkbBehavior));
|
|
for (i = 0; i < req->totalKeyBehaviors; i++) {
|
|
if ((server->behaviors[wire->key].type & XkbKB_Permanent) == 0) {
|
|
server->behaviors[wire->key].type = wire->type;
|
|
server->behaviors[wire->key].data = wire->data;
|
|
if ((wire->type == XkbKB_RadioGroup) &&
|
|
(((int) wire->data) > maxRG))
|
|
maxRG = wire->data + 1;
|
|
}
|
|
wire++;
|
|
}
|
|
|
|
if (maxRG > (int) xkbi->nRadioGroups) {
|
|
int sz = maxRG * sizeof(XkbRadioGroupRec);
|
|
|
|
if (xkbi->radioGroups)
|
|
xkbi->radioGroups = realloc(xkbi->radioGroups, sz);
|
|
else
|
|
xkbi->radioGroups = calloc(1, sz);
|
|
if (xkbi->radioGroups) {
|
|
if (xkbi->nRadioGroups)
|
|
memset(&xkbi->radioGroups[xkbi->nRadioGroups], 0,
|
|
(maxRG - xkbi->nRadioGroups) * sizeof(XkbRadioGroupRec));
|
|
xkbi->nRadioGroups = maxRG;
|
|
}
|
|
else
|
|
xkbi->nRadioGroups = 0;
|
|
/* should compute members here */
|
|
}
|
|
if (changes->map.changed & XkbKeyBehaviorsMask) {
|
|
unsigned oldLast;
|
|
|
|
oldLast = changes->map.first_key_behavior +
|
|
changes->map.num_key_behaviors - 1;
|
|
if (changes->map.first_key_behavior < req->firstKeyBehavior)
|
|
first = changes->map.first_key_behavior;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.changed |= XkbKeyBehaviorsMask;
|
|
changes->map.first_key_behavior = first;
|
|
changes->map.num_key_behaviors = (last - first + 1);
|
|
return (char *) wire;
|
|
}
|
|
|
|
static char *
|
|
SetVirtualMods(XkbSrvInfoPtr xkbi, xkbSetMapReq * req, CARD8 *wire,
|
|
XkbChangesPtr changes)
|
|
{
|
|
register int i, bit, nMods;
|
|
XkbServerMapPtr srv = xkbi->desc->server;
|
|
|
|
if (((req->present & XkbVirtualModsMask) == 0) || (req->virtualMods == 0))
|
|
return (char *) wire;
|
|
for (i = nMods = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
|
|
if (req->virtualMods & bit) {
|
|
if (srv->vmods[i] != wire[nMods]) {
|
|
changes->map.changed |= XkbVirtualModsMask;
|
|
changes->map.vmods |= bit;
|
|
srv->vmods[i] = wire[nMods];
|
|
}
|
|
nMods++;
|
|
}
|
|
}
|
|
return (char *) (wire + XkbPaddedSize(nMods));
|
|
}
|
|
|
|
static char *
|
|
SetKeyExplicit(XkbSrvInfoPtr xkbi, xkbSetMapReq * req, CARD8 *wire,
|
|
XkbChangesPtr changes)
|
|
{
|
|
register unsigned i, first, last;
|
|
XkbServerMapPtr xkb = xkbi->desc->server;
|
|
CARD8 *start;
|
|
|
|
start = wire;
|
|
first = req->firstKeyExplicit;
|
|
last = req->firstKeyExplicit + req->nKeyExplicit - 1;
|
|
memset(&xkb->explicit[first], 0, req->nKeyExplicit);
|
|
for (i = 0; i < req->totalKeyExplicit; i++, wire += 2) {
|
|
xkb->explicit[wire[0]] = wire[1];
|
|
}
|
|
if (first > 0) {
|
|
if (changes->map.changed & XkbExplicitComponentsMask) {
|
|
int oldLast;
|
|
|
|
oldLast = changes->map.first_key_explicit +
|
|
changes->map.num_key_explicit - 1;
|
|
if (changes->map.first_key_explicit < first)
|
|
first = changes->map.first_key_explicit;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.first_key_explicit = first;
|
|
changes->map.num_key_explicit = (last - first) + 1;
|
|
}
|
|
wire += XkbPaddedSize(wire - start) - (wire - start);
|
|
return (char *) wire;
|
|
}
|
|
|
|
static char *
|
|
SetModifierMap(XkbSrvInfoPtr xkbi,
|
|
xkbSetMapReq * req, CARD8 *wire, XkbChangesPtr changes)
|
|
{
|
|
register unsigned i, first, last;
|
|
XkbClientMapPtr xkb = xkbi->desc->map;
|
|
CARD8 *start;
|
|
|
|
start = wire;
|
|
first = req->firstModMapKey;
|
|
last = req->firstModMapKey + req->nModMapKeys - 1;
|
|
memset(&xkb->modmap[first], 0, req->nModMapKeys);
|
|
for (i = 0; i < req->totalModMapKeys; i++, wire += 2) {
|
|
xkb->modmap[wire[0]] = wire[1];
|
|
}
|
|
if (first > 0) {
|
|
if (changes->map.changed & XkbModifierMapMask) {
|
|
int oldLast;
|
|
|
|
oldLast = changes->map.first_modmap_key +
|
|
changes->map.num_modmap_keys - 1;
|
|
if (changes->map.first_modmap_key < first)
|
|
first = changes->map.first_modmap_key;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.first_modmap_key = first;
|
|
changes->map.num_modmap_keys = (last - first) + 1;
|
|
}
|
|
wire += XkbPaddedSize(wire - start) - (wire - start);
|
|
return (char *) wire;
|
|
}
|
|
|
|
static char *
|
|
SetVirtualModMap(XkbSrvInfoPtr xkbi,
|
|
xkbSetMapReq * req,
|
|
xkbVModMapWireDesc * wire, XkbChangesPtr changes)
|
|
{
|
|
register unsigned i, first, last;
|
|
XkbServerMapPtr srv = xkbi->desc->server;
|
|
|
|
first = req->firstVModMapKey;
|
|
last = req->firstVModMapKey + req->nVModMapKeys - 1;
|
|
memset(&srv->vmodmap[first], 0, req->nVModMapKeys * sizeof(unsigned short));
|
|
for (i = 0; i < req->totalVModMapKeys; i++, wire++) {
|
|
srv->vmodmap[wire->key] = wire->vmods;
|
|
}
|
|
if (first > 0) {
|
|
if (changes->map.changed & XkbVirtualModMapMask) {
|
|
int oldLast;
|
|
|
|
oldLast = changes->map.first_vmodmap_key +
|
|
changes->map.num_vmodmap_keys - 1;
|
|
if (changes->map.first_vmodmap_key < first)
|
|
first = changes->map.first_vmodmap_key;
|
|
if (oldLast > last)
|
|
last = oldLast;
|
|
}
|
|
changes->map.first_vmodmap_key = first;
|
|
changes->map.num_vmodmap_keys = (last - first) + 1;
|
|
}
|
|
return (char *) wire;
|
|
}
|
|
|
|
/**
|
|
* Check if the given request can be applied to the given device but don't
|
|
* actually do anything..
|
|
*/
|
|
static int
|
|
_XkbSetMapChecks(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req,
|
|
char *values)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbDescPtr xkb;
|
|
int error;
|
|
int nTypes = 0, nActions;
|
|
CARD8 mapWidths[XkbMaxLegalKeyCode + 1] = { 0 };
|
|
CARD16 symsPerKey[XkbMaxLegalKeyCode + 1] = { 0 };
|
|
XkbSymMapPtr map;
|
|
int i;
|
|
|
|
xkbi = dev->key->xkbInfo;
|
|
xkb = xkbi->desc;
|
|
|
|
if ((xkb->min_key_code != req->minKeyCode) ||
|
|
(xkb->max_key_code != req->maxKeyCode)) {
|
|
if (client->vMajor != 1) { /* pre 1.0 versions of Xlib have a bug */
|
|
req->minKeyCode = xkb->min_key_code;
|
|
req->maxKeyCode = xkb->max_key_code;
|
|
}
|
|
else {
|
|
if (!XkbIsLegalKeycode(req->minKeyCode)) {
|
|
client->errorValue =
|
|
_XkbErrCode3(2, req->minKeyCode, req->maxKeyCode);
|
|
return BadValue;
|
|
}
|
|
if (req->minKeyCode > req->maxKeyCode) {
|
|
client->errorValue =
|
|
_XkbErrCode3(3, req->minKeyCode, req->maxKeyCode);
|
|
return BadMatch;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((req->present & XkbKeyTypesMask) &&
|
|
(!CheckKeyTypes(client, xkb, req, (xkbKeyTypeWireDesc **) &values,
|
|
&nTypes, mapWidths))) {
|
|
client->errorValue = nTypes;
|
|
return BadValue;
|
|
}
|
|
|
|
/* symsPerKey/mapWidths must be filled regardless of client-side flags */
|
|
map = &xkb->map->key_sym_map[xkb->min_key_code];
|
|
for (i = xkb->min_key_code; i < xkb->max_key_code; i++, map++) {
|
|
register int g, ng, w;
|
|
|
|
ng = XkbNumGroups(map->group_info);
|
|
for (w = g = 0; g < ng; g++) {
|
|
if (map->kt_index[g] >= (unsigned) nTypes) {
|
|
client->errorValue = _XkbErrCode4(0x13, i, g, map->kt_index[g]);
|
|
return 0;
|
|
}
|
|
if (mapWidths[map->kt_index[g]] > w)
|
|
w = mapWidths[map->kt_index[g]];
|
|
}
|
|
symsPerKey[i] = w * ng;
|
|
}
|
|
|
|
if ((req->present & XkbKeySymsMask) &&
|
|
(!CheckKeySyms(client, xkb, req, nTypes, mapWidths, symsPerKey,
|
|
(xkbSymMapWireDesc **) &values, &error))) {
|
|
client->errorValue = error;
|
|
return BadValue;
|
|
}
|
|
|
|
if ((req->present & XkbKeyActionsMask) &&
|
|
(!CheckKeyActions(xkb, req, nTypes, mapWidths, symsPerKey,
|
|
(CARD8 **) &values, &nActions))) {
|
|
client->errorValue = nActions;
|
|
return BadValue;
|
|
}
|
|
|
|
if ((req->present & XkbKeyBehaviorsMask) &&
|
|
(!CheckKeyBehaviors
|
|
(xkb, req, (xkbBehaviorWireDesc **) &values, &error))) {
|
|
client->errorValue = error;
|
|
return BadValue;
|
|
}
|
|
|
|
if ((req->present & XkbVirtualModsMask) &&
|
|
(!CheckVirtualMods(xkb, req, (CARD8 **) &values, &error))) {
|
|
client->errorValue = error;
|
|
return BadValue;
|
|
}
|
|
if ((req->present & XkbExplicitComponentsMask) &&
|
|
(!CheckKeyExplicit(xkb, req, (CARD8 **) &values, &error))) {
|
|
client->errorValue = error;
|
|
return BadValue;
|
|
}
|
|
if ((req->present & XkbModifierMapMask) &&
|
|
(!CheckModifierMap(xkb, req, (CARD8 **) &values, &error))) {
|
|
client->errorValue = error;
|
|
return BadValue;
|
|
}
|
|
if ((req->present & XkbVirtualModMapMask) &&
|
|
(!CheckVirtualModMap
|
|
(xkb, req, (xkbVModMapWireDesc **) &values, &error))) {
|
|
client->errorValue = error;
|
|
return BadValue;
|
|
}
|
|
|
|
if (((values - ((char *) req)) / 4) != req->length) {
|
|
ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after check)\n");
|
|
client->errorValue = values - ((char *) &req[1]);
|
|
return BadLength;
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/**
|
|
* Apply the given request on the given device.
|
|
*/
|
|
static int
|
|
_XkbSetMap(ClientPtr client, DeviceIntPtr dev, xkbSetMapReq * req, char *values)
|
|
{
|
|
XkbEventCauseRec cause;
|
|
XkbChangesRec change;
|
|
Bool sentNKN;
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbDescPtr xkb;
|
|
|
|
xkbi = dev->key->xkbInfo;
|
|
xkb = xkbi->desc;
|
|
|
|
XkbSetCauseXkbReq(&cause, X_kbSetMap, client);
|
|
memset(&change, 0, sizeof(change));
|
|
sentNKN = FALSE;
|
|
if ((xkb->min_key_code != req->minKeyCode) ||
|
|
(xkb->max_key_code != req->maxKeyCode)) {
|
|
Status status;
|
|
xkbNewKeyboardNotify nkn;
|
|
|
|
nkn.deviceID = nkn.oldDeviceID = dev->id;
|
|
nkn.oldMinKeyCode = xkb->min_key_code;
|
|
nkn.oldMaxKeyCode = xkb->max_key_code;
|
|
status = XkbChangeKeycodeRange(xkb, req->minKeyCode,
|
|
req->maxKeyCode, &change);
|
|
if (status != Success)
|
|
return status; /* oh-oh. what about the other keyboards? */
|
|
nkn.minKeyCode = xkb->min_key_code;
|
|
nkn.maxKeyCode = xkb->max_key_code;
|
|
nkn.requestMajor = XkbReqCode;
|
|
nkn.requestMinor = X_kbSetMap;
|
|
nkn.changed = XkbNKN_KeycodesMask;
|
|
XkbSendNewKeyboardNotify(dev, &nkn);
|
|
sentNKN = TRUE;
|
|
}
|
|
|
|
if (req->present & XkbKeyTypesMask) {
|
|
values = SetKeyTypes(xkb, req, (xkbKeyTypeWireDesc *) values, &change);
|
|
if (!values)
|
|
goto allocFailure;
|
|
}
|
|
if (req->present & XkbKeySymsMask) {
|
|
values =
|
|
SetKeySyms(client, xkb, req, (xkbSymMapWireDesc *) values, &change,
|
|
dev);
|
|
if (!values)
|
|
goto allocFailure;
|
|
}
|
|
if (req->present & XkbKeyActionsMask) {
|
|
values = SetKeyActions(xkb, req, (CARD8 *) values, &change);
|
|
if (!values)
|
|
goto allocFailure;
|
|
}
|
|
if (req->present & XkbKeyBehaviorsMask) {
|
|
values =
|
|
SetKeyBehaviors(xkbi, req, (xkbBehaviorWireDesc *) values, &change);
|
|
if (!values)
|
|
goto allocFailure;
|
|
}
|
|
if (req->present & XkbVirtualModsMask)
|
|
values = SetVirtualMods(xkbi, req, (CARD8 *) values, &change);
|
|
if (req->present & XkbExplicitComponentsMask)
|
|
values = SetKeyExplicit(xkbi, req, (CARD8 *) values, &change);
|
|
if (req->present & XkbModifierMapMask)
|
|
values = SetModifierMap(xkbi, req, (CARD8 *) values, &change);
|
|
if (req->present & XkbVirtualModMapMask)
|
|
values =
|
|
SetVirtualModMap(xkbi, req, (xkbVModMapWireDesc *) values, &change);
|
|
if (((values - ((char *) req)) / 4) != req->length) {
|
|
ErrorF("[xkb] Internal error! Bad length in XkbSetMap (after set)\n");
|
|
client->errorValue = values - ((char *) &req[1]);
|
|
return BadLength;
|
|
}
|
|
if (req->flags & XkbSetMapRecomputeActions) {
|
|
KeyCode first, last, firstMM, lastMM;
|
|
|
|
if (change.map.num_key_syms > 0) {
|
|
first = change.map.first_key_sym;
|
|
last = first + change.map.num_key_syms - 1;
|
|
}
|
|
else
|
|
first = last = 0;
|
|
if (change.map.num_modmap_keys > 0) {
|
|
firstMM = change.map.first_modmap_key;
|
|
lastMM = first + change.map.num_modmap_keys - 1;
|
|
}
|
|
else
|
|
firstMM = lastMM = 0;
|
|
if ((last > 0) && (lastMM > 0)) {
|
|
if (firstMM < first)
|
|
first = firstMM;
|
|
if (lastMM > last)
|
|
last = lastMM;
|
|
}
|
|
else if (lastMM > 0) {
|
|
first = firstMM;
|
|
last = lastMM;
|
|
}
|
|
if (last > 0) {
|
|
unsigned check = 0;
|
|
|
|
XkbUpdateActions(dev, first, (last - first + 1), &change, &check,
|
|
&cause);
|
|
if (check)
|
|
XkbCheckSecondaryEffects(xkbi, check, &change, &cause);
|
|
}
|
|
}
|
|
if (!sentNKN)
|
|
XkbSendNotification(dev, &change, &cause);
|
|
|
|
return Success;
|
|
allocFailure:
|
|
return BadAlloc;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetMap(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
char *tmp;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetMapReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetMapReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
CHK_MASK_LEGAL(0x01, stuff->present, XkbAllMapComponentsMask);
|
|
|
|
tmp = (char *) &stuff[1];
|
|
|
|
/* Check if we can to the SetMap on the requested device. If this
|
|
succeeds, do the same thing for all extension devices (if needed).
|
|
If any of them fails, fail. */
|
|
rc = _XkbSetMapChecks(client, dev, stuff, tmp);
|
|
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success) {
|
|
rc = _XkbSetMapChecks(client, other, stuff, tmp);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We know now that we will succed with the SetMap. In theory anyway. */
|
|
rc = _XkbSetMap(client, dev, stuff, tmp);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success)
|
|
_XkbSetMap(client, other, stuff, tmp);
|
|
/* ignore rc. if the SetMap failed although the check above
|
|
reported true there isn't much we can do. we still need to
|
|
set all other devices, hoping that at least they stay in
|
|
sync. */
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static Status
|
|
XkbComputeGetCompatMapReplySize(XkbCompatMapPtr compat,
|
|
xkbGetCompatMapReply * rep)
|
|
{
|
|
unsigned size, nGroups;
|
|
|
|
nGroups = 0;
|
|
if (rep->groups != 0) {
|
|
register int i, bit;
|
|
|
|
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
|
|
if (rep->groups & bit)
|
|
nGroups++;
|
|
}
|
|
}
|
|
size = nGroups * SIZEOF(xkbModsWireDesc);
|
|
size += (rep->nSI * SIZEOF(xkbSymInterpretWireDesc));
|
|
rep->length = size / 4;
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
XkbSendCompatMap(ClientPtr client,
|
|
XkbCompatMapPtr compat, xkbGetCompatMapReply * rep)
|
|
{
|
|
char *data;
|
|
int size;
|
|
|
|
size = rep->length * 4;
|
|
if (size > 0) {
|
|
data = malloc(size);
|
|
if (data) {
|
|
register unsigned i, bit;
|
|
xkbModsWireDesc *grp;
|
|
XkbSymInterpretPtr sym = &compat->sym_interpret[rep->firstSI];
|
|
xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *) data;
|
|
|
|
for (i = 0; i < rep->nSI; i++, sym++, wire++) {
|
|
wire->sym = sym->sym;
|
|
wire->mods = sym->mods;
|
|
wire->match = sym->match;
|
|
wire->virtualMod = sym->virtual_mod;
|
|
wire->flags = sym->flags;
|
|
memcpy((char *) &wire->act, (char *) &sym->act,
|
|
sz_xkbActionWireDesc);
|
|
if (client->swapped) {
|
|
swapl(&wire->sym);
|
|
}
|
|
}
|
|
if (rep->groups) {
|
|
grp = (xkbModsWireDesc *) wire;
|
|
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
|
|
if (rep->groups & bit) {
|
|
grp->mask = compat->groups[i].mask;
|
|
grp->realMods = compat->groups[i].real_mods;
|
|
grp->virtualMods = compat->groups[i].vmods;
|
|
if (client->swapped) {
|
|
swaps(&grp->virtualMods);
|
|
}
|
|
grp++;
|
|
}
|
|
}
|
|
wire = (xkbSymInterpretWireDesc *) grp;
|
|
}
|
|
}
|
|
else
|
|
return BadAlloc;
|
|
}
|
|
else
|
|
data = NULL;
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep->sequenceNumber);
|
|
swapl(&rep->length);
|
|
swaps(&rep->firstSI);
|
|
swaps(&rep->nSI);
|
|
swaps(&rep->nTotalSI);
|
|
}
|
|
|
|
WriteToClient(client, SIZEOF(xkbGetCompatMapReply), rep);
|
|
if (data) {
|
|
WriteToClient(client, size, data);
|
|
free((char *) data);
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbGetCompatMap(ClientPtr client)
|
|
{
|
|
xkbGetCompatMapReply rep;
|
|
DeviceIntPtr dev;
|
|
XkbDescPtr xkb;
|
|
XkbCompatMapPtr compat;
|
|
|
|
REQUEST(xkbGetCompatMapReq);
|
|
REQUEST_SIZE_MATCH(xkbGetCompatMapReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
compat = xkb->compat;
|
|
|
|
rep = (xkbGetCompatMapReply) {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.deviceID = dev->id,
|
|
.firstSI = stuff->firstSI,
|
|
.nSI = stuff->nSI
|
|
};
|
|
if (stuff->getAllSI) {
|
|
rep.firstSI = 0;
|
|
rep.nSI = compat->num_si;
|
|
}
|
|
else if ((((unsigned) stuff->nSI) > 0) &&
|
|
((unsigned) (stuff->firstSI + stuff->nSI - 1) >= compat->num_si)) {
|
|
client->errorValue = _XkbErrCode2(0x05, compat->num_si);
|
|
return BadValue;
|
|
}
|
|
rep.nTotalSI = compat->num_si;
|
|
rep.groups = stuff->groups;
|
|
XkbComputeGetCompatMapReplySize(compat, &rep);
|
|
return XkbSendCompatMap(client, compat, &rep);
|
|
}
|
|
|
|
/**
|
|
* Apply the given request on the given device.
|
|
* If dryRun is TRUE, then value checks are performed, but the device isn't
|
|
* modified.
|
|
*/
|
|
static int
|
|
_XkbSetCompatMap(ClientPtr client, DeviceIntPtr dev,
|
|
xkbSetCompatMapReq * req, char *data, BOOL dryRun)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbDescPtr xkb;
|
|
XkbCompatMapPtr compat;
|
|
int nGroups;
|
|
unsigned i, bit;
|
|
|
|
xkbi = dev->key->xkbInfo;
|
|
xkb = xkbi->desc;
|
|
compat = xkb->compat;
|
|
|
|
if ((req->nSI > 0) || (req->truncateSI)) {
|
|
xkbSymInterpretWireDesc *wire;
|
|
|
|
if (req->firstSI > compat->num_si) {
|
|
client->errorValue = _XkbErrCode2(0x02, compat->num_si);
|
|
return BadValue;
|
|
}
|
|
wire = (xkbSymInterpretWireDesc *) data;
|
|
wire += req->nSI;
|
|
data = (char *) wire;
|
|
}
|
|
|
|
nGroups = 0;
|
|
if (req->groups != 0) {
|
|
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
|
|
if (req->groups & bit)
|
|
nGroups++;
|
|
}
|
|
}
|
|
data += nGroups * SIZEOF(xkbModsWireDesc);
|
|
if (((data - ((char *) req)) / 4) != req->length) {
|
|
return BadLength;
|
|
}
|
|
|
|
/* Done all the checks we can do */
|
|
if (dryRun)
|
|
return Success;
|
|
|
|
data = (char *) &req[1];
|
|
if (req->nSI > 0) {
|
|
xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *) data;
|
|
XkbSymInterpretPtr sym;
|
|
unsigned int skipped = 0;
|
|
|
|
if ((unsigned) (req->firstSI + req->nSI) > compat->num_si) {
|
|
compat->num_si = req->firstSI + req->nSI;
|
|
compat->sym_interpret = realloc(compat->sym_interpret,
|
|
compat->num_si *
|
|
sizeof(XkbSymInterpretRec));
|
|
if (!compat->sym_interpret) {
|
|
compat->num_si = 0;
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
else if (req->truncateSI) {
|
|
compat->num_si = req->firstSI + req->nSI;
|
|
}
|
|
sym = &compat->sym_interpret[req->firstSI];
|
|
for (i = 0; i < req->nSI; i++, wire++) {
|
|
if (client->swapped) {
|
|
swapl(&wire->sym);
|
|
}
|
|
if (wire->sym == NoSymbol && wire->match == XkbSI_AnyOfOrNone &&
|
|
(wire->mods & 0xff) == 0xff &&
|
|
wire->act.type == XkbSA_XFree86Private) {
|
|
ErrorF("XKB: Skipping broken Any+AnyOfOrNone(All) -> Private "
|
|
"action from client\n");
|
|
skipped++;
|
|
continue;
|
|
}
|
|
sym->sym = wire->sym;
|
|
sym->mods = wire->mods;
|
|
sym->match = wire->match;
|
|
sym->flags = wire->flags;
|
|
sym->virtual_mod = wire->virtualMod;
|
|
memcpy((char *) &sym->act, (char *) &wire->act,
|
|
SIZEOF(xkbActionWireDesc));
|
|
sym++;
|
|
}
|
|
if (skipped) {
|
|
if (req->firstSI + req->nSI < compat->num_si)
|
|
memmove(sym, sym + skipped,
|
|
(compat->num_si - req->firstSI - req->nSI) *
|
|
sizeof(*sym));
|
|
compat->num_si -= skipped;
|
|
}
|
|
data = (char *) wire;
|
|
}
|
|
else if (req->truncateSI) {
|
|
compat->num_si = req->firstSI;
|
|
}
|
|
|
|
if (req->groups != 0) {
|
|
xkbModsWireDesc *wire = (xkbModsWireDesc *) data;
|
|
|
|
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
|
|
if (req->groups & bit) {
|
|
if (client->swapped) {
|
|
swaps(&wire->virtualMods);
|
|
}
|
|
compat->groups[i].mask = wire->realMods;
|
|
compat->groups[i].real_mods = wire->realMods;
|
|
compat->groups[i].vmods = wire->virtualMods;
|
|
if (wire->virtualMods != 0) {
|
|
unsigned tmp;
|
|
|
|
tmp = XkbMaskForVMask(xkb, wire->virtualMods);
|
|
compat->groups[i].mask |= tmp;
|
|
}
|
|
data += SIZEOF(xkbModsWireDesc);
|
|
wire = (xkbModsWireDesc *) data;
|
|
}
|
|
}
|
|
}
|
|
i = XkbPaddedSize((data - ((char *) req)));
|
|
if ((i / 4) != req->length) {
|
|
ErrorF("[xkb] Internal length error on read in _XkbSetCompatMap\n");
|
|
return BadLength;
|
|
}
|
|
|
|
if (dev->xkb_interest) {
|
|
xkbCompatMapNotify ev;
|
|
|
|
ev.deviceID = dev->id;
|
|
ev.changedGroups = req->groups;
|
|
ev.firstSI = req->firstSI;
|
|
ev.nSI = req->nSI;
|
|
ev.nTotalSI = compat->num_si;
|
|
XkbSendCompatMapNotify(dev, &ev);
|
|
}
|
|
|
|
if (req->recomputeActions) {
|
|
XkbChangesRec change;
|
|
unsigned check;
|
|
XkbEventCauseRec cause;
|
|
|
|
XkbSetCauseXkbReq(&cause, X_kbSetCompatMap, client);
|
|
memset(&change, 0, sizeof(XkbChangesRec));
|
|
XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &change,
|
|
&check, &cause);
|
|
if (check)
|
|
XkbCheckSecondaryEffects(xkbi, check, &change, &cause);
|
|
XkbSendNotification(dev, &change, &cause);
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetCompatMap(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
char *data;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetCompatMapReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetCompatMapReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
|
|
data = (char *) &stuff[1];
|
|
|
|
/* check first using a dry-run */
|
|
rc = _XkbSetCompatMap(client, dev, stuff, data, TRUE);
|
|
if (rc != Success)
|
|
return rc;
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success) {
|
|
/* dry-run */
|
|
rc = _XkbSetCompatMap(client, other, stuff, data, TRUE);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Yay, the dry-runs succeed. Let's apply */
|
|
rc = _XkbSetCompatMap(client, dev, stuff, data, FALSE);
|
|
if (rc != Success)
|
|
return rc;
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success) {
|
|
rc = _XkbSetCompatMap(client, other, stuff, data, FALSE);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbGetIndicatorState(ClientPtr client)
|
|
{
|
|
xkbGetIndicatorStateReply rep;
|
|
XkbSrvLedInfoPtr sli;
|
|
DeviceIntPtr dev;
|
|
|
|
REQUEST(xkbGetIndicatorStateReq);
|
|
REQUEST_SIZE_MATCH(xkbGetIndicatorStateReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess);
|
|
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId,
|
|
XkbXI_IndicatorStateMask);
|
|
if (!sli)
|
|
return BadAlloc;
|
|
|
|
rep = (xkbGetIndicatorStateReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.state = sli->effectiveState
|
|
};
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.state);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetIndicatorStateReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static Status
|
|
XkbComputeGetIndicatorMapReplySize(XkbIndicatorPtr indicators,
|
|
xkbGetIndicatorMapReply * rep)
|
|
{
|
|
register int i, bit;
|
|
int nIndicators;
|
|
|
|
rep->realIndicators = indicators->phys_indicators;
|
|
for (i = nIndicators = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (rep->which & bit)
|
|
nIndicators++;
|
|
}
|
|
rep->length = (nIndicators * SIZEOF(xkbIndicatorMapWireDesc)) / 4;
|
|
rep->nIndicators = nIndicators;
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
XkbSendIndicatorMap(ClientPtr client,
|
|
XkbIndicatorPtr indicators, xkbGetIndicatorMapReply * rep)
|
|
{
|
|
int length;
|
|
CARD8 *map;
|
|
register int i;
|
|
register unsigned bit;
|
|
|
|
length = rep->length * 4;
|
|
if (length > 0) {
|
|
CARD8 *to;
|
|
|
|
to = map = malloc(length);
|
|
if (map) {
|
|
xkbIndicatorMapWireDesc *wire = (xkbIndicatorMapWireDesc *) to;
|
|
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (rep->which & bit) {
|
|
wire->flags = indicators->maps[i].flags;
|
|
wire->whichGroups = indicators->maps[i].which_groups;
|
|
wire->groups = indicators->maps[i].groups;
|
|
wire->whichMods = indicators->maps[i].which_mods;
|
|
wire->mods = indicators->maps[i].mods.mask;
|
|
wire->realMods = indicators->maps[i].mods.real_mods;
|
|
wire->virtualMods = indicators->maps[i].mods.vmods;
|
|
wire->ctrls = indicators->maps[i].ctrls;
|
|
if (client->swapped) {
|
|
swaps(&wire->virtualMods);
|
|
swapl(&wire->ctrls);
|
|
}
|
|
wire++;
|
|
}
|
|
}
|
|
to = (CARD8 *) wire;
|
|
if ((to - map) != length) {
|
|
client->errorValue = _XkbErrCode2(0xff, length);
|
|
free(map);
|
|
return BadLength;
|
|
}
|
|
}
|
|
else
|
|
return BadAlloc;
|
|
}
|
|
else
|
|
map = NULL;
|
|
if (client->swapped) {
|
|
swaps(&rep->sequenceNumber);
|
|
swapl(&rep->length);
|
|
swapl(&rep->which);
|
|
swapl(&rep->realIndicators);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetIndicatorMapReply), rep);
|
|
if (map) {
|
|
WriteToClient(client, length, map);
|
|
free((char *) map);
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbGetIndicatorMap(ClientPtr client)
|
|
{
|
|
xkbGetIndicatorMapReply rep;
|
|
DeviceIntPtr dev;
|
|
XkbDescPtr xkb;
|
|
XkbIndicatorPtr leds;
|
|
|
|
REQUEST(xkbGetIndicatorMapReq);
|
|
REQUEST_SIZE_MATCH(xkbGetIndicatorMapReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
leds = xkb->indicators;
|
|
|
|
rep = (xkbGetIndicatorMapReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.which = stuff->which
|
|
};
|
|
XkbComputeGetIndicatorMapReplySize(leds, &rep);
|
|
return XkbSendIndicatorMap(client, leds, &rep);
|
|
}
|
|
|
|
/**
|
|
* Apply the given map to the given device. Which specifies which components
|
|
* to apply.
|
|
*/
|
|
static int
|
|
_XkbSetIndicatorMap(ClientPtr client, DeviceIntPtr dev,
|
|
int which, xkbIndicatorMapWireDesc * desc)
|
|
{
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbSrvLedInfoPtr sli;
|
|
XkbEventCauseRec cause;
|
|
int i, bit;
|
|
|
|
xkbi = dev->key->xkbInfo;
|
|
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId,
|
|
XkbXI_IndicatorMapsMask);
|
|
if (!sli)
|
|
return BadAlloc;
|
|
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (which & bit) {
|
|
sli->maps[i].flags = desc->flags;
|
|
sli->maps[i].which_groups = desc->whichGroups;
|
|
sli->maps[i].groups = desc->groups;
|
|
sli->maps[i].which_mods = desc->whichMods;
|
|
sli->maps[i].mods.mask = desc->mods;
|
|
sli->maps[i].mods.real_mods = desc->mods;
|
|
sli->maps[i].mods.vmods = desc->virtualMods;
|
|
sli->maps[i].ctrls = desc->ctrls;
|
|
if (desc->virtualMods != 0) {
|
|
unsigned tmp;
|
|
|
|
tmp = XkbMaskForVMask(xkbi->desc, desc->virtualMods);
|
|
sli->maps[i].mods.mask = desc->mods | tmp;
|
|
}
|
|
desc++;
|
|
}
|
|
}
|
|
|
|
XkbSetCauseXkbReq(&cause, X_kbSetIndicatorMap, client);
|
|
XkbApplyLedMapChanges(dev, sli, which, NULL, NULL, &cause);
|
|
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetIndicatorMap(ClientPtr client)
|
|
{
|
|
int i, bit;
|
|
int nIndicators;
|
|
DeviceIntPtr dev;
|
|
xkbIndicatorMapWireDesc *from;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetIndicatorMapReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetIndicatorMapReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
|
|
|
|
if (stuff->which == 0)
|
|
return Success;
|
|
|
|
for (nIndicators = i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (stuff->which & bit)
|
|
nIndicators++;
|
|
}
|
|
if (stuff->length != ((SIZEOF(xkbSetIndicatorMapReq) +
|
|
(nIndicators * SIZEOF(xkbIndicatorMapWireDesc))) /
|
|
4)) {
|
|
return BadLength;
|
|
}
|
|
|
|
from = (xkbIndicatorMapWireDesc *) &stuff[1];
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (stuff->which & bit) {
|
|
if (client->swapped) {
|
|
swaps(&from->virtualMods);
|
|
swapl(&from->ctrls);
|
|
}
|
|
CHK_MASK_LEGAL(i, from->whichGroups, XkbIM_UseAnyGroup);
|
|
CHK_MASK_LEGAL(i, from->whichMods, XkbIM_UseAnyMods);
|
|
from++;
|
|
}
|
|
}
|
|
|
|
from = (xkbIndicatorMapWireDesc *) &stuff[1];
|
|
rc = _XkbSetIndicatorMap(client, dev, stuff->which, from);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixSetAttrAccess);
|
|
if (rc == Success)
|
|
_XkbSetIndicatorMap(client, other, stuff->which, from);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbGetNamedIndicator(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
xkbGetNamedIndicatorReply rep;
|
|
register int i = 0;
|
|
XkbSrvLedInfoPtr sli;
|
|
XkbIndicatorMapPtr map = NULL;
|
|
|
|
REQUEST(xkbGetNamedIndicatorReq);
|
|
REQUEST_SIZE_MATCH(xkbGetNamedIndicatorReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixReadAccess);
|
|
CHK_ATOM_ONLY(stuff->indicator);
|
|
|
|
sli = XkbFindSrvLedInfo(dev, stuff->ledClass, stuff->ledID, 0);
|
|
if (!sli)
|
|
return BadAlloc;
|
|
|
|
i = 0;
|
|
map = NULL;
|
|
if ((sli->names) && (sli->maps)) {
|
|
for (i = 0; i < XkbNumIndicators; i++) {
|
|
if (stuff->indicator == sli->names[i]) {
|
|
map = &sli->maps[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
rep = (xkbGetNamedIndicatorReply) {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.deviceID = dev->id,
|
|
.indicator = stuff->indicator
|
|
};
|
|
if (map != NULL) {
|
|
rep.found = TRUE;
|
|
rep.on = ((sli->effectiveState & (1 << i)) != 0);
|
|
rep.realIndicator = ((sli->physIndicators & (1 << i)) != 0);
|
|
rep.ndx = i;
|
|
rep.flags = map->flags;
|
|
rep.whichGroups = map->which_groups;
|
|
rep.groups = map->groups;
|
|
rep.whichMods = map->which_mods;
|
|
rep.mods = map->mods.mask;
|
|
rep.realMods = map->mods.real_mods;
|
|
rep.virtualMods = map->mods.vmods;
|
|
rep.ctrls = map->ctrls;
|
|
rep.supported = TRUE;
|
|
}
|
|
else {
|
|
rep.found = FALSE;
|
|
rep.on = FALSE;
|
|
rep.realIndicator = FALSE;
|
|
rep.ndx = XkbNoIndicator;
|
|
rep.flags = 0;
|
|
rep.whichGroups = 0;
|
|
rep.groups = 0;
|
|
rep.whichMods = 0;
|
|
rep.mods = 0;
|
|
rep.realMods = 0;
|
|
rep.virtualMods = 0;
|
|
rep.ctrls = 0;
|
|
rep.supported = TRUE;
|
|
}
|
|
if (client->swapped) {
|
|
swapl(&rep.length);
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.indicator);
|
|
swaps(&rep.virtualMods);
|
|
swapl(&rep.ctrls);
|
|
}
|
|
|
|
WriteToClient(client, SIZEOF(xkbGetNamedIndicatorReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/**
|
|
* Find the IM on the device.
|
|
* Returns the map, or NULL if the map doesn't exist.
|
|
* If the return value is NULL, led_return is undefined. Otherwise, led_return
|
|
* is set to the led index of the map.
|
|
*/
|
|
static XkbIndicatorMapPtr
|
|
_XkbFindNamedIndicatorMap(XkbSrvLedInfoPtr sli, Atom indicator, int *led_return)
|
|
{
|
|
XkbIndicatorMapPtr map;
|
|
|
|
/* search for the right indicator */
|
|
map = NULL;
|
|
if (sli->names && sli->maps) {
|
|
int led;
|
|
|
|
for (led = 0; (led < XkbNumIndicators) && (map == NULL); led++) {
|
|
if (sli->names[led] == indicator) {
|
|
map = &sli->maps[led];
|
|
*led_return = led;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
/**
|
|
* Creates an indicator map on the device. If dryRun is TRUE, it only checks
|
|
* if creation is possible, but doesn't actually create it.
|
|
*/
|
|
static int
|
|
_XkbCreateIndicatorMap(DeviceIntPtr dev, Atom indicator,
|
|
int ledClass, int ledID,
|
|
XkbIndicatorMapPtr * map_return, int *led_return,
|
|
Bool dryRun)
|
|
{
|
|
XkbSrvLedInfoPtr sli;
|
|
XkbIndicatorMapPtr map;
|
|
int led;
|
|
|
|
sli = XkbFindSrvLedInfo(dev, ledClass, ledID, XkbXI_IndicatorsMask);
|
|
if (!sli)
|
|
return BadAlloc;
|
|
|
|
map = _XkbFindNamedIndicatorMap(sli, indicator, &led);
|
|
|
|
if (!map) {
|
|
/* find first unused indicator maps and assign the name to it */
|
|
for (led = 0, map = NULL; (led < XkbNumIndicators) && (map == NULL);
|
|
led++) {
|
|
if ((sli->names) && (sli->maps) && (sli->names[led] == None) &&
|
|
(!XkbIM_InUse(&sli->maps[led]))) {
|
|
map = &sli->maps[led];
|
|
if (!dryRun)
|
|
sli->names[led] = indicator;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!map)
|
|
return BadAlloc;
|
|
|
|
*led_return = led;
|
|
*map_return = map;
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
_XkbSetNamedIndicator(ClientPtr client, DeviceIntPtr dev,
|
|
xkbSetNamedIndicatorReq * stuff)
|
|
{
|
|
unsigned int extDevReason;
|
|
unsigned int statec, namec, mapc;
|
|
XkbSrvLedInfoPtr sli;
|
|
int led = 0;
|
|
XkbIndicatorMapPtr map;
|
|
DeviceIntPtr kbd;
|
|
XkbEventCauseRec cause;
|
|
xkbExtensionDeviceNotify ed;
|
|
XkbChangesRec changes;
|
|
int rc;
|
|
|
|
rc = _XkbCreateIndicatorMap(dev, stuff->indicator, stuff->ledClass,
|
|
stuff->ledID, &map, &led, FALSE);
|
|
if (rc != Success || !map) /* oh-oh */
|
|
return rc;
|
|
|
|
sli = XkbFindSrvLedInfo(dev, stuff->ledClass, stuff->ledID,
|
|
XkbXI_IndicatorsMask);
|
|
if (!sli)
|
|
return BadAlloc;
|
|
|
|
namec = mapc = statec = 0;
|
|
extDevReason = 0;
|
|
|
|
namec |= (1 << led);
|
|
sli->namesPresent |= ((stuff->indicator != None) ? (1 << led) : 0);
|
|
extDevReason |= XkbXI_IndicatorNamesMask;
|
|
|
|
if (stuff->setMap) {
|
|
map->flags = stuff->flags;
|
|
map->which_groups = stuff->whichGroups;
|
|
map->groups = stuff->groups;
|
|
map->which_mods = stuff->whichMods;
|
|
map->mods.mask = stuff->realMods;
|
|
map->mods.real_mods = stuff->realMods;
|
|
map->mods.vmods = stuff->virtualMods;
|
|
map->ctrls = stuff->ctrls;
|
|
mapc |= (1 << led);
|
|
}
|
|
|
|
if ((stuff->setState) && ((map->flags & XkbIM_NoExplicit) == 0)) {
|
|
if (stuff->on)
|
|
sli->explicitState |= (1 << led);
|
|
else
|
|
sli->explicitState &= ~(1 << led);
|
|
statec |= ((sli->effectiveState ^ sli->explicitState) & (1 << led));
|
|
}
|
|
|
|
memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
memset((char *) &changes, 0, sizeof(XkbChangesRec));
|
|
XkbSetCauseXkbReq(&cause, X_kbSetNamedIndicator, client);
|
|
if (namec)
|
|
XkbApplyLedNameChanges(dev, sli, namec, &ed, &changes, &cause);
|
|
if (mapc)
|
|
XkbApplyLedMapChanges(dev, sli, mapc, &ed, &changes, &cause);
|
|
if (statec)
|
|
XkbApplyLedStateChanges(dev, sli, statec, &ed, &changes, &cause);
|
|
|
|
kbd = dev;
|
|
if ((sli->flags & XkbSLI_HasOwnState) == 0)
|
|
kbd = inputInfo.keyboard;
|
|
XkbFlushLedEvents(dev, kbd, sli, &ed, &changes, &cause);
|
|
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetNamedIndicator(ClientPtr client)
|
|
{
|
|
int rc;
|
|
DeviceIntPtr dev;
|
|
int led = 0;
|
|
XkbIndicatorMapPtr map;
|
|
|
|
REQUEST(xkbSetNamedIndicatorReq);
|
|
REQUEST_SIZE_MATCH(xkbSetNamedIndicatorReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_LED_DEVICE(dev, stuff->deviceSpec, client, DixSetAttrAccess);
|
|
CHK_ATOM_ONLY(stuff->indicator);
|
|
CHK_MASK_LEGAL(0x10, stuff->whichGroups, XkbIM_UseAnyGroup);
|
|
CHK_MASK_LEGAL(0x11, stuff->whichMods, XkbIM_UseAnyMods);
|
|
|
|
/* Dry-run for checks */
|
|
rc = _XkbCreateIndicatorMap(dev, stuff->indicator,
|
|
stuff->ledClass, stuff->ledID,
|
|
&map, &led, TRUE);
|
|
if (rc != Success || !map) /* couldn't be created or didn't exist */
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd ||
|
|
stuff->deviceSpec == XkbUseCorePtr) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev && (other->kbdfeed ||
|
|
other->leds) &&
|
|
(XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess)
|
|
== Success)) {
|
|
rc = _XkbCreateIndicatorMap(other, stuff->indicator,
|
|
stuff->ledClass, stuff->ledID, &map,
|
|
&led, TRUE);
|
|
if (rc != Success || !map)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* All checks passed, let's do it */
|
|
rc = _XkbSetNamedIndicator(client, dev, stuff);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd ||
|
|
stuff->deviceSpec == XkbUseCorePtr) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev && (other->kbdfeed ||
|
|
other->leds) &&
|
|
(XaceHook(XACE_DEVICE_ACCESS, client, other, DixSetAttrAccess)
|
|
== Success)) {
|
|
_XkbSetNamedIndicator(client, other, stuff);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static CARD32
|
|
_XkbCountAtoms(Atom *atoms, int maxAtoms, int *count)
|
|
{
|
|
register unsigned int i, bit, nAtoms;
|
|
register CARD32 atomsPresent;
|
|
|
|
for (i = nAtoms = atomsPresent = 0, bit = 1; i < maxAtoms; i++, bit <<= 1) {
|
|
if (atoms[i] != None) {
|
|
atomsPresent |= bit;
|
|
nAtoms++;
|
|
}
|
|
}
|
|
if (count)
|
|
*count = nAtoms;
|
|
return atomsPresent;
|
|
}
|
|
|
|
static char *
|
|
_XkbWriteAtoms(char *wire, Atom *atoms, int maxAtoms, int swap)
|
|
{
|
|
register unsigned int i;
|
|
Atom *atm;
|
|
|
|
atm = (Atom *) wire;
|
|
for (i = 0; i < maxAtoms; i++) {
|
|
if (atoms[i] != None) {
|
|
*atm = atoms[i];
|
|
if (swap) {
|
|
swapl(atm);
|
|
}
|
|
atm++;
|
|
}
|
|
}
|
|
return (char *) atm;
|
|
}
|
|
|
|
static Status
|
|
XkbComputeGetNamesReplySize(XkbDescPtr xkb, xkbGetNamesReply * rep)
|
|
{
|
|
register unsigned which, length;
|
|
register int i;
|
|
|
|
rep->minKeyCode = xkb->min_key_code;
|
|
rep->maxKeyCode = xkb->max_key_code;
|
|
which = rep->which;
|
|
length = 0;
|
|
if (xkb->names != NULL) {
|
|
if (which & XkbKeycodesNameMask)
|
|
length++;
|
|
if (which & XkbGeometryNameMask)
|
|
length++;
|
|
if (which & XkbSymbolsNameMask)
|
|
length++;
|
|
if (which & XkbPhysSymbolsNameMask)
|
|
length++;
|
|
if (which & XkbTypesNameMask)
|
|
length++;
|
|
if (which & XkbCompatNameMask)
|
|
length++;
|
|
}
|
|
else
|
|
which &= ~XkbComponentNamesMask;
|
|
|
|
if (xkb->map != NULL) {
|
|
if (which & XkbKeyTypeNamesMask)
|
|
length += xkb->map->num_types;
|
|
rep->nTypes = xkb->map->num_types;
|
|
if (which & XkbKTLevelNamesMask) {
|
|
XkbKeyTypePtr pType = xkb->map->types;
|
|
int nKTLevels = 0;
|
|
|
|
length += XkbPaddedSize(xkb->map->num_types) / 4;
|
|
for (i = 0; i < xkb->map->num_types; i++, pType++) {
|
|
if (pType->level_names != NULL)
|
|
nKTLevels += pType->num_levels;
|
|
}
|
|
rep->nKTLevels = nKTLevels;
|
|
length += nKTLevels;
|
|
}
|
|
}
|
|
else {
|
|
rep->nTypes = 0;
|
|
rep->nKTLevels = 0;
|
|
which &= ~(XkbKeyTypeNamesMask | XkbKTLevelNamesMask);
|
|
}
|
|
|
|
rep->minKeyCode = xkb->min_key_code;
|
|
rep->maxKeyCode = xkb->max_key_code;
|
|
rep->indicators = 0;
|
|
rep->virtualMods = 0;
|
|
rep->groupNames = 0;
|
|
if (xkb->names != NULL) {
|
|
if (which & XkbIndicatorNamesMask) {
|
|
int nLeds;
|
|
|
|
rep->indicators =
|
|
_XkbCountAtoms(xkb->names->indicators, XkbNumIndicators,
|
|
&nLeds);
|
|
length += nLeds;
|
|
if (nLeds == 0)
|
|
which &= ~XkbIndicatorNamesMask;
|
|
}
|
|
|
|
if (which & XkbVirtualModNamesMask) {
|
|
int nVMods;
|
|
|
|
rep->virtualMods =
|
|
_XkbCountAtoms(xkb->names->vmods, XkbNumVirtualMods, &nVMods);
|
|
length += nVMods;
|
|
if (nVMods == 0)
|
|
which &= ~XkbVirtualModNamesMask;
|
|
}
|
|
|
|
if (which & XkbGroupNamesMask) {
|
|
int nGroups;
|
|
|
|
rep->groupNames =
|
|
_XkbCountAtoms(xkb->names->groups, XkbNumKbdGroups, &nGroups);
|
|
length += nGroups;
|
|
if (nGroups == 0)
|
|
which &= ~XkbGroupNamesMask;
|
|
}
|
|
|
|
if ((which & XkbKeyNamesMask) && (xkb->names->keys))
|
|
length += rep->nKeys;
|
|
else
|
|
which &= ~XkbKeyNamesMask;
|
|
|
|
if ((which & XkbKeyAliasesMask) &&
|
|
(xkb->names->key_aliases) && (xkb->names->num_key_aliases > 0)) {
|
|
rep->nKeyAliases = xkb->names->num_key_aliases;
|
|
length += rep->nKeyAliases * 2;
|
|
}
|
|
else {
|
|
which &= ~XkbKeyAliasesMask;
|
|
rep->nKeyAliases = 0;
|
|
}
|
|
|
|
if ((which & XkbRGNamesMask) && (xkb->names->num_rg > 0))
|
|
length += xkb->names->num_rg;
|
|
else
|
|
which &= ~XkbRGNamesMask;
|
|
}
|
|
else {
|
|
which &= ~(XkbIndicatorNamesMask | XkbVirtualModNamesMask);
|
|
which &= ~(XkbGroupNamesMask | XkbKeyNamesMask | XkbKeyAliasesMask);
|
|
which &= ~XkbRGNamesMask;
|
|
}
|
|
|
|
rep->length = length;
|
|
rep->which = which;
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
XkbSendNames(ClientPtr client, XkbDescPtr xkb, xkbGetNamesReply * rep)
|
|
{
|
|
register unsigned i, length, which;
|
|
char *start;
|
|
char *desc;
|
|
|
|
length = rep->length * 4;
|
|
which = rep->which;
|
|
if (client->swapped) {
|
|
swaps(&rep->sequenceNumber);
|
|
swapl(&rep->length);
|
|
swapl(&rep->which);
|
|
swaps(&rep->virtualMods);
|
|
swapl(&rep->indicators);
|
|
}
|
|
|
|
start = desc = calloc(1, length);
|
|
if (!start)
|
|
return BadAlloc;
|
|
if (xkb->names) {
|
|
if (which & XkbKeycodesNameMask) {
|
|
*((CARD32 *) desc) = xkb->names->keycodes;
|
|
if (client->swapped) {
|
|
swapl((int *) desc);
|
|
}
|
|
desc += 4;
|
|
}
|
|
if (which & XkbGeometryNameMask) {
|
|
*((CARD32 *) desc) = xkb->names->geometry;
|
|
if (client->swapped) {
|
|
swapl((int *) desc);
|
|
}
|
|
desc += 4;
|
|
}
|
|
if (which & XkbSymbolsNameMask) {
|
|
*((CARD32 *) desc) = xkb->names->symbols;
|
|
if (client->swapped) {
|
|
swapl((int *) desc);
|
|
}
|
|
desc += 4;
|
|
}
|
|
if (which & XkbPhysSymbolsNameMask) {
|
|
register CARD32 *atm = (CARD32 *) desc;
|
|
|
|
atm[0] = (CARD32) xkb->names->phys_symbols;
|
|
if (client->swapped) {
|
|
swapl(&atm[0]);
|
|
}
|
|
desc += 4;
|
|
}
|
|
if (which & XkbTypesNameMask) {
|
|
*((CARD32 *) desc) = (CARD32) xkb->names->types;
|
|
if (client->swapped) {
|
|
swapl((int *) desc);
|
|
}
|
|
desc += 4;
|
|
}
|
|
if (which & XkbCompatNameMask) {
|
|
*((CARD32 *) desc) = (CARD32) xkb->names->compat;
|
|
if (client->swapped) {
|
|
swapl((int *) desc);
|
|
}
|
|
desc += 4;
|
|
}
|
|
if (which & XkbKeyTypeNamesMask) {
|
|
register CARD32 *atm = (CARD32 *) desc;
|
|
register XkbKeyTypePtr type = xkb->map->types;
|
|
|
|
for (i = 0; i < xkb->map->num_types; i++, atm++, type++) {
|
|
*atm = (CARD32) type->name;
|
|
if (client->swapped) {
|
|
swapl(atm);
|
|
}
|
|
}
|
|
desc = (char *) atm;
|
|
}
|
|
if (which & XkbKTLevelNamesMask && xkb->map) {
|
|
XkbKeyTypePtr type = xkb->map->types;
|
|
register CARD32 *atm;
|
|
|
|
for (i = 0; i < rep->nTypes; i++, type++) {
|
|
*desc++ = type->num_levels;
|
|
}
|
|
desc += XkbPaddedSize(rep->nTypes) - rep->nTypes;
|
|
|
|
atm = (CARD32 *) desc;
|
|
type = xkb->map->types;
|
|
for (i = 0; i < xkb->map->num_types; i++, type++) {
|
|
register unsigned l;
|
|
|
|
if (type->level_names) {
|
|
for (l = 0; l < type->num_levels; l++, atm++) {
|
|
*atm = type->level_names[l];
|
|
if (client->swapped) {
|
|
swapl(atm);
|
|
}
|
|
}
|
|
desc += type->num_levels * 4;
|
|
}
|
|
}
|
|
}
|
|
if (which & XkbIndicatorNamesMask) {
|
|
desc =
|
|
_XkbWriteAtoms(desc, xkb->names->indicators, XkbNumIndicators,
|
|
client->swapped);
|
|
}
|
|
if (which & XkbVirtualModNamesMask) {
|
|
desc = _XkbWriteAtoms(desc, xkb->names->vmods, XkbNumVirtualMods,
|
|
client->swapped);
|
|
}
|
|
if (which & XkbGroupNamesMask) {
|
|
desc = _XkbWriteAtoms(desc, xkb->names->groups, XkbNumKbdGroups,
|
|
client->swapped);
|
|
}
|
|
if (which & XkbKeyNamesMask) {
|
|
for (i = 0; i < rep->nKeys; i++, desc += sizeof(XkbKeyNameRec)) {
|
|
*((XkbKeyNamePtr) desc) = xkb->names->keys[i + rep->firstKey];
|
|
}
|
|
}
|
|
if (which & XkbKeyAliasesMask) {
|
|
XkbKeyAliasPtr pAl;
|
|
|
|
pAl = xkb->names->key_aliases;
|
|
for (i = 0; i < rep->nKeyAliases;
|
|
i++, pAl++, desc += 2 * XkbKeyNameLength) {
|
|
*((XkbKeyAliasPtr) desc) = *pAl;
|
|
}
|
|
}
|
|
if ((which & XkbRGNamesMask) && (rep->nRadioGroups > 0)) {
|
|
register CARD32 *atm = (CARD32 *) desc;
|
|
|
|
for (i = 0; i < rep->nRadioGroups; i++, atm++) {
|
|
*atm = (CARD32) xkb->names->radio_groups[i];
|
|
if (client->swapped) {
|
|
swapl(atm);
|
|
}
|
|
}
|
|
desc += rep->nRadioGroups * 4;
|
|
}
|
|
}
|
|
|
|
if ((desc - start) != (length)) {
|
|
ErrorF("[xkb] BOGUS LENGTH in write names, expected %d, got %ld\n",
|
|
length, (unsigned long) (desc - start));
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetNamesReply), rep);
|
|
WriteToClient(client, length, start);
|
|
free((char *) start);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbGetNames(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
XkbDescPtr xkb;
|
|
xkbGetNamesReply rep;
|
|
|
|
REQUEST(xkbGetNamesReq);
|
|
REQUEST_SIZE_MATCH(xkbGetNamesReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
CHK_MASK_LEGAL(0x01, stuff->which, XkbAllNamesMask);
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
rep = (xkbGetNamesReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.which = stuff->which,
|
|
.nTypes = xkb->map->num_types,
|
|
.firstKey = xkb->min_key_code,
|
|
.nKeys = XkbNumKeys(xkb),
|
|
.nKeyAliases = xkb->names ? xkb->names->num_key_aliases : 0,
|
|
.nRadioGroups = xkb->names ? xkb->names->num_rg : 0
|
|
};
|
|
XkbComputeGetNamesReplySize(xkb, &rep);
|
|
return XkbSendNames(client, xkb, &rep);
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static CARD32 *
|
|
_XkbCheckAtoms(CARD32 *wire, int nAtoms, int swapped, Atom *pError)
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; i < nAtoms; i++, wire++) {
|
|
if (swapped) {
|
|
swapl(wire);
|
|
}
|
|
if ((((Atom) *wire) != None) && (!ValidAtom((Atom) *wire))) {
|
|
*pError = ((Atom) *wire);
|
|
return NULL;
|
|
}
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static CARD32 *
|
|
_XkbCheckMaskedAtoms(CARD32 *wire, int nAtoms, CARD32 present, int swapped,
|
|
Atom *pError)
|
|
{
|
|
register unsigned i, bit;
|
|
|
|
for (i = 0, bit = 1; (i < nAtoms) && (present); i++, bit <<= 1) {
|
|
if ((present & bit) == 0)
|
|
continue;
|
|
if (swapped) {
|
|
swapl(wire);
|
|
}
|
|
if ((((Atom) *wire) != None) && (!ValidAtom(((Atom) *wire)))) {
|
|
*pError = (Atom) *wire;
|
|
return NULL;
|
|
}
|
|
wire++;
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static Atom *
|
|
_XkbCopyMaskedAtoms(Atom *wire, Atom *dest, int nAtoms, CARD32 present)
|
|
{
|
|
register int i, bit;
|
|
|
|
for (i = 0, bit = 1; (i < nAtoms) && (present); i++, bit <<= 1) {
|
|
if ((present & bit) == 0)
|
|
continue;
|
|
dest[i] = *wire++;
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static Bool
|
|
_XkbCheckTypeName(Atom name, int typeNdx)
|
|
{
|
|
const char *str;
|
|
|
|
str = NameForAtom(name);
|
|
if ((strcmp(str, "ONE_LEVEL") == 0) || (strcmp(str, "TWO_LEVEL") == 0) ||
|
|
(strcmp(str, "ALPHABETIC") == 0) || (strcmp(str, "KEYPAD") == 0))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Check the device-dependent data in the request against the device. Returns
|
|
* Success, or the appropriate error code.
|
|
*/
|
|
static int
|
|
_XkbSetNamesCheck(ClientPtr client, DeviceIntPtr dev,
|
|
xkbSetNamesReq * stuff, CARD32 *data)
|
|
{
|
|
XkbDescRec *xkb;
|
|
CARD32 *tmp;
|
|
Atom bad;
|
|
|
|
tmp = data;
|
|
xkb = dev->key->xkbInfo->desc;
|
|
|
|
if (stuff->which & XkbKeyTypeNamesMask) {
|
|
int i;
|
|
CARD32 *old;
|
|
|
|
if (stuff->nTypes < 1) {
|
|
client->errorValue = _XkbErrCode2(0x02, stuff->nTypes);
|
|
return BadValue;
|
|
}
|
|
if ((unsigned) (stuff->firstType + stuff->nTypes - 1) >=
|
|
xkb->map->num_types) {
|
|
client->errorValue =
|
|
_XkbErrCode4(0x03, stuff->firstType, stuff->nTypes,
|
|
xkb->map->num_types);
|
|
return BadValue;
|
|
}
|
|
if (((unsigned) stuff->firstType) <= XkbLastRequiredType) {
|
|
client->errorValue = _XkbErrCode2(0x04, stuff->firstType);
|
|
return BadAccess;
|
|
}
|
|
old = tmp;
|
|
tmp = _XkbCheckAtoms(tmp, stuff->nTypes, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
for (i = 0; i < stuff->nTypes; i++, old++) {
|
|
if (!_XkbCheckTypeName((Atom) *old, stuff->firstType + i))
|
|
client->errorValue = _XkbErrCode2(0x05, i);
|
|
}
|
|
}
|
|
if (stuff->which & XkbKTLevelNamesMask) {
|
|
unsigned i;
|
|
XkbKeyTypePtr type;
|
|
CARD8 *width;
|
|
|
|
if (stuff->nKTLevels < 1) {
|
|
client->errorValue = _XkbErrCode2(0x05, stuff->nKTLevels);
|
|
return BadValue;
|
|
}
|
|
if ((unsigned) (stuff->firstKTLevel + stuff->nKTLevels - 1) >=
|
|
xkb->map->num_types) {
|
|
client->errorValue = _XkbErrCode4(0x06, stuff->firstKTLevel,
|
|
stuff->nKTLevels,
|
|
xkb->map->num_types);
|
|
return BadValue;
|
|
}
|
|
width = (CARD8 *) tmp;
|
|
tmp = (CARD32 *) (((char *) tmp) + XkbPaddedSize(stuff->nKTLevels));
|
|
type = &xkb->map->types[stuff->firstKTLevel];
|
|
for (i = 0; i < stuff->nKTLevels; i++, type++) {
|
|
if (width[i] == 0)
|
|
continue;
|
|
else if (width[i] != type->num_levels) {
|
|
client->errorValue = _XkbErrCode4(0x07, i + stuff->firstKTLevel,
|
|
type->num_levels, width[i]);
|
|
return BadMatch;
|
|
}
|
|
tmp = _XkbCheckAtoms(tmp, width[i], client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
}
|
|
if (stuff->which & XkbIndicatorNamesMask) {
|
|
if (stuff->indicators == 0) {
|
|
client->errorValue = 0x08;
|
|
return BadMatch;
|
|
}
|
|
tmp = _XkbCheckMaskedAtoms(tmp, XkbNumIndicators, stuff->indicators,
|
|
client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbVirtualModNamesMask) {
|
|
if (stuff->virtualMods == 0) {
|
|
client->errorValue = 0x09;
|
|
return BadMatch;
|
|
}
|
|
tmp = _XkbCheckMaskedAtoms(tmp, XkbNumVirtualMods,
|
|
(CARD32) stuff->virtualMods,
|
|
client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbGroupNamesMask) {
|
|
if (stuff->groupNames == 0) {
|
|
client->errorValue = 0x0a;
|
|
return BadMatch;
|
|
}
|
|
tmp = _XkbCheckMaskedAtoms(tmp, XkbNumKbdGroups,
|
|
(CARD32) stuff->groupNames,
|
|
client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbKeyNamesMask) {
|
|
if (stuff->firstKey < (unsigned) xkb->min_key_code) {
|
|
client->errorValue = _XkbErrCode3(0x0b, xkb->min_key_code,
|
|
stuff->firstKey);
|
|
return BadValue;
|
|
}
|
|
if (((unsigned) (stuff->firstKey + stuff->nKeys - 1) >
|
|
xkb->max_key_code) || (stuff->nKeys < 1)) {
|
|
client->errorValue =
|
|
_XkbErrCode4(0x0c, xkb->max_key_code, stuff->firstKey,
|
|
stuff->nKeys);
|
|
return BadValue;
|
|
}
|
|
tmp += stuff->nKeys;
|
|
}
|
|
if ((stuff->which & XkbKeyAliasesMask) && (stuff->nKeyAliases > 0)) {
|
|
tmp += stuff->nKeyAliases * 2;
|
|
}
|
|
if (stuff->which & XkbRGNamesMask) {
|
|
if (stuff->nRadioGroups < 1) {
|
|
client->errorValue = _XkbErrCode2(0x0d, stuff->nRadioGroups);
|
|
return BadValue;
|
|
}
|
|
tmp = _XkbCheckAtoms(tmp, stuff->nRadioGroups, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if ((tmp - ((CARD32 *) stuff)) != stuff->length) {
|
|
client->errorValue = stuff->length;
|
|
return BadLength;
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
_XkbSetNames(ClientPtr client, DeviceIntPtr dev, xkbSetNamesReq * stuff)
|
|
{
|
|
XkbDescRec *xkb;
|
|
XkbNamesRec *names;
|
|
CARD32 *tmp;
|
|
xkbNamesNotify nn;
|
|
|
|
tmp = (CARD32 *) &stuff[1];
|
|
xkb = dev->key->xkbInfo->desc;
|
|
names = xkb->names;
|
|
|
|
if (XkbAllocNames(xkb, stuff->which, stuff->nRadioGroups,
|
|
stuff->nKeyAliases) != Success) {
|
|
return BadAlloc;
|
|
}
|
|
|
|
memset(&nn, 0, sizeof(xkbNamesNotify));
|
|
nn.changed = stuff->which;
|
|
tmp = (CARD32 *) &stuff[1];
|
|
if (stuff->which & XkbKeycodesNameMask)
|
|
names->keycodes = *tmp++;
|
|
if (stuff->which & XkbGeometryNameMask)
|
|
names->geometry = *tmp++;
|
|
if (stuff->which & XkbSymbolsNameMask)
|
|
names->symbols = *tmp++;
|
|
if (stuff->which & XkbPhysSymbolsNameMask)
|
|
names->phys_symbols = *tmp++;
|
|
if (stuff->which & XkbTypesNameMask)
|
|
names->types = *tmp++;
|
|
if (stuff->which & XkbCompatNameMask)
|
|
names->compat = *tmp++;
|
|
if ((stuff->which & XkbKeyTypeNamesMask) && (stuff->nTypes > 0)) {
|
|
register unsigned i;
|
|
register XkbKeyTypePtr type;
|
|
|
|
type = &xkb->map->types[stuff->firstType];
|
|
for (i = 0; i < stuff->nTypes; i++, type++) {
|
|
type->name = *tmp++;
|
|
}
|
|
nn.firstType = stuff->firstType;
|
|
nn.nTypes = stuff->nTypes;
|
|
}
|
|
if (stuff->which & XkbKTLevelNamesMask) {
|
|
register XkbKeyTypePtr type;
|
|
register unsigned i;
|
|
CARD8 *width;
|
|
|
|
width = (CARD8 *) tmp;
|
|
tmp = (CARD32 *) (((char *) tmp) + XkbPaddedSize(stuff->nKTLevels));
|
|
type = &xkb->map->types[stuff->firstKTLevel];
|
|
for (i = 0; i < stuff->nKTLevels; i++, type++) {
|
|
if (width[i] > 0) {
|
|
if (type->level_names) {
|
|
register unsigned n;
|
|
|
|
for (n = 0; n < width[i]; n++) {
|
|
type->level_names[n] = tmp[n];
|
|
}
|
|
}
|
|
tmp += width[i];
|
|
}
|
|
}
|
|
nn.firstLevelName = 0;
|
|
nn.nLevelNames = stuff->nTypes;
|
|
}
|
|
if (stuff->which & XkbIndicatorNamesMask) {
|
|
tmp = _XkbCopyMaskedAtoms(tmp, names->indicators, XkbNumIndicators,
|
|
stuff->indicators);
|
|
nn.changedIndicators = stuff->indicators;
|
|
}
|
|
if (stuff->which & XkbVirtualModNamesMask) {
|
|
tmp = _XkbCopyMaskedAtoms(tmp, names->vmods, XkbNumVirtualMods,
|
|
stuff->virtualMods);
|
|
nn.changedVirtualMods = stuff->virtualMods;
|
|
}
|
|
if (stuff->which & XkbGroupNamesMask) {
|
|
tmp = _XkbCopyMaskedAtoms(tmp, names->groups, XkbNumKbdGroups,
|
|
stuff->groupNames);
|
|
nn.changedVirtualMods = stuff->groupNames;
|
|
}
|
|
if (stuff->which & XkbKeyNamesMask) {
|
|
memcpy((char *) &names->keys[stuff->firstKey], (char *) tmp,
|
|
stuff->nKeys * XkbKeyNameLength);
|
|
tmp += stuff->nKeys;
|
|
nn.firstKey = stuff->firstKey;
|
|
nn.nKeys = stuff->nKeys;
|
|
}
|
|
if (stuff->which & XkbKeyAliasesMask) {
|
|
if (stuff->nKeyAliases > 0) {
|
|
register int na = stuff->nKeyAliases;
|
|
|
|
if (XkbAllocNames(xkb, XkbKeyAliasesMask, 0, na) != Success)
|
|
return BadAlloc;
|
|
memcpy((char *) names->key_aliases, (char *) tmp,
|
|
stuff->nKeyAliases * sizeof(XkbKeyAliasRec));
|
|
tmp += stuff->nKeyAliases * 2;
|
|
}
|
|
else if (names->key_aliases != NULL) {
|
|
free(names->key_aliases);
|
|
names->key_aliases = NULL;
|
|
names->num_key_aliases = 0;
|
|
}
|
|
nn.nAliases = names->num_key_aliases;
|
|
}
|
|
if (stuff->which & XkbRGNamesMask) {
|
|
if (stuff->nRadioGroups > 0) {
|
|
register unsigned i, nrg;
|
|
|
|
nrg = stuff->nRadioGroups;
|
|
if (XkbAllocNames(xkb, XkbRGNamesMask, nrg, 0) != Success)
|
|
return BadAlloc;
|
|
|
|
for (i = 0; i < stuff->nRadioGroups; i++) {
|
|
names->radio_groups[i] = tmp[i];
|
|
}
|
|
tmp += stuff->nRadioGroups;
|
|
}
|
|
else if (names->radio_groups) {
|
|
free(names->radio_groups);
|
|
names->radio_groups = NULL;
|
|
names->num_rg = 0;
|
|
}
|
|
nn.nRadioGroups = names->num_rg;
|
|
}
|
|
if (nn.changed) {
|
|
Bool needExtEvent;
|
|
|
|
needExtEvent = (nn.changed & XkbIndicatorNamesMask) != 0;
|
|
XkbSendNamesNotify(dev, &nn);
|
|
if (needExtEvent) {
|
|
XkbSrvLedInfoPtr sli;
|
|
xkbExtensionDeviceNotify edev;
|
|
register int i;
|
|
register unsigned bit;
|
|
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId,
|
|
XkbXI_IndicatorsMask);
|
|
sli->namesPresent = 0;
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (names->indicators[i] != None)
|
|
sli->namesPresent |= bit;
|
|
}
|
|
memset(&edev, 0, sizeof(xkbExtensionDeviceNotify));
|
|
edev.reason = XkbXI_IndicatorNamesMask;
|
|
edev.ledClass = KbdFeedbackClass;
|
|
edev.ledID = dev->kbdfeed->ctrl.id;
|
|
edev.ledsDefined = sli->namesPresent | sli->mapsPresent;
|
|
edev.ledState = sli->effectiveState;
|
|
edev.firstBtn = 0;
|
|
edev.nBtns = 0;
|
|
edev.supported = XkbXI_AllFeaturesMask;
|
|
edev.unsupported = 0;
|
|
XkbSendExtensionDeviceNotify(dev, client, &edev);
|
|
}
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetNames(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
CARD32 *tmp;
|
|
Atom bad;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetNamesReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetNamesReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
CHK_MASK_LEGAL(0x01, stuff->which, XkbAllNamesMask);
|
|
|
|
/* check device-independent stuff */
|
|
tmp = (CARD32 *) &stuff[1];
|
|
|
|
if (stuff->which & XkbKeycodesNameMask) {
|
|
tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbGeometryNameMask) {
|
|
tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbSymbolsNameMask) {
|
|
tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbPhysSymbolsNameMask) {
|
|
tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbTypesNameMask) {
|
|
tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
if (stuff->which & XkbCompatNameMask) {
|
|
tmp = _XkbCheckAtoms(tmp, 1, client->swapped, &bad);
|
|
if (!tmp) {
|
|
client->errorValue = bad;
|
|
return BadAtom;
|
|
}
|
|
}
|
|
|
|
/* start of device-dependent tests */
|
|
rc = _XkbSetNamesCheck(client, dev, stuff, tmp);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success) {
|
|
rc = _XkbSetNamesCheck(client, other, stuff, tmp);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* everything is okay -- update names */
|
|
|
|
rc = _XkbSetNames(client, dev, stuff);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success)
|
|
_XkbSetNames(client, other, stuff);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* everything is okay -- update names */
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
#include "xkbgeom.h"
|
|
|
|
#define XkbSizeCountedString(s) ((s)?((((2+strlen(s))+3)/4)*4):4)
|
|
|
|
/**
|
|
* Write the zero-terminated string str into wire as a pascal string with a
|
|
* 16-bit length field prefixed before the actual string.
|
|
*
|
|
* @param wire The destination array, usually the wire struct
|
|
* @param str The source string as zero-terminated C string
|
|
* @param swap If TRUE, the length field is swapped.
|
|
*
|
|
* @return The input string in the format <string length><string> with a
|
|
* (swapped) 16 bit string length, non-zero terminated.
|
|
*/
|
|
static char *
|
|
XkbWriteCountedString(char *wire, const char *str, Bool swap)
|
|
{
|
|
CARD16 len, *pLen, paddedLen;
|
|
|
|
if (!str)
|
|
return wire;
|
|
|
|
len = strlen(str);
|
|
pLen = (CARD16 *) wire;
|
|
*pLen = len;
|
|
if (swap) {
|
|
swaps(pLen);
|
|
}
|
|
paddedLen = pad_to_int32(sizeof(len) + len) - sizeof(len);
|
|
strncpy(&wire[sizeof(len)], str, paddedLen);
|
|
wire += sizeof(len) + paddedLen;
|
|
return wire;
|
|
}
|
|
|
|
static int
|
|
XkbSizeGeomProperties(XkbGeometryPtr geom)
|
|
{
|
|
register int i, size;
|
|
XkbPropertyPtr prop;
|
|
|
|
for (size = i = 0, prop = geom->properties; i < geom->num_properties;
|
|
i++, prop++) {
|
|
size += XkbSizeCountedString(prop->name);
|
|
size += XkbSizeCountedString(prop->value);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomProperties(char *wire, XkbGeometryPtr geom, Bool swap)
|
|
{
|
|
register int i;
|
|
register XkbPropertyPtr prop;
|
|
|
|
for (i = 0, prop = geom->properties; i < geom->num_properties; i++, prop++) {
|
|
wire = XkbWriteCountedString(wire, prop->name, swap);
|
|
wire = XkbWriteCountedString(wire, prop->value, swap);
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static int
|
|
XkbSizeGeomKeyAliases(XkbGeometryPtr geom)
|
|
{
|
|
return geom->num_key_aliases * (2 * XkbKeyNameLength);
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomKeyAliases(char *wire, XkbGeometryPtr geom, Bool swap)
|
|
{
|
|
register int sz;
|
|
|
|
sz = geom->num_key_aliases * (XkbKeyNameLength * 2);
|
|
if (sz > 0) {
|
|
memcpy(wire, (char *) geom->key_aliases, sz);
|
|
wire += sz;
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static int
|
|
XkbSizeGeomColors(XkbGeometryPtr geom)
|
|
{
|
|
register int i, size;
|
|
register XkbColorPtr color;
|
|
|
|
for (i = size = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
|
|
size += XkbSizeCountedString(color->spec);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomColors(char *wire, XkbGeometryPtr geom, Bool swap)
|
|
{
|
|
register int i;
|
|
register XkbColorPtr color;
|
|
|
|
for (i = 0, color = geom->colors; i < geom->num_colors; i++, color++) {
|
|
wire = XkbWriteCountedString(wire, color->spec, swap);
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static int
|
|
XkbSizeGeomShapes(XkbGeometryPtr geom)
|
|
{
|
|
register int i, size;
|
|
register XkbShapePtr shape;
|
|
|
|
for (i = size = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
|
|
register int n;
|
|
register XkbOutlinePtr ol;
|
|
|
|
size += SIZEOF(xkbShapeWireDesc);
|
|
for (n = 0, ol = shape->outlines; n < shape->num_outlines; n++, ol++) {
|
|
size += SIZEOF(xkbOutlineWireDesc);
|
|
size += ol->num_points * SIZEOF(xkbPointWireDesc);
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomShapes(char *wire, XkbGeometryPtr geom, Bool swap)
|
|
{
|
|
int i;
|
|
XkbShapePtr shape;
|
|
xkbShapeWireDesc *shapeWire;
|
|
|
|
for (i = 0, shape = geom->shapes; i < geom->num_shapes; i++, shape++) {
|
|
register int o;
|
|
XkbOutlinePtr ol;
|
|
xkbOutlineWireDesc *olWire;
|
|
|
|
shapeWire = (xkbShapeWireDesc *) wire;
|
|
shapeWire->name = shape->name;
|
|
shapeWire->nOutlines = shape->num_outlines;
|
|
if (shape->primary != NULL)
|
|
shapeWire->primaryNdx = XkbOutlineIndex(shape, shape->primary);
|
|
else
|
|
shapeWire->primaryNdx = XkbNoShape;
|
|
if (shape->approx != NULL)
|
|
shapeWire->approxNdx = XkbOutlineIndex(shape, shape->approx);
|
|
else
|
|
shapeWire->approxNdx = XkbNoShape;
|
|
shapeWire->pad = 0;
|
|
if (swap) {
|
|
swapl(&shapeWire->name);
|
|
}
|
|
wire = (char *) &shapeWire[1];
|
|
for (o = 0, ol = shape->outlines; o < shape->num_outlines; o++, ol++) {
|
|
register int p;
|
|
XkbPointPtr pt;
|
|
xkbPointWireDesc *ptWire;
|
|
|
|
olWire = (xkbOutlineWireDesc *) wire;
|
|
olWire->nPoints = ol->num_points;
|
|
olWire->cornerRadius = ol->corner_radius;
|
|
olWire->pad = 0;
|
|
wire = (char *) &olWire[1];
|
|
ptWire = (xkbPointWireDesc *) wire;
|
|
for (p = 0, pt = ol->points; p < ol->num_points; p++, pt++) {
|
|
ptWire[p].x = pt->x;
|
|
ptWire[p].y = pt->y;
|
|
if (swap) {
|
|
swaps(&ptWire[p].x);
|
|
swaps(&ptWire[p].y);
|
|
}
|
|
}
|
|
wire = (char *) &ptWire[ol->num_points];
|
|
}
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static int
|
|
XkbSizeGeomDoodads(int num_doodads, XkbDoodadPtr doodad)
|
|
{
|
|
register int i, size;
|
|
|
|
for (i = size = 0; i < num_doodads; i++, doodad++) {
|
|
size += SIZEOF(xkbAnyDoodadWireDesc);
|
|
if (doodad->any.type == XkbTextDoodad) {
|
|
size += XkbSizeCountedString(doodad->text.text);
|
|
size += XkbSizeCountedString(doodad->text.font);
|
|
}
|
|
else if (doodad->any.type == XkbLogoDoodad) {
|
|
size += XkbSizeCountedString(doodad->logo.logo_name);
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomDoodads(char *wire, int num_doodads, XkbDoodadPtr doodad, Bool swap)
|
|
{
|
|
register int i;
|
|
xkbDoodadWireDesc *doodadWire;
|
|
|
|
for (i = 0; i < num_doodads; i++, doodad++) {
|
|
doodadWire = (xkbDoodadWireDesc *) wire;
|
|
wire = (char *) &doodadWire[1];
|
|
memset(doodadWire, 0, SIZEOF(xkbDoodadWireDesc));
|
|
doodadWire->any.name = doodad->any.name;
|
|
doodadWire->any.type = doodad->any.type;
|
|
doodadWire->any.priority = doodad->any.priority;
|
|
doodadWire->any.top = doodad->any.top;
|
|
doodadWire->any.left = doodad->any.left;
|
|
if (swap) {
|
|
swapl(&doodadWire->any.name);
|
|
swaps(&doodadWire->any.top);
|
|
swaps(&doodadWire->any.left);
|
|
}
|
|
switch (doodad->any.type) {
|
|
case XkbOutlineDoodad:
|
|
case XkbSolidDoodad:
|
|
doodadWire->shape.angle = doodad->shape.angle;
|
|
doodadWire->shape.colorNdx = doodad->shape.color_ndx;
|
|
doodadWire->shape.shapeNdx = doodad->shape.shape_ndx;
|
|
if (swap) {
|
|
swaps(&doodadWire->shape.angle);
|
|
}
|
|
break;
|
|
case XkbTextDoodad:
|
|
doodadWire->text.angle = doodad->text.angle;
|
|
doodadWire->text.width = doodad->text.width;
|
|
doodadWire->text.height = doodad->text.height;
|
|
doodadWire->text.colorNdx = doodad->text.color_ndx;
|
|
if (swap) {
|
|
swaps(&doodadWire->text.angle);
|
|
swaps(&doodadWire->text.width);
|
|
swaps(&doodadWire->text.height);
|
|
}
|
|
wire = XkbWriteCountedString(wire, doodad->text.text, swap);
|
|
wire = XkbWriteCountedString(wire, doodad->text.font, swap);
|
|
break;
|
|
case XkbIndicatorDoodad:
|
|
doodadWire->indicator.shapeNdx = doodad->indicator.shape_ndx;
|
|
doodadWire->indicator.onColorNdx = doodad->indicator.on_color_ndx;
|
|
doodadWire->indicator.offColorNdx = doodad->indicator.off_color_ndx;
|
|
break;
|
|
case XkbLogoDoodad:
|
|
doodadWire->logo.angle = doodad->logo.angle;
|
|
doodadWire->logo.colorNdx = doodad->logo.color_ndx;
|
|
doodadWire->logo.shapeNdx = doodad->logo.shape_ndx;
|
|
wire = XkbWriteCountedString(wire, doodad->logo.logo_name, swap);
|
|
break;
|
|
default:
|
|
ErrorF("[xkb] Unknown doodad type %d in XkbWriteGeomDoodads\n",
|
|
doodad->any.type);
|
|
ErrorF("[xkb] Ignored\n");
|
|
break;
|
|
}
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomOverlay(char *wire, XkbOverlayPtr ol, Bool swap)
|
|
{
|
|
register int r;
|
|
XkbOverlayRowPtr row;
|
|
xkbOverlayWireDesc *olWire;
|
|
|
|
olWire = (xkbOverlayWireDesc *) wire;
|
|
olWire->name = ol->name;
|
|
olWire->nRows = ol->num_rows;
|
|
olWire->pad1 = 0;
|
|
olWire->pad2 = 0;
|
|
if (swap) {
|
|
swapl(&olWire->name);
|
|
}
|
|
wire = (char *) &olWire[1];
|
|
for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
|
|
unsigned int k;
|
|
XkbOverlayKeyPtr key;
|
|
xkbOverlayRowWireDesc *rowWire;
|
|
|
|
rowWire = (xkbOverlayRowWireDesc *) wire;
|
|
rowWire->rowUnder = row->row_under;
|
|
rowWire->nKeys = row->num_keys;
|
|
rowWire->pad1 = 0;
|
|
wire = (char *) &rowWire[1];
|
|
for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
|
|
xkbOverlayKeyWireDesc *keyWire;
|
|
|
|
keyWire = (xkbOverlayKeyWireDesc *) wire;
|
|
memcpy(keyWire->over, key->over.name, XkbKeyNameLength);
|
|
memcpy(keyWire->under, key->under.name, XkbKeyNameLength);
|
|
wire = (char *) &keyWire[1];
|
|
}
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static int
|
|
XkbSizeGeomSections(XkbGeometryPtr geom)
|
|
{
|
|
register int i, size;
|
|
XkbSectionPtr section;
|
|
|
|
for (i = size = 0, section = geom->sections; i < geom->num_sections;
|
|
i++, section++) {
|
|
size += SIZEOF(xkbSectionWireDesc);
|
|
if (section->rows) {
|
|
int r;
|
|
XkbRowPtr row;
|
|
|
|
for (r = 0, row = section->rows; r < section->num_rows; row++, r++) {
|
|
size += SIZEOF(xkbRowWireDesc);
|
|
size += row->num_keys * SIZEOF(xkbKeyWireDesc);
|
|
}
|
|
}
|
|
if (section->doodads)
|
|
size += XkbSizeGeomDoodads(section->num_doodads, section->doodads);
|
|
if (section->overlays) {
|
|
int o;
|
|
XkbOverlayPtr ol;
|
|
|
|
for (o = 0, ol = section->overlays; o < section->num_overlays;
|
|
o++, ol++) {
|
|
int r;
|
|
XkbOverlayRowPtr row;
|
|
|
|
size += SIZEOF(xkbOverlayWireDesc);
|
|
for (r = 0, row = ol->rows; r < ol->num_rows; r++, row++) {
|
|
size += SIZEOF(xkbOverlayRowWireDesc);
|
|
size += row->num_keys * SIZEOF(xkbOverlayKeyWireDesc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static char *
|
|
XkbWriteGeomSections(char *wire, XkbGeometryPtr geom, Bool swap)
|
|
{
|
|
register int i;
|
|
XkbSectionPtr section;
|
|
xkbSectionWireDesc *sectionWire;
|
|
|
|
for (i = 0, section = geom->sections; i < geom->num_sections;
|
|
i++, section++) {
|
|
sectionWire = (xkbSectionWireDesc *) wire;
|
|
sectionWire->name = section->name;
|
|
sectionWire->top = section->top;
|
|
sectionWire->left = section->left;
|
|
sectionWire->width = section->width;
|
|
sectionWire->height = section->height;
|
|
sectionWire->angle = section->angle;
|
|
sectionWire->priority = section->priority;
|
|
sectionWire->nRows = section->num_rows;
|
|
sectionWire->nDoodads = section->num_doodads;
|
|
sectionWire->nOverlays = section->num_overlays;
|
|
sectionWire->pad = 0;
|
|
if (swap) {
|
|
swapl(§ionWire->name);
|
|
swaps(§ionWire->top);
|
|
swaps(§ionWire->left);
|
|
swaps(§ionWire->width);
|
|
swaps(§ionWire->height);
|
|
swaps(§ionWire->angle);
|
|
}
|
|
wire = (char *) §ionWire[1];
|
|
if (section->rows) {
|
|
int r;
|
|
XkbRowPtr row;
|
|
xkbRowWireDesc *rowWire;
|
|
|
|
for (r = 0, row = section->rows; r < section->num_rows; r++, row++) {
|
|
rowWire = (xkbRowWireDesc *) wire;
|
|
rowWire->top = row->top;
|
|
rowWire->left = row->left;
|
|
rowWire->nKeys = row->num_keys;
|
|
rowWire->vertical = row->vertical;
|
|
rowWire->pad = 0;
|
|
if (swap) {
|
|
swaps(&rowWire->top);
|
|
swaps(&rowWire->left);
|
|
}
|
|
wire = (char *) &rowWire[1];
|
|
if (row->keys) {
|
|
int k;
|
|
XkbKeyPtr key;
|
|
xkbKeyWireDesc *keyWire;
|
|
|
|
keyWire = (xkbKeyWireDesc *) wire;
|
|
for (k = 0, key = row->keys; k < row->num_keys; k++, key++) {
|
|
memcpy(keyWire[k].name, key->name.name,
|
|
XkbKeyNameLength);
|
|
keyWire[k].gap = key->gap;
|
|
keyWire[k].shapeNdx = key->shape_ndx;
|
|
keyWire[k].colorNdx = key->color_ndx;
|
|
if (swap) {
|
|
swaps(&keyWire[k].gap);
|
|
}
|
|
}
|
|
wire = (char *) &keyWire[row->num_keys];
|
|
}
|
|
}
|
|
}
|
|
if (section->doodads) {
|
|
wire = XkbWriteGeomDoodads(wire,
|
|
section->num_doodads, section->doodads,
|
|
swap);
|
|
}
|
|
if (section->overlays) {
|
|
register int o;
|
|
|
|
for (o = 0; o < section->num_overlays; o++) {
|
|
wire = XkbWriteGeomOverlay(wire, §ion->overlays[o], swap);
|
|
}
|
|
}
|
|
}
|
|
return wire;
|
|
}
|
|
|
|
static Status
|
|
XkbComputeGetGeometryReplySize(XkbGeometryPtr geom,
|
|
xkbGetGeometryReply * rep, Atom name)
|
|
{
|
|
int len;
|
|
|
|
if (geom != NULL) {
|
|
len = XkbSizeCountedString(geom->label_font);
|
|
len += XkbSizeGeomProperties(geom);
|
|
len += XkbSizeGeomColors(geom);
|
|
len += XkbSizeGeomShapes(geom);
|
|
len += XkbSizeGeomSections(geom);
|
|
len += XkbSizeGeomDoodads(geom->num_doodads, geom->doodads);
|
|
len += XkbSizeGeomKeyAliases(geom);
|
|
rep->length = len / 4;
|
|
rep->found = TRUE;
|
|
rep->name = geom->name;
|
|
rep->widthMM = geom->width_mm;
|
|
rep->heightMM = geom->height_mm;
|
|
rep->nProperties = geom->num_properties;
|
|
rep->nColors = geom->num_colors;
|
|
rep->nShapes = geom->num_shapes;
|
|
rep->nSections = geom->num_sections;
|
|
rep->nDoodads = geom->num_doodads;
|
|
rep->nKeyAliases = geom->num_key_aliases;
|
|
rep->baseColorNdx = XkbGeomColorIndex(geom, geom->base_color);
|
|
rep->labelColorNdx = XkbGeomColorIndex(geom, geom->label_color);
|
|
}
|
|
else {
|
|
rep->length = 0;
|
|
rep->found = FALSE;
|
|
rep->name = name;
|
|
rep->widthMM = rep->heightMM = 0;
|
|
rep->nProperties = rep->nColors = rep->nShapes = 0;
|
|
rep->nSections = rep->nDoodads = 0;
|
|
rep->nKeyAliases = 0;
|
|
rep->labelColorNdx = rep->baseColorNdx = 0;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
XkbSendGeometry(ClientPtr client,
|
|
XkbGeometryPtr geom, xkbGetGeometryReply * rep, Bool freeGeom)
|
|
{
|
|
char *desc, *start;
|
|
int len;
|
|
|
|
if (geom != NULL) {
|
|
len = rep->length * 4;
|
|
start = desc = malloc(len);
|
|
if (!start)
|
|
return BadAlloc;
|
|
desc = XkbWriteCountedString(desc, geom->label_font, client->swapped);
|
|
if (rep->nProperties > 0)
|
|
desc = XkbWriteGeomProperties(desc, geom, client->swapped);
|
|
if (rep->nColors > 0)
|
|
desc = XkbWriteGeomColors(desc, geom, client->swapped);
|
|
if (rep->nShapes > 0)
|
|
desc = XkbWriteGeomShapes(desc, geom, client->swapped);
|
|
if (rep->nSections > 0)
|
|
desc = XkbWriteGeomSections(desc, geom, client->swapped);
|
|
if (rep->nDoodads > 0)
|
|
desc = XkbWriteGeomDoodads(desc, geom->num_doodads, geom->doodads,
|
|
client->swapped);
|
|
if (rep->nKeyAliases > 0)
|
|
desc = XkbWriteGeomKeyAliases(desc, geom, client->swapped);
|
|
if ((desc - start) != (len)) {
|
|
ErrorF
|
|
("[xkb] BOGUS LENGTH in XkbSendGeometry, expected %d, got %ld\n",
|
|
len, (unsigned long) (desc - start));
|
|
}
|
|
}
|
|
else {
|
|
len = 0;
|
|
start = NULL;
|
|
}
|
|
if (client->swapped) {
|
|
swaps(&rep->sequenceNumber);
|
|
swapl(&rep->length);
|
|
swapl(&rep->name);
|
|
swaps(&rep->widthMM);
|
|
swaps(&rep->heightMM);
|
|
swaps(&rep->nProperties);
|
|
swaps(&rep->nColors);
|
|
swaps(&rep->nShapes);
|
|
swaps(&rep->nSections);
|
|
swaps(&rep->nDoodads);
|
|
swaps(&rep->nKeyAliases);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetGeometryReply), rep);
|
|
if (len > 0)
|
|
WriteToClient(client, len, start);
|
|
if (start != NULL)
|
|
free((char *) start);
|
|
if (freeGeom)
|
|
XkbFreeGeometry(geom, XkbGeomAllMask, TRUE);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbGetGeometry(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
xkbGetGeometryReply rep;
|
|
XkbGeometryPtr geom;
|
|
Bool shouldFree;
|
|
Status status;
|
|
|
|
REQUEST(xkbGetGeometryReq);
|
|
REQUEST_SIZE_MATCH(xkbGetGeometryReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
CHK_ATOM_OR_NONE(stuff->name);
|
|
|
|
geom = XkbLookupNamedGeometry(dev, stuff->name, &shouldFree);
|
|
rep = (xkbGetGeometryReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0
|
|
};
|
|
status = XkbComputeGetGeometryReplySize(geom, &rep, stuff->name);
|
|
if (status != Success)
|
|
return status;
|
|
else
|
|
return XkbSendGeometry(client, geom, &rep, shouldFree);
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static Status
|
|
_GetCountedString(char **wire_inout, ClientPtr client, char **str)
|
|
{
|
|
char *wire, *next;
|
|
CARD16 len;
|
|
|
|
wire = *wire_inout;
|
|
len = *(CARD16 *) wire;
|
|
if (client->swapped) {
|
|
swaps(&len);
|
|
}
|
|
next = wire + XkbPaddedSize(len + 2);
|
|
/* Check we're still within the size of the request */
|
|
if (client->req_len <
|
|
bytes_to_int32(next - (char *) client->requestBuffer))
|
|
return BadValue;
|
|
*str = malloc(len + 1);
|
|
if (!*str)
|
|
return BadAlloc;
|
|
memcpy(*str, &wire[2], len);
|
|
*(*str + len) = '\0';
|
|
*wire_inout = next;
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
_CheckSetDoodad(char **wire_inout,
|
|
XkbGeometryPtr geom, XkbSectionPtr section, ClientPtr client)
|
|
{
|
|
char *wire;
|
|
xkbDoodadWireDesc *dWire;
|
|
xkbAnyDoodadWireDesc any;
|
|
xkbTextDoodadWireDesc text;
|
|
XkbDoodadPtr doodad;
|
|
Status status;
|
|
|
|
dWire = (xkbDoodadWireDesc *) (*wire_inout);
|
|
any = dWire->any;
|
|
wire = (char *) &dWire[1];
|
|
if (client->swapped) {
|
|
swapl(&any.name);
|
|
swaps(&any.top);
|
|
swaps(&any.left);
|
|
swaps(&any.angle);
|
|
}
|
|
CHK_ATOM_ONLY(dWire->any.name);
|
|
doodad = XkbAddGeomDoodad(geom, section, any.name);
|
|
if (!doodad)
|
|
return BadAlloc;
|
|
doodad->any.type = dWire->any.type;
|
|
doodad->any.priority = dWire->any.priority;
|
|
doodad->any.top = any.top;
|
|
doodad->any.left = any.left;
|
|
doodad->any.angle = any.angle;
|
|
switch (doodad->any.type) {
|
|
case XkbOutlineDoodad:
|
|
case XkbSolidDoodad:
|
|
if (dWire->shape.colorNdx >= geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x40, geom->num_colors,
|
|
dWire->shape.colorNdx);
|
|
return BadMatch;
|
|
}
|
|
if (dWire->shape.shapeNdx >= geom->num_shapes) {
|
|
client->errorValue = _XkbErrCode3(0x41, geom->num_shapes,
|
|
dWire->shape.shapeNdx);
|
|
return BadMatch;
|
|
}
|
|
doodad->shape.color_ndx = dWire->shape.colorNdx;
|
|
doodad->shape.shape_ndx = dWire->shape.shapeNdx;
|
|
break;
|
|
case XkbTextDoodad:
|
|
if (dWire->text.colorNdx >= geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x42, geom->num_colors,
|
|
dWire->text.colorNdx);
|
|
return BadMatch;
|
|
}
|
|
text = dWire->text;
|
|
if (client->swapped) {
|
|
swaps(&text.width);
|
|
swaps(&text.height);
|
|
}
|
|
doodad->text.width = text.width;
|
|
doodad->text.height = text.height;
|
|
doodad->text.color_ndx = dWire->text.colorNdx;
|
|
status = _GetCountedString(&wire, client, &doodad->text.text);
|
|
if (status != Success)
|
|
return status;
|
|
status = _GetCountedString(&wire, client, &doodad->text.font);
|
|
if (status != Success) {
|
|
free (doodad->text.text);
|
|
return status;
|
|
}
|
|
break;
|
|
case XkbIndicatorDoodad:
|
|
if (dWire->indicator.onColorNdx >= geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x43, geom->num_colors,
|
|
dWire->indicator.onColorNdx);
|
|
return BadMatch;
|
|
}
|
|
if (dWire->indicator.offColorNdx >= geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x44, geom->num_colors,
|
|
dWire->indicator.offColorNdx);
|
|
return BadMatch;
|
|
}
|
|
if (dWire->indicator.shapeNdx >= geom->num_shapes) {
|
|
client->errorValue = _XkbErrCode3(0x45, geom->num_shapes,
|
|
dWire->indicator.shapeNdx);
|
|
return BadMatch;
|
|
}
|
|
doodad->indicator.shape_ndx = dWire->indicator.shapeNdx;
|
|
doodad->indicator.on_color_ndx = dWire->indicator.onColorNdx;
|
|
doodad->indicator.off_color_ndx = dWire->indicator.offColorNdx;
|
|
break;
|
|
case XkbLogoDoodad:
|
|
if (dWire->logo.colorNdx >= geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x46, geom->num_colors,
|
|
dWire->logo.colorNdx);
|
|
return BadMatch;
|
|
}
|
|
if (dWire->logo.shapeNdx >= geom->num_shapes) {
|
|
client->errorValue = _XkbErrCode3(0x47, geom->num_shapes,
|
|
dWire->logo.shapeNdx);
|
|
return BadMatch;
|
|
}
|
|
doodad->logo.color_ndx = dWire->logo.colorNdx;
|
|
doodad->logo.shape_ndx = dWire->logo.shapeNdx;
|
|
status = _GetCountedString(&wire, client, &doodad->logo.logo_name);
|
|
if (status != Success)
|
|
return status;
|
|
break;
|
|
default:
|
|
client->errorValue = _XkbErrCode2(0x4F, dWire->any.type);
|
|
return BadValue;
|
|
}
|
|
*wire_inout = wire;
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
_CheckSetOverlay(char **wire_inout,
|
|
XkbGeometryPtr geom, XkbSectionPtr section, ClientPtr client)
|
|
{
|
|
register int r;
|
|
char *wire;
|
|
XkbOverlayPtr ol;
|
|
xkbOverlayWireDesc *olWire;
|
|
xkbOverlayRowWireDesc *rWire;
|
|
|
|
wire = *wire_inout;
|
|
olWire = (xkbOverlayWireDesc *) wire;
|
|
if (client->swapped) {
|
|
swapl(&olWire->name);
|
|
}
|
|
CHK_ATOM_ONLY(olWire->name);
|
|
ol = XkbAddGeomOverlay(section, olWire->name, olWire->nRows);
|
|
rWire = (xkbOverlayRowWireDesc *) &olWire[1];
|
|
for (r = 0; r < olWire->nRows; r++) {
|
|
register int k;
|
|
xkbOverlayKeyWireDesc *kWire;
|
|
XkbOverlayRowPtr row;
|
|
|
|
if (rWire->rowUnder > section->num_rows) {
|
|
client->errorValue = _XkbErrCode4(0x20, r, section->num_rows,
|
|
rWire->rowUnder);
|
|
return BadMatch;
|
|
}
|
|
row = XkbAddGeomOverlayRow(ol, rWire->rowUnder, rWire->nKeys);
|
|
kWire = (xkbOverlayKeyWireDesc *) &rWire[1];
|
|
for (k = 0; k < rWire->nKeys; k++, kWire++) {
|
|
if (XkbAddGeomOverlayKey(ol, row,
|
|
(char *) kWire->over,
|
|
(char *) kWire->under) == NULL) {
|
|
client->errorValue = _XkbErrCode3(0x21, r, k);
|
|
return BadMatch;
|
|
}
|
|
}
|
|
rWire = (xkbOverlayRowWireDesc *) kWire;
|
|
}
|
|
olWire = (xkbOverlayWireDesc *) rWire;
|
|
wire = (char *) olWire;
|
|
*wire_inout = wire;
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
_CheckSetSections(XkbGeometryPtr geom,
|
|
xkbSetGeometryReq * req, char **wire_inout, ClientPtr client)
|
|
{
|
|
Status status;
|
|
register int s;
|
|
char *wire;
|
|
xkbSectionWireDesc *sWire;
|
|
XkbSectionPtr section;
|
|
|
|
wire = *wire_inout;
|
|
if (req->nSections < 1)
|
|
return Success;
|
|
sWire = (xkbSectionWireDesc *) wire;
|
|
for (s = 0; s < req->nSections; s++) {
|
|
register int r;
|
|
xkbRowWireDesc *rWire;
|
|
|
|
if (client->swapped) {
|
|
swapl(&sWire->name);
|
|
swaps(&sWire->top);
|
|
swaps(&sWire->left);
|
|
swaps(&sWire->width);
|
|
swaps(&sWire->height);
|
|
swaps(&sWire->angle);
|
|
}
|
|
CHK_ATOM_ONLY(sWire->name);
|
|
section = XkbAddGeomSection(geom, sWire->name, sWire->nRows,
|
|
sWire->nDoodads, sWire->nOverlays);
|
|
if (!section)
|
|
return BadAlloc;
|
|
section->priority = sWire->priority;
|
|
section->top = sWire->top;
|
|
section->left = sWire->left;
|
|
section->width = sWire->width;
|
|
section->height = sWire->height;
|
|
section->angle = sWire->angle;
|
|
rWire = (xkbRowWireDesc *) &sWire[1];
|
|
for (r = 0; r < sWire->nRows; r++) {
|
|
register int k;
|
|
XkbRowPtr row;
|
|
xkbKeyWireDesc *kWire;
|
|
|
|
if (client->swapped) {
|
|
swaps(&rWire->top);
|
|
swaps(&rWire->left);
|
|
}
|
|
row = XkbAddGeomRow(section, rWire->nKeys);
|
|
if (!row)
|
|
return BadAlloc;
|
|
row->top = rWire->top;
|
|
row->left = rWire->left;
|
|
row->vertical = rWire->vertical;
|
|
kWire = (xkbKeyWireDesc *) &rWire[1];
|
|
for (k = 0; k < rWire->nKeys; k++) {
|
|
XkbKeyPtr key;
|
|
|
|
key = XkbAddGeomKey(row);
|
|
if (!key)
|
|
return BadAlloc;
|
|
memcpy(key->name.name, kWire[k].name, XkbKeyNameLength);
|
|
key->gap = kWire[k].gap;
|
|
key->shape_ndx = kWire[k].shapeNdx;
|
|
key->color_ndx = kWire[k].colorNdx;
|
|
if (key->shape_ndx >= geom->num_shapes) {
|
|
client->errorValue = _XkbErrCode3(0x10, key->shape_ndx,
|
|
geom->num_shapes);
|
|
return BadMatch;
|
|
}
|
|
if (key->color_ndx >= geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x11, key->color_ndx,
|
|
geom->num_colors);
|
|
return BadMatch;
|
|
}
|
|
}
|
|
rWire = (xkbRowWireDesc *) &kWire[rWire->nKeys];
|
|
}
|
|
wire = (char *) rWire;
|
|
if (sWire->nDoodads > 0) {
|
|
register int d;
|
|
|
|
for (d = 0; d < sWire->nDoodads; d++) {
|
|
status = _CheckSetDoodad(&wire, geom, section, client);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
}
|
|
if (sWire->nOverlays > 0) {
|
|
register int o;
|
|
|
|
for (o = 0; o < sWire->nOverlays; o++) {
|
|
status = _CheckSetOverlay(&wire, geom, section, client);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
}
|
|
sWire = (xkbSectionWireDesc *) wire;
|
|
}
|
|
wire = (char *) sWire;
|
|
*wire_inout = wire;
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
_CheckSetShapes(XkbGeometryPtr geom,
|
|
xkbSetGeometryReq * req, char **wire_inout, ClientPtr client)
|
|
{
|
|
register int i;
|
|
char *wire;
|
|
|
|
wire = *wire_inout;
|
|
if (req->nShapes < 1) {
|
|
client->errorValue = _XkbErrCode2(0x06, req->nShapes);
|
|
return BadValue;
|
|
}
|
|
else {
|
|
xkbShapeWireDesc *shapeWire;
|
|
XkbShapePtr shape;
|
|
register int o;
|
|
|
|
shapeWire = (xkbShapeWireDesc *) wire;
|
|
for (i = 0; i < req->nShapes; i++) {
|
|
xkbOutlineWireDesc *olWire;
|
|
XkbOutlinePtr ol;
|
|
|
|
shape =
|
|
XkbAddGeomShape(geom, shapeWire->name, shapeWire->nOutlines);
|
|
if (!shape)
|
|
return BadAlloc;
|
|
olWire = (xkbOutlineWireDesc *) (&shapeWire[1]);
|
|
for (o = 0; o < shapeWire->nOutlines; o++) {
|
|
register int p;
|
|
XkbPointPtr pt;
|
|
xkbPointWireDesc *ptWire;
|
|
|
|
ol = XkbAddGeomOutline(shape, olWire->nPoints);
|
|
if (!ol)
|
|
return BadAlloc;
|
|
ol->corner_radius = olWire->cornerRadius;
|
|
ptWire = (xkbPointWireDesc *) &olWire[1];
|
|
for (p = 0, pt = ol->points; p < olWire->nPoints; p++, pt++) {
|
|
pt->x = ptWire[p].x;
|
|
pt->y = ptWire[p].y;
|
|
if (client->swapped) {
|
|
swaps(&pt->x);
|
|
swaps(&pt->y);
|
|
}
|
|
}
|
|
ol->num_points = olWire->nPoints;
|
|
olWire = (xkbOutlineWireDesc *) (&ptWire[olWire->nPoints]);
|
|
}
|
|
if (shapeWire->primaryNdx != XkbNoShape)
|
|
shape->primary = &shape->outlines[shapeWire->primaryNdx];
|
|
if (shapeWire->approxNdx != XkbNoShape)
|
|
shape->approx = &shape->outlines[shapeWire->approxNdx];
|
|
shapeWire = (xkbShapeWireDesc *) olWire;
|
|
}
|
|
wire = (char *) shapeWire;
|
|
}
|
|
if (geom->num_shapes != req->nShapes) {
|
|
client->errorValue = _XkbErrCode3(0x07, geom->num_shapes, req->nShapes);
|
|
return BadMatch;
|
|
}
|
|
|
|
*wire_inout = wire;
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
_CheckSetGeom(XkbGeometryPtr geom, xkbSetGeometryReq * req, ClientPtr client)
|
|
{
|
|
register int i;
|
|
Status status;
|
|
char *wire;
|
|
|
|
wire = (char *) &req[1];
|
|
status = _GetCountedString(&wire, client, &geom->label_font);
|
|
if (status != Success)
|
|
return status;
|
|
|
|
for (i = 0; i < req->nProperties; i++) {
|
|
char *name, *val;
|
|
|
|
status = _GetCountedString(&wire, client, &name);
|
|
if (status != Success)
|
|
return status;
|
|
status = _GetCountedString(&wire, client, &val);
|
|
if (status != Success) {
|
|
free(name);
|
|
return status;
|
|
}
|
|
if (XkbAddGeomProperty(geom, name, val) == NULL) {
|
|
free(name);
|
|
free(val);
|
|
return BadAlloc;
|
|
}
|
|
free(name);
|
|
free(val);
|
|
}
|
|
|
|
if (req->nColors < 2) {
|
|
client->errorValue = _XkbErrCode3(0x01, 2, req->nColors);
|
|
return BadValue;
|
|
}
|
|
if (req->baseColorNdx > req->nColors) {
|
|
client->errorValue =
|
|
_XkbErrCode3(0x03, req->nColors, req->baseColorNdx);
|
|
return BadMatch;
|
|
}
|
|
if (req->labelColorNdx > req->nColors) {
|
|
client->errorValue =
|
|
_XkbErrCode3(0x03, req->nColors, req->labelColorNdx);
|
|
return BadMatch;
|
|
}
|
|
if (req->labelColorNdx == req->baseColorNdx) {
|
|
client->errorValue = _XkbErrCode3(0x04, req->baseColorNdx,
|
|
req->labelColorNdx);
|
|
return BadMatch;
|
|
}
|
|
|
|
for (i = 0; i < req->nColors; i++) {
|
|
char *name;
|
|
|
|
status = _GetCountedString(&wire, client, &name);
|
|
if (status != Success)
|
|
return status;
|
|
if (!XkbAddGeomColor(geom, name, geom->num_colors)) {
|
|
free(name);
|
|
return BadAlloc;
|
|
}
|
|
free(name);
|
|
}
|
|
if (req->nColors != geom->num_colors) {
|
|
client->errorValue = _XkbErrCode3(0x05, req->nColors, geom->num_colors);
|
|
return BadMatch;
|
|
}
|
|
geom->label_color = &geom->colors[req->labelColorNdx];
|
|
geom->base_color = &geom->colors[req->baseColorNdx];
|
|
|
|
if ((status = _CheckSetShapes(geom, req, &wire, client)) != Success)
|
|
return status;
|
|
|
|
if ((status = _CheckSetSections(geom, req, &wire, client)) != Success)
|
|
return status;
|
|
|
|
for (i = 0; i < req->nDoodads; i++) {
|
|
status = _CheckSetDoodad(&wire, geom, NULL, client);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
|
|
for (i = 0; i < req->nKeyAliases; i++) {
|
|
if (XkbAddGeomKeyAlias(geom, &wire[XkbKeyNameLength], wire) == NULL)
|
|
return BadAlloc;
|
|
wire += 2 * XkbKeyNameLength;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
_XkbSetGeometry(ClientPtr client, DeviceIntPtr dev, xkbSetGeometryReq * stuff)
|
|
{
|
|
XkbDescPtr xkb;
|
|
Bool new_name;
|
|
xkbNewKeyboardNotify nkn;
|
|
XkbGeometryPtr geom, old;
|
|
XkbGeometrySizesRec sizes;
|
|
Status status;
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
old = xkb->geom;
|
|
xkb->geom = NULL;
|
|
|
|
sizes.which = XkbGeomAllMask;
|
|
sizes.num_properties = stuff->nProperties;
|
|
sizes.num_colors = stuff->nColors;
|
|
sizes.num_shapes = stuff->nShapes;
|
|
sizes.num_sections = stuff->nSections;
|
|
sizes.num_doodads = stuff->nDoodads;
|
|
sizes.num_key_aliases = stuff->nKeyAliases;
|
|
if ((status = XkbAllocGeometry(xkb, &sizes)) != Success) {
|
|
xkb->geom = old;
|
|
return status;
|
|
}
|
|
geom = xkb->geom;
|
|
geom->name = stuff->name;
|
|
geom->width_mm = stuff->widthMM;
|
|
geom->height_mm = stuff->heightMM;
|
|
if ((status = _CheckSetGeom(geom, stuff, client)) != Success) {
|
|
XkbFreeGeometry(geom, XkbGeomAllMask, TRUE);
|
|
xkb->geom = old;
|
|
return status;
|
|
}
|
|
new_name = (xkb->names->geometry != geom->name);
|
|
xkb->names->geometry = geom->name;
|
|
if (old)
|
|
XkbFreeGeometry(old, XkbGeomAllMask, TRUE);
|
|
if (new_name) {
|
|
xkbNamesNotify nn;
|
|
|
|
memset(&nn, 0, sizeof(xkbNamesNotify));
|
|
nn.changed = XkbGeometryNameMask;
|
|
XkbSendNamesNotify(dev, &nn);
|
|
}
|
|
nkn.deviceID = nkn.oldDeviceID = dev->id;
|
|
nkn.minKeyCode = nkn.oldMinKeyCode = xkb->min_key_code;
|
|
nkn.maxKeyCode = nkn.oldMaxKeyCode = xkb->max_key_code;
|
|
nkn.requestMajor = XkbReqCode;
|
|
nkn.requestMinor = X_kbSetGeometry;
|
|
nkn.changed = XkbNKN_GeometryMask;
|
|
XkbSendNewKeyboardNotify(dev, &nkn);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetGeometry(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetGeometryReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetGeometryReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
CHK_ATOM_OR_NONE(stuff->name);
|
|
|
|
rc = _XkbSetGeometry(client, dev, stuff);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if ((other != dev) && other->key && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success)
|
|
_XkbSetGeometry(client, other, stuff);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbPerClientFlags(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
xkbPerClientFlagsReply rep;
|
|
XkbInterestPtr interest;
|
|
Mask access_mode = DixGetAttrAccess | DixSetAttrAccess;
|
|
|
|
REQUEST(xkbPerClientFlagsReq);
|
|
REQUEST_SIZE_MATCH(xkbPerClientFlagsReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode);
|
|
CHK_MASK_LEGAL(0x01, stuff->change, XkbPCF_AllFlagsMask);
|
|
CHK_MASK_MATCH(0x02, stuff->change, stuff->value);
|
|
|
|
interest = XkbFindClientResource((DevicePtr) dev, client);
|
|
if (stuff->change) {
|
|
client->xkbClientFlags &= ~stuff->change;
|
|
client->xkbClientFlags |= stuff->value;
|
|
}
|
|
if (stuff->change & XkbPCF_AutoResetControlsMask) {
|
|
Bool want;
|
|
|
|
want = stuff->value & XkbPCF_AutoResetControlsMask;
|
|
if (interest && !want) {
|
|
interest->autoCtrls = interest->autoCtrlValues = 0;
|
|
}
|
|
else if (want && (!interest)) {
|
|
XID id = FakeClientID(client->index);
|
|
|
|
if (!AddResource(id, RT_XKBCLIENT, dev))
|
|
return BadAlloc;
|
|
interest = XkbAddClientResource((DevicePtr) dev, client, id);
|
|
if (!interest)
|
|
return BadAlloc;
|
|
}
|
|
if (interest && want) {
|
|
register unsigned affect;
|
|
|
|
affect = stuff->ctrlsToChange;
|
|
|
|
CHK_MASK_LEGAL(0x03, affect, XkbAllBooleanCtrlsMask);
|
|
CHK_MASK_MATCH(0x04, affect, stuff->autoCtrls);
|
|
CHK_MASK_MATCH(0x05, stuff->autoCtrls, stuff->autoCtrlValues);
|
|
|
|
interest->autoCtrls &= ~affect;
|
|
interest->autoCtrlValues &= ~affect;
|
|
interest->autoCtrls |= stuff->autoCtrls & affect;
|
|
interest->autoCtrlValues |= stuff->autoCtrlValues & affect;
|
|
}
|
|
}
|
|
|
|
rep = (xkbPerClientFlagsReply) {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.supported = XkbPCF_AllFlagsMask,
|
|
.value = client->xkbClientFlags & XkbPCF_AllFlagsMask,
|
|
.autoCtrls = interest ? interest->autoCtrls : 0,
|
|
.autoCtrlValues = interest ? interest->autoCtrlValues : 0,
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.supported);
|
|
swapl(&rep.value);
|
|
swapl(&rep.autoCtrls);
|
|
swapl(&rep.autoCtrlValues);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbPerClientFlagsReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/* all latin-1 alphanumerics, plus parens, minus, underscore, slash */
|
|
/* and wildcards */
|
|
static unsigned char componentSpecLegal[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x87,
|
|
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
|
|
};
|
|
|
|
/* same as above but accepts percent, plus and bar too */
|
|
static unsigned char componentExprLegal[] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x20, 0xaf, 0xff, 0x87,
|
|
0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x17,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
|
|
};
|
|
|
|
static char *
|
|
GetComponentSpec(unsigned char **pWire, Bool allowExpr, int *errRtrn)
|
|
{
|
|
int len;
|
|
register int i;
|
|
unsigned char *wire, *str, *tmp, *legal;
|
|
|
|
if (allowExpr)
|
|
legal = &componentExprLegal[0];
|
|
else
|
|
legal = &componentSpecLegal[0];
|
|
|
|
wire = *pWire;
|
|
len = (*(unsigned char *) wire++);
|
|
if (len > 0) {
|
|
str = calloc(1, len + 1);
|
|
if (str) {
|
|
tmp = str;
|
|
for (i = 0; i < len; i++) {
|
|
if (legal[(*wire) / 8] & (1 << ((*wire) % 8)))
|
|
*tmp++ = *wire++;
|
|
else
|
|
wire++;
|
|
}
|
|
if (tmp != str)
|
|
*tmp++ = '\0';
|
|
else {
|
|
free(str);
|
|
str = NULL;
|
|
}
|
|
}
|
|
else {
|
|
*errRtrn = BadAlloc;
|
|
}
|
|
}
|
|
else {
|
|
str = NULL;
|
|
}
|
|
*pWire = wire;
|
|
return (char *) str;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbListComponents(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
xkbListComponentsReply rep;
|
|
unsigned len;
|
|
unsigned char *str;
|
|
uint8_t size;
|
|
int i;
|
|
|
|
REQUEST(xkbListComponentsReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbListComponentsReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
|
|
/* The request is followed by six Pascal strings (i.e. size in characters
|
|
* followed by a string pattern) describing what the client wants us to
|
|
* list. We don't care, but might as well check they haven't got the
|
|
* length wrong. */
|
|
str = (unsigned char *) &stuff[1];
|
|
for (i = 0; i < 6; i++) {
|
|
size = *((uint8_t *)str);
|
|
len = (str + size + 1) - ((unsigned char *) stuff);
|
|
if ((XkbPaddedSize(len) / 4) > stuff->length)
|
|
return BadLength;
|
|
str += (size + 1);
|
|
}
|
|
if ((XkbPaddedSize(len) / 4) != stuff->length)
|
|
return BadLength;
|
|
rep = (xkbListComponentsReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.nKeymaps = 0,
|
|
.nKeycodes = 0,
|
|
.nTypes = 0,
|
|
.nCompatMaps = 0,
|
|
.nSymbols = 0,
|
|
.nGeometries = 0,
|
|
.extra = 0
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swaps(&rep.nKeymaps);
|
|
swaps(&rep.nKeycodes);
|
|
swaps(&rep.nTypes);
|
|
swaps(&rep.nCompatMaps);
|
|
swaps(&rep.nSymbols);
|
|
swaps(&rep.nGeometries);
|
|
swaps(&rep.extra);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbListComponentsReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbGetKbdByName(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
DeviceIntPtr tmpd;
|
|
DeviceIntPtr master;
|
|
xkbGetKbdByNameReply rep = { 0 };
|
|
xkbGetMapReply mrep = { 0 };
|
|
xkbGetCompatMapReply crep = { 0 };
|
|
xkbGetIndicatorMapReply irep = { 0 };
|
|
xkbGetNamesReply nrep = { 0 };
|
|
xkbGetGeometryReply grep = { 0 };
|
|
XkbComponentNamesRec names = { 0 };
|
|
XkbDescPtr xkb, new;
|
|
unsigned char *str;
|
|
char mapFile[PATH_MAX];
|
|
unsigned len;
|
|
unsigned fwant, fneed, reported;
|
|
int status;
|
|
Bool geom_changed;
|
|
XkbSrvLedInfoPtr old_sli;
|
|
XkbSrvLedInfoPtr sli;
|
|
Mask access_mode = DixGetAttrAccess | DixManageAccess;
|
|
|
|
REQUEST(xkbGetKbdByNameReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbGetKbdByNameReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_KBD_DEVICE(dev, stuff->deviceSpec, client, access_mode);
|
|
master = GetMaster(dev, MASTER_KEYBOARD);
|
|
|
|
xkb = dev->key->xkbInfo->desc;
|
|
status = Success;
|
|
str = (unsigned char *) &stuff[1];
|
|
if (GetComponentSpec(&str, TRUE, &status)) /* keymap, unsupported */
|
|
return BadMatch;
|
|
names.keycodes = GetComponentSpec(&str, TRUE, &status);
|
|
names.types = GetComponentSpec(&str, TRUE, &status);
|
|
names.compat = GetComponentSpec(&str, TRUE, &status);
|
|
names.symbols = GetComponentSpec(&str, TRUE, &status);
|
|
names.geometry = GetComponentSpec(&str, TRUE, &status);
|
|
if (status != Success)
|
|
return status;
|
|
len = str - ((unsigned char *) stuff);
|
|
if ((XkbPaddedSize(len) / 4) != stuff->length)
|
|
return BadLength;
|
|
|
|
CHK_MASK_LEGAL(0x01, stuff->want, XkbGBN_AllComponentsMask);
|
|
CHK_MASK_LEGAL(0x02, stuff->need, XkbGBN_AllComponentsMask);
|
|
|
|
if (stuff->load)
|
|
fwant = XkbGBN_AllComponentsMask;
|
|
else
|
|
fwant = stuff->want | stuff->need;
|
|
if ((!names.compat) &&
|
|
(fwant & (XkbGBN_CompatMapMask | XkbGBN_IndicatorMapMask))) {
|
|
names.compat = Xstrdup("%");
|
|
}
|
|
if ((!names.types) && (fwant & (XkbGBN_TypesMask))) {
|
|
names.types = Xstrdup("%");
|
|
}
|
|
if ((!names.symbols) && (fwant & XkbGBN_SymbolsMask)) {
|
|
names.symbols = Xstrdup("%");
|
|
}
|
|
geom_changed = ((names.geometry != NULL) &&
|
|
(strcmp(names.geometry, "%") != 0));
|
|
if ((!names.geometry) && (fwant & XkbGBN_GeometryMask)) {
|
|
names.geometry = Xstrdup("%");
|
|
geom_changed = FALSE;
|
|
}
|
|
|
|
memset(mapFile, 0, PATH_MAX);
|
|
rep.type = X_Reply;
|
|
rep.deviceID = dev->id;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.length = 0;
|
|
rep.minKeyCode = xkb->min_key_code;
|
|
rep.maxKeyCode = xkb->max_key_code;
|
|
rep.loaded = FALSE;
|
|
fwant =
|
|
XkbConvertGetByNameComponents(TRUE, stuff->want) | XkmVirtualModsMask;
|
|
fneed = XkbConvertGetByNameComponents(TRUE, stuff->need);
|
|
rep.reported = XkbConvertGetByNameComponents(FALSE, fwant | fneed);
|
|
if (stuff->load) {
|
|
fneed |= XkmKeymapRequired;
|
|
fwant |= XkmKeymapLegal;
|
|
}
|
|
if ((fwant | fneed) & XkmSymbolsMask) {
|
|
fneed |= XkmKeyNamesIndex | XkmTypesIndex;
|
|
fwant |= XkmIndicatorsIndex;
|
|
}
|
|
|
|
/* We pass dev in here so we can get the old names out if needed. */
|
|
rep.found = XkbDDXLoadKeymapByNames(dev, &names, fwant, fneed, &new,
|
|
mapFile, PATH_MAX);
|
|
rep.newKeyboard = FALSE;
|
|
rep.pad1 = rep.pad2 = rep.pad3 = rep.pad4 = 0;
|
|
|
|
stuff->want |= stuff->need;
|
|
if (new == NULL)
|
|
rep.reported = 0;
|
|
else {
|
|
if (stuff->load)
|
|
rep.loaded = TRUE;
|
|
if (stuff->load ||
|
|
((rep.reported & XkbGBN_SymbolsMask) && (new->compat))) {
|
|
XkbChangesRec changes;
|
|
|
|
memset(&changes, 0, sizeof(changes));
|
|
XkbUpdateDescActions(new,
|
|
new->min_key_code, XkbNumKeys(new), &changes);
|
|
}
|
|
|
|
if (new->map == NULL)
|
|
rep.reported &= ~(XkbGBN_SymbolsMask | XkbGBN_TypesMask);
|
|
else if (rep.reported & (XkbGBN_SymbolsMask | XkbGBN_TypesMask)) {
|
|
mrep.type = X_Reply;
|
|
mrep.deviceID = dev->id;
|
|
mrep.sequenceNumber = client->sequence;
|
|
mrep.length =
|
|
((SIZEOF(xkbGetMapReply) - SIZEOF(xGenericReply)) >> 2);
|
|
mrep.minKeyCode = new->min_key_code;
|
|
mrep.maxKeyCode = new->max_key_code;
|
|
mrep.present = 0;
|
|
mrep.totalSyms = mrep.totalActs =
|
|
mrep.totalKeyBehaviors = mrep.totalKeyExplicit =
|
|
mrep.totalModMapKeys = mrep.totalVModMapKeys = 0;
|
|
if (rep.reported & (XkbGBN_TypesMask | XkbGBN_ClientSymbolsMask)) {
|
|
mrep.present |= XkbKeyTypesMask;
|
|
mrep.firstType = 0;
|
|
mrep.nTypes = mrep.totalTypes = new->map->num_types;
|
|
}
|
|
else {
|
|
mrep.firstType = mrep.nTypes = 0;
|
|
mrep.totalTypes = 0;
|
|
}
|
|
if (rep.reported & XkbGBN_ClientSymbolsMask) {
|
|
mrep.present |= (XkbKeySymsMask | XkbModifierMapMask);
|
|
mrep.firstKeySym = mrep.firstModMapKey = new->min_key_code;
|
|
mrep.nKeySyms = mrep.nModMapKeys = XkbNumKeys(new);
|
|
}
|
|
else {
|
|
mrep.firstKeySym = mrep.firstModMapKey = 0;
|
|
mrep.nKeySyms = mrep.nModMapKeys = 0;
|
|
}
|
|
if (rep.reported & XkbGBN_ServerSymbolsMask) {
|
|
mrep.present |= XkbAllServerInfoMask;
|
|
mrep.virtualMods = ~0;
|
|
mrep.firstKeyAct = mrep.firstKeyBehavior =
|
|
mrep.firstKeyExplicit = new->min_key_code;
|
|
mrep.nKeyActs = mrep.nKeyBehaviors =
|
|
mrep.nKeyExplicit = XkbNumKeys(new);
|
|
mrep.firstVModMapKey = new->min_key_code;
|
|
mrep.nVModMapKeys = XkbNumKeys(new);
|
|
}
|
|
else {
|
|
mrep.virtualMods = 0;
|
|
mrep.firstKeyAct = mrep.firstKeyBehavior =
|
|
mrep.firstKeyExplicit = 0;
|
|
mrep.nKeyActs = mrep.nKeyBehaviors = mrep.nKeyExplicit = 0;
|
|
}
|
|
XkbComputeGetMapReplySize(new, &mrep);
|
|
rep.length += SIZEOF(xGenericReply) / 4 + mrep.length;
|
|
}
|
|
if (new->compat == NULL)
|
|
rep.reported &= ~XkbGBN_CompatMapMask;
|
|
else if (rep.reported & XkbGBN_CompatMapMask) {
|
|
crep.type = X_Reply;
|
|
crep.deviceID = dev->id;
|
|
crep.sequenceNumber = client->sequence;
|
|
crep.length = 0;
|
|
crep.groups = XkbAllGroupsMask;
|
|
crep.firstSI = 0;
|
|
crep.nSI = crep.nTotalSI = new->compat->num_si;
|
|
XkbComputeGetCompatMapReplySize(new->compat, &crep);
|
|
rep.length += SIZEOF(xGenericReply) / 4 + crep.length;
|
|
}
|
|
if (new->indicators == NULL)
|
|
rep.reported &= ~XkbGBN_IndicatorMapMask;
|
|
else if (rep.reported & XkbGBN_IndicatorMapMask) {
|
|
irep.type = X_Reply;
|
|
irep.deviceID = dev->id;
|
|
irep.sequenceNumber = client->sequence;
|
|
irep.length = 0;
|
|
irep.which = XkbAllIndicatorsMask;
|
|
XkbComputeGetIndicatorMapReplySize(new->indicators, &irep);
|
|
rep.length += SIZEOF(xGenericReply) / 4 + irep.length;
|
|
}
|
|
if (new->names == NULL)
|
|
rep.reported &= ~(XkbGBN_OtherNamesMask | XkbGBN_KeyNamesMask);
|
|
else if (rep.reported & (XkbGBN_OtherNamesMask | XkbGBN_KeyNamesMask)) {
|
|
nrep.type = X_Reply;
|
|
nrep.deviceID = dev->id;
|
|
nrep.sequenceNumber = client->sequence;
|
|
nrep.length = 0;
|
|
nrep.minKeyCode = new->min_key_code;
|
|
nrep.maxKeyCode = new->max_key_code;
|
|
if (rep.reported & XkbGBN_OtherNamesMask) {
|
|
nrep.which = XkbAllNamesMask;
|
|
if (new->map != NULL)
|
|
nrep.nTypes = new->map->num_types;
|
|
else
|
|
nrep.nTypes = 0;
|
|
nrep.nKTLevels = 0;
|
|
nrep.groupNames = XkbAllGroupsMask;
|
|
nrep.virtualMods = XkbAllVirtualModsMask;
|
|
nrep.indicators = XkbAllIndicatorsMask;
|
|
nrep.nRadioGroups = new->names->num_rg;
|
|
}
|
|
else {
|
|
nrep.which = 0;
|
|
nrep.nTypes = 0;
|
|
nrep.nKTLevels = 0;
|
|
nrep.groupNames = 0;
|
|
nrep.virtualMods = 0;
|
|
nrep.indicators = 0;
|
|
nrep.nRadioGroups = 0;
|
|
}
|
|
if (rep.reported & XkbGBN_KeyNamesMask) {
|
|
nrep.which |= XkbKeyNamesMask;
|
|
nrep.firstKey = new->min_key_code;
|
|
nrep.nKeys = XkbNumKeys(new);
|
|
nrep.nKeyAliases = new->names->num_key_aliases;
|
|
if (nrep.nKeyAliases)
|
|
nrep.which |= XkbKeyAliasesMask;
|
|
}
|
|
else {
|
|
nrep.which &= ~(XkbKeyNamesMask | XkbKeyAliasesMask);
|
|
nrep.firstKey = nrep.nKeys = 0;
|
|
nrep.nKeyAliases = 0;
|
|
}
|
|
XkbComputeGetNamesReplySize(new, &nrep);
|
|
rep.length += SIZEOF(xGenericReply) / 4 + nrep.length;
|
|
}
|
|
if (new->geom == NULL)
|
|
rep.reported &= ~XkbGBN_GeometryMask;
|
|
else if (rep.reported & XkbGBN_GeometryMask) {
|
|
grep.type = X_Reply;
|
|
grep.deviceID = dev->id;
|
|
grep.sequenceNumber = client->sequence;
|
|
grep.length = 0;
|
|
grep.found = TRUE;
|
|
grep.pad = 0;
|
|
grep.widthMM = grep.heightMM = 0;
|
|
grep.nProperties = grep.nColors = grep.nShapes = 0;
|
|
grep.nSections = grep.nDoodads = 0;
|
|
grep.baseColorNdx = grep.labelColorNdx = 0;
|
|
XkbComputeGetGeometryReplySize(new->geom, &grep, None);
|
|
rep.length += SIZEOF(xGenericReply) / 4 + grep.length;
|
|
}
|
|
}
|
|
|
|
reported = rep.reported;
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swaps(&rep.found);
|
|
swaps(&rep.reported);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetKbdByNameReply), &rep);
|
|
if (reported & (XkbGBN_SymbolsMask | XkbGBN_TypesMask))
|
|
XkbSendMap(client, new, &mrep);
|
|
if (reported & XkbGBN_CompatMapMask)
|
|
XkbSendCompatMap(client, new->compat, &crep);
|
|
if (reported & XkbGBN_IndicatorMapMask)
|
|
XkbSendIndicatorMap(client, new->indicators, &irep);
|
|
if (reported & (XkbGBN_KeyNamesMask | XkbGBN_OtherNamesMask))
|
|
XkbSendNames(client, new, &nrep);
|
|
if (reported & XkbGBN_GeometryMask)
|
|
XkbSendGeometry(client, new->geom, &grep, FALSE);
|
|
if (rep.loaded) {
|
|
XkbDescPtr old_xkb;
|
|
xkbNewKeyboardNotify nkn;
|
|
|
|
old_xkb = xkb;
|
|
xkb = new;
|
|
dev->key->xkbInfo->desc = xkb;
|
|
new = old_xkb; /* so it'll get freed automatically */
|
|
|
|
XkbCopyControls(xkb, old_xkb);
|
|
|
|
nkn.deviceID = nkn.oldDeviceID = dev->id;
|
|
nkn.minKeyCode = new->min_key_code;
|
|
nkn.maxKeyCode = new->max_key_code;
|
|
nkn.oldMinKeyCode = xkb->min_key_code;
|
|
nkn.oldMaxKeyCode = xkb->max_key_code;
|
|
nkn.requestMajor = XkbReqCode;
|
|
nkn.requestMinor = X_kbGetKbdByName;
|
|
nkn.changed = XkbNKN_KeycodesMask;
|
|
if (geom_changed)
|
|
nkn.changed |= XkbNKN_GeometryMask;
|
|
XkbSendNewKeyboardNotify(dev, &nkn);
|
|
|
|
/* Update the map and LED info on the device itself, as well as
|
|
* any slaves if it's an MD, or its MD if it's an SD and was the
|
|
* last device used on that MD. */
|
|
for (tmpd = inputInfo.devices; tmpd; tmpd = tmpd->next) {
|
|
if (tmpd != dev && GetMaster(tmpd, MASTER_KEYBOARD) != dev &&
|
|
(tmpd != master || dev != master->lastSlave))
|
|
continue;
|
|
|
|
if (tmpd != dev)
|
|
XkbDeviceApplyKeymap(tmpd, xkb);
|
|
|
|
if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) {
|
|
old_sli = tmpd->kbdfeed->xkb_sli;
|
|
tmpd->kbdfeed->xkb_sli = NULL;
|
|
sli = XkbAllocSrvLedInfo(tmpd, tmpd->kbdfeed, NULL, 0);
|
|
if (sli) {
|
|
sli->explicitState = old_sli->explicitState;
|
|
sli->effectiveState = old_sli->effectiveState;
|
|
}
|
|
tmpd->kbdfeed->xkb_sli = sli;
|
|
XkbFreeSrvLedInfo(old_sli);
|
|
}
|
|
}
|
|
}
|
|
if ((new != NULL) && (new != xkb)) {
|
|
XkbFreeKeyboard(new, XkbAllComponentsMask, TRUE);
|
|
new = NULL;
|
|
}
|
|
XkbFreeComponentNames(&names, FALSE);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static int
|
|
ComputeDeviceLedInfoSize(DeviceIntPtr dev,
|
|
unsigned int what, XkbSrvLedInfoPtr sli)
|
|
{
|
|
int nNames, nMaps;
|
|
register unsigned n, bit;
|
|
|
|
if (sli == NULL)
|
|
return 0;
|
|
nNames = nMaps = 0;
|
|
if ((what & XkbXI_IndicatorNamesMask) == 0)
|
|
sli->namesPresent = 0;
|
|
if ((what & XkbXI_IndicatorMapsMask) == 0)
|
|
sli->mapsPresent = 0;
|
|
|
|
for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
|
|
if (sli->names && sli->names[n] != None) {
|
|
sli->namesPresent |= bit;
|
|
nNames++;
|
|
}
|
|
if (sli->maps && XkbIM_InUse(&sli->maps[n])) {
|
|
sli->mapsPresent |= bit;
|
|
nMaps++;
|
|
}
|
|
}
|
|
return (nNames * 4) + (nMaps * SIZEOF(xkbIndicatorMapWireDesc));
|
|
}
|
|
|
|
static int
|
|
CheckDeviceLedFBs(DeviceIntPtr dev,
|
|
int class,
|
|
int id, xkbGetDeviceInfoReply * rep, ClientPtr client)
|
|
{
|
|
int nFBs = 0;
|
|
int length = 0;
|
|
Bool classOk;
|
|
|
|
if (class == XkbDfltXIClass) {
|
|
if (dev->kbdfeed)
|
|
class = KbdFeedbackClass;
|
|
else if (dev->leds)
|
|
class = LedFeedbackClass;
|
|
else {
|
|
client->errorValue = _XkbErrCode2(XkbErr_BadClass, class);
|
|
return XkbKeyboardErrorCode;
|
|
}
|
|
}
|
|
classOk = FALSE;
|
|
if ((dev->kbdfeed) &&
|
|
((class == KbdFeedbackClass) || (class == XkbAllXIClasses))) {
|
|
KbdFeedbackPtr kf;
|
|
|
|
classOk = TRUE;
|
|
for (kf = dev->kbdfeed; (kf); kf = kf->next) {
|
|
if ((id != XkbAllXIIds) && (id != XkbDfltXIId) &&
|
|
(id != kf->ctrl.id))
|
|
continue;
|
|
nFBs++;
|
|
length += SIZEOF(xkbDeviceLedsWireDesc);
|
|
if (!kf->xkb_sli)
|
|
kf->xkb_sli = XkbAllocSrvLedInfo(dev, kf, NULL, 0);
|
|
length += ComputeDeviceLedInfoSize(dev, rep->present, kf->xkb_sli);
|
|
if (id != XkbAllXIIds)
|
|
break;
|
|
}
|
|
}
|
|
if ((dev->leds) &&
|
|
((class == LedFeedbackClass) || (class == XkbAllXIClasses))) {
|
|
LedFeedbackPtr lf;
|
|
|
|
classOk = TRUE;
|
|
for (lf = dev->leds; (lf); lf = lf->next) {
|
|
if ((id != XkbAllXIIds) && (id != XkbDfltXIId) &&
|
|
(id != lf->ctrl.id))
|
|
continue;
|
|
nFBs++;
|
|
length += SIZEOF(xkbDeviceLedsWireDesc);
|
|
if (!lf->xkb_sli)
|
|
lf->xkb_sli = XkbAllocSrvLedInfo(dev, NULL, lf, 0);
|
|
length += ComputeDeviceLedInfoSize(dev, rep->present, lf->xkb_sli);
|
|
if (id != XkbAllXIIds)
|
|
break;
|
|
}
|
|
}
|
|
if (nFBs > 0) {
|
|
rep->nDeviceLedFBs = nFBs;
|
|
rep->length += (length / 4);
|
|
return Success;
|
|
}
|
|
if (classOk)
|
|
client->errorValue = _XkbErrCode2(XkbErr_BadId, id);
|
|
else
|
|
client->errorValue = _XkbErrCode2(XkbErr_BadClass, class);
|
|
return XkbKeyboardErrorCode;
|
|
}
|
|
|
|
static int
|
|
SendDeviceLedInfo(XkbSrvLedInfoPtr sli, ClientPtr client)
|
|
{
|
|
xkbDeviceLedsWireDesc wire;
|
|
int length;
|
|
|
|
length = 0;
|
|
wire.ledClass = sli->class;
|
|
wire.ledID = sli->id;
|
|
wire.namesPresent = sli->namesPresent;
|
|
wire.mapsPresent = sli->mapsPresent;
|
|
wire.physIndicators = sli->physIndicators;
|
|
wire.state = sli->effectiveState;
|
|
if (client->swapped) {
|
|
swaps(&wire.ledClass);
|
|
swaps(&wire.ledID);
|
|
swapl(&wire.namesPresent);
|
|
swapl(&wire.mapsPresent);
|
|
swapl(&wire.physIndicators);
|
|
swapl(&wire.state);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbDeviceLedsWireDesc), &wire);
|
|
length += SIZEOF(xkbDeviceLedsWireDesc);
|
|
if (sli->namesPresent | sli->mapsPresent) {
|
|
register unsigned i, bit;
|
|
|
|
if (sli->namesPresent) {
|
|
CARD32 awire;
|
|
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
if (sli->namesPresent & bit) {
|
|
awire = (CARD32) sli->names[i];
|
|
if (client->swapped) {
|
|
swapl(&awire);
|
|
}
|
|
WriteToClient(client, 4, &awire);
|
|
length += 4;
|
|
}
|
|
}
|
|
}
|
|
if (sli->mapsPresent) {
|
|
for (i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1) {
|
|
xkbIndicatorMapWireDesc iwire;
|
|
|
|
if (sli->mapsPresent & bit) {
|
|
iwire.flags = sli->maps[i].flags;
|
|
iwire.whichGroups = sli->maps[i].which_groups;
|
|
iwire.groups = sli->maps[i].groups;
|
|
iwire.whichMods = sli->maps[i].which_mods;
|
|
iwire.mods = sli->maps[i].mods.mask;
|
|
iwire.realMods = sli->maps[i].mods.real_mods;
|
|
iwire.virtualMods = sli->maps[i].mods.vmods;
|
|
iwire.ctrls = sli->maps[i].ctrls;
|
|
if (client->swapped) {
|
|
swaps(&iwire.virtualMods);
|
|
swapl(&iwire.ctrls);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbIndicatorMapWireDesc),
|
|
&iwire);
|
|
length += SIZEOF(xkbIndicatorMapWireDesc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return length;
|
|
}
|
|
|
|
static int
|
|
SendDeviceLedFBs(DeviceIntPtr dev,
|
|
int class, int id, unsigned wantLength, ClientPtr client)
|
|
{
|
|
int length = 0;
|
|
|
|
if (class == XkbDfltXIClass) {
|
|
if (dev->kbdfeed)
|
|
class = KbdFeedbackClass;
|
|
else if (dev->leds)
|
|
class = LedFeedbackClass;
|
|
}
|
|
if ((dev->kbdfeed) &&
|
|
((class == KbdFeedbackClass) || (class == XkbAllXIClasses))) {
|
|
KbdFeedbackPtr kf;
|
|
|
|
for (kf = dev->kbdfeed; (kf); kf = kf->next) {
|
|
if ((id == XkbAllXIIds) || (id == XkbDfltXIId) ||
|
|
(id == kf->ctrl.id)) {
|
|
length += SendDeviceLedInfo(kf->xkb_sli, client);
|
|
if (id != XkbAllXIIds)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((dev->leds) &&
|
|
((class == LedFeedbackClass) || (class == XkbAllXIClasses))) {
|
|
LedFeedbackPtr lf;
|
|
|
|
for (lf = dev->leds; (lf); lf = lf->next) {
|
|
if ((id == XkbAllXIIds) || (id == XkbDfltXIId) ||
|
|
(id == lf->ctrl.id)) {
|
|
length += SendDeviceLedInfo(lf->xkb_sli, client);
|
|
if (id != XkbAllXIIds)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (length == wantLength)
|
|
return Success;
|
|
else
|
|
return BadLength;
|
|
}
|
|
|
|
int
|
|
ProcXkbGetDeviceInfo(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
xkbGetDeviceInfoReply rep;
|
|
int status, nDeviceLedFBs;
|
|
unsigned length, nameLen;
|
|
CARD16 ledClass, ledID;
|
|
unsigned wanted;
|
|
char *str;
|
|
|
|
REQUEST(xkbGetDeviceInfoReq);
|
|
REQUEST_SIZE_MATCH(xkbGetDeviceInfoReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
wanted = stuff->wanted;
|
|
|
|
CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixGetAttrAccess);
|
|
CHK_MASK_LEGAL(0x01, wanted, XkbXI_AllDeviceFeaturesMask);
|
|
|
|
if ((!dev->button) || ((stuff->nBtns < 1) && (!stuff->allBtns)))
|
|
wanted &= ~XkbXI_ButtonActionsMask;
|
|
if ((!dev->kbdfeed) && (!dev->leds))
|
|
wanted &= ~XkbXI_IndicatorsMask;
|
|
|
|
nameLen = XkbSizeCountedString(dev->name);
|
|
rep = (xkbGetDeviceInfoReply) {
|
|
.type = X_Reply,
|
|
.deviceID = dev->id,
|
|
.sequenceNumber = client->sequence,
|
|
.length = nameLen / 4,
|
|
.present = wanted,
|
|
.supported = XkbXI_AllDeviceFeaturesMask,
|
|
.unsupported = 0,
|
|
.nDeviceLedFBs = 0,
|
|
.firstBtnWanted = 0,
|
|
.nBtnsWanted = 0,
|
|
.firstBtnRtrn = 0,
|
|
.nBtnsRtrn = 0,
|
|
.totalBtns = dev->button ? dev->button->numButtons : 0,
|
|
.hasOwnState = (dev->key && dev->key->xkbInfo),
|
|
.dfltKbdFB = dev->kbdfeed ? dev->kbdfeed->ctrl.id : XkbXINone,
|
|
.dfltLedFB = dev->leds ? dev->leds->ctrl.id : XkbXINone,
|
|
.devType = dev->xinput_type
|
|
};
|
|
|
|
ledClass = stuff->ledClass;
|
|
ledID = stuff->ledID;
|
|
|
|
if (wanted & XkbXI_ButtonActionsMask) {
|
|
if (stuff->allBtns) {
|
|
stuff->firstBtn = 0;
|
|
stuff->nBtns = dev->button->numButtons;
|
|
}
|
|
|
|
if ((stuff->firstBtn + stuff->nBtns) > dev->button->numButtons) {
|
|
client->errorValue = _XkbErrCode4(0x02, dev->button->numButtons,
|
|
stuff->firstBtn, stuff->nBtns);
|
|
return BadValue;
|
|
}
|
|
else {
|
|
rep.firstBtnWanted = stuff->firstBtn;
|
|
rep.nBtnsWanted = stuff->nBtns;
|
|
if (dev->button->xkb_acts != NULL) {
|
|
XkbAction *act;
|
|
register int i;
|
|
|
|
rep.firstBtnRtrn = stuff->firstBtn;
|
|
rep.nBtnsRtrn = stuff->nBtns;
|
|
act = &dev->button->xkb_acts[rep.firstBtnWanted];
|
|
for (i = 0; i < rep.nBtnsRtrn; i++, act++) {
|
|
if (act->type != XkbSA_NoAction)
|
|
break;
|
|
}
|
|
rep.firstBtnRtrn += i;
|
|
rep.nBtnsRtrn -= i;
|
|
act =
|
|
&dev->button->xkb_acts[rep.firstBtnRtrn + rep.nBtnsRtrn -
|
|
1];
|
|
for (i = 0; i < rep.nBtnsRtrn; i++, act--) {
|
|
if (act->type != XkbSA_NoAction)
|
|
break;
|
|
}
|
|
rep.nBtnsRtrn -= i;
|
|
}
|
|
rep.length += (rep.nBtnsRtrn * SIZEOF(xkbActionWireDesc)) / 4;
|
|
}
|
|
}
|
|
|
|
if (wanted & XkbXI_IndicatorsMask) {
|
|
status = CheckDeviceLedFBs(dev, ledClass, ledID, &rep, client);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
length = rep.length * 4;
|
|
nDeviceLedFBs = rep.nDeviceLedFBs;
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.length);
|
|
swaps(&rep.present);
|
|
swaps(&rep.supported);
|
|
swaps(&rep.unsupported);
|
|
swaps(&rep.nDeviceLedFBs);
|
|
swaps(&rep.dfltKbdFB);
|
|
swaps(&rep.dfltLedFB);
|
|
swapl(&rep.devType);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbGetDeviceInfoReply), &rep);
|
|
|
|
str = malloc(nameLen);
|
|
if (!str)
|
|
return BadAlloc;
|
|
XkbWriteCountedString(str, dev->name, client->swapped);
|
|
WriteToClient(client, nameLen, str);
|
|
free(str);
|
|
length -= nameLen;
|
|
|
|
if (rep.nBtnsRtrn > 0) {
|
|
int sz;
|
|
xkbActionWireDesc *awire;
|
|
|
|
sz = rep.nBtnsRtrn * SIZEOF(xkbActionWireDesc);
|
|
awire = (xkbActionWireDesc *) &dev->button->xkb_acts[rep.firstBtnRtrn];
|
|
WriteToClient(client, sz, awire);
|
|
length -= sz;
|
|
}
|
|
if (nDeviceLedFBs > 0) {
|
|
status = SendDeviceLedFBs(dev, ledClass, ledID, length, client);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
else if (length != 0) {
|
|
ErrorF("[xkb] Internal Error! BadLength in ProcXkbGetDeviceInfo\n");
|
|
ErrorF("[xkb] Wrote %d fewer bytes than expected\n",
|
|
length);
|
|
return BadLength;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
static char *
|
|
CheckSetDeviceIndicators(char *wire,
|
|
DeviceIntPtr dev,
|
|
int num, int *status_rtrn, ClientPtr client)
|
|
{
|
|
xkbDeviceLedsWireDesc *ledWire;
|
|
int i;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
ledWire = (xkbDeviceLedsWireDesc *) wire;
|
|
for (i = 0; i < num; i++) {
|
|
if (client->swapped) {
|
|
swaps(&ledWire->ledClass);
|
|
swaps(&ledWire->ledID);
|
|
swapl(&ledWire->namesPresent);
|
|
swapl(&ledWire->mapsPresent);
|
|
swapl(&ledWire->physIndicators);
|
|
}
|
|
|
|
sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID,
|
|
XkbXI_IndicatorsMask);
|
|
if (sli != NULL) {
|
|
register int n;
|
|
register unsigned bit;
|
|
int nMaps, nNames;
|
|
CARD32 *atomWire;
|
|
xkbIndicatorMapWireDesc *mapWire;
|
|
|
|
nMaps = nNames = 0;
|
|
for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
|
|
if (ledWire->namesPresent & bit)
|
|
nNames++;
|
|
if (ledWire->mapsPresent & bit)
|
|
nMaps++;
|
|
}
|
|
atomWire = (CARD32 *) &ledWire[1];
|
|
if (nNames > 0) {
|
|
for (n = 0; n < nNames; n++) {
|
|
if (client->swapped) {
|
|
swapl(atomWire);
|
|
}
|
|
CHK_ATOM_OR_NONE3(((Atom) (*atomWire)), client->errorValue,
|
|
*status_rtrn, NULL);
|
|
atomWire++;
|
|
}
|
|
}
|
|
mapWire = (xkbIndicatorMapWireDesc *) atomWire;
|
|
if (nMaps > 0) {
|
|
for (n = 0; n < nMaps; n++) {
|
|
if (client->swapped) {
|
|
swaps(&mapWire->virtualMods);
|
|
swapl(&mapWire->ctrls);
|
|
}
|
|
CHK_MASK_LEGAL3(0x21, mapWire->whichGroups,
|
|
XkbIM_UseAnyGroup,
|
|
client->errorValue, *status_rtrn, NULL);
|
|
CHK_MASK_LEGAL3(0x22, mapWire->whichMods, XkbIM_UseAnyMods,
|
|
client->errorValue, *status_rtrn, NULL);
|
|
mapWire++;
|
|
}
|
|
}
|
|
ledWire = (xkbDeviceLedsWireDesc *) mapWire;
|
|
}
|
|
else {
|
|
/* SHOULD NEVER HAPPEN */
|
|
return (char *) ledWire;
|
|
}
|
|
}
|
|
return (char *) ledWire;
|
|
}
|
|
|
|
static char *
|
|
SetDeviceIndicators(char *wire,
|
|
DeviceIntPtr dev,
|
|
unsigned changed,
|
|
int num,
|
|
int *status_rtrn,
|
|
ClientPtr client, xkbExtensionDeviceNotify * ev)
|
|
{
|
|
xkbDeviceLedsWireDesc *ledWire;
|
|
int i;
|
|
XkbEventCauseRec cause;
|
|
unsigned namec, mapc, statec;
|
|
xkbExtensionDeviceNotify ed;
|
|
XkbChangesRec changes;
|
|
DeviceIntPtr kbd;
|
|
|
|
memset((char *) &ed, 0, sizeof(xkbExtensionDeviceNotify));
|
|
memset((char *) &changes, 0, sizeof(XkbChangesRec));
|
|
XkbSetCauseXkbReq(&cause, X_kbSetDeviceInfo, client);
|
|
ledWire = (xkbDeviceLedsWireDesc *) wire;
|
|
for (i = 0; i < num; i++) {
|
|
register int n;
|
|
register unsigned bit;
|
|
CARD32 *atomWire;
|
|
xkbIndicatorMapWireDesc *mapWire;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
namec = mapc = statec = 0;
|
|
sli = XkbFindSrvLedInfo(dev, ledWire->ledClass, ledWire->ledID,
|
|
XkbXI_IndicatorMapsMask);
|
|
if (!sli) {
|
|
/* SHOULD NEVER HAPPEN!! */
|
|
return (char *) ledWire;
|
|
}
|
|
|
|
atomWire = (CARD32 *) &ledWire[1];
|
|
if (changed & XkbXI_IndicatorNamesMask) {
|
|
namec = sli->namesPresent | ledWire->namesPresent;
|
|
memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom));
|
|
}
|
|
if (ledWire->namesPresent) {
|
|
sli->namesPresent = ledWire->namesPresent;
|
|
memset((char *) sli->names, 0, XkbNumIndicators * sizeof(Atom));
|
|
for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
|
|
if (ledWire->namesPresent & bit) {
|
|
sli->names[n] = (Atom) *atomWire;
|
|
if (sli->names[n] == None)
|
|
ledWire->namesPresent &= ~bit;
|
|
atomWire++;
|
|
}
|
|
}
|
|
}
|
|
mapWire = (xkbIndicatorMapWireDesc *) atomWire;
|
|
if (changed & XkbXI_IndicatorMapsMask) {
|
|
mapc = sli->mapsPresent | ledWire->mapsPresent;
|
|
sli->mapsPresent = ledWire->mapsPresent;
|
|
memset((char *) sli->maps, 0,
|
|
XkbNumIndicators * sizeof(XkbIndicatorMapRec));
|
|
}
|
|
if (ledWire->mapsPresent) {
|
|
for (n = 0, bit = 1; n < XkbNumIndicators; n++, bit <<= 1) {
|
|
if (ledWire->mapsPresent & bit) {
|
|
sli->maps[n].flags = mapWire->flags;
|
|
sli->maps[n].which_groups = mapWire->whichGroups;
|
|
sli->maps[n].groups = mapWire->groups;
|
|
sli->maps[n].which_mods = mapWire->whichMods;
|
|
sli->maps[n].mods.mask = mapWire->mods;
|
|
sli->maps[n].mods.real_mods = mapWire->realMods;
|
|
sli->maps[n].mods.vmods = mapWire->virtualMods;
|
|
sli->maps[n].ctrls = mapWire->ctrls;
|
|
mapWire++;
|
|
}
|
|
}
|
|
}
|
|
if (changed & XkbXI_IndicatorStateMask) {
|
|
statec = sli->effectiveState ^ ledWire->state;
|
|
sli->explicitState &= ~statec;
|
|
sli->explicitState |= (ledWire->state & statec);
|
|
}
|
|
if (namec)
|
|
XkbApplyLedNameChanges(dev, sli, namec, &ed, &changes, &cause);
|
|
if (mapc)
|
|
XkbApplyLedMapChanges(dev, sli, mapc, &ed, &changes, &cause);
|
|
if (statec)
|
|
XkbApplyLedStateChanges(dev, sli, statec, &ed, &changes, &cause);
|
|
|
|
kbd = dev;
|
|
if ((sli->flags & XkbSLI_HasOwnState) == 0)
|
|
kbd = inputInfo.keyboard;
|
|
|
|
XkbFlushLedEvents(dev, kbd, sli, &ed, &changes, &cause);
|
|
ledWire = (xkbDeviceLedsWireDesc *) mapWire;
|
|
}
|
|
return (char *) ledWire;
|
|
}
|
|
|
|
static int
|
|
_XkbSetDeviceInfo(ClientPtr client, DeviceIntPtr dev,
|
|
xkbSetDeviceInfoReq * stuff)
|
|
{
|
|
char *wire;
|
|
|
|
wire = (char *) &stuff[1];
|
|
if (stuff->change & XkbXI_ButtonActionsMask) {
|
|
if (!dev->button) {
|
|
client->errorValue = _XkbErrCode2(XkbErr_BadClass, ButtonClass);
|
|
return XkbKeyboardErrorCode;
|
|
}
|
|
if ((stuff->firstBtn + stuff->nBtns) > dev->button->numButtons) {
|
|
client->errorValue =
|
|
_XkbErrCode4(0x02, stuff->firstBtn, stuff->nBtns,
|
|
dev->button->numButtons);
|
|
return BadMatch;
|
|
}
|
|
wire += (stuff->nBtns * SIZEOF(xkbActionWireDesc));
|
|
}
|
|
if (stuff->change & XkbXI_IndicatorsMask) {
|
|
int status = Success;
|
|
|
|
wire = CheckSetDeviceIndicators(wire, dev, stuff->nDeviceLedFBs,
|
|
&status, client);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
if (((wire - ((char *) stuff)) / 4) != stuff->length)
|
|
return BadLength;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
_XkbSetDeviceInfoCheck(ClientPtr client, DeviceIntPtr dev,
|
|
xkbSetDeviceInfoReq * stuff)
|
|
{
|
|
char *wire;
|
|
xkbExtensionDeviceNotify ed;
|
|
|
|
memset((char *) &ed, 0, SIZEOF(xkbExtensionDeviceNotify));
|
|
ed.deviceID = dev->id;
|
|
wire = (char *) &stuff[1];
|
|
if (stuff->change & XkbXI_ButtonActionsMask) {
|
|
int nBtns, sz, i;
|
|
XkbAction *acts;
|
|
DeviceIntPtr kbd;
|
|
|
|
nBtns = dev->button->numButtons;
|
|
acts = dev->button->xkb_acts;
|
|
if (acts == NULL) {
|
|
acts = calloc(nBtns, sizeof(XkbAction));
|
|
if (!acts)
|
|
return BadAlloc;
|
|
dev->button->xkb_acts = acts;
|
|
}
|
|
sz = stuff->nBtns * SIZEOF(xkbActionWireDesc);
|
|
memcpy((char *) &acts[stuff->firstBtn], (char *) wire, sz);
|
|
wire += sz;
|
|
ed.reason |= XkbXI_ButtonActionsMask;
|
|
ed.firstBtn = stuff->firstBtn;
|
|
ed.nBtns = stuff->nBtns;
|
|
|
|
if (dev->key)
|
|
kbd = dev;
|
|
else
|
|
kbd = inputInfo.keyboard;
|
|
acts = &dev->button->xkb_acts[stuff->firstBtn];
|
|
for (i = 0; i < stuff->nBtns; i++, acts++) {
|
|
if (acts->type != XkbSA_NoAction)
|
|
XkbSetActionKeyMods(kbd->key->xkbInfo->desc, acts, 0);
|
|
}
|
|
}
|
|
if (stuff->change & XkbXI_IndicatorsMask) {
|
|
int status = Success;
|
|
|
|
wire = SetDeviceIndicators(wire, dev, stuff->change,
|
|
stuff->nDeviceLedFBs, &status, client, &ed);
|
|
if (status != Success)
|
|
return status;
|
|
}
|
|
if ((stuff->change) && (ed.reason))
|
|
XkbSendExtensionDeviceNotify(dev, client, &ed);
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcXkbSetDeviceInfo(ClientPtr client)
|
|
{
|
|
DeviceIntPtr dev;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetDeviceInfoReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetDeviceInfoReq);
|
|
|
|
if (!(client->xkbClientFlags & _XkbClientInitialized))
|
|
return BadAccess;
|
|
|
|
CHK_ANY_DEVICE(dev, stuff->deviceSpec, client, DixManageAccess);
|
|
CHK_MASK_LEGAL(0x01, stuff->change, XkbXI_AllFeaturesMask);
|
|
|
|
rc = _XkbSetDeviceInfoCheck(client, dev, stuff);
|
|
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd ||
|
|
stuff->deviceSpec == XkbUseCorePtr) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if (((other != dev) && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) &&
|
|
((stuff->deviceSpec == XkbUseCoreKbd && other->key) ||
|
|
(stuff->deviceSpec == XkbUseCorePtr && other->button))) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success) {
|
|
rc = _XkbSetDeviceInfoCheck(client, other, stuff);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* checks done, apply */
|
|
rc = _XkbSetDeviceInfo(client, dev, stuff);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
if (stuff->deviceSpec == XkbUseCoreKbd ||
|
|
stuff->deviceSpec == XkbUseCorePtr) {
|
|
DeviceIntPtr other;
|
|
|
|
for (other = inputInfo.devices; other; other = other->next) {
|
|
if (((other != dev) && !IsMaster(other) &&
|
|
GetMaster(other, MASTER_KEYBOARD) == dev) &&
|
|
((stuff->deviceSpec == XkbUseCoreKbd && other->key) ||
|
|
(stuff->deviceSpec == XkbUseCorePtr && other->button))) {
|
|
rc = XaceHook(XACE_DEVICE_ACCESS, client, other,
|
|
DixManageAccess);
|
|
if (rc == Success) {
|
|
rc = _XkbSetDeviceInfo(client, other, stuff);
|
|
if (rc != Success)
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
int
|
|
ProcXkbSetDebuggingFlags(ClientPtr client)
|
|
{
|
|
CARD32 newFlags, newCtrls, extraLength;
|
|
xkbSetDebuggingFlagsReply rep;
|
|
int rc;
|
|
|
|
REQUEST(xkbSetDebuggingFlagsReq);
|
|
REQUEST_AT_LEAST_SIZE(xkbSetDebuggingFlagsReq);
|
|
|
|
rc = XaceHook(XACE_SERVER_ACCESS, client, DixDebugAccess);
|
|
if (rc != Success)
|
|
return rc;
|
|
|
|
newFlags = xkbDebugFlags & (~stuff->affectFlags);
|
|
newFlags |= (stuff->flags & stuff->affectFlags);
|
|
newCtrls = xkbDebugCtrls & (~stuff->affectCtrls);
|
|
newCtrls |= (stuff->ctrls & stuff->affectCtrls);
|
|
if (xkbDebugFlags || newFlags || stuff->msgLength) {
|
|
ErrorF("[xkb] XkbDebug: Setting debug flags to 0x%lx\n",
|
|
(long) newFlags);
|
|
if (newCtrls != xkbDebugCtrls)
|
|
ErrorF("[xkb] XkbDebug: Setting debug controls to 0x%lx\n",
|
|
(long) newCtrls);
|
|
}
|
|
extraLength = (stuff->length << 2) - sz_xkbSetDebuggingFlagsReq;
|
|
if (stuff->msgLength > 0) {
|
|
char *msg;
|
|
|
|
if (extraLength < XkbPaddedSize(stuff->msgLength)) {
|
|
ErrorF
|
|
("[xkb] XkbDebug: msgLength= %d, length= %ld (should be %d)\n",
|
|
stuff->msgLength, (long) extraLength,
|
|
XkbPaddedSize(stuff->msgLength));
|
|
return BadLength;
|
|
}
|
|
msg = (char *) &stuff[1];
|
|
if (msg[stuff->msgLength - 1] != '\0') {
|
|
ErrorF("[xkb] XkbDebug: message not null-terminated\n");
|
|
return BadValue;
|
|
}
|
|
ErrorF("[xkb] XkbDebug: %s\n", msg);
|
|
}
|
|
xkbDebugFlags = newFlags;
|
|
xkbDebugCtrls = newCtrls;
|
|
|
|
rep = (xkbSetDebuggingFlagsReply) {
|
|
.type = X_Reply,
|
|
.sequenceNumber = client->sequence,
|
|
.length = 0,
|
|
.currentFlags = newFlags,
|
|
.currentCtrls = newCtrls,
|
|
.supportedFlags = ~0,
|
|
.supportedCtrls = ~0
|
|
};
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber);
|
|
swapl(&rep.currentFlags);
|
|
swapl(&rep.currentCtrls);
|
|
swapl(&rep.supportedFlags);
|
|
swapl(&rep.supportedCtrls);
|
|
}
|
|
WriteToClient(client, SIZEOF(xkbSetDebuggingFlagsReply), &rep);
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static int
|
|
ProcXkbDispatch(ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
switch (stuff->data) {
|
|
case X_kbUseExtension:
|
|
return ProcXkbUseExtension(client);
|
|
case X_kbSelectEvents:
|
|
return ProcXkbSelectEvents(client);
|
|
case X_kbBell:
|
|
return ProcXkbBell(client);
|
|
case X_kbGetState:
|
|
return ProcXkbGetState(client);
|
|
case X_kbLatchLockState:
|
|
return ProcXkbLatchLockState(client);
|
|
case X_kbGetControls:
|
|
return ProcXkbGetControls(client);
|
|
case X_kbSetControls:
|
|
return ProcXkbSetControls(client);
|
|
case X_kbGetMap:
|
|
return ProcXkbGetMap(client);
|
|
case X_kbSetMap:
|
|
return ProcXkbSetMap(client);
|
|
case X_kbGetCompatMap:
|
|
return ProcXkbGetCompatMap(client);
|
|
case X_kbSetCompatMap:
|
|
return ProcXkbSetCompatMap(client);
|
|
case X_kbGetIndicatorState:
|
|
return ProcXkbGetIndicatorState(client);
|
|
case X_kbGetIndicatorMap:
|
|
return ProcXkbGetIndicatorMap(client);
|
|
case X_kbSetIndicatorMap:
|
|
return ProcXkbSetIndicatorMap(client);
|
|
case X_kbGetNamedIndicator:
|
|
return ProcXkbGetNamedIndicator(client);
|
|
case X_kbSetNamedIndicator:
|
|
return ProcXkbSetNamedIndicator(client);
|
|
case X_kbGetNames:
|
|
return ProcXkbGetNames(client);
|
|
case X_kbSetNames:
|
|
return ProcXkbSetNames(client);
|
|
case X_kbGetGeometry:
|
|
return ProcXkbGetGeometry(client);
|
|
case X_kbSetGeometry:
|
|
return ProcXkbSetGeometry(client);
|
|
case X_kbPerClientFlags:
|
|
return ProcXkbPerClientFlags(client);
|
|
case X_kbListComponents:
|
|
return ProcXkbListComponents(client);
|
|
case X_kbGetKbdByName:
|
|
return ProcXkbGetKbdByName(client);
|
|
case X_kbGetDeviceInfo:
|
|
return ProcXkbGetDeviceInfo(client);
|
|
case X_kbSetDeviceInfo:
|
|
return ProcXkbSetDeviceInfo(client);
|
|
case X_kbSetDebuggingFlags:
|
|
return ProcXkbSetDebuggingFlags(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
static int
|
|
XkbClientGone(void *data, XID id)
|
|
{
|
|
DevicePtr pXDev = (DevicePtr) data;
|
|
|
|
if (!XkbRemoveResourceClient(pXDev, id)) {
|
|
ErrorF
|
|
("[xkb] Internal Error! bad RemoveResourceClient in XkbClientGone\n");
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
XkbExtensionInit(void)
|
|
{
|
|
ExtensionEntry *extEntry;
|
|
|
|
RT_XKBCLIENT = CreateNewResourceType(XkbClientGone, "XkbClient");
|
|
if (!RT_XKBCLIENT)
|
|
return;
|
|
|
|
if (!XkbInitPrivates())
|
|
return;
|
|
|
|
if ((extEntry = AddExtension(XkbName, XkbNumberEvents, XkbNumberErrors,
|
|
ProcXkbDispatch, SProcXkbDispatch,
|
|
NULL, StandardMinorOpcode))) {
|
|
XkbReqCode = (unsigned char) extEntry->base;
|
|
XkbEventBase = (unsigned char) extEntry->eventBase;
|
|
XkbErrorBase = (unsigned char) extEntry->errorBase;
|
|
XkbKeyboardErrorCode = XkbErrorBase + XkbKeyboard;
|
|
}
|
|
return;
|
|
}
|