[PATCH] Use cached XKB keymap when rules haven't changed

Dan Nicholson dbn.lists at gmail.com
Wed Nov 26 06:28:58 PST 2008


Rather than compiling a new keymap every time XkbInitKeyboardDeviceStruct is
called, cache the previous keymap and reuse it if the rules have not been
changed. When XkbSetRulesDflts is called, the cached map is invalidated if it
differs from the previous default rules.

The map is also invalidated if named components are supplied. This could be
fixed by caching Ktcsg from the previous run and comparing.

The meaning of xkb_cached_map has been changed in the code to reporesent the
keymap reused over multiple calls. The freshly compiled keymap used by
XkbInitDevice has been renamed to xkb_initial_map.

Signed-off-by: Dan Nicholson <dbn.lists at gmail.com>
---
 So, it turns out that XkbCopyKeymap doesn't quite do what you'd expect,
 failing to copy a few fields of the XkbDescRec. I'm not sure whether it's
 appropriate to copy .device_spec from the cached keymap, but it didn't
 seem to hurt in my testing.

 If this would be more appropriate in XkbCopyKeymap or maybe a new function
 like XkbDuplicateKeymap, let me know.

 This patch also has a minor change to not mess with the XkbInitDevice
 behavior from before. It might not be an issue, but it seems like having
 it pick up any keymap other than one just setup in XkbInitKeyboardDeviceStruct
 would be wrong.

 xkb/xkbInit.c |  186 ++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 125 insertions(+), 61 deletions(-)

diff --git a/xkb/xkbInit.c b/xkb/xkbInit.c
index ea28a5f..025978e 100644
--- a/xkb/xkbInit.c
+++ b/xkb/xkbInit.c
@@ -130,6 +130,7 @@ static char *		XkbLayoutUsed=	NULL;
 static char *		XkbVariantUsed=	NULL;
 static char *		XkbOptionsUsed=	NULL;
 
+static XkbDescPtr       xkb_initial_map = NULL;
 static XkbDescPtr       xkb_cached_map = NULL;
 
 _X_EXPORT Bool		noXkbExtension=		XKB_DFLT_DISABLED;
@@ -244,31 +245,57 @@ _X_EXPORT void
 XkbSetRulesDflts(char *rulesFile,char *model,char *layout,
 					char *variant,char *options)
 {
-    if (XkbRulesFile)
-	_XkbFree(XkbRulesFile);
-    XkbRulesFile= _XkbDupString(rulesFile);
-    rulesDefined= True;
+    Bool changed = False;
+
+    if (!XkbRulesFile || strcmp(rulesFile, XkbRulesFile) != 0) {
+        changed = True;
+        if (XkbRulesFile)
+            _XkbFree(XkbRulesFile);
+        XkbRulesFile = _XkbDupString(rulesFile);
+    }
+    rulesDefined = True;
+
     if (model) {
-	if (XkbModelDflt)
-	    _XkbFree(XkbModelDflt);
-	XkbModelDflt= _XkbDupString(model);
+        if (!XkbModelDflt || strcmp(model, XkbModelDflt) != 0) {
+            changed = True;
+            if (XkbModelDflt)
+                _XkbFree(XkbModelDflt);
+            XkbModelDflt = _XkbDupString(model);
+        }
     }
+
     if (layout) {
-	if (XkbLayoutDflt)
-	    _XkbFree(XkbLayoutDflt);
-	XkbLayoutDflt= _XkbDupString(layout);
+        if (!XkbLayoutDflt || strcmp(layout, XkbLayoutDflt) != 0) {
+            changed = True;
+            if (XkbLayoutDflt)
+                _XkbFree(XkbLayoutDflt);
+            XkbLayoutDflt = _XkbDupString(layout);
+        }
     }
+
     if (variant) {
-	if (XkbVariantDflt)
-	    _XkbFree(XkbVariantDflt);
-	XkbVariantDflt= _XkbDupString(variant);
+        if (!XkbVariantDflt || strcmp(variant, XkbVariantDflt) != 0) {
+            changed = True;
+            if (XkbVariantDflt)
+                _XkbFree(XkbVariantDflt);
+            XkbVariantDflt = _XkbDupString(variant);
+        }
     }
+
     if (options) {
-	if (XkbOptionsDflt)
-	    _XkbFree(XkbOptionsDflt);
-	XkbOptionsDflt= _XkbDupString(options);
+        if (!XkbOptionsDflt || strcmp(options, XkbOptionsDflt) != 0) {
+            changed = True;
+            if (XkbOptionsDflt)
+                _XkbFree(XkbOptionsDflt);
+            XkbOptionsDflt = _XkbDupString(options);
+        }
+    }
+
+    /* If the rules have changed, remove the cached map. */
+    if (changed && xkb_cached_map) {
+        XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, True);
+        xkb_cached_map = NULL;
     }
-    return;
 }
 
 void
@@ -285,6 +312,8 @@ XkbDeleteRulesDflts()
     _XkbFree(XkbOptionsDflt);
     XkbOptionsDflt = NULL;
 
+    XkbFreeKeyboard(xkb_initial_map, XkbAllComponentsMask, True);
+    xkb_initial_map = NULL;
     XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, True);
     xkb_cached_map = NULL;
 }
@@ -488,14 +517,17 @@ XkbEventCauseRec	cause;
     if ( xkbi ) {
 	XkbDescPtr	xkb;
 
-        if (xkb_cached_map) {
-            xkbi->desc = xkb_cached_map;
-            xkb_cached_map = NULL;
+        xkbi->desc = XkbAllocKeyboard();
+        if (!xkbi->desc)
+            FatalError("Couldn't allocate keyboard description\n");
+        if (xkb_initial_map) {
+            if(!XkbCopyKeymap(xkb_initial_map, xkbi->desc, False))
+                FatalError("XKB: Couldn't copy initial keymap\n");
+            xkbi->desc->defined = xkb_initial_map->defined;
+            xkbi->desc->flags = xkb_initial_map->flags;
+            xkbi->desc->device_spec = xkb_initial_map->device_spec;
         }
         else {
-            xkbi->desc= XkbAllocKeyboard();
-            if (!xkbi->desc)
-                FatalError("Couldn't allocate keyboard description\n");
             xkbi->desc->min_key_code = pXDev->key->curKeySyms.minKeyCode;
             xkbi->desc->max_key_code = pXDev->key->curKeySyms.maxKeyCode;
         }
@@ -592,8 +624,6 @@ XkbDescPtr              xkb;
 	return False;
     pSyms= pSymsIn;
     pMods= pModsIn;
-    bzero(&defs,sizeof(XkbRF_VarDefsRec));
-    rules= XkbGetRulesDflts(&defs);
 
     /*
      * The strings are duplicated because it is not guaranteed that
@@ -608,42 +638,76 @@ XkbDescPtr              xkb;
     if (names->geometry) names->geometry = _XkbDupString(names->geometry);
     if (names->symbols) names->symbols = _XkbDupString(names->symbols);
 
-    if (defs.model && defs.layout && rules) {
-	XkbComponentNamesRec	rNames;
-	bzero(&rNames,sizeof(XkbComponentNamesRec));
-	if (XkbDDXNamesFromRules(dev,rules,&defs,&rNames)) {
-	    if (rNames.keycodes) {
-		if (!names->keycodes)
-		    names->keycodes =  rNames.keycodes;
-		else
-		    _XkbFree(rNames.keycodes);
-	    }
-	    if (rNames.types) {
-		if (!names->types)
-		    names->types = rNames.types;
-		else  _XkbFree(rNames.types);
-	    }
-	    if (rNames.compat) {
-		if (!names->compat) 
-		    names->compat =  rNames.compat;
-		else  _XkbFree(rNames.compat);
-	    }
-	    if (rNames.symbols) {
-		if (!names->symbols)
-		    names->symbols =  rNames.symbols;
-		else _XkbFree(rNames.symbols);
-	    }
-	    if (rNames.geometry) {
-		if (!names->geometry)
-		    names->geometry = rNames.geometry;
-		else _XkbFree(rNames.geometry);
-	    }
-	    XkbSetRulesUsed(&defs);
-	}
+    /*
+     * If named components were passed, we can't guarantee the validity
+     * of the cached keymap.
+     */
+    if (xkb_cached_map &&
+        (names->keymap || names->keycodes || names->types ||
+         names->compat || names->geometry || names->symbols)) {
+        XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, True);
+        xkb_cached_map = NULL;
     }
 
-    ok = (Bool) XkbDDXLoadKeymapByNames(dev,names,XkmAllIndicesMask,0,
-                                        &xkb,name,PATH_MAX);
+    /*
+     * If we have a cached compiled map, then the rules have not changed
+     * and we can avoid recompiling.
+     */
+    if (xkb_cached_map) {
+        LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n");
+        xkb = xkb_cached_map;
+        ok = True;
+    }
+    else {
+        bzero(&defs, sizeof(XkbRF_VarDefsRec));
+        rules = XkbGetRulesDflts(&defs);
+
+        if (defs.model && defs.layout && rules) {
+            XkbComponentNamesRec rNames;
+            bzero(&rNames, sizeof(XkbComponentNamesRec));
+
+            if (XkbDDXNamesFromRules(dev, rules, &defs, &rNames)) {
+                if (rNames.keycodes) {
+                    if (!names->keycodes)
+                        names->keycodes = rNames.keycodes;
+                    else
+                        _XkbFree(rNames.keycodes);
+                }
+                if (rNames.types) {
+                    if (!names->types)
+                        names->types = rNames.types;
+                    else
+                        _XkbFree(rNames.types);
+                }
+                if (rNames.compat) {
+                    if (!names->compat)
+                        names->compat = rNames.compat;
+                    else
+                        _XkbFree(rNames.compat);
+                }
+                if (rNames.symbols) {
+                    if (!names->symbols)
+                        names->symbols = rNames.symbols;
+                    else
+                        _XkbFree(rNames.symbols);
+                }
+                if (rNames.geometry) {
+                    if (!names->geometry)
+                        names->geometry = rNames.geometry;
+                    else
+                        _XkbFree(rNames.geometry);
+                }
+                XkbSetRulesUsed(&defs);
+            }
+        }
+
+        ok = (Bool) XkbDDXLoadKeymapByNames(dev, names, XkmAllIndicesMask,
+                                            0, &xkb, name, PATH_MAX);
+
+        /* Cache the map so it can be reused the next time. */
+        if (ok && xkb)
+            xkb_cached_map = xkb;
+    }
 
     if (ok && (xkb!=NULL)) {
 	KeyCode		minKC,maxKC;
@@ -679,13 +743,13 @@ XkbDescPtr              xkb;
 	}
         /* Store the map here so we can pick it back up in XkbInitDevice.
          * Sigh. */
-        xkb_cached_map = xkb;
+        xkb_initial_map = xkb;
     }
     else {
 	LogMessage(X_WARNING, "Couldn't load XKB keymap, falling back to pre-XKB keymap\n");
     }
     ok= InitKeyboardDeviceStruct((DevicePtr)dev,pSyms,pMods,bellProc,ctrlProc);
-    xkb_cached_map = NULL;
+    xkb_initial_map = NULL;
     if ((pSyms==&tmpSyms)&&(pSyms->map!=NULL)) {
 	_XkbFree(pSyms->map);
 	pSyms->map= NULL;
-- 
1.5.6.5




More information about the xorg mailing list