xkb: ProcXkbSetCompatMap should work on all attached SDs.

If called with XkbUseCoreKbd, run through all attached SDs and replicate the
call. This way, we keep the SDs in sync with the MD as long as core clients
control the MDs.
This commit is contained in:
Peter Hutterer 2008-08-01 16:37:39 +09:30
parent 3c7740aa8f
commit e8c2a3d7c9

152
xkb/xkb.c
View File

@ -2727,57 +2727,58 @@ ProcXkbGetCompatMap(ClientPtr client)
return XkbSendCompatMap(client,compat,&rep); return XkbSendCompatMap(client,compat,&rep);
} }
/* FIXME: Needs to set compat map on all core-sending devices. */ /**
int * Apply the given request on the given device.
ProcXkbSetCompatMap(ClientPtr client) * 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)
{ {
DeviceIntPtr dev;
XkbSrvInfoPtr xkbi; XkbSrvInfoPtr xkbi;
XkbDescPtr xkb; XkbDescPtr xkb;
XkbCompatMapPtr compat; XkbCompatMapPtr compat;
char * data;
int nGroups; int nGroups;
register unsigned i,bit; unsigned i,bit;
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];
xkbi = dev->key->xkbInfo; xkbi = dev->key->xkbInfo;
xkb = xkbi->desc; xkb = xkbi->desc;
compat = xkb->compat; compat = xkb->compat;
if ((stuff->nSI>0)||(stuff->truncateSI)) {
if ((req->nSI>0)||(req->truncateSI)) {
xkbSymInterpretWireDesc *wire; xkbSymInterpretWireDesc *wire;
if (stuff->firstSI>compat->num_si) { if (req->firstSI>compat->num_si) {
client->errorValue = _XkbErrCode2(0x02,compat->num_si); client->errorValue = _XkbErrCode2(0x02,compat->num_si);
return BadValue; return BadValue;
} }
wire= (xkbSymInterpretWireDesc *)data; wire= (xkbSymInterpretWireDesc *)data;
wire+= stuff->nSI; wire+= req->nSI;
data = (char *)wire; data = (char *)wire;
} }
nGroups= 0; nGroups= 0;
if (stuff->groups!=0) { if (req->groups!=0) {
for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) { for (i=0,bit=1;i<XkbNumKbdGroups;i++,bit<<=1) {
if ( stuff->groups&bit ) if ( req->groups&bit )
nGroups++; nGroups++;
} }
} }
data+= nGroups*SIZEOF(xkbModsWireDesc); data+= nGroups*SIZEOF(xkbModsWireDesc);
if (((data-((char *)stuff))/4)!=stuff->length) { if (((data-((char *)req))/4)!=req->length) {
return BadLength; return BadLength;
} }
data = (char *)&stuff[1];
if (stuff->nSI>0) { /* Done all the checks we can do */
if (dryRun)
return Success;
data = (char *)&req[1];
if (req->nSI>0) {
xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data; xkbSymInterpretWireDesc *wire = (xkbSymInterpretWireDesc *)data;
XkbSymInterpretPtr sym; XkbSymInterpretPtr sym;
if ((unsigned)(stuff->firstSI+stuff->nSI)>compat->num_si) { if ((unsigned)(req->firstSI+req->nSI)>compat->num_si) {
compat->num_si= stuff->firstSI+stuff->nSI; compat->num_si= req->firstSI+req->nSI;
compat->sym_interpret= _XkbTypedRealloc(compat->sym_interpret, compat->sym_interpret= _XkbTypedRealloc(compat->sym_interpret,
compat->num_si, compat->num_si,
XkbSymInterpretRec); XkbSymInterpretRec);
@ -2786,13 +2787,13 @@ ProcXkbSetCompatMap(ClientPtr client)
return BadAlloc; return BadAlloc;
} }
} }
else if (stuff->truncateSI) { else if (req->truncateSI) {
compat->num_si = stuff->firstSI+stuff->nSI; compat->num_si = req->firstSI+req->nSI;
} }
sym = &compat->sym_interpret[stuff->firstSI]; sym = &compat->sym_interpret[req->firstSI];
for (i=0;i<stuff->nSI;i++,wire++,sym++) { for (i=0;i<req->nSI;i++,wire++,sym++) {
if (client->swapped) { if (client->swapped) {
register int n; int n;
swapl(&wire->sym,n); swapl(&wire->sym,n);
} }
sym->sym= wire->sym; sym->sym= wire->sym;
@ -2805,17 +2806,17 @@ ProcXkbSetCompatMap(ClientPtr client)
} }
data = (char *)wire; data = (char *)wire;
} }
else if (stuff->truncateSI) { else if (req->truncateSI) {
compat->num_si = stuff->firstSI; compat->num_si = req->firstSI;
} }
if (stuff->groups!=0) { if (req->groups!=0) {
register unsigned i,bit; unsigned i, bit;
xkbModsWireDesc *wire = (xkbModsWireDesc *)data; xkbModsWireDesc *wire = (xkbModsWireDesc *)data;
for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) { for (i = 0, bit = 1; i < XkbNumKbdGroups; i++, bit <<= 1) {
if (stuff->groups&bit) { if (req->groups & bit) {
if (client->swapped) { if (client->swapped) {
register int n; int n;
swaps(&wire->virtualMods,n); swaps(&wire->virtualMods,n);
} }
compat->groups[i].mask= wire->realMods; compat->groups[i].mask= wire->realMods;
@ -2831,23 +2832,23 @@ ProcXkbSetCompatMap(ClientPtr client)
} }
} }
} }
i= XkbPaddedSize((data-((char *)stuff))); i= XkbPaddedSize((data-((char *)req)));
if ((i/4)!=stuff->length) { if ((i/4)!=req->length) {
ErrorF("[xkb] Internal length error on read in ProcXkbSetCompatMap\n"); ErrorF("[xkb] Internal length error on read in _XkbSetCompatMap\n");
return BadLength; return BadLength;
} }
if (dev->xkb_interest) { if (dev->xkb_interest) {
xkbCompatMapNotify ev; xkbCompatMapNotify ev;
ev.deviceID = dev->id; ev.deviceID = dev->id;
ev.changedGroups = stuff->groups; ev.changedGroups = req->groups;
ev.firstSI = stuff->firstSI; ev.firstSI = req->firstSI;
ev.nSI = stuff->nSI; ev.nSI = req->nSI;
ev.nTotalSI = compat->num_si; ev.nTotalSI = compat->num_si;
XkbSendCompatMapNotify(dev,&ev); XkbSendCompatMapNotify(dev,&ev);
} }
if (stuff->recomputeActions) { if (req->recomputeActions) {
XkbChangesRec change; XkbChangesRec change;
unsigned check; unsigned check;
XkbEventCauseRec cause; XkbEventCauseRec cause;
@ -2861,6 +2862,71 @@ ProcXkbSetCompatMap(ClientPtr client)
XkbUpdateCoreDescription(dev,False); XkbUpdateCoreDescription(dev,False);
XkbSendNotification(dev,&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 && !other->isMaster && (other->u.master == 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, 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 && !other->isMaster && (other->u.master == dev))
{
rc = XaceHook(XACE_DEVICE_ACCESS, client, other, DixManageAccess);
if (rc == Success)
{
rc = _XkbSetCompatMap(client, other, stuff, data, TRUE);
if (rc != Success)
return rc;
}
}
}
}
return client->noClientException; return client->noClientException;
} }