summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Udaltsov <svu@gnome.org>2003-12-30 23:40:33 +0000
committerSergey Udaltsov <svu@gnome.org>2003-12-30 23:40:33 +0000
commitb26841741f28d0cf432c3e3d03b95215fa8ca4ef (patch)
treef182114c140a52c4bfea711ab6c7904efe51a3a1
parent99c4fcc88f4c4b6ec9b199fa8624f133f3a7e079 (diff)
downloadlibxklavier-b26841741f28d0cf432c3e3d03b95215fa8ca4ef.tar.gz
first step in separating all xkb-related things
-rw-r--r--libxklavier/Makefile.am4
-rw-r--r--libxklavier/xklavier.c284
-rw-r--r--libxklavier/xklavier_config.c213
-rw-r--r--libxklavier/xklavier_config.h7
-rw-r--r--libxklavier/xklavier_config_xkb.c257
-rw-r--r--libxklavier/xklavier_dump.c2
-rw-r--r--libxklavier/xklavier_evt.c1
-rw-r--r--libxklavier/xklavier_private.h27
-rw-r--r--libxklavier/xklavier_private_xkb.h25
-rw-r--r--libxklavier/xklavier_props.c202
-rw-r--r--libxklavier/xklavier_util.c184
-rw-r--r--libxklavier/xklavier_xkb.c658
12 files changed, 966 insertions, 898 deletions
diff --git a/libxklavier/Makefile.am b/libxklavier/Makefile.am
index 6f9db74..c5f82d8 100644
--- a/libxklavier/Makefile.am
+++ b/libxklavier/Makefile.am
@@ -1,12 +1,12 @@
AM_CFLAGS = -DDATA_DIR=\"$(datadir)/$(PACKAGE)\" -I. -I$(includedir) $(XML_CFLAGS) -I$(x_includes) -I$(top_srcdir)
lib_LTLIBRARIES = libxklavier.la
-noinst_HEADERS = xklavier_private.h
+noinst_HEADERS = xklavier_private.h xklavier_private_xkb.h
xklavierincdir = $(includedir)/libxklavier
xklavierinc_HEADERS = xklavier.h xklavier_config.h
-libxklavier_la_SOURCES = xklavier.c xklavier_evt.c xklavier_util.c xklavier_config.c xklavier_config_i18n.c xklavier_props.c xklavier_dump.c \
+libxklavier_la_SOURCES = xklavier.c xklavier_xkb.c xklavier_evt.c xklavier_util.c xklavier_config.c xklavier_config_xkb.c xklavier_config_i18n.c xklavier_props.c xklavier_dump.c \
$(noinst_HEADERS) $(xklavierinc_HEADERS)
libxklavier_la_LDFLAGS = -version-info @VERSION_INFO@ $(XML_LIBS) -lxkbfile -L$(x_libraries)
diff --git a/libxklavier/xklavier.c b/libxklavier/xklavier.c
index c84010e..8c81b1d 100644
--- a/libxklavier/xklavier.c
+++ b/libxklavier/xklavier.c
@@ -1,4 +1,3 @@
-#include <stdio.h>
#include <time.h>
#include <X11/Xatom.h>
@@ -12,8 +11,6 @@ Display *_xklDpy;
Bool _xklXkbExtPresent;
-XkbDescPtr _xklXkb;
-
XklState _xklCurState;
Window _xklCurClient;
@@ -24,14 +21,6 @@ const char *_xklLastErrorMsg;
XErrorHandler _xklDefaultErrHandler;
-char *_xklIndicatorNames[XkbNumIndicators];
-
-Atom _xklIndicatorAtoms[XkbNumIndicators];
-
-unsigned _xklPhysIndicatorsMask;
-
-int _xklXkbEventType, _xklXkbError;
-
Atom _xklAtoms[TOTAL_ATOMS];
Window _xklRootWindow;
@@ -48,8 +37,8 @@ int _xklDebugLevel = 160;
Window _xklPrevAppWindow;
-static XklConfigCallback configCallback = NULL;
-static void *configCallbackData;
+XklConfigCallback _xklConfigCallback = NULL;
+void *_xklConfigCallbackData;
static XklStateCallback stateCallback = NULL;
static void *stateCallbackData;
@@ -59,8 +48,6 @@ static void *winCallbackData;
static XklLogAppender logAppender = XklDefaultLogAppender;
-static char *groupNames[XkbNumKbdGroups];
-
static Bool groupPerApp = True;
static Bool handleIndicators = False;
@@ -75,11 +62,6 @@ Bool XklGetIndicatorsHandling( void )
return handleIndicators;
}
-const char **XklGetGroupNames( void )
-{
- return ( const char ** ) groupNames;
-}
-
void XklSetDebugLevel( int level )
{
_xklDebugLevel = level;
@@ -123,8 +105,8 @@ int XklGetSecondaryGroupsMask( void )
int XklRegisterConfigCallback( XklConfigCallback fun, void *data )
{
- configCallback = fun;
- configCallbackData = data;
+ _xklConfigCallback = fun;
+ _xklConfigCallbackData = data;
return 0;
}
@@ -147,48 +129,6 @@ void XklSetLogAppender( XklLogAppender fun )
logAppender = fun;
}
-int XklInit( Display * a_dpy )
-{
- int opcode;
- int scr;
-
- _xklDefaultErrHandler =
- XSetErrorHandler( ( XErrorHandler ) _XklErrHandler );
-
- /* Lets begin */
- _xklXkbExtPresent = XkbQueryExtension( _xklDpy = a_dpy,
- &opcode, &_xklXkbEventType,
- &_xklXkbError, NULL, NULL );
- if( !_xklXkbExtPresent )
- {
- return -1;
- }
-
- scr = DefaultScreen( _xklDpy );
- _xklRootWindow = RootWindow( _xklDpy, scr );
- XklDebug( 160,
- "xkbEvenType: %X, xkbError: %X, display: %p, root: " WINID_FORMAT
- "\n", _xklXkbEventType, _xklXkbError, _xklDpy, _xklRootWindow );
-
- _xklAtoms[WM_NAME] = XInternAtom( _xklDpy, "WM_NAME", False );
- _xklAtoms[WM_STATE] = XInternAtom( _xklDpy, "WM_STATE", False );
- _xklAtoms[XKLAVIER_STATE] = XInternAtom( _xklDpy, "XKLAVIER_STATE", False );
- _xklAtoms[XKLAVIER_TRANSPARENT] =
- XInternAtom( _xklDpy, "XKLAVIER_TRANSPARENT", False );
- _xklAtoms[XKB_RF_NAMES_PROP_ATOM] =
- XInternAtom( _xklDpy, _XKB_RF_NAMES_PROP_ATOM, False );
- _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP] =
- XInternAtom( _xklDpy, "_XKB_RULES_NAMES_BACKUP", False );
-
- _xklAllowSecondaryGroupOnce = False;
- _xklSkipOneRestore = False;
- _xklDefaultGroup = -1;
- _xklSecondaryGroupsMask = 0L;
- _xklPrevAppWindow = 0;
-
- return _XklLoadAllInfo( )? 0 : _xklLastErrorCode;
-}
-
int XklStartListen( )
{
XklResumeListen( );
@@ -197,54 +137,6 @@ int XklStartListen( )
return 0;
}
-int XklPauseListen( )
-{
- XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XkbAllEventsMask, 0 );
-// XkbSelectEventDetails( _xklDpy,
- // XkbUseCoreKbd,
- // XkbStateNotify,
- // 0,
- // 0 );
-
- //!!_XklSelectInput( _xklRootWindow, 0 );
- return 0;
-}
-
-int XklResumeListen( )
-{
- /* What events we want */
-#define XKB_EVT_MASK \
- (XkbStateNotifyMask| \
- XkbNamesNotifyMask| \
- XkbControlsNotifyMask| \
- XkbIndicatorStateNotifyMask| \
- XkbIndicatorMapNotifyMask| \
- XkbNewKeyboardNotifyMask)
-
- XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XKB_EVT_MASK, XKB_EVT_MASK );
-
-#define XKB_STATE_EVT_DTL_MASK \
- (XkbGroupStateMask)
-
- XkbSelectEventDetails( _xklDpy,
- XkbUseCoreKbd,
- XkbStateNotify,
- XKB_STATE_EVT_DTL_MASK, XKB_STATE_EVT_DTL_MASK );
-
-#define XKB_NAMES_EVT_DTL_MASK \
- (XkbGroupNamesMask|XkbIndicatorNamesMask)
-
- XkbSelectEventDetails( _xklDpy,
- XkbUseCoreKbd,
- XkbNamesNotify,
- XKB_NAMES_EVT_DTL_MASK, XKB_NAMES_EVT_DTL_MASK );
-
- _XklSelectInputMerging( _xklRootWindow,
- SubstructureNotifyMask | PropertyChangeMask );
- _XklGetRealState( &_xklCurState );
- return 0;
-}
-
int XklStopListen( )
{
XklPauseListen( );
@@ -254,7 +146,7 @@ int XklStopListen( )
int XklTerm( )
{
XSetErrorHandler( ( XErrorHandler ) _xklDefaultErrHandler );
- configCallback = NULL;
+ _xklConfigCallback = NULL;
stateCallback = NULL;
winCallback = NULL;
@@ -307,22 +199,6 @@ Bool XklUngrabKey( int key, unsigned modifiers )
return Success == XUngrabKey( _xklDpy, keyCode, 0, _xklRootWindow );
}
-unsigned XklGetNumGroups( )
-{
- return _xklXkb->ctrls->num_groups;
-}
-
-int XklGetNextGroup( )
-{
- return ( _xklCurState.group + 1 ) % _xklXkb->ctrls->num_groups;
-}
-
-int XklGetPrevGroup( )
-{
- int n = _xklXkb->ctrls->num_groups;
- return ( _xklCurState.group + n - 1 ) % n;
-}
-
int XklGetRestoreGroup( )
{
XklState state;
@@ -584,101 +460,6 @@ Bool _XklLoadWindowTree( )
return retval;
}
-#define KBD_MASK \
- ( 0 )
-#define CTRLS_MASK \
- ( XkbSlowKeysMask )
-#define NAMES_MASK \
- ( XkbGroupNamesMask | XkbIndicatorNamesMask )
-
-void _XklFreeAllInfo( )
-{
- if( _xklXkb != NULL )
- {
- int i;
- char **groupName = groupNames;
- for( i = _xklXkb->ctrls->num_groups; --i >= 0; groupName++ )
- if( *groupName )
- XFree( *groupName );
- XkbFreeKeyboard( _xklXkb, XkbAllComponentsMask, True );
- _xklXkb = NULL;
- }
-}
-
-/**
- * Load some XKB parameters
- */
-Bool _XklLoadAllInfo( )
-{
- int i;
- unsigned bit;
- Atom *gna;
- char **groupName;
-
- _xklXkb = XkbGetMap( _xklDpy, KBD_MASK, XkbUseCoreKbd );
- if( _xklXkb == NULL )
- {
- _xklLastErrorMsg = "Could not load keyboard";
- return False;
- }
-
- _xklLastErrorCode = XkbGetControls( _xklDpy, CTRLS_MASK, _xklXkb );
-
- if( _xklLastErrorCode != Success )
- {
- _xklLastErrorMsg = "Could not load controls";
- return False;
- }
-
- XklDebug( 200, "found %d groups\n", _xklXkb->ctrls->num_groups );
-
- _xklLastErrorCode = XkbGetNames( _xklDpy, NAMES_MASK, _xklXkb );
-
- if( _xklLastErrorCode != Success )
- {
- _xklLastErrorMsg = "Could not load names";
- return False;
- }
-
- gna = _xklXkb->names->groups;
- groupName = groupNames;
- for( i = _xklXkb->ctrls->num_groups; --i >= 0; gna++, groupName++ )
- {
- *groupName = XGetAtomName( _xklDpy,
- *gna == None ?
- XInternAtom( _xklDpy, "-", False ) : *gna );
- XklDebug( 200, "group %d has name [%s]\n", i, *groupName );
- }
-
- _xklLastErrorCode =
- XkbGetIndicatorMap( _xklDpy, XkbAllIndicatorsMask, _xklXkb );
-
- if( _xklLastErrorCode != Success )
- {
- _xklLastErrorMsg = "Could not load indicator map";
- return False;
- }
-
- for( i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1 )
- {
- Atom a = _xklXkb->names->indicators[i];
- if( a != None )
- _xklIndicatorNames[i] = XGetAtomName( _xklDpy, a );
- else
- _xklIndicatorNames[i] = "";
-
- XklDebug( 200, "Indicator[%d] is %s\n", i, _xklIndicatorNames[i] );
- }
-
- XklDebug( 200, "Real indicators are %X\n",
- _xklXkb->indicators->phys_indicators );
-
- if( configCallback != NULL )
- ( *configCallback ) ( configCallbackData );
-
- return True;
-}
-
void _XklDebug( const char file[], const char function[], int level,
const char format[], ... )
{
@@ -701,57 +482,6 @@ void XklDefaultLogAppender( const char file[], const char function[],
vfprintf( stdout, format, args );
}
-#define PROP_LENGTH 2
-
-/**
- * Gets the state from the window property
- */
-Bool _XklGetAppState( Window appWin, XklState * state_return )
-{
- Atom type_ret;
- int format_ret;
- unsigned long nitems, rest;
- CARD32 *prop = NULL;
- Bool ret = False;
-
- int grp = -1;
- unsigned inds = -1;
-
- if( ( XGetWindowProperty
- ( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE], 0L, PROP_LENGTH, False,
- XA_INTEGER, &type_ret, &format_ret, &nitems, &rest,
- ( unsigned char ** ) &prop ) == Success )
- && ( type_ret == XA_INTEGER ) && ( format_ret == 32 ) )
- {
- grp = prop[0];
- if( grp >= _xklXkb->ctrls->num_groups || grp < 0 )
- grp = 0;
-
- inds = prop[1];
-
- if( state_return != NULL )
- {
- state_return->group = grp;
- state_return->indicators = inds;
- }
- if( prop != NULL )
- XFree( prop );
-
- ret = True;
- }
-
- if( ret )
- XklDebug( 150,
- "Appwin " WINID_FORMAT
- ", '%s' has the group %d, indicators %X\n", appWin,
- _XklGetDebugWindowTitle( appWin ), grp, inds );
- else
- XklDebug( 150, "Appwin " WINID_FORMAT ", '%s' does not have state\n",
- appWin, _XklGetDebugWindowTitle( appWin ) );
-
- return ret;
-}
-
/**
* Deletes the state from the window properties
*/
@@ -765,14 +495,14 @@ void _XklDelAppState( Window appWin )
*/
void _XklSaveAppState( Window appWin, XklState * state )
{
- CARD32 prop[PROP_LENGTH];
+ CARD32 prop[XKLAVIER_STATE_PROP_LENGTH];
prop[0] = state->group;
prop[1] = state->indicators;
XChangeProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE], XA_INTEGER,
32, PropModeReplace, ( const unsigned char * ) prop,
- PROP_LENGTH );
+ XKLAVIER_STATE_PROP_LENGTH );
XklDebug( 160,
"Saved the group %d, indicators %X for appwin " WINID_FORMAT "\n",
diff --git a/libxklavier/xklavier_config.c b/libxklavier/xklavier_config.c
index 1c33131..f5c9bd2 100644
--- a/libxklavier/xklavier_config.c
+++ b/libxklavier/xklavier_config.c
@@ -9,23 +9,6 @@
#include "xklavier_private.h"
-#include <X11/extensions/XKBfile.h>
-#include <X11/extensions/XKM.h>
-
-#define RULES_FILE "xfree86"
-
-#define RULES_PATH ( XKB_BASE "/rules/" RULES_FILE )
-
-#define XML_CFG_PATH ( XKB_BASE "/rules/xfree86.xml" )
-
-// For "bad" X servers we hold our own copy
-#define XML_CFG_FALLBACK_PATH ( DATA_DIR "/xfree86.xml" )
-
-#define MULTIPLE_LAYOUTS_CHECK_PATH ( XKB_BASE "/symbols/pc/en_US" )
-
-#define XK_XKB_KEYS
-#include <X11/keysymdef.h>
-
typedef struct _XklConfigRegistry
{
xmlDocPtr doc;
@@ -33,18 +16,12 @@ typedef struct _XklConfigRegistry
}
XklConfigRegistry;
-XkbRF_VarDefsRec _xklVarDefs;
-
static XklConfigRegistry theRegistry;
static xmlXPathCompExprPtr modelsXPath;
static xmlXPathCompExprPtr layoutsXPath;
static xmlXPathCompExprPtr optionGroupsXPath;
-static XkbRF_RulesPtr rules;
-static XkbComponentNamesRec componentNames;
-static char *locale;
-
#define _XklConfigRegistryIsInitialized() \
( theRegistry.xpathContext != NULL )
@@ -356,63 +333,6 @@ void _XklConfigRecSplitByComma( char ***array,
}
}
-static Bool _XklConfigPrepareBeforeKbd( const XklConfigRecPtr data )
-{
- memset( &_xklVarDefs, 0, sizeof( _xklVarDefs ) );
-
- _xklVarDefs.model = ( char * ) data->model;
-
- if( data->layouts != NULL )
- _xklVarDefs.layout = _XklConfigRecMergeLayouts( data );
-
- if( data->variants != NULL )
- _xklVarDefs.variant = _XklConfigRecMergeVariants( data );
-
- if( data->options != NULL )
- _xklVarDefs.options = _XklConfigRecMergeOptions( data );
-
- locale = setlocale( LC_ALL, NULL );
- if( locale != NULL )
- locale = strdup( locale );
-
- rules = XkbRF_Load( RULES_PATH, locale, True, True );
-
- if( rules == NULL )
- {
- _xklLastErrorMsg = "Could not load rules";
- return False;
- }
-
- if( !XkbRF_GetComponents( rules, &_xklVarDefs, &componentNames ) )
- {
- _xklLastErrorMsg = "Could not translate rules into components";
- return False;
- }
-
- return True;
-}
-
-static void _XklConfigCleanAfterKbd( )
-{
- XkbRF_Free( rules, True );
-
- if( locale != NULL )
- {
- free( locale );
- locale = NULL;
- }
- if( _xklVarDefs.layout != NULL )
- {
- free( _xklVarDefs.layout );
- _xklVarDefs.layout = NULL;
- }
- if( _xklVarDefs.options != NULL )
- {
- free( _xklVarDefs.options );
- _xklVarDefs.options = NULL;
- }
-}
-
static void _XklApplyFun2XkbDesc( XkbDescPtr xkb, XkbDescModifierFunc fun,
void *userData, Bool activeInServer )
{
@@ -471,14 +391,8 @@ void XklConfigTerm( void )
}
}
-Bool XklConfigLoadRegistry( void )
+Bool XklConfigLoadRegistryFromFile( const char * fileName )
{
- struct stat statBuf;
-
- const char *fileName = XML_CFG_PATH;
- if( stat( XML_CFG_PATH, &statBuf ) != 0 )
- fileName = XML_CFG_FALLBACK_PATH;
-
theRegistry.doc = xmlParseFile( fileName );
if( theRegistry.doc == NULL )
{
@@ -620,128 +534,3 @@ Bool XklConfigFindOption( const char *optionGroupName,
"[../configItem/name = '%s' and configItem/name = '%s']",
optionGroupName, ptr, NULL );
}
-
-Bool XklMultipleLayoutsSupported( void )
-{
- struct stat buf;
- return 0 == stat( MULTIPLE_LAYOUTS_CHECK_PATH, &buf );
-}
-
-Bool XklConfigActivate( const XklConfigRecPtr data, XkbDescModifierFunc fun,
- void *userData )
-{
- Bool rv = False;
-#if 0
- {
- int i;
- XklDebug( 150, "New model: [%s]\n", data->model );
- XklDebug( 150, "New layouts: %p\n", data->layouts );
- for( i = data->numLayouts; --i >= 0; )
- XklDebug( 150, "New layout[%d]: [%s]\n", i, data->layouts[i] );
- XklDebug( 150, "New variants: %p\n", data->variants );
- for( i = data->numVariants; --i >= 0; )
- XklDebug( 150, "New variant[%d]: [%s]\n", i, data->variants[i] );
- XklDebug( 150, "New options: %p\n", data->options );
- for( i = data->numOptions; --i >= 0; )
- XklDebug( 150, "New option[%d]: [%s]\n", i, data->options[i] );
- }
-#endif
-
- if( _XklConfigPrepareBeforeKbd( data ) )
- {
- XkbDescPtr xkb;
- xkb =
- XkbGetKeyboardByName( _xklDpy, XkbUseCoreKbd, &componentNames,
- XkbGBN_AllComponentsMask,
- XkbGBN_AllComponentsMask &
- ( ~XkbGBN_GeometryMask ), True );
-
- //!! Do I need to free it anywhere?
- if( xkb != NULL )
- {
- _XklApplyFun2XkbDesc( xkb, fun, userData, True );
-#if 0
- XklDumpXkbDesc( "config.xkb", xkb );
-#endif
-
- if( XklSetNamesProp
- ( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], RULES_FILE, data ) )
- rv = True;
- else
- _xklLastErrorMsg = "Could not set names property";
- XkbFreeKeyboard( xkb, XkbAllComponentsMask, True );
- } else
- {
- _xklLastErrorMsg = "Could not load keyboard description";
- }
- }
- _XklConfigCleanAfterKbd( );
- return rv;
-}
-
-int XklSetKeyAsSwitcher( XkbDescPtr kbd, void *userData )
-{
- if( kbd != NULL )
- {
- XkbClientMapPtr map = kbd->map;
- if( map != NULL )
- {
- KeySym keysym = ( KeySym ) userData;
- KeySym *psym = map->syms;
- int symno;
-
- for( symno = map->num_syms; --symno >= 0; psym++ )
- {
- if( *psym == keysym )
- {
- XklDebug( 160, "Changing %s to %s at %d\n",
- XKeysymToString( *psym ),
- XKeysymToString( XK_ISO_Next_Group ), psym - map->syms );
- *psym = XK_ISO_Next_Group;
- break;
- }
- }
- } else
- XklDebug( 160, "No client map in the keyboard description?\n" );
- }
- return XkbKeySymsMask | XkbKeyTypesMask | XkbKeyActionsMask;
-}
-
-Bool XklConfigWriteXKMFile( const char *fileName, const XklConfigRecPtr data,
- XkbDescModifierFunc fun, void *userData )
-{
- Bool rv = False;
-
- FILE *output = fopen( fileName, "w" );
- XkbFileInfo dumpInfo;
-
- if( output == NULL )
- {
- _xklLastErrorMsg = "Could not open the XKB file";
- return False;
- }
-
- if( _XklConfigPrepareBeforeKbd( data ) )
- {
- XkbDescPtr xkb;
- xkb =
- XkbGetKeyboardByName( _xklDpy, XkbUseCoreKbd, &componentNames,
- XkbGBN_AllComponentsMask,
- XkbGBN_AllComponentsMask &
- ( ~XkbGBN_GeometryMask ), False );
- if( xkb != NULL )
- {
- _XklApplyFun2XkbDesc( xkb, fun, userData, False );
-
- dumpInfo.defined = 0;
- dumpInfo.xkb = xkb;
- dumpInfo.type = XkmKeymapFile;
- rv = XkbWriteXKMFile( output, &dumpInfo );
- XkbFreeKeyboard( xkb, XkbGBN_AllComponentsMask, True );
- } else
- _xklLastErrorMsg = "Could not load keyboard description";
- }
- _XklConfigCleanAfterKbd( );
- fclose( output );
- return rv;
-}
diff --git a/libxklavier/xklavier_config.h b/libxklavier/xklavier_config.h
index 18fd71d..5087314 100644
--- a/libxklavier/xklavier_config.h
+++ b/libxklavier/xklavier_config.h
@@ -105,6 +105,13 @@ extern "C"
/**
* Loads XML configuration registry
+ * @param fileName file name to load
+ * @return true on success
+ */
+ extern Bool XklConfigLoadRegistryFromFile( const char* fileName );
+
+/**
+ * Loads XML configuration registry
* @return true on success
*/
extern Bool XklConfigLoadRegistry( void );
diff --git a/libxklavier/xklavier_config_xkb.c b/libxklavier/xklavier_config_xkb.c
new file mode 100644
index 0000000..b9de6b5
--- /dev/null
+++ b/libxklavier/xklavier_config_xkb.c
@@ -0,0 +1,257 @@
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+#include <sys/stat.h>
+
+#include <libxml/xpath.h>
+
+#include "config.h"
+
+#include "xklavier_private.h"
+
+#include "xklavier_private_xkb.h"
+
+#include <X11/extensions/XKBfile.h>
+#include <X11/extensions/XKM.h>
+
+#define RULES_FILE "xfree86"
+
+#define RULES_PATH ( XKB_BASE "/rules/" RULES_FILE )
+
+#define XML_CFG_PATH ( XKB_BASE "/rules/xfree86.xml" )
+
+// For "bad" X servers we hold our own copy
+#define XML_CFG_FALLBACK_PATH ( DATA_DIR "/xfree86.xml" )
+
+#define MULTIPLE_LAYOUTS_CHECK_PATH ( XKB_BASE "/symbols/pc/en_US" )
+
+#define XK_XKB_KEYS
+#include <X11/keysymdef.h>
+
+XkbRF_VarDefsRec _xklVarDefs;
+
+static XkbRF_RulesPtr rules;
+static XkbComponentNamesRec componentNames;
+static char *locale;
+
+Bool XklConfigLoadRegistry( void )
+{
+ struct stat statBuf;
+
+ const char *fileName = XML_CFG_PATH;
+ if( stat( XML_CFG_PATH, &statBuf ) != 0 )
+ fileName = XML_CFG_FALLBACK_PATH;
+
+ return XklConfigLoadRegistryFromFile( fileName );
+}
+
+static Bool _XklConfigPrepareBeforeKbd( const XklConfigRecPtr data )
+{
+ memset( &_xklVarDefs, 0, sizeof( _xklVarDefs ) );
+
+ _xklVarDefs.model = ( char * ) data->model;
+
+ if( data->layouts != NULL )
+ _xklVarDefs.layout = _XklConfigRecMergeLayouts( data );
+
+ if( data->variants != NULL )
+ _xklVarDefs.variant = _XklConfigRecMergeVariants( data );
+
+ if( data->options != NULL )
+ _xklVarDefs.options = _XklConfigRecMergeOptions( data );
+
+ locale = setlocale( LC_ALL, NULL );
+ if( locale != NULL )
+ locale = strdup( locale );
+
+ rules = XkbRF_Load( RULES_PATH, locale, True, True );
+
+ if( rules == NULL )
+ {
+ _xklLastErrorMsg = "Could not load rules";
+ return False;
+ }
+
+ if( !XkbRF_GetComponents( rules, &_xklVarDefs, &componentNames ) )
+ {
+ _xklLastErrorMsg = "Could not translate rules into components";
+ return False;
+ }
+
+ return True;
+}
+
+static void _XklConfigCleanAfterKbd( )
+{
+ XkbRF_Free( rules, True );
+
+ if( locale != NULL )
+ {
+ free( locale );
+ locale = NULL;
+ }
+ if( _xklVarDefs.layout != NULL )
+ {
+ free( _xklVarDefs.layout );
+ _xklVarDefs.layout = NULL;
+ }
+ if( _xklVarDefs.options != NULL )
+ {
+ free( _xklVarDefs.options );
+ _xklVarDefs.options = NULL;
+ }
+}
+
+static void _XklApplyFun2XkbDesc( XkbDescPtr xkb, XkbDescModifierFunc fun,
+ void *userData, Bool activeInServer )
+{
+ int mask;
+ // XklDumpXkbDesc( "comp.xkb", xkb );
+ if( fun == NULL )
+ return;
+
+ if( activeInServer )
+ {
+ mask = ( *fun ) ( NULL, NULL );
+ if( mask == 0 )
+ return;
+ XkbGetUpdatedMap( _xklDpy, mask, xkb );
+ // XklDumpXkbDesc( "restored1.xkb", xkb );
+ }
+
+ mask = ( *fun ) ( xkb, userData );
+ if( activeInServer )
+ {
+ // XklDumpXkbDesc( "comp+.xkb", xkb );
+ XkbSetMap( _xklDpy, mask, xkb );
+ XSync( _xklDpy, False );
+
+ // XkbGetUpdatedMap( _xklDpy, XkbAllMapComponentsMask, xkb );
+ // XklDumpXkbDesc( "restored2.xkb", xkb );
+ }
+}
+
+Bool XklMultipleLayoutsSupported( void )
+{
+ struct stat buf;
+ return 0 == stat( MULTIPLE_LAYOUTS_CHECK_PATH, &buf );
+}
+
+Bool XklConfigActivate( const XklConfigRecPtr data, XkbDescModifierFunc fun,
+ void *userData )
+{
+ Bool rv = False;
+#if 0
+ {
+ int i;
+ XklDebug( 150, "New model: [%s]\n", data->model );
+ XklDebug( 150, "New layouts: %p\n", data->layouts );
+ for( i = data->numLayouts; --i >= 0; )
+ XklDebug( 150, "New layout[%d]: [%s]\n", i, data->layouts[i] );
+ XklDebug( 150, "New variants: %p\n", data->variants );
+ for( i = data->numVariants; --i >= 0; )
+ XklDebug( 150, "New variant[%d]: [%s]\n", i, data->variants[i] );
+ XklDebug( 150, "New options: %p\n", data->options );
+ for( i = data->numOptions; --i >= 0; )
+ XklDebug( 150, "New option[%d]: [%s]\n", i, data->options[i] );
+ }
+#endif
+
+ if( _XklConfigPrepareBeforeKbd( data ) )
+ {
+ XkbDescPtr xkb;
+ xkb =
+ XkbGetKeyboardByName( _xklDpy, XkbUseCoreKbd, &componentNames,
+ XkbGBN_AllComponentsMask,
+ XkbGBN_AllComponentsMask &
+ ( ~XkbGBN_GeometryMask ), True );
+
+ //!! Do I need to free it anywhere?
+ if( xkb != NULL )
+ {
+ _XklApplyFun2XkbDesc( xkb, fun, userData, True );
+#if 0
+ XklDumpXkbDesc( "config.xkb", xkb );
+#endif
+
+ if( XklSetNamesProp
+ ( _xklAtoms[XKB_RF_NAMES_PROP_ATOM], RULES_FILE, data ) )
+ rv = True;
+ else
+ _xklLastErrorMsg = "Could not set names property";
+ XkbFreeKeyboard( xkb, XkbAllComponentsMask, True );
+ } else
+ {
+ _xklLastErrorMsg = "Could not load keyboard description";
+ }
+ }
+ _XklConfigCleanAfterKbd( );
+ return rv;
+}
+
+int XklSetKeyAsSwitcher( XkbDescPtr kbd, void *userData )
+{
+ if( kbd != NULL )
+ {
+ XkbClientMapPtr map = kbd->map;
+ if( map != NULL )
+ {
+ KeySym keysym = ( KeySym ) userData;
+ KeySym *psym = map->syms;
+ int symno;
+
+ for( symno = map->num_syms; --symno >= 0; psym++ )
+ {
+ if( *psym == keysym )
+ {
+ XklDebug( 160, "Changing %s to %s at %d\n",
+ XKeysymToString( *psym ),
+ XKeysymToString( XK_ISO_Next_Group ), psym - map->syms );
+ *psym = XK_ISO_Next_Group;
+ break;
+ }
+ }
+ } else
+ XklDebug( 160, "No client map in the keyboard description?\n" );
+ }
+ return XkbKeySymsMask | XkbKeyTypesMask | XkbKeyActionsMask;
+}
+
+Bool XklConfigWriteXKMFile( const char *fileName, const XklConfigRecPtr data,
+ XkbDescModifierFunc fun, void *userData )
+{
+ Bool rv = False;
+
+ FILE *output = fopen( fileName, "w" );
+ XkbFileInfo dumpInfo;
+
+ if( output == NULL )
+ {
+ _xklLastErrorMsg = "Could not open the XKB file";
+ return False;
+ }
+
+ if( _XklConfigPrepareBeforeKbd( data ) )
+ {
+ XkbDescPtr xkb;
+ xkb =
+ XkbGetKeyboardByName( _xklDpy, XkbUseCoreKbd, &componentNames,
+ XkbGBN_AllComponentsMask,
+ XkbGBN_AllComponentsMask &
+ ( ~XkbGBN_GeometryMask ), False );
+ if( xkb != NULL )
+ {
+ _XklApplyFun2XkbDesc( xkb, fun, userData, False );
+
+ dumpInfo.defined = 0;
+ dumpInfo.xkb = xkb;
+ dumpInfo.type = XkmKeymapFile;
+ rv = XkbWriteXKMFile( output, &dumpInfo );
+ XkbFreeKeyboard( xkb, XkbGBN_AllComponentsMask, True );
+ } else
+ _xklLastErrorMsg = "Could not load keyboard description";
+ }
+ _XklConfigCleanAfterKbd( );
+ fclose( output );
+ return rv;
+}
diff --git a/libxklavier/xklavier_dump.c b/libxklavier/xklavier_dump.c
index bc7ab08..70d345c 100644
--- a/libxklavier/xklavier_dump.c
+++ b/libxklavier/xklavier_dump.c
@@ -14,10 +14,10 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <stdio.h>
#include <string.h>
#include "xklavier_private.h"
+#include "xklavier_private_xkb.h"
static void _XkbModsRecDump( FILE * fs, XkbModsRec * mods )
{
diff --git a/libxklavier/xklavier_evt.c b/libxklavier/xklavier_evt.c
index 243dd68..cf492a6 100644
--- a/libxklavier/xklavier_evt.c
+++ b/libxklavier/xklavier_evt.c
@@ -6,6 +6,7 @@
#include <X11/Xlibint.h>
#include "xklavier_private.h"
+#include "xklavier_private_xkb.h"
int XklFilterEvents( XEvent * xev )
{
diff --git a/libxklavier/xklavier_private.h b/libxklavier/xklavier_private.h
index 7735f86..f158fa8 100644
--- a/libxklavier/xklavier_private.h
+++ b/libxklavier/xklavier_private.h
@@ -5,17 +5,12 @@
#include <libxklavier/xklavier_config.h>
-#include <X11/extensions/XKBrules.h>
-
extern void _XklGetRealState( XklState * curState_return );
extern void _XklAddAppWindow( Window win, Window parent, Bool force,
XklState * initState );
extern Bool _XklGetAppWindowBottomToTop( Window win, Window * appWin_return );
extern Bool _XklGetAppWindow( Window win, Window * appWin_return );
-extern void _XklStdXkbHandler( int grp, XklStateChange changeType,
- unsigned inds, Bool setInds );
-extern void _XklXkbEvHandler( XkbEvent * kev );
extern void _XklFocusInEvHandler( XFocusChangeEvent * fev );
extern void _XklFocusOutEvHandler( XFocusChangeEvent * fev );
extern void _XklPropertyEvHandler( XPropertyEvent * rev );
@@ -78,20 +73,14 @@ extern void _XklConfigRecSplitVariants( XklConfigRecPtr data,
extern void _XklConfigRecSplitOptions( XklConfigRecPtr data,
const char *merged );
-extern void XklDumpXkbDesc( const char *filename, XkbDescPtr kbd );
-
extern const char *_XklGetEventName( int type );
extern Bool _XklIsTransparentAppWindow( Window appWin );
extern Display *_xklDpy;
-extern Bool _xklXkbExtPresent;
-
extern Window _xklRootWindow;
-extern XkbDescPtr _xklXkb;
-
extern XklState _xklCurState;
extern Window _xklCurClient;
@@ -104,12 +93,6 @@ extern XErrorHandler _xklDefaultErrHandler;
extern char *_xklIndicatorNames[];
-#define ForPhysIndicators( i, bit ) \
- for ( i=0, bit=1; i<XkbNumIndicators; i++, bit<<=1 ) \
- if ( _xklXkb->indicators->phys_indicators & bit )
-
-extern int _xklXkbEventType, _xklXkbError;
-
#define WM_NAME 0
#define WM_STATE 1
#define XKLAVIER_STATE 2
@@ -118,9 +101,9 @@ extern int _xklXkbEventType, _xklXkbError;
#define XKB_RF_NAMES_PROP_ATOM_BACKUP 5
#define TOTAL_ATOMS 6
-extern Atom _xklAtoms[];
+#define XKLAVIER_STATE_PROP_LENGTH 2
-extern XkbRF_VarDefsRec _xklVarDefs;
+extern Atom _xklAtoms[];
extern Bool _xklAllowSecondaryGroupOnce;
@@ -128,7 +111,7 @@ extern int _xklDefaultGroup;
extern Bool _xklSkipOneRestore;
-extern int _xklSecondaryGroupMask;
+extern int _xklSecondaryGroupsMask;
extern int _xklDebugLevel;
@@ -136,4 +119,8 @@ extern Window _xklPrevAppWindow;
#define WINID_FORMAT "%lx"
+extern XklConfigCallback _xklConfigCallback;
+
+extern void *_xklConfigCallbackData;
+
#endif
diff --git a/libxklavier/xklavier_private_xkb.h b/libxklavier/xklavier_private_xkb.h
new file mode 100644
index 0000000..8616789
--- /dev/null
+++ b/libxklavier/xklavier_private_xkb.h
@@ -0,0 +1,25 @@
+#ifndef __XKLAVIER_PRIVATE_XKB_H__
+#define __XKLAVIER_PRIVATE_XKB_H__
+
+#include <X11/extensions/XKBrules.h>
+
+extern void _XklStdXkbHandler( int grp, XklStateChange changeType,
+ unsigned inds, Bool setInds );
+
+extern void _XklXkbEvHandler( XkbEvent * kev );
+
+extern void XklDumpXkbDesc( const char *filename, XkbDescPtr kbd );
+
+extern Bool _xklXkbExtPresent;
+
+extern XkbDescPtr _xklXkb;
+
+#define ForPhysIndicators( i, bit ) \
+ for ( i=0, bit=1; i<XkbNumIndicators; i++, bit<<=1 ) \
+ if ( _xklXkb->indicators->phys_indicators & bit )
+
+extern int _xklXkbEventType, _xklXkbError;
+
+extern XkbRF_VarDefsRec _xklVarDefs;
+
+#endif
diff --git a/libxklavier/xklavier_props.c b/libxklavier/xklavier_props.c
index 79b305a..98a7338 100644
--- a/libxklavier/xklavier_props.c
+++ b/libxklavier/xklavier_props.c
@@ -1,14 +1,9 @@
-#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <locale.h>
#include <X11/Xlib.h>
-#include <X11/XKBlib.h>
#include <X11/Xatom.h>
-#include <X11/extensions/XKBfile.h>
-#include <X11/extensions/XKBrules.h>
-#include <X11/extensions/XKM.h>
#include <libxml/xpath.h>
@@ -83,203 +78,6 @@ Bool XklConfigGetFromBackup( XklConfigRecPtr data )
return rv;
}
-// taken from XFree86 maprules.c
-Bool XklGetNamesProp( Atom rulesAtom,
- char **rulesFileOut, XklConfigRecPtr data )
-{
- Atom realPropType;
- int fmt;
- unsigned long nitems, extraBytes;
- char *propData, *out;
- Status rtrn;
-
- // no such atom!
- if( rulesAtom == None ) /* property cannot exist */
- {
- _xklLastErrorMsg = "Could not find the atom";
- return False;
- }
-
- rtrn =
- XGetWindowProperty( _xklDpy, _xklRootWindow, rulesAtom, 0L,
- _XKB_RF_NAMES_PROP_MAXLEN, False, XA_STRING,
- &realPropType, &fmt, &nitems, &extraBytes,
- ( unsigned char ** ) &propData );
- // property not found!
- if( rtrn != Success )
- {
- _xklLastErrorMsg = "Could not get the property";
- return False;
- }
- // set rules file to ""
- if( rulesFileOut )
- *rulesFileOut = NULL;
-
- // has to be array of strings
- if( ( extraBytes > 0 ) || ( realPropType != XA_STRING ) || ( fmt != 8 ) )
- {
- if( propData )
- XFree( propData );
- _xklLastErrorMsg = "Wrong property format";
- return False;
- }
- // rules file
- out = propData;
- if( out && ( *out ) && rulesFileOut )
- *rulesFileOut = strdup( out );
- out += strlen( out ) + 1;
-
- if( ( out - propData ) < nitems )
- {
- if( *out )
- data->model = strdup( out );
- out += strlen( out ) + 1;
- }
-
- if( ( out - propData ) < nitems )
- {
- _XklConfigRecSplitLayouts( data, out );
- out += strlen( out ) + 1;
- }
-
- if( ( out - propData ) < nitems )
- {
- int i;
- char **theLayout, **theVariant;
- _XklConfigRecSplitVariants( data, out );
- /*
- Now have to ensure that number of variants matches the number of layouts
- The 'remainder' is filled with NULLs (not ""s!)
- */
- if( data->numVariants < data->numLayouts )
- {
- data->variants =
- realloc( data->variants, data->numLayouts * sizeof( char * ) );
- memset( data->variants + data->numVariants, 0,
- ( data->numLayouts - data->numVariants ) * sizeof( char * ) );
- data->numVariants = data->numLayouts;
- }
- // take variants from layouts like ru(winkeys)
- theLayout = data->layouts;
- theVariant = data->variants;
- for( i = data->numLayouts; --i >= 0; theLayout++, theVariant++ )
- {
- if( *theLayout != NULL )
- {
- char *varstart = strchr( *theLayout, '(' );
- if( varstart != NULL )
- {
- char *varend = strchr( varstart, ')' );
- if( varend != NULL )
- {
- int varlen = varend - varstart;
- int laylen = varstart - *theLayout;
- // I am not sure - but I assume variants in layout have priority
- char *var = *theVariant = ( *theVariant != NULL ) ?
- realloc( *theVariant, varlen ) : malloc( varlen );
- memcpy( var, varstart + 1, --varlen );
- var[varlen] = '\0';
- realloc( *theLayout, laylen + 1 );
- ( *theLayout )[laylen] = '\0';
- }
- }
- }
- }
- out += strlen( out ) + 1;
- }
-
- if( ( out - propData ) < nitems )
- {
- _XklConfigRecSplitOptions( data, out );
-// out += strlen( out ) + 1;
- }
- XFree( propData );
- return True;
-}
-
-// taken from XFree86 maprules.c
-Bool XklSetNamesProp( Atom rulesAtom,
- char *rulesFile, const XklConfigRecPtr data )
-{
- int len, i, rv;
- char *pval;
- char *next;
- char *allLayouts = _XklConfigRecMergeLayouts( data );
- char *allVariants = _XklConfigRecMergeVariants( data );
- char *allOptions = _XklConfigRecMergeOptions( data );
-
- len = ( rulesFile ? strlen( rulesFile ) : 0 );
- len += ( data->model ? strlen( data->model ) : 0 );
- len += ( allLayouts ? strlen( allLayouts ) : 0 );
- len += ( allVariants ? strlen( allVariants ) : 0 );
- len += ( allOptions ? strlen( allOptions ) : 0 );
- if( len < 1 )
- return True;
-
- len += 5; /* trailing NULs */
-
- pval = next = ( char * ) malloc( len + 1 );
- if( !pval )
- {
- _xklLastErrorMsg = "Could not allocate buffer";
- return False;
- }
- if( rulesFile )
- {
- strcpy( next, rulesFile );
- next += strlen( rulesFile );
- }
- *next++ = '\0';
- if( data->model )
- {
- strcpy( next, data->model );
- next += strlen( data->model );
- }
- *next++ = '\0';
- if( data->layouts )
- {
- strcpy( next, allLayouts );
- next += strlen( allLayouts );
- }
- *next++ = '\0';
- if( data->variants )
- {
- strcpy( next, allVariants );
- next += strlen( allVariants );
- }
- *next++ = '\0';
- if( data->options )
- {
- strcpy( next, allOptions );
- next += strlen( allOptions );
- }
- *next++ = '\0';
- if( ( next - pval ) != len )
- {
- XklDebug( 150, "Illegal final position: %d/%d\n", ( next - pval ), len );
- if( allOptions != NULL )
- free( allOptions );
- free( pval );
- _xklLastErrorMsg = "Internal property parsing error";
- return False;
- }
-
- rv = XChangeProperty( _xklDpy, _xklRootWindow, rulesAtom, XA_STRING, 8,
- PropModeReplace, ( unsigned char * ) pval, len );
- XSync( _xklDpy, False );
-#if 0
- for( i = len - 1; --i >= 0; )
- if( pval[i] == '\0' )
- pval[i] = '?';
- XklDebug( 150, "Stored [%s] of length %d to [%s] of %X: %d\n", pval, len,
- propName, _xklRootWindow, rv );
-#endif
- if( allOptions != NULL )
- free( allOptions );
- free( pval );
- return True;
-}
-
Bool XklBackupNamesProp( )
{
char *rf;
diff --git a/libxklavier/xklavier_util.c b/libxklavier/xklavier_util.c
index 76921bd..b555c43 100644
--- a/libxklavier/xklavier_util.c
+++ b/libxklavier/xklavier_util.c
@@ -32,13 +32,6 @@ char *XklGetWindowTitle( Window w )
return NULL;
}
-void XklLockGroup( int group )
-{
- XklDebug( 100, "Posted request for change the group to %d ##\n", group );
- XkbLockGroup( _xklDpy, XkbUseCoreKbd, group );
- XSync( _xklDpy, False );
-}
-
Bool XklIsSameApp( Window win1, Window win2 )
{
Window app1, app2;
@@ -77,26 +70,6 @@ void XklSaveState( Window win, XklState * state )
}
/**
- * Updates current internal state from X state
- */
-void _XklGetRealState( XklState * curState_return )
-{
- XkbStateRec state;
-
- curState_return->group = 0;
- if( Success == XkbGetState( _xklDpy, XkbUseCoreKbd, &state ) )
- curState_return->group = state.locked_group;
-
- if( Success ==
- XkbGetIndicatorState( _xklDpy, XkbUseCoreKbd,
- &curState_return->indicators ) )
- curState_return->indicators &= _xklXkb->indicators->phys_indicators;
- else
- curState_return->indicators = 0;
-
-}
-
-/**
* Prepares the name of window suitable for debugging (32characters long).
*/
char *_XklGetDebugWindowTitle( Window win )
@@ -241,163 +214,6 @@ Status _XklStatusQueryTree( Display * display,
return result ? Success : FirstExtensionError;
}
-/*
- * Actually taken from mxkbledpanel, valueChangedProc
- */
-Bool _XklSetIndicator( int indicatorNum, Bool set )
-{
- XkbIndicatorMapPtr map;
-
- map = _xklXkb->indicators->maps + indicatorNum;
-
- /* The 'flags' field tells whether this indicator is automatic
- * (XkbIM_NoExplicit - 0x80), explicit (XkbIM_NoAutomatic - 0x40),
- * or neither (both - 0xC0).
- *
- * If NoAutomatic is set, the server ignores the rest of the
- * fields in the indicator map (i.e. it disables automatic control
- * of the LED). If NoExplicit is set, the server prevents clients
- * from explicitly changing the value of the LED (using the core
- * protocol *or* XKB). If NoAutomatic *and* NoExplicit are set,
- * the LED cannot be changed (unless you change the map first).
- * If neither NoAutomatic nor NoExplicit are set, the server will
- * change the LED according to the indicator map, but clients can
- * override that (until the next automatic change) using the core
- * protocol or XKB.
- */
- switch ( map->flags & ( XkbIM_NoExplicit | XkbIM_NoAutomatic ) )
- {
- case XkbIM_NoExplicit | XkbIM_NoAutomatic:
- {
- // Can do nothing. Just ignore the indicator
- return True;
- }
-
- case XkbIM_NoAutomatic:
- {
- if( _xklXkb->names->indicators[indicatorNum] != None )
- XkbSetNamedIndicator( _xklDpy, XkbUseCoreKbd,
- _xklXkb->names->indicators[indicatorNum], set,
- False, NULL );
- else
- {
- XKeyboardControl xkc;
- xkc.led = indicatorNum;
- xkc.led_mode = set ? LedModeOn : LedModeOff;
- XChangeKeyboardControl( _xklDpy, KBLed | KBLedMode, &xkc );
- XSync( _xklDpy, 0 );
- }
-
- return True;
- }
-
- case XkbIM_NoExplicit:
- break;
- }
-
- /* The 'ctrls' field tells what controls tell this indicator to
- * to turn on: RepeatKeys (0x1), SlowKeys (0x2), BounceKeys (0x4),
- * StickyKeys (0x8), MouseKeys (0x10), AccessXKeys (0x20),
- * TimeOut (0x40), Feedback (0x80), ToggleKeys (0x100),
- * Overlay1 (0x200), Overlay2 (0x400), GroupsWrap (0x800),
- * InternalMods (0x1000), IgnoreLockMods (0x2000),
- * PerKeyRepeat (0x3000), or ControlsEnabled (0x4000)
- */
- if( map->ctrls )
- {
- unsigned long which = map->ctrls;
-
- XkbGetControls( _xklDpy, XkbAllControlsMask, _xklXkb );
- if( set )
- _xklXkb->ctrls->enabled_ctrls |= which;
- else
- _xklXkb->ctrls->enabled_ctrls &= ~which;
- XkbSetControls( _xklDpy, which | XkbControlsEnabledMask, _xklXkb );
- }
-
- /* The 'which_groups' field tells when this indicator turns on
- * * for the 'groups' field: base (0x1), latched (0x2), locked (0x4),
- * * or effective (0x8).
- * */
- if( map->groups )
- {
- int i;
- unsigned int group = 1;
-
- /* Turning on a group indicator is kind of tricky. For
- * now, we will just Latch or Lock the first group we find
- * if that is what this indicator does. Otherwise, we're
- * just going to punt and get out of here.
- */
- if( set )
- {
- for( i = XkbNumKbdGroups; --i >= 0; )
- if( ( 1 << i ) & map->groups )
- {
- group = i;
- break;
- }
- if( map->which_groups & ( XkbIM_UseLocked | XkbIM_UseEffective ) )
- {
- // Important: Groups should be ignored here - because they are handled separately!
- // XklLockGroup( group );
- } else if( map->which_groups & XkbIM_UseLatched )
- XkbLatchGroup( _xklDpy, XkbUseCoreKbd, group );
- else
- {
- // Can do nothing. Just ignore the indicator
- return True;
- }
- } else
- /* Turning off a group indicator will mean that we just
- * Lock the first group that this indicator doesn't watch.
- */
- {
- for( i = XkbNumKbdGroups; --i >= 0; )
- if( !( ( 1 << i ) & map->groups ) )
- {
- group = i;
- break;
- }
- XklLockGroup( group );
- }
- }
-
- /* The 'which_mods' field tells when this indicator turns on
- * for the modifiers: base (0x1), latched (0x2), locked (0x4),
- * or effective (0x8).
- *
- * The 'real_mods' field tells whether this turns on when one of
- * the real X modifiers is set: Shift (0x1), Lock (0x2), Control (0x4),
- * Mod1 (0x8), Mod2 (0x10), Mod3 (0x20), Mod4 (0x40), or Mod5 (0x80).
- *
- * The 'virtual_mods' field tells whether this turns on when one of
- * the virtual modifiers is set.
- *
- * The 'mask' field tells what real X modifiers the virtual_modifiers
- * map to?
- */
- if( map->mods.real_mods || map->mods.mask )
- {
- unsigned int affect, mods;
-
- affect = ( map->mods.real_mods | map->mods.mask );
-
- mods = set ? affect : 0;
-
- if( map->which_mods & ( XkbIM_UseLocked | XkbIM_UseEffective ) )
- XkbLockModifiers( _xklDpy, XkbUseCoreKbd, affect, mods );
- else if( map->which_mods & XkbIM_UseLatched )
- XkbLatchModifiers( _xklDpy, XkbUseCoreKbd, affect, mods );
- else
- {
- return True;
- }
- }
-
- return True;
-}
-
const char *_XklGetEventName( int type )
{
// Not really good to use the fact of consecutivity
diff --git a/libxklavier/xklavier_xkb.c b/libxklavier/xklavier_xkb.c
new file mode 100644
index 0000000..8f8176c
--- /dev/null
+++ b/libxklavier/xklavier_xkb.c
@@ -0,0 +1,658 @@
+#include <time.h>
+
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xlibint.h>
+
+#include "xklavier_private.h"
+#include "xklavier_private_xkb.h"
+
+XkbDescPtr _xklXkb;
+
+char *_xklIndicatorNames[XkbNumIndicators];
+
+Atom _xklIndicatorAtoms[XkbNumIndicators];
+
+unsigned _xklPhysIndicatorsMask;
+
+int _xklXkbEventType, _xklXkbError;
+
+static char *groupNames[XkbNumKbdGroups];
+
+const char **XklGetGroupNames( void )
+{
+ return ( const char ** ) groupNames;
+}
+
+int XklInit( Display * a_dpy )
+{
+ int opcode;
+ int scr;
+
+ _xklDefaultErrHandler =
+ XSetErrorHandler( ( XErrorHandler ) _XklErrHandler );
+
+ /* Lets begin */
+ _xklXkbExtPresent = XkbQueryExtension( _xklDpy = a_dpy,
+ &opcode, &_xklXkbEventType,
+ &_xklXkbError, NULL, NULL );
+ if( !_xklXkbExtPresent )
+ {
+ return -1;
+ }
+
+ scr = DefaultScreen( _xklDpy );
+ _xklRootWindow = RootWindow( _xklDpy, scr );
+ XklDebug( 160,
+ "xkbEvenType: %X, xkbError: %X, display: %p, root: " WINID_FORMAT
+ "\n", _xklXkbEventType, _xklXkbError, _xklDpy, _xklRootWindow );
+
+ _xklAtoms[WM_NAME] = XInternAtom( _xklDpy, "WM_NAME", False );
+ _xklAtoms[WM_STATE] = XInternAtom( _xklDpy, "WM_STATE", False );
+ _xklAtoms[XKLAVIER_STATE] = XInternAtom( _xklDpy, "XKLAVIER_STATE", False );
+ _xklAtoms[XKLAVIER_TRANSPARENT] =
+ XInternAtom( _xklDpy, "XKLAVIER_TRANSPARENT", False );
+ _xklAtoms[XKB_RF_NAMES_PROP_ATOM] =
+ XInternAtom( _xklDpy, _XKB_RF_NAMES_PROP_ATOM, False );
+ _xklAtoms[XKB_RF_NAMES_PROP_ATOM_BACKUP] =
+ XInternAtom( _xklDpy, "_XKB_RULES_NAMES_BACKUP", False );
+
+ _xklAllowSecondaryGroupOnce = False;
+ _xklSkipOneRestore = False;
+ _xklDefaultGroup = -1;
+ _xklSecondaryGroupsMask = 0L;
+ _xklPrevAppWindow = 0;
+
+ return _XklLoadAllInfo( )? 0 : _xklLastErrorCode;
+}
+
+int XklPauseListen( )
+{
+ XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XkbAllEventsMask, 0 );
+// XkbSelectEventDetails( _xklDpy,
+ // XkbUseCoreKbd,
+ // XkbStateNotify,
+ // 0,
+ // 0 );
+
+ //!!_XklSelectInput( _xklRootWindow, 0 );
+ return 0;
+}
+
+int XklResumeListen( )
+{
+ /* What events we want */
+#define XKB_EVT_MASK \
+ (XkbStateNotifyMask| \
+ XkbNamesNotifyMask| \
+ XkbControlsNotifyMask| \
+ XkbIndicatorStateNotifyMask| \
+ XkbIndicatorMapNotifyMask| \
+ XkbNewKeyboardNotifyMask)
+
+ XkbSelectEvents( _xklDpy, XkbUseCoreKbd, XKB_EVT_MASK, XKB_EVT_MASK );
+
+#define XKB_STATE_EVT_DTL_MASK \
+ (XkbGroupStateMask)
+
+ XkbSelectEventDetails( _xklDpy,
+ XkbUseCoreKbd,
+ XkbStateNotify,
+ XKB_STATE_EVT_DTL_MASK, XKB_STATE_EVT_DTL_MASK );
+
+#define XKB_NAMES_EVT_DTL_MASK \
+ (XkbGroupNamesMask|XkbIndicatorNamesMask)
+
+ XkbSelectEventDetails( _xklDpy,
+ XkbUseCoreKbd,
+ XkbNamesNotify,
+ XKB_NAMES_EVT_DTL_MASK, XKB_NAMES_EVT_DTL_MASK );
+
+ _XklSelectInputMerging( _xklRootWindow,
+ SubstructureNotifyMask | PropertyChangeMask );
+ _XklGetRealState( &_xklCurState );
+ return 0;
+}
+
+unsigned XklGetNumGroups( )
+{
+ return _xklXkb->ctrls->num_groups;
+}
+
+int XklGetNextGroup( )
+{
+ return ( _xklCurState.group + 1 ) % _xklXkb->ctrls->num_groups;
+}
+
+int XklGetPrevGroup( )
+{
+ int n = _xklXkb->ctrls->num_groups;
+ return ( _xklCurState.group + n - 1 ) % n;
+}
+
+#define KBD_MASK \
+ ( 0 )
+#define CTRLS_MASK \
+ ( XkbSlowKeysMask )
+#define NAMES_MASK \
+ ( XkbGroupNamesMask | XkbIndicatorNamesMask )
+
+void _XklFreeAllInfo( )
+{
+ if( _xklXkb != NULL )
+ {
+ int i;
+ char **groupName = groupNames;
+ for( i = _xklXkb->ctrls->num_groups; --i >= 0; groupName++ )
+ if( *groupName )
+ XFree( *groupName );
+ XkbFreeKeyboard( _xklXkb, XkbAllComponentsMask, True );
+ _xklXkb = NULL;
+ }
+}
+
+/**
+ * Load some XKB parameters
+ */
+Bool _XklLoadAllInfo( )
+{
+ int i;
+ unsigned bit;
+ Atom *gna;
+ char **groupName;
+
+ _xklXkb = XkbGetMap( _xklDpy, KBD_MASK, XkbUseCoreKbd );
+ if( _xklXkb == NULL )
+ {
+ _xklLastErrorMsg = "Could not load keyboard";
+ return False;
+ }
+
+ _xklLastErrorCode = XkbGetControls( _xklDpy, CTRLS_MASK, _xklXkb );
+
+ if( _xklLastErrorCode != Success )
+ {
+ _xklLastErrorMsg = "Could not load controls";
+ return False;
+ }
+
+ XklDebug( 200, "found %d groups\n", _xklXkb->ctrls->num_groups );
+
+ _xklLastErrorCode = XkbGetNames( _xklDpy, NAMES_MASK, _xklXkb );
+
+ if( _xklLastErrorCode != Success )
+ {
+ _xklLastErrorMsg = "Could not load names";
+ return False;
+ }
+
+ gna = _xklXkb->names->groups;
+ groupName = groupNames;
+ for( i = _xklXkb->ctrls->num_groups; --i >= 0; gna++, groupName++ )
+ {
+ *groupName = XGetAtomName( _xklDpy,
+ *gna == None ?
+ XInternAtom( _xklDpy, "-", False ) : *gna );
+ XklDebug( 200, "group %d has name [%s]\n", i, *groupName );
+ }
+
+ _xklLastErrorCode =
+ XkbGetIndicatorMap( _xklDpy, XkbAllIndicatorsMask, _xklXkb );
+
+ if( _xklLastErrorCode != Success )
+ {
+ _xklLastErrorMsg = "Could not load indicator map";
+ return False;
+ }
+
+ for( i = 0, bit = 1; i < XkbNumIndicators; i++, bit <<= 1 )
+ {
+ Atom a = _xklXkb->names->indicators[i];
+ if( a != None )
+ _xklIndicatorNames[i] = XGetAtomName( _xklDpy, a );
+ else
+ _xklIndicatorNames[i] = "";
+
+ XklDebug( 200, "Indicator[%d] is %s\n", i, _xklIndicatorNames[i] );
+ }
+
+ XklDebug( 200, "Real indicators are %X\n",
+ _xklXkb->indicators->phys_indicators );
+
+ if( _xklConfigCallback != NULL )
+ ( *_xklConfigCallback ) ( _xklConfigCallbackData );
+
+ return True;
+}
+
+/**
+ * Gets the state from the window property
+ */
+Bool _XklGetAppState( Window appWin, XklState * state_return )
+{
+ Atom type_ret;
+ int format_ret;
+ unsigned long nitems, rest;
+ CARD32 *prop = NULL;
+ Bool ret = False;
+
+ int grp = -1;
+ unsigned inds = -1;
+
+ if( ( XGetWindowProperty
+ ( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE], 0L,
+ XKLAVIER_STATE_PROP_LENGTH, False,
+ XA_INTEGER, &type_ret, &format_ret, &nitems, &rest,
+ ( unsigned char ** ) &prop ) == Success )
+ && ( type_ret == XA_INTEGER ) && ( format_ret == 32 ) )
+ {
+ grp = prop[0];
+ if( grp >= _xklXkb->ctrls->num_groups || grp < 0 )
+ grp = 0;
+
+ inds = prop[1];
+
+ if( state_return != NULL )
+ {
+ state_return->group = grp;
+ state_return->indicators = inds;
+ }
+ if( prop != NULL )
+ XFree( prop );
+
+ ret = True;
+ }
+
+ if( ret )
+ XklDebug( 150,
+ "Appwin " WINID_FORMAT
+ ", '%s' has the group %d, indicators %X\n", appWin,
+ _XklGetDebugWindowTitle( appWin ), grp, inds );
+ else
+ XklDebug( 150, "Appwin " WINID_FORMAT ", '%s' does not have state\n",
+ appWin, _XklGetDebugWindowTitle( appWin ) );
+
+ return ret;
+}
+
+void XklLockGroup( int group )
+{
+ XklDebug( 100, "Posted request for change the group to %d ##\n", group );
+ XkbLockGroup( _xklDpy, XkbUseCoreKbd, group );
+ XSync( _xklDpy, False );
+}
+
+/**
+ * Updates current internal state from X state
+ */
+void _XklGetRealState( XklState * curState_return )
+{
+ XkbStateRec state;
+
+ curState_return->group = 0;
+ if( Success == XkbGetState( _xklDpy, XkbUseCoreKbd, &state ) )
+ curState_return->group = state.locked_group;
+
+ if( Success ==
+ XkbGetIndicatorState( _xklDpy, XkbUseCoreKbd,
+ &curState_return->indicators ) )
+ curState_return->indicators &= _xklXkb->indicators->phys_indicators;
+ else
+ curState_return->indicators = 0;
+
+}
+
+/*
+ * Actually taken from mxkbledpanel, valueChangedProc
+ */
+Bool _XklSetIndicator( int indicatorNum, Bool set )
+{
+ XkbIndicatorMapPtr map;
+
+ map = _xklXkb->indicators->maps + indicatorNum;
+
+ /* The 'flags' field tells whether this indicator is automatic
+ * (XkbIM_NoExplicit - 0x80), explicit (XkbIM_NoAutomatic - 0x40),
+ * or neither (both - 0xC0).
+ *
+ * If NoAutomatic is set, the server ignores the rest of the
+ * fields in the indicator map (i.e. it disables automatic control
+ * of the LED). If NoExplicit is set, the server prevents clients
+ * from explicitly changing the value of the LED (using the core
+ * protocol *or* XKB). If NoAutomatic *and* NoExplicit are set,
+ * the LED cannot be changed (unless you change the map first).
+ * If neither NoAutomatic nor NoExplicit are set, the server will
+ * change the LED according to the indicator map, but clients can
+ * override that (until the next automatic change) using the core
+ * protocol or XKB.
+ */
+ switch ( map->flags & ( XkbIM_NoExplicit | XkbIM_NoAutomatic ) )
+ {
+ case XkbIM_NoExplicit | XkbIM_NoAutomatic:
+ {
+ // Can do nothing. Just ignore the indicator
+ return True;
+ }
+
+ case XkbIM_NoAutomatic:
+ {
+ if( _xklXkb->names->indicators[indicatorNum] != None )
+ XkbSetNamedIndicator( _xklDpy, XkbUseCoreKbd,
+ _xklXkb->names->indicators[indicatorNum], set,
+ False, NULL );
+ else
+ {
+ XKeyboardControl xkc;
+ xkc.led = indicatorNum;
+ xkc.led_mode = set ? LedModeOn : LedModeOff;
+ XChangeKeyboardControl( _xklDpy, KBLed | KBLedMode, &xkc );
+ XSync( _xklDpy, 0 );
+ }
+
+ return True;
+ }
+
+ case XkbIM_NoExplicit:
+ break;
+ }
+
+ /* The 'ctrls' field tells what controls tell this indicator to
+ * to turn on: RepeatKeys (0x1), SlowKeys (0x2), BounceKeys (0x4),
+ * StickyKeys (0x8), MouseKeys (0x10), AccessXKeys (0x20),
+ * TimeOut (0x40), Feedback (0x80), ToggleKeys (0x100),
+ * Overlay1 (0x200), Overlay2 (0x400), GroupsWrap (0x800),
+ * InternalMods (0x1000), IgnoreLockMods (0x2000),
+ * PerKeyRepeat (0x3000), or ControlsEnabled (0x4000)
+ */
+ if( map->ctrls )
+ {
+ unsigned long which = map->ctrls;
+
+ XkbGetControls( _xklDpy, XkbAllControlsMask, _xklXkb );
+ if( set )
+ _xklXkb->ctrls->enabled_ctrls |= which;
+ else
+ _xklXkb->ctrls->enabled_ctrls &= ~which;
+ XkbSetControls( _xklDpy, which | XkbControlsEnabledMask, _xklXkb );
+ }
+
+ /* The 'which_groups' field tells when this indicator turns on
+ * * for the 'groups' field: base (0x1), latched (0x2), locked (0x4),
+ * * or effective (0x8).
+ * */
+ if( map->groups )
+ {
+ int i;
+ unsigned int group = 1;
+
+ /* Turning on a group indicator is kind of tricky. For
+ * now, we will just Latch or Lock the first group we find
+ * if that is what this indicator does. Otherwise, we're
+ * just going to punt and get out of here.
+ */
+ if( set )
+ {
+ for( i = XkbNumKbdGroups; --i >= 0; )
+ if( ( 1 << i ) & map->groups )
+ {
+ group = i;
+ break;
+ }
+ if( map->which_groups & ( XkbIM_UseLocked | XkbIM_UseEffective ) )
+ {
+ // Important: Groups should be ignored here - because they are handled separately!
+ // XklLockGroup( group );
+ } else if( map->which_groups & XkbIM_UseLatched )
+ XkbLatchGroup( _xklDpy, XkbUseCoreKbd, group );
+ else
+ {
+ // Can do nothing. Just ignore the indicator
+ return True;
+ }
+ } else
+ /* Turning off a group indicator will mean that we just
+ * Lock the first group that this indicator doesn't watch.
+ */
+ {
+ for( i = XkbNumKbdGroups; --i >= 0; )
+ if( !( ( 1 << i ) & map->groups ) )
+ {
+ group = i;
+ break;
+ }
+ XklLockGroup( group );
+ }
+ }
+
+ /* The 'which_mods' field tells when this indicator turns on
+ * for the modifiers: base (0x1), latched (0x2), locked (0x4),
+ * or effective (0x8).
+ *
+ * The 'real_mods' field tells whether this turns on when one of
+ * the real X modifiers is set: Shift (0x1), Lock (0x2), Control (0x4),
+ * Mod1 (0x8), Mod2 (0x10), Mod3 (0x20), Mod4 (0x40), or Mod5 (0x80).
+ *
+ * The 'virtual_mods' field tells whether this turns on when one of
+ * the virtual modifiers is set.
+ *
+ * The 'mask' field tells what real X modifiers the virtual_modifiers
+ * map to?
+ */
+ if( map->mods.real_mods || map->mods.mask )
+ {
+ unsigned int affect, mods;
+
+ affect = ( map->mods.real_mods | map->mods.mask );
+
+ mods = set ? affect : 0;
+
+ if( map->which_mods & ( XkbIM_UseLocked | XkbIM_UseEffective ) )
+ XkbLockModifiers( _xklDpy, XkbUseCoreKbd, affect, mods );
+ else if( map->which_mods & XkbIM_UseLatched )
+ XkbLatchModifiers( _xklDpy, XkbUseCoreKbd, affect, mods );
+ else
+ {
+ return True;
+ }
+ }
+
+ return True;
+}
+
+// taken from XFree86 maprules.c
+Bool XklGetNamesProp( Atom rulesAtom,
+ char **rulesFileOut, XklConfigRecPtr data )
+{
+ Atom realPropType;
+ int fmt;
+ unsigned long nitems, extraBytes;
+ char *propData, *out;
+ Status rtrn;
+
+ // no such atom!
+ if( rulesAtom == None ) /* property cannot exist */
+ {
+ _xklLastErrorMsg = "Could not find the atom";
+ return False;
+ }
+
+ rtrn =
+ XGetWindowProperty( _xklDpy, _xklRootWindow, rulesAtom, 0L,
+ _XKB_RF_NAMES_PROP_MAXLEN, False, XA_STRING,
+ &realPropType, &fmt, &nitems, &extraBytes,
+ ( unsigned char ** ) &propData );
+ // property not found!
+ if( rtrn != Success )
+ {
+ _xklLastErrorMsg = "Could not get the property";
+ return False;
+ }
+ // set rules file to ""
+ if( rulesFileOut )
+ *rulesFileOut = NULL;
+
+ // has to be array of strings
+ if( ( extraBytes > 0 ) || ( realPropType != XA_STRING ) || ( fmt != 8 ) )
+ {
+ if( propData )
+ XFree( propData );
+ _xklLastErrorMsg = "Wrong property format";
+ return False;
+ }
+ // rules file
+ out = propData;
+ if( out && ( *out ) && rulesFileOut )
+ *rulesFileOut = strdup( out );
+ out += strlen( out ) + 1;
+
+ if( ( out - propData ) < nitems )
+ {
+ if( *out )
+ data->model = strdup( out );
+ out += strlen( out ) + 1;
+ }
+
+ if( ( out - propData ) < nitems )
+ {
+ _XklConfigRecSplitLayouts( data, out );
+ out += strlen( out ) + 1;
+ }
+
+ if( ( out - propData ) < nitems )
+ {
+ int i;
+ char **theLayout, **theVariant;
+ _XklConfigRecSplitVariants( data, out );
+ /*
+ Now have to ensure that number of variants matches the number of layouts
+ The 'remainder' is filled with NULLs (not ""s!)
+ */
+ if( data->numVariants < data->numLayouts )
+ {
+ data->variants =
+ realloc( data->variants, data->numLayouts * sizeof( char * ) );
+ memset( data->variants + data->numVariants, 0,
+ ( data->numLayouts - data->numVariants ) * sizeof( char * ) );
+ data->numVariants = data->numLayouts;
+ }
+ // take variants from layouts like ru(winkeys)
+ theLayout = data->layouts;
+ theVariant = data->variants;
+ for( i = data->numLayouts; --i >= 0; theLayout++, theVariant++ )
+ {
+ if( *theLayout != NULL )
+ {
+ char *varstart = strchr( *theLayout, '(' );
+ if( varstart != NULL )
+ {
+ char *varend = strchr( varstart, ')' );
+ if( varend != NULL )
+ {
+ int varlen = varend - varstart;
+ int laylen = varstart - *theLayout;
+ // I am not sure - but I assume variants in layout have priority
+ char *var = *theVariant = ( *theVariant != NULL ) ?
+ realloc( *theVariant, varlen ) : malloc( varlen );
+ memcpy( var, varstart + 1, --varlen );
+ var[varlen] = '\0';
+ realloc( *theLayout, laylen + 1 );
+ ( *theLayout )[laylen] = '\0';
+ }
+ }
+ }
+ }
+ out += strlen( out ) + 1;
+ }
+
+ if( ( out - propData ) < nitems )
+ {
+ _XklConfigRecSplitOptions( data, out );
+// out += strlen( out ) + 1;
+ }
+ XFree( propData );
+ return True;
+}
+
+// taken from XFree86 maprules.c
+Bool XklSetNamesProp( Atom rulesAtom,
+ char *rulesFile, const XklConfigRecPtr data )
+{
+ int len, i, rv;
+ char *pval;
+ char *next;
+ char *allLayouts = _XklConfigRecMergeLayouts( data );
+ char *allVariants = _XklConfigRecMergeVariants( data );
+ char *allOptions = _XklConfigRecMergeOptions( data );
+
+ len = ( rulesFile ? strlen( rulesFile ) : 0 );
+ len += ( data->model ? strlen( data->model ) : 0 );
+ len += ( allLayouts ? strlen( allLayouts ) : 0 );
+ len += ( allVariants ? strlen( allVariants ) : 0 );
+ len += ( allOptions ? strlen( allOptions ) : 0 );
+ if( len < 1 )
+ return True;
+
+ len += 5; /* trailing NULs */
+
+ pval = next = ( char * ) malloc( len + 1 );
+ if( !pval )
+ {
+ _xklLastErrorMsg = "Could not allocate buffer";
+ return False;
+ }
+ if( rulesFile )
+ {
+ strcpy( next, rulesFile );
+ next += strlen( rulesFile );
+ }
+ *next++ = '\0';
+ if( data->model )
+ {
+ strcpy( next, data->model );
+ next += strlen( data->model );
+ }
+ *next++ = '\0';
+ if( data->layouts )
+ {
+ strcpy( next, allLayouts );
+ next += strlen( allLayouts );
+ }
+ *next++ = '\0';
+ if( data->variants )
+ {
+ strcpy( next, allVariants );
+ next += strlen( allVariants );
+ }
+ *next++ = '\0';
+ if( data->options )
+ {
+ strcpy( next, allOptions );
+ next += strlen( allOptions );
+ }
+ *next++ = '\0';
+ if( ( next - pval ) != len )
+ {
+ XklDebug( 150, "Illegal final position: %d/%d\n", ( next - pval ), len );
+ if( allOptions != NULL )
+ free( allOptions );
+ free( pval );
+ _xklLastErrorMsg = "Internal property parsing error";
+ return False;
+ }
+
+ rv = XChangeProperty( _xklDpy, _xklRootWindow, rulesAtom, XA_STRING, 8,
+ PropModeReplace, ( unsigned char * ) pval, len );
+ XSync( _xklDpy, False );
+#if 0
+ for( i = len - 1; --i >= 0; )
+ if( pval[i] == '\0' )
+ pval[i] = '?';
+ XklDebug( 150, "Stored [%s] of length %d to [%s] of %X: %d\n", pval, len,
+ propName, _xklRootWindow, rv );
+#endif
+ if( allOptions != NULL )
+ free( allOptions );
+ free( pval );
+ return True;
+}