#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "os.h"
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#define NEED_EVENTS 1
#include <X11/X.h>
#include <X11/Xproto.h>
#define XK_CYRILLIC
#include <X11/keysym.h>
#include "misc.h"
#include "inputstr.h"
#define XKBSRV_NEED_FILE_FUNCS
#include <xkbsrv.h>
#include <X11/extensions/XKBgeom.h>
#include "xkb.h"
int XkbDisableLockActions = 0;
DeviceIntPtr
_XkbLookupAnyDevice(int id,int *why_rtrn)
{
DeviceIntPtr dev = NULL;
dev= (DeviceIntPtr)LookupKeyboardDevice();
if ((id==XkbUseCoreKbd)||(dev->id==id))
return dev;
dev= (DeviceIntPtr)LookupPointerDevice();
if ((id==XkbUseCorePtr)||(dev->id==id))
return dev;
if (id&(~0xff))
dev = NULL;
dev= (DeviceIntPtr)LookupDevice(id);
if (dev!=NULL)
return dev;
if ((!dev)&&(why_rtrn))
*why_rtrn= XkbErr_BadDevice;
return dev;
}
DeviceIntPtr
_XkbLookupKeyboard(int id,int *why_rtrn)
{
DeviceIntPtr dev = NULL;
if (id == XkbDfltXIId)
id = XkbUseCoreKbd;
if ((dev= _XkbLookupAnyDevice(id,why_rtrn))==NULL)
return NULL;
else if ((!dev->key)||(!dev->key->xkbInfo)) {
if (why_rtrn)
*why_rtrn= XkbErr_BadClass;
return NULL;
}
return dev;
}
DeviceIntPtr
_XkbLookupBellDevice(int id,int *why_rtrn)
{
DeviceIntPtr dev = NULL;
if ((dev= _XkbLookupAnyDevice(id,why_rtrn))==NULL)
return NULL;
else if ((!dev->kbdfeed)&&(!dev->bell)) {
if (why_rtrn)
*why_rtrn= XkbErr_BadClass;
return NULL;
}
return dev;
}
DeviceIntPtr
_XkbLookupLedDevice(int id,int *why_rtrn)
{
DeviceIntPtr dev = NULL;
if (id == XkbDfltXIId)
id = XkbUseCorePtr;
if ((dev= _XkbLookupAnyDevice(id,why_rtrn))==NULL)
return NULL;
else if ((!dev->kbdfeed)&&(!dev->leds)) {
if (why_rtrn)
*why_rtrn= XkbErr_BadClass;
return NULL;
}
return dev;
}
DeviceIntPtr
_XkbLookupButtonDevice(int id,int *why_rtrn)
{
DeviceIntPtr dev = NULL;
if ((dev= _XkbLookupAnyDevice(id,why_rtrn))==NULL)
return NULL;
else if (!dev->button) {
if (why_rtrn)
*why_rtrn= XkbErr_BadClass;
return NULL;
}
return dev;
}
void
XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
{
register unsigned tmp;
switch (act->type) {
case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
if (act->mods.flags&XkbSA_UseModMapMods)
act->mods.real_mods= act->mods.mask= mods;
if ((tmp= XkbModActionVMods(&act->mods))!=0)
act->mods.mask|= XkbMaskForVMask(xkb,tmp);
break;
case XkbSA_ISOLock:
if (act->iso.flags&XkbSA_UseModMapMods)
act->iso.real_mods= act->iso.mask= mods;
if ((tmp= XkbModActionVMods(&act->iso))!=0)
act->iso.mask|= XkbMaskForVMask(xkb,tmp);
break;
}
return;
}
unsigned
XkbMaskForVMask(XkbDescPtr xkb,unsigned vmask)
{
register int i,bit;
register unsigned mask;
for (mask=i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
if (vmask&bit)
mask|= xkb->server->vmods[i];
}
return mask;
}
void
XkbUpdateKeyTypesFromCore( DeviceIntPtr pXDev,
KeyCode first,
CARD8 num,
XkbChangesPtr changes)
{
XkbDescPtr xkb;
unsigned key,nG,explicit;
KeySymsPtr pCore;
int types[XkbNumKbdGroups];
KeySym tsyms[XkbMaxSymsPerKey],*syms;
XkbMapChangesPtr mc;
xkb= pXDev->key->xkbInfo->desc;
#ifdef NOTYET
if (first<xkb->min_key_code) {
if (first>=XkbMinLegalKeyCode) {
xkb->min_key_code= first;
changes->map.changed|= XkbKeycodesMask;
}
}
#endif
if (first+num-1>xkb->max_key_code) {
num= xkb->max_key_code-first+1;
}
mc= (changes?(&changes->map):NULL);
pCore= &pXDev->key->curKeySyms;
syms= &pCore->map[(first-xkb->min_key_code)*pCore->mapWidth];
for (key=first; key<(first+num); key++,syms+= pCore->mapWidth) {
explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask;
types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index);
types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index);
types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index);
nG= XkbKeyTypesForCoreSymbols(xkb,pCore->mapWidth,syms,explicit,types,
tsyms);
XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc);
memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms,
XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
}
if (changes->map.changed&XkbKeySymsMask) {
CARD8 oldLast,newLast;
oldLast = changes->map.first_key_sym+changes->map.num_key_syms-1;
newLast = first+num-1;
if (first<changes->map.first_key_sym)
changes->map.first_key_sym = first;
if (oldLast>newLast)
newLast= oldLast;
changes->map.num_key_syms = newLast-changes->map.first_key_sym+1;
}
else {
changes->map.changed|= XkbKeySymsMask;
changes->map.first_key_sym = first;
changes->map.num_key_syms = num;
}
return;
}
void
XkbUpdateDescActions( XkbDescPtr xkb,
KeyCode first,
CARD8 num,
XkbChangesPtr changes)
{
register unsigned key;
for (key=first;key<(first+num);key++) {
XkbApplyCompatMapToKey(xkb,key,changes);
}
if (changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask)) {
unsigned char newVMods[XkbNumVirtualMods];
register unsigned bit,i;
unsigned present;
bzero(newVMods,XkbNumVirtualMods);
present= 0;
for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) {
if (xkb->server->vmodmap[key]==0)
continue;
for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
if (bit&xkb->server->vmodmap[key]) {
present|= bit;
newVMods[i]|= xkb->map->modmap[key];
}
}
}
for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
if ((bit&present)&&(newVMods[i]!=xkb->server->vmods[i])) {
changes->map.changed|= XkbVirtualModsMask;
changes->map.vmods|= bit;
xkb->server->vmods[i]= newVMods[i];
}
}
}
if (changes->map.changed&XkbVirtualModsMask)
XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes);
if (changes->map.changed&XkbKeyActionsMask) {
CARD8 oldLast,newLast;
oldLast= changes->map.first_key_act+changes->map.num_key_acts-1;
newLast = first+num-1;
if (first<changes->map.first_key_act)
changes->map.first_key_act = first;
if (newLast>oldLast)
newLast= oldLast;
changes->map.num_key_acts= newLast-changes->map.first_key_act+1;
}
else {
changes->map.changed|= XkbKeyActionsMask;
changes->map.first_key_act = first;
changes->map.num_key_acts = num;
}
return;
}
void
XkbUpdateActions( DeviceIntPtr pXDev,
KeyCode first,
CARD8 num,
XkbChangesPtr changes,
unsigned * needChecksRtrn,
XkbEventCausePtr cause)
{
XkbSrvInfoPtr xkbi;
XkbDescPtr xkb;
CARD8 * repeat;
if (needChecksRtrn)
*needChecksRtrn= 0;
xkbi= pXDev->key->xkbInfo;
xkb= xkbi->desc;
repeat= xkb->ctrls->per_key_repeat;
if (pXDev->kbdfeed)
memcpy(repeat,pXDev->kbdfeed->ctrl.autoRepeats,32);
XkbUpdateDescActions(xkb,first,num,changes);
if ((pXDev->kbdfeed)&&
(changes->ctrls.enabled_ctrls_changes&XkbPerKeyRepeatMask)) {
memcpy(pXDev->kbdfeed->ctrl.autoRepeats,repeat, 32);
(*pXDev->kbdfeed->CtrlProc)(pXDev, &pXDev->kbdfeed->ctrl);
}
return;
}
void
XkbUpdateCoreDescription(DeviceIntPtr keybd,Bool resize)
{
register int key,tmp;
int maxSymsPerKey,maxKeysPerMod;
int first,last,firstCommon,lastCommon;
XkbDescPtr xkb;
KeyClassPtr keyc;
CARD8 keysPerMod[XkbNumModifiers];
if (!keybd || !keybd->key || !keybd->key->xkbInfo)
return;
xkb= keybd->key->xkbInfo->desc;
keyc= keybd->key;
maxSymsPerKey= maxKeysPerMod= 0;
bzero(keysPerMod,sizeof(keysPerMod));
memcpy(keyc->modifierMap,xkb->map->modmap,xkb->max_key_code+1);
if ((xkb->min_key_code==keyc->curKeySyms.minKeyCode)&&
(xkb->max_key_code==keyc->curKeySyms.maxKeyCode)) {
first= firstCommon= xkb->min_key_code;
last= lastCommon= xkb->max_key_code;
}
else if (resize) {
keyc->curKeySyms.minKeyCode= xkb->min_key_code;
keyc->curKeySyms.maxKeyCode= xkb->max_key_code;
tmp= keyc->curKeySyms.mapWidth*_XkbCoreNumKeys(keyc);
keyc->curKeySyms.map= _XkbTypedRealloc(keyc->curKeySyms.map,tmp,KeySym);
if (!keyc->curKeySyms.map)
FatalError("Couldn't allocate keysyms\n");
first= firstCommon= xkb->min_key_code;
last= lastCommon= xkb->max_key_code;
}
else {
if (xkb->min_key_code<keyc->curKeySyms.minKeyCode) {
first= xkb->min_key_code;
firstCommon= keyc->curKeySyms.minKeyCode;
}
else {
firstCommon= xkb->min_key_code;
first= keyc->curKeySyms.minKeyCode;
}
if (xkb->max_key_code>keyc->curKeySyms.maxKeyCode) {
lastCommon= keyc->curKeySyms.maxKeyCode;
last= xkb->max_key_code;
}
else {
lastCommon= xkb->max_key_code;
last= keyc->curKeySyms.maxKeyCode;
}
}
for (key=first;key<=last;key++) {
if (XkbKeycodeInRange(xkb,key)) {
int nGroups;
int w;
nGroups= XkbKeyNumGroups(xkb,key);
tmp= 0;
if (nGroups>0) {
if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup1Index))<=2)
tmp+= 2;
else tmp+= w + 2;
}
if (nGroups>1) {
if (tmp <= 2) {
if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))<2)
tmp+= 2;
else tmp+= w;
} else {
if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2)
tmp+= w - 2;
}
}
if (nGroups>2)
tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup3Index);
if (nGroups>3)
tmp+= XkbKeyGroupWidth(xkb,key,XkbGroup4Index);
if (tmp>maxSymsPerKey)
maxSymsPerKey= tmp;
}
if (_XkbCoreKeycodeInRange(keyc,key)) {
if (keyc->modifierMap[key]!=0) {
register unsigned bit,i,mask;
mask= keyc->modifierMap[key];
for (i=0,bit=1;i<XkbNumModifiers;i++,bit<<=1) {
if (mask&bit) {
keysPerMod[i]++;
if (keysPerMod[i]>maxKeysPerMod)
maxKeysPerMod= keysPerMod[i];
}
}
}
}
}
if (maxKeysPerMod>0) {
tmp= maxKeysPerMod*XkbNumModifiers;
if (keyc->modifierKeyMap==NULL)
keyc->modifierKeyMap= (KeyCode *)_XkbCalloc(1, tmp);
else if (keyc->maxKeysPerModifier<maxKeysPerMod)
keyc->modifierKeyMap= (KeyCode *)_XkbRealloc(keyc->modifierKeyMap,tmp);
if (keyc->modifierKeyMap==NULL)
FatalError("Couldn't allocate modifierKeyMap in UpdateCore\n");
bzero(keyc->modifierKeyMap,tmp);
}
else if ((keyc->maxKeysPerModifier>0)&&(keyc->modifierKeyMap!=NULL)) {
_XkbFree(keyc->modifierKeyMap);
keyc->modifierKeyMap= NULL;
}
keyc->maxKeysPerModifier= maxKeysPerMod;
if (maxSymsPerKey>0) {
tmp= maxSymsPerKey*_XkbCoreNumKeys(keyc);
keyc->curKeySyms.map= _XkbTypedRealloc(keyc->curKeySyms.map,tmp,KeySym);
if (keyc->curKeySyms.map==NULL)
FatalError("Couldn't allocate symbols map in UpdateCore\n");
}
else if ((keyc->curKeySyms.mapWidth>0)&&(keyc->curKeySyms.map!=NULL)) {
_XkbFree(keyc->curKeySyms.map);
keyc->curKeySyms.map= NULL;
}
keyc->curKeySyms.mapWidth= maxSymsPerKey;
bzero(keysPerMod,sizeof(keysPerMod));
for (key=firstCommon;key<=lastCommon;key++) {
if (keyc->curKeySyms.map!=NULL) {
KeySym *pCore,*pXKB;
unsigned nGroups,groupWidth,n,nOut;
nGroups= XkbKeyNumGroups(xkb,key);
n= (key-keyc->curKeySyms.minKeyCode)*maxSymsPerKey;
pCore= &keyc->curKeySyms.map[n];
bzero(pCore,maxSymsPerKey*sizeof(KeySym));
pXKB= XkbKeySymsPtr(xkb,key);
nOut= 2;
if (nGroups>0) {
groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup1Index);
if (groupWidth>0) pCore[0]= pXKB[0];
if (groupWidth>1) pCore[1]= pXKB[1];
for (n=2;n<groupWidth;n++) {
pCore[2+n]= pXKB[n];
}
if (groupWidth>2)
nOut= groupWidth;
}
pXKB+= XkbKeyGroupsWidth(xkb,key);
nOut+= 2;
if (nGroups>1) {
groupWidth= XkbKeyGroupWidth(xkb,key,XkbGroup2Index);
if (groupWidth>0) pCore[2]= pXKB[0];
if (groupWidth>1) pCore[3]= pXKB[1];
for (n=2;n<groupWidth;n++) {
pCore[nOut+(n-2)]= pXKB[n];
}
if (groupWidth>2)
nOut+= (groupWidth-2);
}
pXKB+= XkbKeyGroupsWidth(xkb,key);
for (n=XkbGroup3Index;n<nGroups;n++) {
register int s;
groupWidth= XkbKeyGroupWidth(xkb,key,n);
for (s=0;s<groupWidth;s++) {
pCore[nOut++]= pXKB[s];
}
pXKB+= XkbKeyGroupsWidth(xkb,key);
}
if (!pCore[2] && !pCore[3] && maxSymsPerKey >= 6 &&
(pCore[4] || pCore[5])) {
pCore[2] = pCore[4];
pCore[3] = pCore[5];
}
}
if (keyc->modifierMap[key]!=0) {
register unsigned bit,i,mask;
mask= keyc->modifierMap[key];
for (i=0,bit=1;i<XkbNumModifiers;i++,bit<<=1) {
if (mask&bit) {
tmp= i*maxKeysPerMod+keysPerMod[i];
keyc->modifierKeyMap[tmp]= key;
keysPerMod[i]++;
}
}
}
}
return;
}
void
XkbSetRepeatKeys(DeviceIntPtr pXDev,int key,int onoff)
{
if (pXDev && pXDev->key && pXDev->key->xkbInfo) {
xkbControlsNotify cn;
XkbControlsPtr ctrls = pXDev->key->xkbInfo->desc->ctrls;
XkbControlsRec old;
old = *ctrls;
if (key== -1) {
if (onoff) ctrls->enabled_ctrls |= XkbRepeatKeysMask;
else ctrls->enabled_ctrls &= ~XkbRepeatKeysMask;
}
else if (pXDev->kbdfeed) {
ctrls->per_key_repeat[key/8] =
pXDev->kbdfeed->ctrl.autoRepeats[key/8];
}
if (XkbComputeControlsNotify(pXDev,&old,ctrls,&cn,True))
XkbSendControlsNotify(pXDev,&cn);
}
return;
}
void
XkbApplyMappingChange( DeviceIntPtr kbd,
CARD8 request,
KeyCode firstKey,
CARD8 num,
ClientPtr client)
{
XkbEventCauseRec cause;
XkbChangesRec changes;
unsigned check;
if (kbd->key->xkbInfo==NULL)
XkbInitDevice(kbd);
bzero(&changes,sizeof(XkbChangesRec));
check= 0;
if (request==MappingKeyboard) {
XkbSetCauseCoreReq(&cause,X_ChangeKeyboardMapping,client);
XkbUpdateKeyTypesFromCore(kbd,firstKey,num,&changes);
XkbUpdateActions(kbd,firstKey,num,&changes,&check,&cause);
if (check)
XkbCheckSecondaryEffects(kbd->key->xkbInfo,check,&changes,&cause);
}
else if (request==MappingModifier) {
XkbDescPtr xkb= kbd->key->xkbInfo->desc;
XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client);
num = xkb->max_key_code-xkb->min_key_code+1;
memcpy(xkb->map->modmap,kbd->key->modifierMap,xkb->max_key_code+1);
changes.map.changed|= XkbModifierMapMask;
changes.map.first_modmap_key= xkb->min_key_code;
changes.map.num_modmap_keys= num;
XkbUpdateActions(kbd,xkb->min_key_code,num,&changes,&check,&cause);
if (check)
XkbCheckSecondaryEffects(kbd->key->xkbInfo,check,&changes,&cause);
}
XkbSendNotification(kbd,&changes,&cause);
return;
}
void
XkbDisableComputedAutoRepeats(DeviceIntPtr dev,unsigned key)
{
XkbSrvInfoPtr xkbi = dev->key->xkbInfo;
xkbMapNotify mn;
xkbi->desc->server->explicit[key]|= XkbExplicitAutoRepeatMask;
bzero(&mn,sizeof(mn));
mn.changed= XkbExplicitComponentsMask;
mn.firstKeyExplicit= key;
mn.nKeyExplicit= 1;
XkbSendMapNotify(dev,&mn);
return;
}
unsigned
XkbStateChangedFlags(XkbStatePtr old,XkbStatePtr new)
{
int changed;
changed=(old->group!=new->group?XkbGroupStateMask:0);
changed|=(old->base_group!=new->base_group?XkbGroupBaseMask:0);
changed|=(old->latched_group!=new->latched_group?XkbGroupLatchMask:0);
changed|=(old->locked_group!=new->locked_group?XkbGroupLockMask:0);
changed|=(old->mods!=new->mods?XkbModifierStateMask:0);
changed|=(old->base_mods!=new->base_mods?XkbModifierBaseMask:0);
changed|=(old->latched_mods!=new->latched_mods?XkbModifierLatchMask:0);
changed|=(old->locked_mods!=new->locked_mods?XkbModifierLockMask:0);
changed|=(old->compat_state!=new->compat_state?XkbCompatStateMask:0);
changed|=(old->grab_mods!=new->grab_mods?XkbGrabModsMask:0);
if (old->compat_grab_mods!=new->compat_grab_mods)
changed|= XkbCompatGrabModsMask;
changed|=(old->lookup_mods!=new->lookup_mods?XkbLookupModsMask:0);
if (old->compat_lookup_mods!=new->compat_lookup_mods)
changed|= XkbCompatLookupModsMask;
changed|=(old->ptr_buttons!=new->ptr_buttons?XkbPointerButtonMask:0);
return changed;
}
static void
XkbComputeCompatState(XkbSrvInfoPtr xkbi)
{
CARD16 grp_mask;
XkbStatePtr state= &xkbi->state;
XkbCompatMapPtr map;
if (!state || !xkbi->desc || !xkbi->desc->ctrls || !xkbi->desc->compat)
return;
map= xkbi->desc->compat;
grp_mask= map->groups[state->group].mask;
state->compat_state = state->mods|grp_mask;
state->compat_lookup_mods= state->lookup_mods|grp_mask;
if (xkbi->desc->ctrls->enabled_ctrls&XkbIgnoreGroupLockMask)
grp_mask= map->groups[state->base_group].mask;
state->compat_grab_mods= state->grab_mods|grp_mask;
return;
}
unsigned
XkbAdjustGroup(int group,XkbControlsPtr ctrls)
{
unsigned act;
act= XkbOutOfRangeGroupAction(ctrls->groups_wrap);
if (group<0) {
while ( group < 0 ) {
if (act==XkbClampIntoRange) {
group= XkbGroup1Index;
}
else if (act==XkbRedirectIntoRange) {
int newGroup;
newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap);
if (newGroup>=ctrls->num_groups)
group= XkbGroup1Index;
else group= newGroup;
}
else {
group+= ctrls->num_groups;
}
}
}
else if (group>=ctrls->num_groups) {
if (act==XkbClampIntoRange) {
group= ctrls->num_groups-1;
}
else if (act==XkbRedirectIntoRange) {
int newGroup;
newGroup= XkbOutOfRangeGroupNumber(ctrls->groups_wrap);
if (newGroup>=ctrls->num_groups)
group= XkbGroup1Index;
else group= newGroup;
}
else {
group%= ctrls->num_groups;
}
}
return group;
}
void
XkbComputeDerivedState(XkbSrvInfoPtr xkbi)
{
XkbStatePtr state= &xkbi->state;
XkbControlsPtr ctrls= xkbi->desc->ctrls;
unsigned char grp;
if (!state || !ctrls)
return;
state->mods= (state->base_mods|state->latched_mods);
state->mods|= state->locked_mods;
state->lookup_mods= state->mods&(~ctrls->internal.mask);
state->grab_mods= state->lookup_mods&(~ctrls->ignore_lock.mask);
state->grab_mods|=
((state->base_mods|state->latched_mods)&ctrls->ignore_lock.mask);
grp= state->locked_group;
if (grp>=ctrls->num_groups)
state->locked_group= XkbAdjustGroup(XkbCharToInt(grp),ctrls);
grp= state->locked_group+state->base_group+state->latched_group;
if (grp>=ctrls->num_groups)
state->group= XkbAdjustGroup(XkbCharToInt(grp),ctrls);
else state->group= grp;
XkbComputeCompatState(xkbi);
return;
}
void
XkbCheckSecondaryEffects( XkbSrvInfoPtr xkbi,
unsigned which,
XkbChangesPtr changes,
XkbEventCausePtr cause)
{
if (which&XkbStateNotifyMask) {
XkbStateRec old;
old= xkbi->state;
changes->state_changes|= XkbStateChangedFlags(&old,&xkbi->state);
XkbComputeDerivedState(xkbi);
}
if (which&XkbIndicatorStateNotifyMask)
XkbUpdateIndicators(xkbi->device,XkbAllIndicatorsMask,True,changes,
cause);
return;
}
Bool
XkbEnableDisableControls( XkbSrvInfoPtr xkbi,
unsigned long change,
unsigned long newValues,
XkbChangesPtr changes,
XkbEventCausePtr cause)
{
XkbControlsPtr ctrls;
unsigned old;
XkbSrvLedInfoPtr sli;
ctrls= xkbi->desc->ctrls;
old= ctrls->enabled_ctrls;
ctrls->enabled_ctrls&= ~change;
ctrls->enabled_ctrls|= (change&newValues);
if (old==ctrls->enabled_ctrls)
return False;
if (cause!=NULL) {
xkbControlsNotify cn;
cn.numGroups= ctrls->num_groups;
cn.changedControls|= XkbControlsEnabledMask;
cn.enabledControls= ctrls->enabled_ctrls;
cn.enabledControlChanges= (ctrls->enabled_ctrls^old);
cn.keycode= cause->kc;
cn.eventType= cause->event;
cn.requestMajor= cause->mjr;
cn.requestMinor= cause->mnr;
XkbSendControlsNotify(xkbi->device,&cn);
}
else {
changes->ctrls.enabled_ctrls_changes^= (ctrls->enabled_ctrls^old);
if (changes->ctrls.enabled_ctrls_changes)
changes->ctrls.changed_ctrls|= XkbControlsEnabledMask;
else changes->ctrls.changed_ctrls&= ~XkbControlsEnabledMask;
}
sli= XkbFindSrvLedInfo(xkbi->device,XkbDfltXIClass,XkbDfltXIId,0);
XkbUpdateIndicators(xkbi->device,sli->usesControls,True,changes,cause);
return True;
}
#define MAX_TOC 16
XkbGeometryPtr
XkbLookupNamedGeometry(DeviceIntPtr dev,Atom name,Bool *shouldFree)
{
XkbSrvInfoPtr xkbi= dev->key->xkbInfo;
XkbDescPtr xkb= xkbi->desc;
*shouldFree= 0;
if (name==None) {
if (xkb->geom!=NULL)
return xkb->geom;
name= xkb->names->geometry;
}
if ((xkb->geom!=NULL)&&(xkb->geom->name==name))
return xkb->geom;
*shouldFree= 1;
return NULL;
}
void
XkbConvertCase(register KeySym sym, KeySym *lower, KeySym *upper)
{
*lower = sym;
*upper = sym;
switch(sym >> 8) {
case 0:
if ((sym >= XK_A) && (sym <= XK_Z))
*lower += (XK_a - XK_A);
else if ((sym >= XK_a) && (sym <= XK_z))
*upper -= (XK_a - XK_A);
else if ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
*lower += (XK_agrave - XK_Agrave);
else if ((sym >= XK_agrave) && (sym <= XK_odiaeresis))
*upper -= (XK_agrave - XK_Agrave);
else if ((sym >= XK_Ooblique) && (sym <= XK_Thorn))
*lower += (XK_oslash - XK_Ooblique);
else if ((sym >= XK_oslash) && (sym <= XK_thorn))
*upper -= (XK_oslash - XK_Ooblique);
break;
case 1:
if (sym == XK_Aogonek)
*lower = XK_aogonek;
else if (sym >= XK_Lstroke && sym <= XK_Sacute)
*lower += (XK_lstroke - XK_Lstroke);
else if (sym >= XK_Scaron && sym <= XK_Zacute)
*lower += (XK_scaron - XK_Scaron);
else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
*lower += (XK_zcaron - XK_Zcaron);
else if (sym == XK_aogonek)
*upper = XK_Aogonek;
else if (sym >= XK_lstroke && sym <= XK_sacute)
*upper -= (XK_lstroke - XK_Lstroke);
else if (sym >= XK_scaron && sym <= XK_zacute)
*upper -= (XK_scaron - XK_Scaron);
else if (sym >= XK_zcaron && sym <= XK_zabovedot)
*upper -= (XK_zcaron - XK_Zcaron);
else if (sym >= XK_Racute && sym <= XK_Tcedilla)
*lower += (XK_racute - XK_Racute);
else if (sym >= XK_racute && sym <= XK_tcedilla)
*upper -= (XK_racute - XK_Racute);
break;
case 2:
if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
*lower += (XK_hstroke - XK_Hstroke);
else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
*lower += (XK_gbreve - XK_Gbreve);
else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
*upper -= (XK_hstroke - XK_Hstroke);
else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
*upper -= (XK_gbreve - XK_Gbreve);
else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
*lower += (XK_cabovedot - XK_Cabovedot);
else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
*upper -= (XK_cabovedot - XK_Cabovedot);
break;
case 3:
if (sym >= XK_Rcedilla && sym <= XK_Tslash)
*lower += (XK_rcedilla - XK_Rcedilla);
else if (sym >= XK_rcedilla && sym <= XK_tslash)
*upper -= (XK_rcedilla - XK_Rcedilla);
else if (sym == XK_ENG)
*lower = XK_eng;
else if (sym == XK_eng)
*upper = XK_ENG;
else if (sym >= XK_Amacron && sym <= XK_Umacron)
*lower += (XK_amacron - XK_Amacron);
else if (sym >= XK_amacron && sym <= XK_umacron)
*upper -= (XK_amacron - XK_Amacron);
break;
case 6:
if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
*lower -= (XK_Serbian_DJE - XK_Serbian_dje);
else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
*upper += (XK_Serbian_DJE - XK_Serbian_dje);
else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
*lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
*upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
break;
case 7:
if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
*lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
sym != XK_Greek_iotaaccentdieresis &&
sym != XK_Greek_upsilonaccentdieresis)
*upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
*lower += (XK_Greek_alpha - XK_Greek_ALPHA);
else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
sym != XK_Greek_finalsmallsigma)
*upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
break;
}
}
Bool
XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies)
{
int i = 0, j = 0, k = 0;
void *tmp = NULL;
XkbColorPtr scolor = NULL, dcolor = NULL;
XkbDoodadPtr sdoodad = NULL, ddoodad = NULL;
XkbKeyTypePtr stype = NULL, dtype = NULL;
XkbOutlinePtr soutline = NULL, doutline = NULL;
XkbPropertyPtr sprop = NULL, dprop = NULL;
XkbRowPtr srow = NULL, drow = NULL;
XkbSectionPtr ssection = NULL, dsection = NULL;
XkbShapePtr sshape = NULL, dshape = NULL;
DeviceIntPtr pDev = NULL, tmpDev = NULL;
xkbMapNotify mn;
xkbNewKeyboardNotify nkn;
if (!src || !dst || src == dst)
return FALSE;
if (src->map) {
if (!dst->map) {
tmp = xcalloc(1, sizeof(XkbClientMapRec));
if (!tmp)
return FALSE;
dst->map = tmp;
}
if (src->map->syms) {
if (src->map->size_syms != dst->map->size_syms) {
if (dst->map->syms)
tmp = xrealloc(dst->map->syms,
src->map->size_syms * sizeof(KeySym));
else
tmp = xalloc(src->map->size_syms * sizeof(KeySym));
if (!tmp)
return FALSE;
dst->map->syms = tmp;
}
memcpy(dst->map->syms, src->map->syms,
src->map->size_syms * sizeof(KeySym));
}
else {
if (dst->map->syms) {
xfree(dst->map->syms);
dst->map->syms = NULL;
}
}
dst->map->num_syms = src->map->num_syms;
dst->map->size_syms = src->map->size_syms;
if (src->map->key_sym_map) {
if (src->max_key_code != dst->max_key_code) {
if (dst->map->key_sym_map)
tmp = xrealloc(dst->map->key_sym_map,
(src->max_key_code + 1) *
sizeof(XkbSymMapRec));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(XkbSymMapRec));
if (!tmp)
return FALSE;
dst->map->key_sym_map = tmp;
}
memcpy(dst->map->key_sym_map, src->map->key_sym_map,
(src->max_key_code + 1) * sizeof(XkbSymMapRec));
}
else {
if (dst->map->key_sym_map) {
xfree(dst->map->key_sym_map);
dst->map->key_sym_map = NULL;
}
}
if (src->map->types && src->map->num_types) {
if (src->map->num_types > dst->map->size_types ||
!dst->map->types || !dst->map->size_types) {
if (dst->map->types && dst->map->size_types) {
tmp = xrealloc(dst->map->types,
src->map->num_types * sizeof(XkbKeyTypeRec));
if (!tmp)
return FALSE;
dst->map->types = tmp;
bzero(dst->map->types + dst->map->num_types,
(src->map->num_types - dst->map->num_types) *
sizeof(XkbKeyTypeRec));
}
else {
tmp = xcalloc(src->map->num_types, sizeof(XkbKeyTypeRec));
if (!tmp)
return FALSE;
dst->map->types = tmp;
}
}
else if (src->map->num_types < dst->map->num_types &&
dst->map->types) {
for (i = src->map->num_types, dtype = (dst->map->types + i);
i < dst->map->num_types; i++, dtype++) {
if (dtype->level_names)
xfree(dtype->level_names);
dtype->level_names = NULL;
dtype->num_levels = 0;
if (dtype->map_count) {
if (dtype->map)
xfree(dtype->map);
if (dtype->preserve)
xfree(dtype->preserve);
}
}
}
stype = src->map->types;
dtype = dst->map->types;
for (i = 0; i < src->map->num_types; i++, dtype++, stype++) {
if (stype->num_levels && stype->level_names) {
if (stype->num_levels != dtype->num_levels &&
dtype->num_levels && dtype->level_names &&
i < dst->map->num_types) {
tmp = xrealloc(dtype->level_names,
stype->num_levels * sizeof(Atom));
if (!tmp)
continue;
dtype->level_names = tmp;
}
else if (!dtype->num_levels || !dtype->level_names ||
i >= dst->map->num_types) {
tmp = xalloc(stype->num_levels * sizeof(Atom));
if (!tmp)
continue;
dtype->level_names = tmp;
}
dtype->num_levels = stype->num_levels;
memcpy(dtype->level_names, stype->level_names,
stype->num_levels * sizeof(Atom));
}
else {
if (dtype->num_levels && dtype->level_names &&
i < dst->map->num_types)
xfree(dtype->level_names);
dtype->num_levels = 0;
dtype->level_names = NULL;
}
dtype->name = stype->name;
memcpy(&dtype->mods, &stype->mods, sizeof(XkbModsRec));
if (stype->map_count) {
if (stype->map) {
if (stype->map_count != dtype->map_count &&
dtype->map_count && dtype->map &&
i < dst->map->num_types) {
tmp = xrealloc(dtype->map,
stype->map_count *
sizeof(XkbKTMapEntryRec));
if (!tmp)
return FALSE;
dtype->map = tmp;
}
else if (!dtype->map_count || !dtype->map ||
i >= dst->map->num_types) {
tmp = xalloc(stype->map_count *
sizeof(XkbKTMapEntryRec));
if (!tmp)
return FALSE;
dtype->map = tmp;
}
memcpy(dtype->map, stype->map,
stype->map_count * sizeof(XkbKTMapEntryRec));
}
else {
if (dtype->map && i < dst->map->num_types)
xfree(dtype->map);
dtype->map = NULL;
}
if (stype->preserve) {
if (stype->map_count != dtype->map_count &&
dtype->map_count && dtype->preserve &&
i < dst->map->num_types) {
tmp = xrealloc(dtype->preserve,
stype->map_count *
sizeof(XkbModsRec));
if (!tmp)
return FALSE;
dtype->preserve = tmp;
}
else if (!dtype->preserve || !dtype->map_count ||
i >= dst->map->num_types) {
tmp = xalloc(stype->map_count *
sizeof(XkbModsRec));
if (!tmp)
return FALSE;
dtype->preserve = tmp;
}
memcpy(dtype->preserve, stype->preserve,
stype->map_count * sizeof(XkbModsRec));
}
else {
if (dtype->preserve && i < dst->map->num_types)
xfree(dtype->preserve);
dtype->preserve = NULL;
}
dtype->map_count = stype->map_count;
}
else {
if (dtype->map_count && i < dst->map->num_types) {
if (dtype->map)
xfree(dtype->map);
if (dtype->preserve)
xfree(dtype->preserve);
}
dtype->map_count = 0;
dtype->map = NULL;
dtype->preserve = NULL;
}
}
dst->map->size_types = src->map->num_types;
dst->map->num_types = src->map->num_types;
}
else {
if (dst->map->types) {
for (i = 0, dtype = dst->map->types; i < dst->map->num_types;
i++, dtype++) {
if (dtype->level_names)
xfree(dtype->level_names);
if (dtype->map && dtype->map_count)
xfree(dtype->map);
if (dtype->preserve && dtype->map_count)
xfree(dtype->preserve);
}
xfree(dst->map->types);
dst->map->types = NULL;
}
dst->map->num_types = 0;
dst->map->size_types = 0;
}
if (src->map->modmap) {
if (src->max_key_code != dst->max_key_code) {
if (dst->map->modmap)
tmp = xrealloc(dst->map->modmap, src->max_key_code + 1);
else
tmp = xalloc(src->max_key_code + 1);
if (!tmp)
return FALSE;
dst->map->modmap = tmp;
}
memcpy(dst->map->modmap, src->map->modmap, src->max_key_code + 1);
}
else {
if (dst->map->modmap) {
xfree(dst->map->modmap);
dst->map->modmap = NULL;
}
}
}
else {
if (dst->map)
XkbFreeClientMap(dst, XkbAllClientInfoMask, True);
}
if (src->server) {
if (!dst->server) {
tmp = xcalloc(1, sizeof(XkbServerMapRec));
if (!tmp)
return FALSE;
dst->server = tmp;
}
if (src->server->explicit) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->explicit)
tmp = xrealloc(dst->server->explicit, src->max_key_code + 1);
else
tmp = xalloc(src->max_key_code + 1);
if (!tmp)
return FALSE;
dst->server->explicit = tmp;
}
memcpy(dst->server->explicit, src->server->explicit,
src->max_key_code + 1);
}
else {
if (dst->server->explicit) {
xfree(dst->server->explicit);
dst->server->explicit = NULL;
}
}
if (src->server->acts) {
if (src->server->size_acts != dst->server->size_acts) {
if (dst->server->acts)
tmp = xrealloc(dst->server->acts,
src->server->size_acts * sizeof(XkbAction));
else
tmp = xalloc(src->server->size_acts * sizeof(XkbAction));
if (!tmp)
return FALSE;
dst->server->acts = tmp;
}
memcpy(dst->server->acts, src->server->acts,
src->server->size_acts * sizeof(XkbAction));
}
else {
if (dst->server->acts) {
xfree(dst->server->acts);
dst->server->acts = NULL;
}
}
dst->server->size_acts = src->server->size_acts;
dst->server->num_acts = src->server->num_acts;
if (src->server->key_acts) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->key_acts)
tmp = xrealloc(dst->server->key_acts,
(src->max_key_code + 1) *
sizeof(unsigned short));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(unsigned short));
if (!tmp)
return FALSE;
dst->server->key_acts = tmp;
}
memcpy(dst->server->key_acts, src->server->key_acts,
(src->max_key_code + 1) * sizeof(unsigned short));
}
else {
if (dst->server->key_acts) {
xfree(dst->server->key_acts);
dst->server->key_acts = NULL;
}
}
if (src->server->behaviors) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->behaviors)
tmp = xrealloc(dst->server->behaviors,
(src->max_key_code + 1) *
sizeof(XkbBehavior));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(XkbBehavior));
if (!tmp)
return FALSE;
dst->server->behaviors = tmp;
}
memcpy(dst->server->behaviors, src->server->behaviors,
(src->max_key_code + 1) * sizeof(XkbBehavior));
}
else {
if (dst->server->behaviors) {
xfree(dst->server->behaviors);
dst->server->behaviors = NULL;
}
}
memcpy(dst->server->vmods, src->server->vmods, XkbNumVirtualMods);
if (src->server->vmodmap) {
if (src->max_key_code != dst->max_key_code) {
if (dst->server->vmodmap)
tmp = xrealloc(dst->server->vmodmap,
(src->max_key_code + 1) *
sizeof(unsigned short));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(unsigned short));
if (!tmp)
return FALSE;
dst->server->vmodmap = tmp;
}
memcpy(dst->server->vmodmap, src->server->vmodmap,
(src->max_key_code + 1) * sizeof(unsigned short));
}
else {
if (dst->server->vmodmap) {
xfree(dst->server->vmodmap);
dst->server->vmodmap = NULL;
}
}
}
else {
if (dst->server)
XkbFreeServerMap(dst, XkbAllServerInfoMask, True);
}
if (src->indicators) {
if (!dst->indicators) {
dst->indicators = xalloc(sizeof(XkbIndicatorRec));
if (!dst->indicators)
return FALSE;
}
memcpy(dst->indicators, src->indicators, sizeof(XkbIndicatorRec));
}
else {
if (dst->indicators) {
xfree(dst->indicators);
dst->indicators = NULL;
}
}
if (src->ctrls) {
if (!dst->ctrls) {
dst->ctrls = xalloc(sizeof(XkbControlsRec));
if (!dst->ctrls)
return FALSE;
}
memcpy(dst->ctrls, src->ctrls, sizeof(XkbControlsRec));
}
else {
if (dst->ctrls) {
xfree(dst->ctrls);
dst->ctrls = NULL;
}
}
if (src->names) {
if (!dst->names) {
dst->names = xcalloc(1, sizeof(XkbNamesRec));
if (!dst->names)
return FALSE;
}
if (src->names->keys) {
if (src->max_key_code != dst->max_key_code) {
if (dst->names->keys)
tmp = xrealloc(dst->names->keys, (src->max_key_code + 1) *
sizeof(XkbKeyNameRec));
else
tmp = xalloc((src->max_key_code + 1) *
sizeof(XkbKeyNameRec));
if (!tmp)
return FALSE;
dst->names->keys = tmp;
}
memcpy(dst->names->keys, src->names->keys,
(src->max_key_code + 1) * sizeof(XkbKeyNameRec));
}
else {
if (dst->names->keys) {
xfree(dst->names->keys);
dst->names->keys = NULL;
}
}
if (src->names->num_key_aliases) {
if (src->names->num_key_aliases != dst->names->num_key_aliases) {
if (dst->names->key_aliases)
tmp = xrealloc(dst->names->key_aliases,
src->names->num_key_aliases *
sizeof(XkbKeyAliasRec));
else
tmp = xalloc(src->names->num_key_aliases *
sizeof(XkbKeyAliasRec));
if (!tmp)
return FALSE;
dst->names->key_aliases = tmp;
}
memcpy(dst->names->key_aliases, src->names->key_aliases,
src->names->num_key_aliases * sizeof(XkbKeyAliasRec));
}
else {
if (dst->names->key_aliases) {
xfree(dst->names->key_aliases);
dst->names->key_aliases = NULL;
}
}
dst->names->num_key_aliases = src->names->num_key_aliases;
if (src->names->num_rg) {
if (src->names->num_rg != dst->names->num_rg) {
if (dst->names->radio_groups)
tmp = xrealloc(dst->names->radio_groups,
src->names->num_rg * sizeof(Atom));
else
tmp = xalloc(src->names->num_rg * sizeof(Atom));
if (!tmp)
return FALSE;
dst->names->radio_groups = tmp;
}
memcpy(dst->names->radio_groups, src->names->radio_groups,
src->names->num_rg * sizeof(Atom));
}
else {
if (dst->names->radio_groups)
xfree(dst->names->radio_groups);
}
dst->names->num_rg = src->names->num_rg;
dst->names->keycodes = src->names->keycodes;
dst->names->geometry = src->names->geometry;
dst->names->symbols = src->names->symbols;
dst->names->types = src->names->types;
dst->names->compat = src->names->compat;
dst->names->phys_symbols = src->names->phys_symbols;
memcpy(dst->names->vmods, src->names->vmods,
XkbNumVirtualMods * sizeof(Atom));
memcpy(dst->names->indicators, src->names->indicators,
XkbNumIndicators * sizeof(Atom));
memcpy(dst->names->groups, src->names->groups,
XkbNumKbdGroups * sizeof(Atom));
}
else {
if (dst->names)
XkbFreeNames(dst, XkbAllNamesMask, True);
}
if (src->compat) {
if (!dst->compat) {
dst->compat = xcalloc(1, sizeof(XkbCompatMapRec));
if (!dst->compat)
return FALSE;
}
if (src->compat->sym_interpret && src->compat->num_si) {
if (src->compat->num_si != dst->compat->size_si) {
if (dst->compat->sym_interpret)
tmp = xrealloc(dst->compat->sym_interpret,
src->compat->num_si *
sizeof(XkbSymInterpretRec));
else
tmp = xalloc(src->compat->num_si *
sizeof(XkbSymInterpretRec));
if (!tmp)
return FALSE;
dst->compat->sym_interpret = tmp;
}
memcpy(dst->compat->sym_interpret, src->compat->sym_interpret,
src->compat->num_si * sizeof(XkbSymInterpretRec));
dst->compat->num_si = src->compat->num_si;
dst->compat->size_si = src->compat->num_si;
}
else {
if (dst->compat->sym_interpret && dst->compat->size_si)
xfree(dst->compat->sym_interpret);
dst->compat->sym_interpret = NULL;
dst->compat->num_si = 0;
dst->compat->size_si = 0;
}
memcpy(dst->compat->groups, src->compat->groups,
XkbNumKbdGroups * sizeof(XkbModsRec));
}
else {
if (dst->compat)
XkbFreeCompatMap(dst, XkbAllCompatMask, True);
}
if (src->geom) {
if (!dst->geom) {
dst->geom = xcalloc(sizeof(XkbGeometryRec), 1);
if (!dst->geom)
return FALSE;
}
if (src->geom->num_properties) {
if (src->geom->num_properties != dst->geom->sz_properties) {
if (src->geom->num_properties < dst->geom->sz_properties) {
for (i = src->geom->num_properties,
dprop = dst->geom->properties +
src->geom->num_properties;
i < dst->geom->num_properties;
i++, dprop++) {
xfree(dprop->name);
xfree(dprop->value);
}
}
if (dst->geom->sz_properties)
tmp = xrealloc(dst->geom->properties,
src->geom->num_properties *
sizeof(XkbPropertyRec));
else
tmp = xalloc(src->geom->num_properties *
sizeof(XkbPropertyRec));
if (!tmp)
return FALSE;
dst->geom->properties = tmp;
}
dst->geom->sz_properties = src->geom->num_properties;
if (dst->geom->sz_properties > dst->geom->num_properties) {
bzero(dst->geom->properties + dst->geom->num_properties,
(dst->geom->sz_properties - dst->geom->num_properties) *
sizeof(XkbPropertyRec));
}
for (i = 0,
sprop = src->geom->properties,
dprop = dst->geom->properties;
i < src->geom->num_properties;
i++, sprop++, dprop++) {
if (i < dst->geom->num_properties) {
if (strlen(sprop->name) != strlen(dprop->name)) {
tmp = xrealloc(dprop->name, strlen(sprop->name) + 1);
if (!tmp)
return FALSE;
dprop->name = tmp;
}
if (strlen(sprop->value) != strlen(dprop->value)) {
tmp = xrealloc(dprop->value, strlen(sprop->value) + 1);
if (!tmp)
return FALSE;
dprop->value = tmp;
}
strcpy(dprop->name, sprop->name);
strcpy(dprop->value, sprop->value);
}
else {
dprop->name = xstrdup(sprop->name);
dprop->value = xstrdup(sprop->value);
}
}
dst->geom->num_properties = dst->geom->sz_properties;
}
else {
if (dst->geom->sz_properties) {
for (i = 0, dprop = dst->geom->properties;
i < dst->geom->num_properties;
i++, dprop++) {
xfree(dprop->name);
xfree(dprop->value);
}
xfree(dst->geom->properties);
dst->geom->properties = NULL;
}
dst->geom->num_properties = 0;
dst->geom->sz_properties = 0;
}
if (src->geom->num_colors) {
if (src->geom->num_colors != dst->geom->sz_colors) {
if (src->geom->num_colors < dst->geom->sz_colors) {
for (i = src->geom->num_colors,
dcolor = dst->geom->colors +
src->geom->num_colors;
i < dst->geom->num_colors;
i++, dcolor++) {
xfree(dcolor->spec);
}
}
if (dst->geom->sz_colors)
tmp = xrealloc(dst->geom->colors,
src->geom->num_colors *
sizeof(XkbColorRec));
else
tmp = xalloc(src->geom->num_colors *
sizeof(XkbColorRec));
if (!tmp)
return FALSE;
dst->geom->colors = tmp;
}
dst->geom->sz_colors = src->geom->num_colors;
if (dst->geom->sz_colors > dst->geom->num_colors) {
bzero(dst->geom->colors + dst->geom->num_colors,
(dst->geom->sz_colors - dst->geom->num_colors) *
sizeof(XkbColorRec));
}
for (i = 0,
scolor = src->geom->colors,
dcolor = dst->geom->colors;
i < src->geom->num_colors;
i++, scolor++, dcolor++) {
if (i < dst->geom->num_colors) {
if (strlen(scolor->spec) != strlen(dcolor->spec)) {
tmp = xrealloc(dcolor->spec, strlen(scolor->spec) + 1);
if (!tmp)
return FALSE;
dcolor->spec = tmp;
}
strcpy(dcolor->spec, scolor->spec);
}
else {
dcolor->spec = xstrdup(scolor->spec);
}
}
dst->geom->num_colors = dst->geom->sz_colors;
}
else {
if (dst->geom->sz_colors) {
for (i = 0, dcolor = dst->geom->colors;
i < dst->geom->num_colors;
i++, dcolor++) {
xfree(dcolor->spec);
}
xfree(dst->geom->colors);
dst->geom->colors = NULL;
}
dst->geom->num_colors = 0;
dst->geom->sz_colors = 0;
}
if (dst->geom->num_shapes) {
for (i = 0, dshape = dst->geom->shapes;
i < dst->geom->num_shapes;
i++, dshape++) {
for (j = 0, doutline = dshape->outlines;
j < dshape->num_outlines;
j++, doutline++) {
if (doutline->sz_points)
xfree(doutline->points);
}
if (dshape->sz_outlines) {
xfree(dshape->outlines);
dshape->outlines = NULL;
}
dshape->num_outlines = 0;
dshape->sz_outlines = 0;
}
}
if (src->geom->num_shapes) {
tmp = xcalloc(src->geom->num_shapes, sizeof(XkbShapeRec));
if (!tmp)
return FALSE;
dst->geom->shapes = tmp;
for (i = 0, sshape = src->geom->shapes, dshape = dst->geom->shapes;
i < src->geom->num_shapes;
i++, sshape++, dshape++) {
if (sshape->num_outlines) {
tmp = xcalloc(sshape->num_outlines, sizeof(XkbOutlineRec));
if (!tmp)
return FALSE;
dshape->outlines = tmp;
for (j = 0,
soutline = sshape->outlines,
doutline = dshape->outlines;
j < sshape->num_outlines;
j++, soutline++, doutline++) {
if (soutline->num_points) {
tmp = xalloc(soutline->num_points *
sizeof(XkbPointRec));
if (!tmp)
return FALSE;
doutline->points = tmp;
memcpy(doutline->points, soutline->points,
soutline->num_points * sizeof(XkbPointRec));
}
doutline->num_points = soutline->num_points;
doutline->sz_points = soutline->sz_points;
}
}
dshape->num_outlines = sshape->num_outlines;
dshape->sz_outlines = sshape->num_outlines;
}
dst->geom->num_shapes = src->geom->num_shapes;
dst->geom->sz_shapes = src->geom->num_shapes;
}
else {
if (dst->geom->sz_shapes) {
xfree(dst->geom->shapes);
}
dst->geom->shapes = NULL;
dst->geom->num_shapes = 0;
dst->geom->sz_shapes = 0;
}
if (dst->geom->num_sections) {
for (i = 0, dsection = dst->geom->sections;
i < dst->geom->num_sections;
i++, dsection++) {
for (j = 0, drow = dsection->rows;
j < dsection->num_rows;
j++, drow++) {
if (drow->num_keys)
xfree(drow->keys);
}
if (dsection->num_rows)
xfree(dsection->rows);
for (j = 0, ddoodad = dsection->doodads;
j < dsection->num_doodads;
j++, ddoodad++) {
if (ddoodad->any.type == XkbTextDoodad) {
if (ddoodad->text.text) {
xfree(ddoodad->text.text);
ddoodad->text.text = NULL;
}
if (ddoodad->text.font) {
xfree(ddoodad->text.font);
ddoodad->text.font = NULL;
}
}
else if (ddoodad->any.type == XkbLogoDoodad) {
if (ddoodad->logo.logo_name) {
xfree(ddoodad->logo.logo_name);
ddoodad->logo.logo_name = NULL;
}
}
}
if (dsection->num_doodads)
xfree(dsection->doodads);
}
dst->geom->num_sections = 0;
dst->geom->sections = NULL;
}
if (src->geom->num_sections) {
if (dst->geom->sz_sections)
tmp = xrealloc(dst->geom->sections,
src->geom->num_sections *
sizeof(XkbSectionRec));
else
tmp = xalloc(src->geom->num_sections * sizeof(XkbSectionRec));
if (!tmp)
return FALSE;
memset(tmp, 0, src->geom->num_sections * sizeof(XkbSectionRec));
dst->geom->sections = tmp;
dst->geom->num_sections = src->geom->num_sections;
for (i = 0,
ssection = src->geom->sections,
dsection = dst->geom->sections;
i < src->geom->num_sections;
i++, ssection++, dsection++) {
if (ssection->num_rows) {
tmp = xcalloc(ssection->num_rows, sizeof(XkbRowRec));
if (!tmp)
return FALSE;
dsection->rows = tmp;
}
for (j = 0, srow = ssection->rows, drow = dsection->rows;
j < ssection->num_rows;
j++, srow++, drow++) {
if (srow->num_keys) {
tmp = xalloc(srow->num_keys * sizeof(XkbKeyRec));
if (!tmp)
return FALSE;
drow->keys = tmp;
memcpy(drow->keys, srow->keys,
srow->num_keys * sizeof(XkbKeyRec));
}
drow->num_keys = srow->num_keys;
drow->sz_keys = srow->num_keys;
}
if (ssection->num_doodads) {
tmp = xcalloc(ssection->num_doodads, sizeof(XkbDoodadRec));
if (!tmp)
return FALSE;
dsection->doodads = tmp;
}
else {
dsection->doodads = NULL;
}
for (k = 0,
sdoodad = ssection->doodads,
ddoodad = dsection->doodads;
k < ssection->num_doodads;
k++, sdoodad++, ddoodad++) {
if (sdoodad->any.type == XkbTextDoodad) {
if (sdoodad->text.text)
ddoodad->text.text =
xstrdup(sdoodad->text.text);
if (sdoodad->text.font)
ddoodad->text.font =
xstrdup(sdoodad->text.font);
}
else if (sdoodad->any.type == XkbLogoDoodad) {
if (sdoodad->logo.logo_name)
ddoodad->logo.logo_name =
xstrdup(sdoodad->logo.logo_name);
}
ddoodad->any.type = sdoodad->any.type;
}
dsection->num_doodads = ssection->num_doodads;
dsection->sz_doodads = ssection->num_doodads;
}
}
else {
if (dst->geom->sz_sections) {
xfree(dst->geom->sections);
}
dst->geom->sections = NULL;
dst->geom->num_sections = 0;
dst->geom->sz_sections = 0;
}
if (dst->geom->num_doodads) {
for (i = src->geom->num_doodads,
ddoodad = dst->geom->doodads +
src->geom->num_doodads;
i < dst->geom->num_doodads;
i++, ddoodad++) {
if (ddoodad->any.type == XkbTextDoodad) {
if (ddoodad->text.text) {
xfree(ddoodad->text.text);
ddoodad->text.text = NULL;
}
if (ddoodad->text.font) {
xfree(ddoodad->text.font);
ddoodad->text.font = NULL;
}
}
else if (ddoodad->any.type == XkbLogoDoodad) {
if (ddoodad->logo.logo_name) {
xfree(ddoodad->logo.logo_name);
ddoodad->logo.logo_name = NULL;
}
}
}
dst->geom->num_doodads = 0;
dst->geom->doodads = NULL;
}
if (src->geom->num_doodads) {
if (dst->geom->sz_doodads)
tmp = xrealloc(dst->geom->doodads,
src->geom->num_doodads *
sizeof(XkbDoodadRec));
else
tmp = xalloc(src->geom->num_doodads *
sizeof(XkbDoodadRec));
if (!tmp)
return FALSE;
memset(tmp, 0, src->geom->num_doodads * sizeof(XkbDoodadRec));
dst->geom->doodads = tmp;
dst->geom->sz_doodads = src->geom->num_doodads;
for (i = 0,
sdoodad = src->geom->doodads,
ddoodad = dst->geom->doodads;
i < src->geom->num_doodads;
i++, sdoodad++, ddoodad++) {
ddoodad->any.type = sdoodad->any.type;
if (sdoodad->any.type == XkbTextDoodad) {
if (sdoodad->text.text)
ddoodad->text.text = xstrdup(sdoodad->text.text);
if (sdoodad->text.font)
ddoodad->text.font = xstrdup(sdoodad->text.font);
}
else if (sdoodad->any.type == XkbLogoDoodad) {
if (sdoodad->logo.logo_name)
ddoodad->logo.logo_name =
xstrdup(sdoodad->logo.logo_name);
}
}
dst->geom->num_doodads = dst->geom->sz_doodads;
}
else {
if (dst->geom->sz_doodads) {
xfree(dst->geom->doodads);
}
dst->geom->doodads = NULL;
dst->geom->num_doodads = 0;
dst->geom->sz_doodads = 0;
}
if (src->geom->num_key_aliases) {
if (src->geom->num_key_aliases != dst->geom->sz_key_aliases) {
if (dst->geom->sz_key_aliases)
tmp = xrealloc(dst->geom->key_aliases,
src->geom->num_key_aliases *
2 * XkbKeyNameLength);
else
tmp = xalloc(src->geom->num_key_aliases *
2 * XkbKeyNameLength);
if (!tmp)
return FALSE;
dst->geom->key_aliases = tmp;
dst->geom->sz_key_aliases = src->geom->num_key_aliases;
}
memcpy(dst->geom->key_aliases, src->geom->key_aliases,
src->geom->num_key_aliases * 2 * XkbKeyNameLength);
dst->geom->num_key_aliases = dst->geom->sz_key_aliases;
}
else {
if (dst->geom->key_aliases) {
xfree(dst->geom->key_aliases);
}
dst->geom->key_aliases = NULL;
dst->geom->num_key_aliases = 0;
dst->geom->sz_key_aliases = 0;
}
if (src->geom->label_font) {
if (!dst->geom->label_font) {
tmp = xalloc(strlen(src->geom->label_font));
if (!tmp)
return FALSE;
dst->geom->label_font = tmp;
}
else if (strlen(src->geom->label_font) !=
strlen(dst->geom->label_font)) {
tmp = xrealloc(dst->geom->label_font,
strlen(src->geom->label_font));
if (!tmp)
return FALSE;
dst->geom->label_font = tmp;
}
strcpy(dst->geom->label_font, src->geom->label_font);
i = XkbGeomColorIndex(src->geom, src->geom->label_color);
dst->geom->label_color = &(src->geom->colors[i]);
i = XkbGeomColorIndex(src->geom, src->geom->base_color);
dst->geom->base_color = &(src->geom->colors[i]);
}
else {
if (dst->geom->label_font) {
xfree(dst->geom->label_font);
}
dst->geom->label_font = NULL;
dst->geom->label_color = NULL;
dst->geom->base_color = NULL;
}
dst->geom->name = src->geom->name;
dst->geom->width_mm = src->geom->width_mm;
dst->geom->height_mm = src->geom->height_mm;
}
else
{
if (dst->geom) {
XkbFreeGeometry(dst->geom, XkbGeomAllMask, True);
dst->geom = NULL;
}
}
if (inputInfo.keyboard->key->xkbInfo &&
inputInfo.keyboard->key->xkbInfo->desc == dst) {
pDev = inputInfo.keyboard;
}
else {
for (tmpDev = inputInfo.devices; tmpDev && !pDev;
tmpDev = tmpDev->next) {
if (tmpDev->key && tmpDev->key->xkbInfo &&
tmpDev->key->xkbInfo->desc == dst) {
pDev = tmpDev;
break;
}
}
for (tmpDev = inputInfo.off_devices; tmpDev && !pDev;
tmpDev = tmpDev->next) {
if (tmpDev->key && tmpDev->key->xkbInfo &&
tmpDev->key->xkbInfo->desc == dst) {
pDev = tmpDev;
break;
}
}
}
if (sendNotifies) {
if (!pDev) {
ErrorF("XkbCopyKeymap: asked for notifies, but can't find device!\n");
}
else {
if ((src->min_key_code != dst->min_key_code ||
src->max_key_code != dst->max_key_code) && sendNotifies) {
nkn.oldMinKeyCode = dst->min_key_code;
nkn.oldMaxKeyCode = dst->max_key_code;
nkn.deviceID = nkn.oldDeviceID = pDev->id;
nkn.minKeyCode = src->min_key_code;
nkn.maxKeyCode = src->max_key_code;
nkn.requestMajor = XkbReqCode;
nkn.requestMinor = X_kbSetMap;
nkn.changed = XkbAllNewKeyboardEventsMask;
XkbSendNewKeyboardNotify(pDev, &nkn);
}
else if (sendNotifies) {
mn.deviceID = pDev->id;
mn.minKeyCode = src->min_key_code;
mn.maxKeyCode = src->max_key_code;
mn.firstType = 0;
mn.nTypes = src->map->num_types;
mn.firstKeySym = src->min_key_code;
mn.nKeySyms = XkbNumKeys(src);
mn.firstKeyAct = src->min_key_code;
mn.nKeyActs = XkbNumKeys(src);
mn.firstKeyBehavior = src->min_key_code;
mn.nKeyBehaviors = XkbNumKeys(src);
mn.firstKeyExplicit = src->min_key_code;
mn.nKeyExplicit = XkbNumKeys(src);
mn.firstModMapKey = src->min_key_code;
mn.nModMapKeys = XkbNumKeys(src);
mn.firstVModMapKey = src->min_key_code;
mn.nVModMapKeys = XkbNumKeys(src);
mn.virtualMods = ~0;
mn.changed = XkbAllMapComponentsMask;
XkbSendMapNotify(pDev, &mn);
}
}
}
dst->min_key_code = src->min_key_code;
dst->max_key_code = src->max_key_code;
return TRUE;
}