several fixes for XKB

[email protected] (Michal Maruška)
Newsgroups gmane.comp.xfree86.devel
Message-ID <[email protected]>
hello fellow _xfree86_ hackers!

In order to provide to my friends, and maybe one day customers, a way to type
differently, as described at http://maruska.dyndns.org/wiki/forkExtension.html

... i would like to donate a necessary infrastructure to xfree86 project,
to be distributed under the xfree86 version 1.1 licence. 
I also provide patches exclusively under this license.


I'm working on the documentation (and final patches), which i will send here as
several emails, you can see a pre-version at:

http://maruska.dyndns.org/wiki/x-plugin


In this email, I provide some patches(against CVS)/fixes for XKB:


*  memory allocation
in file lib/X11/XKBMAlloc.c

**  off-by-one errors. bzero-ing wrong regions.

This is only triggered by a keyboard driver, which (at start) registers <256 keycodes.
It is also impossible to change the interval of *core* valid keycodes.
I have hacked a (probably unacceptable) workaround, by updating ConnectionInfo
(from DIX).  A part of my work is a new keyboard driver
( http://maruska.dyndns.org/wiki/medved ), and if this workaround is not
accepted (nor easily corrected), i'll just force registering of all 256 keycodes.


** growing tables w/o never shrinking.

table of XKB actions and keysyms.   (i provide comments in the patch)



* client requests for info
lib/X11/XKBGetMap.c
various vmodmap vs. modmap  "incomplete cut-n-paste" bugs


* client request to change XKB configuration failing (ProcXkbSetMap)
programs/Xserver/xkb/xkb.c
if the client request does not specify (XKB) types, the request fails.


*   notify event processing
in  lib/X11/XKBUse.c

If number of XKB types changes (by calling apropriate functions),
the XKB-unaware applications (eg. xterm) don't notice it!
In other words (client side) synthesized core X events were not sufficiently informative.



Next patches (some against the same files) will not contain these
modifications (i hope).
xkb.patch (text/x-patch, 16.3 KB)
--- /linux/13/x/xfree86/xc/lib/X11/XKBGetMap.c	2003-11-17 23:20:09.000000000 +0100
+++ lib/X11/XKBGetMap.c	2005-04-12 22:13:22.000000000 +0200
@@ -150,6 +150,7 @@
 register int i;
 XkbClientMapPtr	map;
 
+   if ( rep->totalSyms>0 ) {    /* mmc: */
     map= xkb->map;
     if (map->key_sym_map==NULL) {
 	register int offset;
@@ -236,6 +237,7 @@
 	    oldMap->width = newMap->width;
 	}
     }
+   }
     return Success;
 }
 
@@ -263,8 +265,16 @@
 	    ret = BadLength;
 	    goto done;
 	}
+#if 0        
+        /* mmc:  this probably should check that the number of actions & keysyms is the same for each keycode.
+         * But for now it doesn't, so i disable it. */
 	symMap = &info->map->key_sym_map[rep->firstKeyAct];
-	for (i=0;i<(int)rep->nKeyActs;i++,symMap++) {
+#endif        
+	for (i=0;i<(int)rep->nKeyActs;i++
+#if 0
+                ,symMap++
+#endif
+           ) {
 	    if (numDesc[i]==0) {
 		info->server->key_acts[i+rep->firstKeyAct]= 0;
 	    }
@@ -478,7 +488,7 @@
     }
     extraData= (int)(rep->length*4);
     extraData-= (SIZEOF(xkbGetMapReply)-SIZEOF(xGenericReply));
-    if (rep->length) {
+    if (extraData) {
 	XkbReadBufferRec	buf;
 	int			left;
 	if (_XkbInitReadBuffer(dpy,&buf,extraData)) {
@@ -683,6 +693,8 @@
 
     req = _XkbGetGetMapReq(dpy, xkb);
     req->virtualMods = which;
+    /* mmc:  we want this information, so the mask must be set! */
+    req->partial = XkbVirtualModsMask;
     status= _XkbHandleGetMapReply(dpy, xkb);
 
     UnlockDisplay(dpy);
@@ -740,6 +752,7 @@
     req = _XkbGetGetMapReq(dpy, xkb);
     req->firstModMapKey = first;
     req->nModMapKeys = num;
+    req->partial = XkbModifierMapMask;               /* mmc: once again (see above) */
     if ((xkb!=NULL) && (xkb->map!=NULL) && (xkb->map->modmap!=NULL)) {
 	if ((num>0)&&(first>=xkb->min_key_code)&&(first+num<=xkb->max_key_code))
 	    bzero(&xkb->map->modmap[first],num);
@@ -767,9 +780,10 @@
     LockDisplay(dpy);
 
     req = _XkbGetGetMapReq(dpy, xkb);
+    req->partial = XkbVirtualModMapMask;
     req->firstVModMapKey = first;
     req->nVModMapKeys = num;
-    if ((xkb!=NULL) && (xkb->map!=NULL) && (xkb->map->modmap!=NULL)) {
+    if ((xkb!=NULL) && (xkb->server!=NULL) && (xkb->server->vmodmap!=NULL)) {
 	if ((num>0)&&(first>=xkb->min_key_code)&&(first+num<=xkb->max_key_code))
 	    bzero(&xkb->server->vmodmap[first],num*sizeof(unsigned short));
     }
--- /linux/13/x/xfree86/xc/lib/X11/XKBMAlloc.c	2003-11-17 23:20:09.000000000 +0100
+++ lib/X11/XKBMAlloc.c	2005-06-02 16:01:39.000000000 +0200
@@ -363,7 +363,7 @@
 Status
 XkbResizeKeyType(	XkbDescPtr	xkb,
 			int		type_ndx,
-			int		map_count,
+			int		map_count, /* number of mappings: modifier-set -> level  */
 			Bool		want_preserve,
 			int		new_num_lvls)
 {
@@ -596,6 +596,7 @@
 	int nCopy;
 
 	nCopy= nKeySyms= XkbKeyNumSyms(xkb,i);
+        /* i could invert these following 2 IFs: */
 	if ((nKeySyms==0)&&(i!=key))
 	    continue;
 	if (i==key)
@@ -610,6 +611,22 @@
     _XkbFree(xkb->map->syms);
     xkb->map->syms = newSyms;
     xkb->map->num_syms = nSyms;
+
+
+    /* mmc: we grow the table when needed, and never shrink it. So i decided to test & shrink here: */
+
+    if (xkb->map->size_syms > 2 * xkb->map->num_syms + 64)
+       {
+#ifdef  XKB_IN_SERVER          
+#ifdef DEBUG
+          ErrorF("%s: reduction! %d ->%d\n", __FUNCTION__, xkb->map->size_syms, 2 * xkb->map->num_syms + 64);
+#endif 
+#endif 
+          xkb->map->size_syms = 2 * xkb->map->num_syms + 64;
+          /* xkb->map->num_syms remains! */
+          /* todo: if this fails....!!  hopefully never, we just shrink. */
+          xkb->map->syms = _XkbTypedRealloc(xkb->map->syms, xkb->map->size_syms, KeySym);
+       }
     return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
 }
 
@@ -702,7 +719,7 @@
 		if (changes) {
 		    changes->map.changed= _ExtendRange(changes->map.changed,
 		    			XkbVirtualModMapMask,minKC,
-		    			&changes->map.first_modmap_key,
+		    			&changes->map.first_vmodmap_key,
     					&changes->map.num_vmodmap_keys);
 		}
 	    }
@@ -732,7 +749,7 @@
 		    _XkbFree(prev_key_sym_map);
 		    return BadAlloc;
 		}
-		bzero((char *)&xkb->map->key_sym_map[xkb->max_key_code],
+		bzero((char *)&xkb->map->key_sym_map[xkb->max_key_code+1],
 					tmp*sizeof(XkbSymMapRec));
 		if (changes) {
 		    changes->map.changed= _ExtendRange(changes->map.changed,
@@ -750,7 +767,7 @@
 		    _XkbFree(prev_modmap);
 		    return BadAlloc;
 		}
-		bzero((char *)&xkb->map->modmap[xkb->max_key_code],tmp);
+		bzero((char *)&xkb->map->modmap[xkb->max_key_code + 1],tmp);
 		if (changes) {
 		    changes->map.changed= _ExtendRange(changes->map.changed,
 		    				XkbModifierMapMask,maxKC,
@@ -769,7 +786,7 @@
 		    _XkbFree(prev_behaviors);
 		    return BadAlloc;
 		}
-		bzero((char *)&xkb->server->behaviors[xkb->max_key_code],
+		bzero((char *)&xkb->server->behaviors[xkb->max_key_code +1],
 						tmp*sizeof(XkbBehavior));
 		if (changes) {
 		    changes->map.changed= _ExtendRange(changes->map.changed,
@@ -787,7 +804,7 @@
 		    _XkbFree(prev_key_acts);
 		    return BadAlloc;
 		}
-		bzero((char *)&xkb->server->key_acts[xkb->max_key_code],
+		bzero((char *)&xkb->server->key_acts[xkb->max_key_code + 1],
 						tmp*sizeof(unsigned short));
 		if (changes) {
 		    changes->map.changed= _ExtendRange(changes->map.changed,
@@ -805,15 +822,34 @@
 		    _XkbFree(prev_vmodmap);
 		    return BadAlloc;
 		}
-		bzero((char *)&xkb->server->vmodmap[xkb->max_key_code],
+		bzero((char *)&xkb->server->vmodmap[xkb->max_key_code + 1],
 						tmp*sizeof(unsigned short));
 		if (changes) {
 		    changes->map.changed= _ExtendRange(changes->map.changed,
 		    			XkbVirtualModMapMask,maxKC,
-		    			&changes->map.first_modmap_key,
+		    			&changes->map.first_vmodmap_key,
     					&changes->map.num_vmodmap_keys);
 		}
 	    }
+        /* mmc: we have to resize server->explicit too. */
+            if (xkb->server->explicit) {
+               unsigned short *prev_explicit = xkb->server->explicit;
+		xkb->server->explicit= _XkbTypedRealloc(xkb->server->explicit,
+						(maxKC+1),unsigned char);
+		if (!xkb->server->explicit) {
+		    _XkbFree(prev_explicit);
+		    return BadAlloc;
+                }
+		bzero((char *)&xkb->server->explicit[xkb->max_key_code + 1],
+						tmp*sizeof(unsigned char));
+		if (changes) {
+		    changes->map.changed= _ExtendRange(changes->map.changed,
+		    			XkbExplicitComponentsMask,maxKC,
+                                                       /* ???? */
+		    			&changes->map.first_key_explicit,
+    					&changes->map.num_key_explicit);
+		}
+	    }
 	}
 	if ((xkb->names)&&(xkb->names->keys)) {
 	    XkbKeyNameRec *prev_keys = xkb->names->keys;
@@ -824,7 +860,7 @@
 		_XkbFree(prev_keys);
 		return BadAlloc;
 	    }
-	    bzero((char *)&xkb->names->keys[xkb->max_key_code],
+	    bzero((char *)&xkb->names->keys[xkb->max_key_code +1],
 	    					tmp*sizeof(XkbKeyNameRec));
 	    if (changes) {
 		changes->names.changed= _ExtendRange(changes->names.changed,
@@ -885,6 +921,21 @@
     _XkbFree(xkb->server->acts);
     xkb->server->acts = newActs;
     xkb->server->num_acts= nActs;
+
+    /* mmc: again (see above for keysyms), we grow the table when needed, and never shrink it. So i decided to test & shrink here: */
+    if (xkb->server->size_acts > 2 * xkb->server->num_acts + 64)
+       {
+#ifdef XKB_IN_SERVER
+#ifdef DEBUG
+          ErrorF("%s: reduction! %d ->%d\n", __FUNCTION__, xkb->server->size_acts, 2 * xkb->server->num_acts + 64);
+#endif 
+#endif 
+          xkb->server->size_acts = 2 * xkb->server->num_acts + 64;
+          
+          /* xkb->server->num_acts remains! */
+          /* fixme: if this fails....! */
+          xkb->server->acts = _XkbTypedRealloc(xkb->server->acts, xkb->server->size_acts, XkbAction);
+       }
     return &xkb->server->acts[xkb->server->key_acts[key]];
 }
 
--- /linux/13/x/xfree86/xc/lib/X11/XKBUse.c	2003-11-17 23:20:10.000000000 +0100
+++ lib/X11/XKBUse.c	2005-04-11 00:30:36.000000000 +0200
@@ -204,6 +204,8 @@
     return;
 }
 
+/* mmc: rewrite xbk event, possibly to a core X event.
+ * EVENT is on wire (xkb event).  RE is where we transfer to (X event). */
 static Bool
 wire_to_event(Display *dpy,XEvent *re,xEvent *event)
 {
@@ -305,7 +307,8 @@
 		    ev->count = mn->nKeySyms;
 		    _XkbNoteCoreMapChanges(&xkbi->changes,ev,XKB_XLIB_MAP_MASK);
 		    if (xkbi->changes.changed)
-			xkbi->flags|= XkbMapPending;
+                       /* if types change, we need to reload all, othewise, _maybe_ only ...  */
+                       xkbi->flags|= XkbMapPending | (mn->nTypes != 0)?0:XkbXlibNewKeyboard; 
 		    return True;
 		}
 	    }
--- /linux/13/x/xfree86/xc/programs/Xserver/xkb/xkb.c	2005-03-28 04:51:13.000000000 +0200
+++ programs/Xserver/xkb/xkb.c	2005-06-02 16:22:16.000000000 +0200
@@ -1514,10 +1514,12 @@
 	*nMapsRtrn = xkb->map->num_types;
 	for (i=0;i<xkb->map->num_types;i++) {
 	    mapWidthRtrn[i] = xkb->map->types[i].num_levels;
+            /* mmc:  mapWidthRtrn is allocated for max keycodes. is the same limit valid for # of levels of Types???*/
 	}
 	return 1;
     }
 
+    /* copy the unaffected interval: */
     for (i=0;i<req->firstType;i++) {
 	mapWidthRtrn[i] = xkb->map->types[i].num_levels;
     }
@@ -1610,14 +1612,30 @@
 		xkbSymMapWireDesc **	wireRtrn,
 		int *			errorRtrn)
 {
+   /* mmc:
+    *   Checks consistency of the data:
+    *   - types inside an interval
+    *   - number of syms must be = width * ngroups
+    *   AND
+    *   constructs the symsPerKey mapping keycode->number.    This will be used by the caller for checking n. of actions! 
+    *   uses mapWidths for that(?)
+    */
 unsigned	i;
 XkbSymMapPtr		map;
 xkbSymMapWireDesc*	wire = *wireRtrn;
 
-    if (!(XkbKeySymsMask&req->present))
+#if 0
+    if (!(XkbKeySymsMask&req->present)) /* mmc: is this correct? symsPerKey would not be computed! */
 	return 1;
+#endif
+    
     CHK_REQ_KEY_RANGE2(0x11,req->firstKeySym,req->nKeySyms,req,(*errorRtrn),0);
     map = &xkb->map->key_sym_map[xkb->min_key_code];
+
+    /* mmc: this checks if the keycodes `below' (think this ordering:
+     *    min_keycode----req->firstKeySym --- (req->firstKeySym + req->nKeySyms) --- max_keycode)
+     * have types above the nTypes. If so -> error.
+     */
     for (i=xkb->min_key_code;i<(unsigned)req->firstKeySym;i++,map++) {
 	int g,ng,w;
 	ng= XkbNumGroups(map->group_info);
@@ -1629,6 +1647,8 @@
 	    if (mapWidths[map->kt_index[g]]>w)
 		w= mapWidths[map->kt_index[g]];
 	}
+       /* mmc: now w is the maximum of widths, and
+        * the caller is interested in this info: */
 	symsPerKey[i] = w*ng;
     }
     for (i=0;i<req->nKeySyms;i++) {
@@ -1637,6 +1657,7 @@
 	if (client->swapped) {
 	    swaps(&wire->nSyms,nG);
 	}
+        /* mmc: checking the Nodes: 1/ good group information? */
 	nG = XkbNumGroups(wire->groupInfo);
 	if (nG>XkbNumKbdGroups) {
 	    *errorRtrn = _XkbErrCode3(0x14,i+req->firstKeySym,nG);
@@ -1668,12 +1689,16 @@
 	    *errorRtrn = _XkbErrCode3(0x17,i+req->firstKeySym,wire->nSyms);
 	    return 0;
 	}
+        /* go to next? skip the record & following syms!*/
 	pSyms = (KeySym *)&wire[1];
 	wire = (xkbSymMapWireDesc *)&pSyms[wire->nSyms];
     }
 
+    /* mmc:
+     * keycodes after affected ones:
+     */
     map = &xkb->map->key_sym_map[i];
-    for (;i<=(unsigned)xkb->max_key_code;i++,map++) {
+    for (i= req->nKeySyms + req->firstKeySym ;i<=(unsigned)xkb->max_key_code;i++,map++) { /* mmc: bug was here */
 	int g,nG,w;
 	nG= XkbKeyNumGroups(xkb,i);
 	for (w=g=0;g<nG;g++)  {
@@ -2088,6 +2113,7 @@
     if (changes->map.changed&XkbKeyActionsMask) {
 	int oldLast;
 	oldLast= changes->map.first_key_act+changes->map.num_key_acts-1;
+        /* mmc: isn't there a function to enlarge an interval to include 2 points?  (inverse of CLAMP)*/
 	if (changes->map.first_key_act<first)
 	    first= changes->map.first_key_act;
 	if (oldLast>last)
@@ -2320,13 +2346,14 @@
     }
 
     tmp = (char *)&stuff[1];
-    if ((stuff->present&XkbKeyTypesMask)&&
+    /* bug: we need `mapWidths' which is calculated in CheckKeyTypes. */
+    if ( /* (stuff->present&XkbKeyTypesMask)&& */
 	(!CheckKeyTypes(client,xkb,stuff,(xkbKeyTypeWireDesc **)&tmp,
 						&nTypes,mapWidths))) {
 	client->errorValue = nTypes;
 	return BadValue;
     }
-    if ((stuff->present&XkbKeySymsMask)&&
+    if ( /* (stuff->present&XkbKeySymsMask)&& */     /* symsPerKey is used later*/
 	(!CheckKeySyms(client,xkb,stuff,nTypes,mapWidths,symsPerKey,
 					(xkbSymMapWireDesc **)&tmp,&error))) {
 	client->errorValue = error;
@@ -2718,7 +2745,9 @@
 									&cause);
 	if (check)
 	    XkbCheckSecondaryEffects(xkbi,check,&change,&cause);
-	XkbUpdateCoreDescription(dev,False);
+        XkbUpdateCoreDescription(dev,True); /* mmc: was False.  I think there will be problems,
+                                             * but i want to discover them. Besides, this function probably
+                                             * does not resize the XKB map */
 	XkbSendNotification(dev,&change,&cause);
     }
     return client->noClientException;
--- /linux/13/x/xfree86/xc/programs/Xserver/xkb/xkbUtils.c	2005-04-14 14:31:58.000000000 +0200
+++ programs/Xserver/xkb/xkbUtils.c	2005-06-02 16:58:43.000000000 +0200
@@ -372,6 +372,8 @@
     return;
 }
 
+extern char* ConnectionInfo;    /* mmc: i think it's a precomputed byte array to send to clients on connection. */
+
 void
 XkbUpdateCoreDescription(DeviceIntPtr keybd,Bool resize)
 {
@@ -388,6 +390,11 @@
     keyc= keybd->key;
     maxSymsPerKey= maxKeysPerMod= 0;
     bzero(keysPerMod,sizeof(keysPerMod));
+
+    /* mmc:
+     * 1/ does it start w/ keycode 0? or min?
+     * 2/ modifierMap is always 256
+     * xkb->max_key_code  might be > keyc->curKeySyms.maxKeyCode */
     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)) {
@@ -403,6 +410,12 @@
 	   FatalError("Couldn't allocate keysyms\n");
 	first= firstCommon= xkb->min_key_code;
 	last= lastCommon= xkb->max_key_code;
+
+        /* mmc: i should recompute: ConnectionInfo in dix/main.c !! */
+#if 1 
+        ((xConnSetup*) ConnectionInfo)->minKeyCode = xkb->min_key_code;
+        ((xConnSetup*) ConnectionInfo)->maxKeyCode = xkb->max_key_code;
+#endif        
     }
     else {
 	if (xkb->min_key_code<keyc->curKeySyms.minKeyCode) {
@@ -410,6 +423,7 @@
 	    firstCommon= keyc->curKeySyms.minKeyCode;
 	}
 	else {
+           /* mmc: core (partly) superset of xkb?  */
 	    firstCommon= xkb->min_key_code;
 	    first= keyc->curKeySyms.minKeyCode;
 	}
@@ -423,7 +437,9 @@
 	}
     }
 
-    /* determine sizes */
+    /* determine sizes:  maxSymsPerKey  and  maxKeysPerMod:
+     *  minimum 2 !  Sum of group1 & group2 ?
+     */
     for (key=first;key<=last;key++) {
 	if (XkbKeycodeInRange(xkb,key)) {
 	    int	nGroups;
@@ -441,6 +457,7 @@
 		          tmp+= 2;
 		     else tmp+= w;
                 } else {
+                   /* group 1 provides more than 2: */
                      if ((w=XkbKeyGroupWidth(xkb,key,XkbGroup2Index))>2)
                           tmp+= w - 2;
                 }
@@ -483,7 +500,8 @@
     }
     keyc->maxKeysPerModifier= maxKeysPerMod;
 
-    if (maxSymsPerKey>0) {
+    /* now, that we have the `maxSymsPerKey'  */
+    if (maxSymsPerKey>0) { /* mmc: this could fail if ...  xkb keycode range is disjoint from the core range? */
 	tmp= maxSymsPerKey*_XkbCoreNumKeys(keyc);
 	keyc->curKeySyms.map= _XkbTypedRealloc(keyc->curKeySyms.map,tmp,KeySym);
 	if (keyc->curKeySyms.map==NULL)
@@ -495,6 +513,8 @@
     }
     keyc->curKeySyms.mapWidth= maxSymsPerKey;
 
+    if (maxSymsPerKey>0){    /* mmc! */
+    /* what use in core for keysPerMod ?  8 numbers-- count of keycodes associtated w/ the modifier bit. */
     bzero(keysPerMod,sizeof(keysPerMod));
     for (key=firstCommon;key<=lastCommon;key++) {
 	if (keyc->curKeySyms.map!=NULL) {
@@ -507,12 +527,13 @@
 	    bzero(pCore,maxSymsPerKey*sizeof(KeySym));
 	    pXKB= XkbKeySymsPtr(xkb,key);
 	    nOut= 2;
+            /* copy the initial keysyms? */
 	    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];
+		    pCore[2+n]= pXKB[n]; /* mmc: why the 2+ skip?  --- b/c below (on 2,3) we put from group2 !*/
 		}
 		if (groupWidth>2)
 		    nOut= groupWidth;
@@ -556,6 +577,7 @@
 	    }
 	}
     }
+    }
 #ifdef MODE_SWITCH
     /* Fix up any of the KME stuff if we changed the core description.
      */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.