diff options
-rw-r--r-- | libxklavier/Makefile.am | 4 | ||||
-rw-r--r-- | libxklavier/xklavier.c | 284 | ||||
-rw-r--r-- | libxklavier/xklavier_config.c | 213 | ||||
-rw-r--r-- | libxklavier/xklavier_config.h | 7 | ||||
-rw-r--r-- | libxklavier/xklavier_config_xkb.c | 257 | ||||
-rw-r--r-- | libxklavier/xklavier_dump.c | 2 | ||||
-rw-r--r-- | libxklavier/xklavier_evt.c | 1 | ||||
-rw-r--r-- | libxklavier/xklavier_private.h | 27 | ||||
-rw-r--r-- | libxklavier/xklavier_private_xkb.h | 25 | ||||
-rw-r--r-- | libxklavier/xklavier_props.c | 202 | ||||
-rw-r--r-- | libxklavier/xklavier_util.c | 184 | ||||
-rw-r--r-- | libxklavier/xklavier_xkb.c | 658 |
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; +} |