From d8339126d5036eb7751b97207afed1eabbd5114c Mon Sep 17 00:00:00 2001 From: Sergey Udaltsov Date: Mon, 27 Mar 2006 23:54:22 +0000 Subject: making xkb config load more robust --- ChangeLog | 5 + libxklavier/xklavier.c | 1404 ++++++++++++++++++------------------- libxklavier/xklavier_config_xkb.c | 796 ++++++++++----------- libxklavier/xklavier_evt.c | 957 +++++++++++-------------- libxklavier/xklavier_private.h | 644 ++++++++--------- 5 files changed, 1769 insertions(+), 2037 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1231054..7156654 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2006-02-28 svu + + * libxklavier/xklavier_config_xkb.c: libxklavier/xklavier_evt.c: + making XKB configuration loading more robust (ignoring ALL xkb errors) + 2006-02-16 svu * libxklavier/xklavier_evt_xmm.c: fixing GCC 2.95 compilation, diff --git a/libxklavier/xklavier.c b/libxklavier/xklavier.c index d20c873..033b0a1 100644 --- a/libxklavier/xklavier.c +++ b/libxklavier/xklavier.c @@ -1,880 +1,862 @@ -#include #include #include #include #include -#include +#include #include "xklavier_private.h" -#include "xkl_engine_marshal.h" -static GObjectClass *parent_class = NULL; +Display *_xklDpy; -static XklEngine *the_engine = NULL; +XklState _xklCurState; -gint xkl_debug_level = 0; +Window _xklCurClient; -static XklLogAppender log_appender = xkl_default_log_appender; +Status _xklLastErrorCode; -const gchar *xkl_last_error_message; +const char *_xklLastErrorMsg; -enum { - PROP_0, - PROP_DISPLAY, - PROP_BACKEND_NAME, - PROP_FEATURES, - PROP_MAX_NUM_GROUPS, - PROP_NUM_GROUPS, - PROP_DEFAULT_GROUP, - PROP_SECONDARY_GROUPS_MASK, - PROP_INDICATORS_HANDLING, -}; +XErrorHandler _xklDefaultErrHandler; -void -xkl_engine_set_indicators_handling(XklEngine * engine, - gboolean whether_handle) +Atom _xklAtoms[TOTAL_ATOMS]; + +Window _xklRootWindow; + +int _xklDefaultGroup; + +Bool _xklSkipOneRestore; + +int _xklSecondaryGroupsMask; + +int _xklDebugLevel = 0; + +Window _xklPrevAppWindow; + +int _xklListenerType = 0; + +XklVTable *xklVTable = NULL; + +XklConfigCallback _xklConfigCallback = NULL; +void *_xklConfigCallbackData; + +Bool _xklCriticalSection = False; + +static XklStateCallback stateCallback = NULL; +static void *stateCallbackData; + +static XklWinCallback winCallback = NULL; +static void *winCallbackData; + +static XklLogAppender logAppender = XklDefaultLogAppender; + +static Bool groupPerApp = True; + +static Bool handleIndicators = False; + + +void XklSetIndicatorsHandling( Bool whetherHandle ) { - xkl_engine_priv(engine, handle_indicators) = whether_handle; + handleIndicators = whetherHandle; } -gboolean -xkl_engine_get_indicators_handling(XklEngine * engine) +Bool XklGetIndicatorsHandling( void ) { - return xkl_engine_priv(engine, handle_indicators); + return handleIndicators; } -void -xkl_set_debug_level(int level) +void XklSetDebugLevel( int level ) { - xkl_debug_level = level; + _xklDebugLevel = level; } -void -xkl_engine_set_group_per_toplevel_window(XklEngine * engine, - gboolean is_set) +void XklSetGroupPerApp( Bool isSet ) { - xkl_engine_priv(engine, group_per_toplevel_window) = is_set; + groupPerApp = isSet; } -gboolean -xkl_engine_is_group_per_toplevel_window(XklEngine * engine) +Bool XklIsGroupPerApp( void ) { - return xkl_engine_priv(engine, group_per_toplevel_window); + return groupPerApp; } -static void -xkl_engine_set_switch_to_secondary_group(XklEngine * engine, gboolean val) +static void _XklSetSwitchToSecondaryGroup( Bool val ) { - CARD32 propval = (CARD32) val; - Display *dpy = xkl_engine_get_display(engine); - XChangeProperty(dpy, - xkl_engine_priv(engine, root_window), - xkl_engine_priv(engine, - atoms)[XKLAVIER_ALLOW_SECONDARY], - XA_INTEGER, 32, PropModeReplace, - (unsigned char *) &propval, 1); - XSync(dpy, False); + CARD32 propval = (CARD32)val; + XChangeProperty( _xklDpy, _xklRootWindow, _xklAtoms[XKLAVIER_ALLOW_SECONDARY], + XA_INTEGER, 32, PropModeReplace, + (unsigned char*)&propval, 1 ); + XSync( _xklDpy, False ); } -void -xkl_engine_allow_one_switch_to_secondary_group(XklEngine * engine) +void XklAllowOneSwitchToSecondaryGroup( void ) { - xkl_debug(150, - "Setting allow_one_switch_to_secondary_group flag\n"); - xkl_engine_set_switch_to_secondary_group(engine, TRUE); + XklDebug( 150, "Setting allowOneSwitchToSecondaryGroup flag\n" ); + _XklSetSwitchToSecondaryGroup( True ); } -gboolean -xkl_engine_is_one_switch_to_secondary_group_allowed(XklEngine * engine) +Bool _XklIsOneSwitchToSecondaryGroupAllowed( void ) { - gboolean rv = FALSE; - unsigned char *propval = NULL; - Atom actual_type; - int actual_format; - unsigned long bytes_remaining; - unsigned long actual_items; - int result; + Bool rv = False; + unsigned char *propval = NULL; + Atom actualType; + int actualFormat; + unsigned long bytesRemaining; + unsigned long actualItems; + int result; - result = - XGetWindowProperty(xkl_engine_get_display(engine), - xkl_engine_priv(engine, root_window), - xkl_engine_priv(engine, atoms) - [XKLAVIER_ALLOW_SECONDARY], 0L, 1L, False, - XA_INTEGER, &actual_type, &actual_format, - &actual_items, &bytes_remaining, &propval); + result = XGetWindowProperty( _xklDpy, _xklRootWindow, + _xklAtoms[XKLAVIER_ALLOW_SECONDARY], 0L, 1L, + False, XA_INTEGER, &actualType, &actualFormat, + &actualItems, &bytesRemaining, + &propval ); - if (Success == result) { - if (actual_format == 32 && actual_items == 1) { - rv = (gboolean) * (Bool *) propval; - } - XFree(propval); - } + if( Success == result ) + { + if( actualFormat == 32 && actualItems == 1 ) + { + rv = *(Bool*)propval; + } + XFree( propval ); + } - return rv; + return rv; } -void -xkl_engine_one_switch_to_secondary_group_performed(XklEngine * engine) +void _XklOneSwitchToSecondaryGroupPerformed( void ) { - xkl_debug(150, - "Resetting allow_one_switch_to_secondary_group flag\n"); - xkl_engine_set_switch_to_secondary_group(engine, FALSE); + XklDebug( 150, "Resetting allowOneSwitchToSecondaryGroup flag\n" ); + _XklSetSwitchToSecondaryGroup( False ); } -void -xkl_engine_set_default_group(XklEngine * engine, gint group) +void XklSetDefaultGroup( int group ) { - xkl_engine_priv(engine, default_group) = group; + _xklDefaultGroup = group; } -gint -xkl_engine_get_default_group(XklEngine * engine) +int XklGetDefaultGroup( void ) { - return xkl_engine_priv(engine, default_group); + return _xklDefaultGroup; } -void -xkl_engine_set_secondary_groups_mask(XklEngine * engine, guint mask) +void XklSetSecondaryGroupsMask( int mask ) { - xkl_engine_priv(engine, secondary_groups_mask) = mask; + _xklSecondaryGroupsMask = mask; } -guint -xkl_engine_get_secondary_groups_mask(XklEngine * engine) +int XklGetSecondaryGroupsMask( void ) { - return xkl_engine_priv(engine, secondary_groups_mask); + return _xklSecondaryGroupsMask; } -void -xkl_set_log_appender(XklLogAppender func) +int XklRegisterConfigCallback( XklConfigCallback fun, void *data ) { - log_appender = func; + _xklConfigCallback = fun; + _xklConfigCallbackData = data; + return 0; } -gint -xkl_engine_start_listen(XklEngine * engine, guint what) +int XklRegisterStateCallback( XklStateCallback fun, void *data ) { - xkl_engine_priv(engine, listener_type) = what; + stateCallback = fun; + stateCallbackData = data; + return 0; +} - if (! - (xkl_engine_priv(engine, features) & - XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT) -&& (what & XKLL_MANAGE_LAYOUTS)) - xkl_debug(0, - "The backend does not require manual layout management - " - "but it is provided by the application"); +int XklRegisterWindowCallback( XklWinCallback fun, void *data ) +{ + winCallback = fun; + winCallbackData = data; + return 0; +} - xkl_engine_resume_listen(engine); - xkl_engine_load_window_tree(engine); - XFlush(xkl_engine_get_display(engine)); - return 0; +void XklSetLogAppender( XklLogAppender fun ) +{ + logAppender = fun; } -gint -xkl_engine_stop_listen(XklEngine * engine) +int XklStartListen( int what ) { - xkl_engine_pause_listen(engine); - return 0; + _xklListenerType = what; + + if( !( xklVTable->features & XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT ) && + ( what & XKLL_MANAGE_LAYOUTS ) ) + XklDebug( 0, "The backend does not require manual layout management - " + "but it is provided by the application" ); + + XklResumeListen( ); + _XklLoadWindowTree( ); + XFlush( _xklDpy ); + return 0; } -XklEngine * -xkl_engine_get_instance(Display * display) +int XklStopListen( void ) { - if (the_engine != NULL) { - g_object_ref(G_OBJECT(the_engine)); - return the_engine; - } + XklPauseListen( ); + return 0; +} - if (!display) { - xkl_debug(10, "xkl_init : display is NULL ?\n"); - return NULL; - } +int XklInit( Display * a_dpy ) +{ + int scr; + char *sdl; + int rv; - the_engine = - XKL_ENGINE(g_object_new - (xkl_engine_get_type(), "display", display, NULL)); + sdl = getenv( "XKL_DEBUG" ); + if( sdl != NULL ) + { + XklSetDebugLevel( atoi( sdl ) ); + } - return the_engine; + if( !a_dpy ) + { + XklDebug( 10, "XklInit : display is NULL ?\n"); + return -1; + } + + _xklDefaultErrHandler = + XSetErrorHandler( ( XErrorHandler ) _XklErrHandler ); + + _xklDpy = a_dpy; + scr = DefaultScreen( _xklDpy ); + _xklRootWindow = RootWindow( _xklDpy, scr ); + + _xklSkipOneRestore = False; + _xklDefaultGroup = -1; + _xklSecondaryGroupsMask = 0L; + _xklPrevAppWindow = 0; + + _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[XKLAVIER_ALLOW_SECONDARY] = + XInternAtom( _xklDpy, "XKLAVIER_ALLOW_SECONDARY", False ); + + _XklOneSwitchToSecondaryGroupPerformed(); + + rv = -1; + XklDebug( 150, "Trying all backends:\n" ); +#ifdef ENABLE_XKB_SUPPORT + XklDebug( 150, "Trying XKB backend\n" ); + rv = _XklXkbInit(); +#endif +#ifdef ENABLE_XMM_SUPPORT + if( rv != 0 ) + { + XklDebug( 150, "Trying XMM backend\n" ); + rv = _XklXmmInit(); + } +#endif + if( rv == 0 ) + { + XklDebug( 150, "Actual backend: %s\n", + XklGetBackendName() ); + } + else + { + XklDebug( 0, "All backends failed, last result: %d\n", rv ); + _xklDpy = NULL; + } + + return ( rv == 0 ) ? + ( _XklLoadAllInfo() ? 0 : _xklLastErrorCode ) : -1; } -gboolean -xkl_engine_grab_key(XklEngine * engine, gint keycode, guint modifiers) +int XklTerm( void ) { - gboolean ret_code; - gchar *keyname; - Display *dpy = xkl_engine_get_display(engine); + XSetErrorHandler( ( XErrorHandler ) _xklDefaultErrHandler ); + _xklConfigCallback = NULL; + stateCallback = NULL; + winCallback = NULL; - if (xkl_debug_level >= 100) { - keyname = - XKeysymToString(XKeycodeToKeysym(dpy, keycode, 0)); - xkl_debug(100, "Listen to the key %d/(%s)/%d\n", keycode, - keyname, modifiers); - } + logAppender = XklDefaultLogAppender; + _XklFreeAllInfo( ); + + return 0; +} + +Bool XklGrabKey( int keycode, unsigned modifiers ) +{ + Bool retCode; + char *keyName; - if (0 == keycode) - return FALSE; + if( _xklDebugLevel >= 100 ) + { + keyName = XKeysymToString( XKeycodeToKeysym( _xklDpy, keycode, 0 ) ); + XklDebug( 100, "Listen to the key %d/(%s)/%d\n", + keycode, keyName, modifiers ); + } - xkl_engine_priv(engine, last_error_code) = Success; + if( ( KeyCode ) NULL == keycode ) + return False; - ret_code = - XGrabKey(dpy, keycode, modifiers, - xkl_engine_priv(engine, root_window), TRUE, - GrabModeAsync, GrabModeAsync); - XSync(dpy, False); + _xklLastErrorCode = Success; - xkl_debug(100, "XGrabKey recode %d/error %d\n", - ret_code, xkl_engine_priv(engine, last_error_code)); + retCode = XGrabKey( _xklDpy, keycode, modifiers, _xklRootWindow, + True, GrabModeAsync, GrabModeAsync ); + XSync( _xklDpy, False ); - ret_code = (xkl_engine_priv(engine, last_error_code) == Success); + XklDebug( 100, "XGrabKey recode %d/error %d\n", retCode, _xklLastErrorCode ); - if (!ret_code) - xkl_last_error_message = "Could not grab the key"; + retCode = ( _xklLastErrorCode == Success ); - return ret_code; + if( !retCode ) + _xklLastErrorMsg = "Could not grab the key"; + + return retCode; } -gboolean -xkl_engine_ungrab_key(XklEngine * engine, gint keycode, guint modifiers) +Bool XklUngrabKey( int keycode, unsigned modifiers ) { - if (0 == keycode) - return FALSE; + if( ( KeyCode ) NULL == keycode ) + return False; - return Success == XUngrabKey(xkl_engine_get_display(engine), - keycode, 0, - xkl_engine_priv(engine, root_window)); + return Success == XUngrabKey( _xklDpy, keycode, 0, _xklRootWindow ); } -gint -xkl_engine_get_next_group(XklEngine * engine) +int XklGetNextGroup( void ) { - gint n = xkl_engine_get_num_groups(engine); - return (xkl_engine_priv(engine, curr_state).group + 1) % n; + return ( _xklCurState.group + 1 ) % XklGetNumGroups( ); } - -gint -xkl_engine_get_prev_group(XklEngine * engine) + +int XklGetPrevGroup( void ) { - gint n = xkl_engine_get_num_groups(engine); - return (xkl_engine_priv(engine, curr_state).group + n - 1) % n; + int n = XklGetNumGroups( ); + return ( _xklCurState.group + n - 1 ) % n; } -gint -xkl_engine_get_current_window_group(XklEngine * engine) +int XklGetRestoreGroup( void ) { - XklState state; - if (xkl_engine_priv(engine, curr_toplvl_win) == (Window) NULL) { - xkl_debug(150, "cannot restore without current client\n"); - } else - if (xkl_engine_get_toplevel_window_state - (engine, xkl_engine_priv(engine, curr_toplvl_win), - &state)) { - return state.group; - } else - xkl_debug(150, - "Unbelievable: current client " WINID_FORMAT - ", '%s' has no group\n", - xkl_engine_priv(engine, curr_toplvl_win), - xkl_get_debug_window_title(engine, - xkl_engine_priv - (engine, - curr_toplvl_win))); - return 0; + XklState state; + if( _xklCurClient == ( Window ) NULL ) + { + XklDebug( 150, "cannot restore without current client\n" ); + } else if( XklGetState( _xklCurClient, &state ) ) + { + return state.group; + } else + XklDebug( 150, + "Unbelievable: current client " WINID_FORMAT + ", '%s' has no group\n", _xklCurClient, + _XklGetDebugWindowTitle( _xklCurClient ) ); + return 0; } -void -xkl_engine_set_transparent(XklEngine * engine, Window win, - gboolean transparent) +void XklSetTransparent( Window win, Bool transparent ) { - Window toplevel_win; - xkl_debug(150, - "setting transparent flag %d for " WINID_FORMAT "\n", - transparent, win); + Window appWin; + Bool wasTransparent; + XklDebug( 150, "setting transparent flag %d for " WINID_FORMAT "\n", + transparent, win ); - if (!xkl_engine_find_toplevel_window(engine, win, &toplevel_win)) { - xkl_debug(150, "No toplevel window!\n"); - /* toplevel_win = win; */ - return; - } + if( !_XklGetAppWindow( win, &appWin ) ) + { + XklDebug( 150, "No app window!\n" ); + /* appWin = win; */ + return; + } - xkl_engine_set_toplevel_window_transparent(engine, toplevel_win, - transparent); + wasTransparent = XklIsTransparent( appWin ); + XklDebug( 150, "appwin " WINID_FORMAT " was %stransparent\n", appWin, + wasTransparent ? "" : "not " ); + if( transparent && !wasTransparent ) + { + CARD32 prop = 1; + XChangeProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_TRANSPARENT], + XA_INTEGER, 32, PropModeReplace, + ( const unsigned char * ) &prop, 1 ); + } else if( !transparent && wasTransparent ) + { + XDeleteProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_TRANSPARENT] ); + } } -gboolean -xkl_engine_is_window_transparent(XklEngine * engine, Window win) +Bool XklIsTransparent( Window win ) { - Window toplevel_win; + Window appWin; - if (!xkl_engine_find_toplevel_window(engine, win, &toplevel_win)) - return FALSE; - return xkl_engine_is_toplevel_window_transparent(engine, - toplevel_win); -} + if( !_XklGetAppWindow( win, &appWin ) ) + return False; + return _XklIsTransparentAppWindow( appWin ); -/** - * Loads the tree recursively. - */ -gboolean -xkl_engine_load_window_tree(XklEngine * engine) -{ - Window focused; - int revert; - gboolean retval = TRUE, have_toplevel_win; - - if (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES) - retval = - xkl_engine_load_subtree(engine, - xkl_engine_priv(engine, - root_window), - 0, &xkl_engine_priv(engine, - curr_state)); - - XGetInputFocus(xkl_engine_get_display(engine), &focused, &revert); - - xkl_debug(160, "initially focused: " WINID_FORMAT ", '%s'\n", - focused, xkl_get_debug_window_title(engine, focused)); - - have_toplevel_win = - xkl_engine_find_toplevel_window(engine, focused, - &xkl_engine_priv(engine, - curr_toplvl_win)); - - if (have_toplevel_win) { - gboolean have_state = - xkl_engine_get_toplevel_window_state(engine, - xkl_engine_priv - (engine, - curr_toplvl_win), - &xkl_engine_priv - (engine, - curr_state)); - xkl_debug(160, - "initial toplevel: " WINID_FORMAT - ", '%s' %s state %d/%X\n", - xkl_engine_priv(engine, curr_toplvl_win), - xkl_get_debug_window_title(engine, - xkl_engine_priv - (engine, - curr_toplvl_win)), - (have_state ? "with" : "without"), - (have_state ? - xkl_engine_priv(engine, curr_state).group : -1), - (have_state ? - xkl_engine_priv(engine, - curr_state).indicators : -1)); - } else { - xkl_debug(160, - "Could not find initial app. " - "Probably, focus belongs to some WM service window. " - "Will try to survive:)"); - } - - return retval; -} - -void -_xkl_debug(const gchar file[], const gchar function[], gint level, - const gchar format[], ...) -{ - va_list lst; - - if (level > xkl_debug_level) - return; - - va_start(lst, format); - if (log_appender != NULL) - (*log_appender) (file, function, level, format, lst); - va_end(lst); -} - -void -xkl_default_log_appender(const gchar file[], const gchar function[], - gint level, const gchar format[], va_list args) -{ - time_t now = time(NULL); - fprintf(stdout, "[%08ld,%03d,%s:%s/] \t", now, level, file, - function); - vfprintf(stdout, format, args); } /** - * Just selects some events from the window. + * "Adds" app window to the set of managed windows. + * Actually, no data structures involved. The only thing we do is save app state + * and register ourselves us listeners. + * Note: User's callback is called */ -void -xkl_engine_select_input(XklEngine * engine, Window win, gulong mask) +void _XklAddAppWindow( Window appWin, Window parent, Bool ignoreExistingState, + XklState * initState ) { - if (xkl_engine_priv(engine, root_window) == win) - xkl_debug(160, - "Someone is looking for %lx on root window ***\n", - mask); + XklState state = *initState; + int defGroupToUse = -1; - XSelectInput(xkl_engine_get_display(engine), win, mask); -} + if( appWin == _xklRootWindow ) + XklDebug( 150, "??? root app win ???\n" ); -void -xkl_engine_select_input_merging(XklEngine * engine, Window win, - gulong mask) -{ - XWindowAttributes attrs; - gulong oldmask = 0L, newmask; - memset(&attrs, 0, sizeof(attrs)); - if (XGetWindowAttributes - (xkl_engine_get_display(engine), win, &attrs)) - oldmask = attrs.your_event_mask; + XklDebug( 150, "Trying to add window " WINID_FORMAT "/%s with group %d\n", + appWin, _XklGetDebugWindowTitle( appWin ), initState->group ); + + if( !ignoreExistingState ) + { + Bool have_state = _XklGetAppState( appWin, &state ); + + if( have_state ) + { + XklDebug( 150, + "The window " WINID_FORMAT + " does not require to be added, it already has the xklavier state \n", + appWin ); + return; + } + } + + if( winCallback != NULL ) + defGroupToUse = ( *winCallback ) ( appWin, parent, winCallbackData ); + + if( defGroupToUse == -1 ) + defGroupToUse = _xklDefaultGroup; + + if( defGroupToUse != -1 ) + state.group = defGroupToUse; - newmask = oldmask | mask; - if (newmask != oldmask) - xkl_engine_select_input(engine, win, newmask); + _XklSaveAppState( appWin, &state ); + _XklSelectInputMerging( appWin, FocusChangeMask | PropertyChangeMask ); + + if( defGroupToUse != -1 ) + { + if( _xklCurClient == appWin ) + { + if( ( _xklSecondaryGroupsMask & ( 1 << defGroupToUse ) ) != 0 ) + XklAllowOneSwitchToSecondaryGroup(); + XklLockGroup( defGroupToUse ); + } + } + + if( parent == ( Window ) NULL ) + parent = _XklGetRegisteredParent( appWin ); + + XklDebug( 150, "done\n" ); } -void -xkl_engine_try_call_state_func(XklEngine * engine, - XklEngineStateChange change_type, - XklState * old_state) +/** + * Checks the window and goes up + */ +Bool _XklGetAppWindowBottomToTop( Window win, Window * appWin_return ) { - gint group = xkl_engine_priv(engine, curr_state).group; - gboolean restore = old_state->group == group; + Window parent = ( Window ) NULL, rwin = ( Window ) NULL, *children = NULL; + unsigned int num = 0; + + if( win == ( Window ) NULL || win == _xklRootWindow ) + { + *appWin_return = win; + _xklLastErrorMsg = "The window is either 0 or root"; + return False; + } + + if( _XklHasWmState( win ) ) + { + *appWin_return = win; + return True; + } - xkl_debug(150, - "change_type: %d, group: %d, secondary_group_mask: %X, allowsecondary: %d\n", - change_type, group, xkl_engine_priv(engine, - secondary_groups_mask), - xkl_engine_is_one_switch_to_secondary_group_allowed - (engine)); + _xklLastErrorCode = + _XklStatusQueryTree( _xklDpy, win, &rwin, &parent, &children, &num ); - if (change_type == GROUP_CHANGED) { - if (!restore) { - if ((xkl_engine_priv(engine, secondary_groups_mask) - & (1 << group)) != 0 - && - !xkl_engine_is_one_switch_to_secondary_group_allowed - (engine)) { - xkl_debug(150, "secondary -> go next\n"); - group = xkl_engine_get_next_group(engine); - xkl_engine_lock_group(engine, group); - return; /* we do not need to revalidate */ - } - } - xkl_engine_one_switch_to_secondary_group_performed(engine); - } + if( _xklLastErrorCode != Success ) + { + *appWin_return = ( Window ) NULL; + return False; + } - g_signal_emit_by_name(engine, "X-state-changed", change_type, - xkl_engine_priv(engine, curr_state).group, - restore); + if( children != NULL ) + XFree( children ); + return _XklGetAppWindowBottomToTop( parent, appWin_return ); } -void -xkl_engine_ensure_vtable_inited(XklEngine * engine) -{ - char *p; - if (xkl_engine_priv(engine, backend_id) == NULL) { - xkl_debug(0, "ERROR: XKL VTable is NOT initialized.\n"); - /* force the crash! */ - p = NULL; - *p = '\0'; - } +/** + * Recursively finds "App window" (window with WM_STATE) for given window. + * First, checks the window itself + * Then, for first level of recursion, checks childen, + * Then, goes to parent. + * NOTE: root window cannot be "App window" under normal circumstances + */ +Bool _XklGetAppWindow( Window win, Window * appWin_return ) +{ + Window parent = ( Window ) NULL, + rwin = ( Window ) NULL, *children = NULL, *child; + unsigned int num = 0; + Bool rv; + + if( win == ( Window ) NULL || win == _xklRootWindow ) + { + *appWin_return = ( Window ) NULL; + _xklLastErrorMsg = "The window is either 0 or root"; + XklDebug( 150, + "Window " WINID_FORMAT + " is either 0 or root so could not get the app window for it\n", + win ); + return False; + } + + if( _XklHasWmState( win ) ) + { + *appWin_return = win; + return True; + } + + _xklLastErrorCode = + _XklStatusQueryTree( _xklDpy, win, &rwin, &parent, &children, &num ); + + if( _xklLastErrorCode != Success ) + { + *appWin_return = ( Window ) NULL; + XklDebug( 150, + "Could not get tree for window " WINID_FORMAT + " so could not get the app window for it\n", win ); + return False; + } + + /** + * Here we first check the children (in case win is just above some "App Window") + * and then go upstairs + */ + child = children; + while( num ) + { + if( _XklHasWmState( *child ) ) + { + *appWin_return = *child; + if( children != NULL ) + XFree( children ); + return True; + } + child++; + num--; + } + + if( children != NULL ) + XFree( children ); + + rv = _XklGetAppWindowBottomToTop( parent, appWin_return ); + + if( !rv ) + XklDebug( 200, "Could not get the app window for " WINID_FORMAT "/%s\n", + win, _XklGetDebugWindowTitle( win ) ); + + return rv; } -const gchar * -xkl_engine_get_backend_name(XklEngine * engine) +/** + * Loads the tree recursively. + */ +Bool _XklLoadWindowTree( void ) { - return xkl_engine_priv(engine, backend_id); + Window focused; + int revert; + Bool retval = True, haveAppWindow; + + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + retval = _XklLoadSubtree( _xklRootWindow, 0, &_xklCurState ); + + XGetInputFocus( _xklDpy, &focused, &revert ); + + XklDebug( 160, "initially focused: " WINID_FORMAT ", '%s'\n", + focused, _XklGetDebugWindowTitle( focused ) ); + + haveAppWindow = _XklGetAppWindow( focused, &_xklCurClient ); + + if( haveAppWindow ) + { + Bool haveState = _XklGetAppState( _xklCurClient, &_xklCurState ); + XklDebug( 160, + "initial _xklCurClient: " WINID_FORMAT + ", '%s' %s state %d/%X\n", _xklCurClient, + _XklGetDebugWindowTitle( _xklCurClient ), + ( haveState ? "with" : "without" ), + ( haveState ? _xklCurState.group : -1 ), + ( haveState ? _xklCurState.indicators : -1 ) ); + } else + { + XklDebug( 160, + "could not find initial app. Probably, focus belongs to some WM service window. Will try to survive:)" ); + } + + return retval; } -guint -xkl_engine_get_features(XklEngine * engine) +void _XklDebug( const char file[], const char function[], int level, + const char format[], ... ) { - return xkl_engine_priv(engine, features); + va_list lst; + + if( level > _xklDebugLevel ) + return; + + va_start( lst, format ); + if( logAppender != NULL ) + ( *logAppender ) ( file, function, level, format, lst ); + va_end( lst ); } -void -xkl_engine_reset_all_info(XklEngine * engine, const gchar reason[]) +void XklDefaultLogAppender( const char file[], const char function[], + int level, const char format[], va_list args ) { - xkl_debug(150, "Resetting all the cached info, reason: [%s]\n", - reason); - xkl_engine_ensure_vtable_inited(engine); - if (!xkl_engine_vcall(engine, if_cached_info_equals_actual) - (engine)) { - xkl_engine_vcall(engine, free_all_info) (engine); - xkl_engine_vcall(engine, load_all_info) (engine); - } else - xkl_debug(100, - "NOT Resetting the cache: same configuration\n"); + time_t now = time( NULL ); + fprintf( stdout, "[%08ld,%03d,%s:%s/] \t", now, level, file, function ); + vfprintf( stdout, format, args ); } /** - * Calling through vtable + * Gets the state from the window property */ -const gchar ** -xkl_engine_groups_get_names(XklEngine * engine) +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 = 0; + + if( ( XGetWindowProperty + ( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE], 0L, + XKLAVIER_STATE_PROP_LENGTH, False, + XA_INTEGER, &type_ret, &format_ret, &nitems, &rest, + ( unsigned char ** ) ( void * ) &prop ) == Success ) + && ( type_ret == XA_INTEGER ) && ( format_ret == 32 ) ) + { + grp = prop[0]; + if( grp >= XklGetNumGroups( ) || 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 + */ +void _XklDelAppState( Window appWin ) { - xkl_engine_ensure_vtable_inited(engine); - return xkl_engine_vcall(engine, get_groups_names) (engine); + XDeleteProperty( _xklDpy, appWin, _xklAtoms[XKLAVIER_STATE] ); } -guint -xkl_engine_get_num_groups(XklEngine * engine) +/** + * Saves the state into the window properties + */ +void _XklSaveAppState( Window appWin, XklState * state ) { - xkl_engine_ensure_vtable_inited(engine); - return xkl_engine_vcall(engine, get_num_groups) (engine); + 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, + XKLAVIER_STATE_PROP_LENGTH ); + + XklDebug( 160, + "Saved the group %d, indicators %X for appwin " WINID_FORMAT "\n", + state->group, state->indicators, appWin ); } -void -xkl_engine_lock_group(XklEngine * engine, int group) +/** + * Just selects some events from the window. + */ +void _XklSelectInput( Window win, long mask ) { - xkl_engine_ensure_vtable_inited(engine); - xkl_engine_vcall(engine, lock_group) (engine, group); + if( _xklRootWindow == win ) + XklDebug( 160, + "Someone is looking for %lx on root window ***\n", + mask ); + + XSelectInput( _xklDpy, win, mask ); } -gint -xkl_engine_pause_listen(XklEngine * engine) +void _XklSelectInputMerging( Window win, long mask ) { - xkl_engine_ensure_vtable_inited(engine); - return xkl_engine_vcall(engine, pause_listen) (engine); + XWindowAttributes attrs; + long oldmask = 0L, newmask; + memset( &attrs, 0, sizeof( attrs ) ); + if( XGetWindowAttributes( _xklDpy, win, &attrs ) ) + oldmask = attrs.your_event_mask; + + newmask = oldmask | mask; + if( newmask != oldmask ) + _XklSelectInput( win, newmask ); } -gint -xkl_engine_resume_listen(XklEngine * engine) +void _XklTryCallStateCallback( XklStateChange changeType, + XklState * oldState ) { - xkl_engine_ensure_vtable_inited(engine); - xkl_debug(150, "listenerType: %x\n", - xkl_engine_priv(engine, listener_type)); - if (xkl_engine_vcall(engine, resume_listen) (engine)) - return 1; + int group = _xklCurState.group; + Bool restore = oldState->group == group; + + XklDebug( 150, + "changeType: %d, group: %d, secondaryGroupMask: %X, allowsecondary: %d\n", + changeType, group, _xklSecondaryGroupsMask, + _XklIsOneSwitchToSecondaryGroupAllowed() ); - xkl_engine_select_input_merging(engine, - xkl_engine_priv(engine, - root_window), - SubstructureNotifyMask | - PropertyChangeMask); + if( changeType == GROUP_CHANGED ) + { + if( !restore ) + { + if( ( _xklSecondaryGroupsMask & ( 1 << group ) ) != 0 && + !_XklIsOneSwitchToSecondaryGroupAllowed() ) + { + XklDebug( 150, "secondary -> go next\n" ); + group = XklGetNextGroup( ); + XklLockGroup( group ); + return; /* we do not need to revalidate */ + } + } + _XklOneSwitchToSecondaryGroupPerformed(); + } + if( stateCallback != NULL ) + { - xkl_engine_vcall(engine, - get_server_state) (engine, - &xkl_engine_priv(engine, - curr_state)); - return 0; + ( *stateCallback ) ( changeType, _xklCurState.group, + restore, stateCallbackData ); + } } -guint -xkl_engine_get_max_num_groups(XklEngine * engine) +Bool _XklIsTransparentAppWindow( Window appWin ) { - xkl_engine_ensure_vtable_inited(engine); - return xkl_engine_vcall(engine, get_max_num_groups) (engine); + Atom type_ret; + int format_ret; + unsigned long nitems, rest; + CARD32 *prop = NULL; + if( ( XGetWindowProperty + ( _xklDpy, appWin, _xklAtoms[XKLAVIER_TRANSPARENT], 0L, 1, False, + XA_INTEGER, &type_ret, &format_ret, &nitems, &rest, + ( unsigned char ** ) ( void * ) &prop ) == Success ) + && ( type_ret == XA_INTEGER ) && ( format_ret == 32 ) ) + { + if( prop != NULL ) + XFree( prop ); + return True; + } + return False; } -XklEngine * -xkl_get_the_engine() +void _XklEnsureVTableInited( void ) { - return the_engine; + char *p; + if ( xklVTable == NULL ) + { + XklDebug( 0, "ERROR: XKL VTable is NOT initialized.\n" ); + /* force the crash! */ + p = NULL; *p = '\0'; + } } -G_DEFINE_TYPE(XklEngine, xkl_engine, G_TYPE_OBJECT) - -static GObject * -xkl_engine_constructor(GType type, - guint n_construct_properties, - GObjectConstructParam * construct_properties) +const char *XklGetBackendName( void ) { - GObject *obj; - - { - /* Invoke parent constructor. */ - XklEngineClass *klass; - klass = - XKL_ENGINE_CLASS(g_type_class_peek(XKL_TYPE_ENGINE)); - obj = - parent_class->constructor(type, n_construct_properties, - construct_properties); - } + return xklVTable->id; +} - XklEngine *engine = XKL_ENGINE(obj); +int XklGetBackendFeatures( void ) +{ + return xklVTable->features; +} - Display *display = - (Display *) g_value_peek_pointer(construct_properties[0]. - value); +void _XklResetAllInfo( const char reason[] ) +{ + XklDebug( 150, "Resetting all the cached info, reason: [%s]\n", reason ); + _XklEnsureVTableInited(); + if( !(*xklVTable->xklIfCachedInfoEqualsActualHandler)() ) + { + (*xklVTable->xklFreeAllInfoHandler)(); + (*xklVTable->xklLoadAllInfoHandler)(); + } else + XklDebug( 100, "NOT Resetting the cache: same configuration\n" ); +} - xkl_engine_priv(engine, display) = display; +/** + * Calling through vtable + */ +const char **XklGetGroupNames( void ) +{ + _XklEnsureVTableInited(); + return (*xklVTable->xklGetGroupNamesHandler)(); +} - int scr; +unsigned XklGetNumGroups( void ) +{ + _XklEnsureVTableInited(); + return (*xklVTable->xklGetNumGroupsHandler)(); +} - xkl_engine_priv(engine, default_error_handler) = - XSetErrorHandler((XErrorHandler) xkl_process_error); +void XklLockGroup( int group ) +{ + _XklEnsureVTableInited(); + (*xklVTable->xklLockGroupHandler)( group ); +} - scr = DefaultScreen(display); - xkl_engine_priv(engine, root_window) = RootWindow(display, scr); +int XklPauseListen( void ) +{ + _XklEnsureVTableInited(); + return (*xklVTable->xklPauseListenHandler)(); +} - xkl_engine_priv(engine, skip_one_restore) = FALSE; - xkl_engine_priv(engine, default_group) = -1; - xkl_engine_priv(engine, secondary_groups_mask) = 0L; - xkl_engine_priv(engine, prev_toplvl_win) = 0; +int XklResumeListen( void ) +{ + _XklEnsureVTableInited(); + XklDebug( 150, "listenerType: %x\n", _xklListenerType ); + if( (*xklVTable->xklResumeListenHandler)() ) + return 1; + + _XklSelectInputMerging( _xklRootWindow, + SubstructureNotifyMask | PropertyChangeMask ); + _XklEnsureVTableInited(); + (*xklVTable->xklGetRealStateHandler)( &_xklCurState ); + return 0; +} - xkl_engine_priv(engine, atoms)[WM_NAME] = - XInternAtom(display, "WM_NAME", False); - xkl_engine_priv(engine, atoms)[WM_STATE] = - XInternAtom(display, "WM_STATE", False); - xkl_engine_priv(engine, atoms)[XKLAVIER_STATE] = - XInternAtom(display, "XKLAVIER_STATE", False); - xkl_engine_priv(engine, atoms)[XKLAVIER_TRANSPARENT] = - XInternAtom(display, "XKLAVIER_TRANSPARENT", False); - xkl_engine_priv(engine, atoms)[XKLAVIER_ALLOW_SECONDARY] = - XInternAtom(display, "XKLAVIER_ALLOW_SECONDARY", False); +Bool _XklLoadAllInfo( void ) +{ + _XklEnsureVTableInited(); + return (*xklVTable->xklLoadAllInfoHandler)(); +} - xkl_engine_one_switch_to_secondary_group_performed(engine); +void _XklFreeAllInfo( void ) +{ + _XklEnsureVTableInited(); + (*xklVTable->xklFreeAllInfoHandler)(); +} - gint rv = -1; - xkl_debug(150, "Trying all backends:\n"); -#ifdef ENABLE_XKB_SUPPORT - xkl_debug(150, "Trying XKB backend\n"); - rv = xkl_xkb_init(engine); -#endif -#ifdef ENABLE_XMM_SUPPORT - if (rv != 0) { - xkl_debug(150, "Trying XMM backend\n"); - rv = xkl_xmm_init(engine); - } -#endif - if (rv == 0) { - xkl_debug(150, "Actual backend: %s\n", - xkl_engine_get_backend_name(engine)); - } else { - xkl_debug(0, "All backends failed, last result: %d\n", rv); - xkl_engine_priv(engine, display) = NULL; - g_object_unref(G_OBJECT(engine)); - return NULL; - } - - xkl_engine_ensure_vtable_inited(engine); - if (!xkl_engine_vcall(engine, load_all_info) (engine)) { - g_object_unref(G_OBJECT(engine)); - return NULL; - } - - return obj; -} - -static void -xkl_engine_init(XklEngine * engine) -{ - engine->priv = g_new0(XklEnginePrivate, 1); -} - -static void -xkl_engine_set_property(GObject * object, - guint property_id, - const GValue * value, GParamSpec * pspec) -{ -} - -static void -xkl_engine_get_property(GObject * object, - guint property_id, - GValue * value, GParamSpec * pspec) -{ - XklEngine *engine = XKL_ENGINE(object); - - switch (property_id) { - case PROP_DISPLAY: - g_value_set_pointer(value, xkl_engine_get_display(engine)); - break; - case PROP_BACKEND_NAME: - g_value_set_string(value, - xkl_engine_priv(engine, backend_id)); - break; - case PROP_FEATURES: - g_value_set_flags(value, - xkl_engine_priv(engine, features)); - break; - case PROP_MAX_NUM_GROUPS: - g_value_set_uint(value, - xkl_engine_vcall(engine, - get_max_num_groups) - (engine)); - break; - case PROP_NUM_GROUPS: - g_value_set_uint(value, - xkl_engine_vcall(engine, get_num_groups) - (engine)); - break; - case PROP_DEFAULT_GROUP: - g_value_set_uint(value, - xkl_engine_priv(engine, default_group)); - break; - case PROP_SECONDARY_GROUPS_MASK: - g_value_set_uint(value, - xkl_engine_priv(engine, - secondary_groups_mask)); - break; - case PROP_INDICATORS_HANDLING: - g_value_set_boolean(value, - xkl_engine_priv(engine, - handle_indicators)); - break; - } -} - -static void -xkl_engine_finalize(GObject * obj) -{ - XklEngine *engine = (XklEngine *) obj; - - XSetErrorHandler((XErrorHandler) - xkl_engine_priv(engine, default_error_handler)); - - xkl_engine_ensure_vtable_inited(engine); - xkl_engine_vcall(engine, free_all_info) (engine); - - xkl_engine_vcall(engine, finalize) (engine); - - gpointer backend = xkl_engine_priv(engine, backend); - if (backend != NULL) - g_free(backend); - g_free(engine->priv); - - G_OBJECT_CLASS(parent_class)->finalize(obj); -} - -static void -xkl_engine_class_init(XklEngineClass * klass) -{ - static GFlagsValue feature_flags[] = { - {XKLF_CAN_TOGGLE_INDICATORS, "XKLF_CAN_TOGGLE_INDICATORS", - NULL}, - {XKLF_CAN_OUTPUT_CONFIG_AS_ASCII, - "XKLF_CAN_OUTPUT_CONFIG_AS_ASCII", NULL}, - {XKLF_CAN_OUTPUT_CONFIG_AS_BINARY, - "XKLF_CAN_OUTPUT_CONFIG_AS_BINARY", NULL}, - {XKLF_MULTIPLE_LAYOUTS_SUPPORTED, - "XKLF_MULTIPLE_LAYOUTS_SUPPORTED", NULL}, - {XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT, - "XKLF_REQUIRES_MANUAL_LAYOUT_MANAGEMENT", NULL}, - {0, NULL, NULL} - }; - static GEnumValue state_change_values[] = { - {GROUP_CHANGED, "GROUP_CHANGED", NULL}, - {INDICATORS_CHANGED, "INDICATORS_CHANGED", NULL}, - {0, NULL, NULL} - }; - - GObjectClass *object_class; - - object_class = (GObjectClass *) klass; - parent_class = g_type_class_peek_parent(object_class); - - object_class->constructor = xkl_engine_constructor; - object_class->finalize = xkl_engine_finalize; - object_class->set_property = xkl_engine_set_property; - object_class->get_property = xkl_engine_get_property; - - GParamSpec *display_param_spec = g_param_spec_pointer("display", - "Display", - "X Display pointer", - G_PARAM_CONSTRUCT_ONLY - | - G_PARAM_READWRITE); - - GParamSpec *backend_name_param_spec = - g_param_spec_string("backendName", - "backendName", - "Backend name", - NULL, - G_PARAM_READABLE); - - GType features_type = g_flags_register_static("XklEngineFeatures", - feature_flags); - - GType state_change_type = - g_enum_register_static("XklEngineStateChangeType", - state_change_values); - - GParamSpec *features_param_spec = g_param_spec_flags("features", - "Features", - "Backend features", - features_type, - 0, - G_PARAM_READABLE); - GParamSpec *max_num_groups_param_spec = - g_param_spec_uint("max-num-groups", - "maxNumGroups", - "Max number of groups", - 0, 0x100, 0, - G_PARAM_READABLE); - - GParamSpec *num_groups_param_spec = g_param_spec_uint("num-groups", - "numGroups", - "Current number of groups", - 0, 0x100, 0, - G_PARAM_READABLE); - - GParamSpec *default_group_param_spec = - g_param_spec_uint("default-group", - "defaultGroup", - "Default group", - 0, 0x100, 0, - G_PARAM_READABLE); - - GParamSpec *secondary_groups_mask_param_spec = - g_param_spec_uint("secondary-groups-mask", - "secondaryGroupsMask", - "Secondary groups mask", - 0, 0x100, 0, - G_PARAM_READABLE); - - GParamSpec *indicators_handling_param_spec = - g_param_spec_boolean("indicators-handling", - "indicatorsHandling", - "Whether engine should handle indicators", - FALSE, - G_PARAM_READABLE); - - g_object_class_install_property(object_class, - PROP_DISPLAY, display_param_spec); - g_object_class_install_property(object_class, - PROP_BACKEND_NAME, - backend_name_param_spec); - g_object_class_install_property(object_class, PROP_FEATURES, - features_param_spec); - g_object_class_install_property(object_class, PROP_MAX_NUM_GROUPS, - max_num_groups_param_spec); - g_object_class_install_property(object_class, PROP_NUM_GROUPS, - num_groups_param_spec); - g_object_class_install_property(object_class, PROP_DEFAULT_GROUP, - default_group_param_spec); - g_object_class_install_property(object_class, - PROP_SECONDARY_GROUPS_MASK, - secondary_groups_mask_param_spec); - g_object_class_install_property(object_class, - PROP_INDICATORS_HANDLING, - indicators_handling_param_spec); - - - g_signal_new("X-config-changed", XKL_TYPE_ENGINE, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(XklEngineClass, - config_notify), - NULL, NULL, xkl_engine_VOID__VOID, G_TYPE_NONE, 0); - - g_signal_new("new-toplevel-window", XKL_TYPE_ENGINE, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(XklEngineClass, - new_window_notify), - NULL, NULL, xkl_engine_INT__LONG_LONG, - G_TYPE_INT, 2, G_TYPE_LONG, G_TYPE_LONG); - - g_signal_new("X-state-changed", XKL_TYPE_ENGINE, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(XklEngineClass, - state_notify), - NULL, NULL, - xkl_engine_VOID__FLAGS_INT_BOOLEAN, - G_TYPE_NONE, 3, state_change_type, G_TYPE_INT, - G_TYPE_BOOLEAN); - - /* 2 Windows passed */ - /* static stuff initialized */ - - const gchar *sdl = g_getenv("XKL_DEBUG"); - - if (sdl != NULL) { - xkl_set_debug_level(atoi(sdl)); - } +unsigned XklGetMaxNumGroups( void ) +{ + _XklEnsureVTableInited(); + return (*xklVTable->xklGetMaxNumGroupsHandler)(); } + diff --git a/libxklavier/xklavier_config_xkb.c b/libxklavier/xklavier_config_xkb.c index 39b74e8..9334a4b 100644 --- a/libxklavier/xklavier_config_xkb.c +++ b/libxklavier/xklavier_config_xkb.c @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include @@ -30,504 +30,426 @@ #include #ifdef XKB_HEADERS_PRESENT -static XkbRF_RulesPtr xkl_rules; +static XkbRF_RulesPtr _xklRules; -static XkbRF_RulesPtr -xkl_rules_set_load(XklEngine * engine) +static XkbRF_RulesPtr _XklLoadRulesSet( void ) { - XkbRF_RulesPtr rules_set = NULL; - char file_name[MAXPATHLEN] = ""; - char *rf = - xkl_engine_get_ruleset_name(engine, XKB_DEFAULT_RULESET); - char *locale = NULL; - - if (rf == NULL) { - xkl_last_error_message = - "Could not find the XKB rules set"; - return NULL; - } - - locale = setlocale(LC_ALL, NULL); - - snprintf(file_name, sizeof file_name, XKB_BASE "/rules/%s", rf); - xkl_debug(160, "Loading rules from [%s]\n", file_name); - - rules_set = XkbRF_Load(file_name, locale, True, True); - - if (rules_set == NULL) { - xkl_last_error_message = "Could not load rules"; - return NULL; - } - return rules_set; + XkbRF_RulesPtr rulesSet = NULL; + char fileName[MAXPATHLEN] = ""; + char *rf = _XklGetRulesSetName( XKB_DEFAULT_RULESET ); + char *locale = NULL; + + if( rf == NULL ) + { + _xklLastErrorMsg = "Could not find the XKB rules set"; + return NULL; + } + + locale = setlocale( LC_ALL, NULL ); + + snprintf( fileName, sizeof fileName, XKB_BASE "/rules/%s", rf ); + XklDebug( 160, "Loading rules from [%s]\n", fileName ); + + rulesSet = XkbRF_Load( fileName, locale, True, True ); + + if( rulesSet == NULL ) + { + _xklLastErrorMsg = "Could not load rules"; + return NULL; + } + return rulesSet; } -static void -xkl_rules_set_free(void) +static void _XklFreeRulesSet( void ) { - if (xkl_rules) - XkbRF_Free(xkl_rules, True); - xkl_rules = NULL; + if ( _xklRules ) + XkbRF_Free( _xklRules, True ); + _xklRules = NULL; } #endif -void -xkl_xkb_init_config_registry(XklConfigRegistry * config) +void _XklXkbConfigInit( void ) { #ifdef XKB_HEADERS_PRESENT - XkbInitAtoms(NULL); + XkbInitAtoms( NULL ); #endif } -gboolean -xkl_xkb_load_config_registry(XklConfigRegistry * config) +Bool _XklXkbConfigLoadRegistry( void ) { - struct stat stat_buf; - char file_name[MAXPATHLEN] = ""; - char *rf = - xkl_engine_get_ruleset_name(xkl_config_registry_get_engine - (config), - XKB_DEFAULT_RULESET); + struct stat statBuf; + char fileName[MAXPATHLEN] = ""; + char* rf = _XklGetRulesSetName( XKB_DEFAULT_RULESET ); - if (rf == NULL) - return FALSE; + if ( rf == NULL ) + return False; - snprintf(file_name, sizeof file_name, XKB_BASE "/rules/%s.xml", - rf); + snprintf( fileName, sizeof fileName, XKB_BASE "/rules/%s.xml", rf ); - if (stat(file_name, &stat_buf) != 0) { - g_strlcpy(file_name, XML_CFG_FALLBACK_PATH, - sizeof file_name); - } + if( stat( fileName, &statBuf ) != 0 ) + { + strncpy( fileName, XML_CFG_FALLBACK_PATH, sizeof fileName ); + fileName[ MAXPATHLEN - 1 ] = '\0'; + } - return xkl_config_registry_load_from_file(config, file_name); + return XklConfigLoadRegistryFromFile( fileName ); } #ifdef XKB_HEADERS_PRESENT -gboolean -xkl_xkb_config_native_prepare(XklEngine * engine, - const XklConfigRec * data, - XkbComponentNamesPtr component_names_ptr) +Bool _XklXkbConfigPrepareNative( const XklConfigRecPtr data, XkbComponentNamesPtr componentNamesPtr ) { - XkbRF_VarDefsRec xkl_var_defs; - gboolean got_components; - - memset(&xkl_var_defs, 0, sizeof(xkl_var_defs)); - - xkl_rules = xkl_rules_set_load(engine); - if (!xkl_rules) { - return FALSE; - } - - xkl_var_defs.model = (char *) data->model; - - if (data->layouts != NULL) - xkl_var_defs.layout = xkl_config_rec_merge_layouts(data); - - if (data->variants != NULL) - xkl_var_defs.variant = xkl_config_rec_merge_variants(data); - - if (data->options != NULL) - xkl_var_defs.options = xkl_config_rec_merge_options(data); - - got_components = - XkbRF_GetComponents(xkl_rules, &xkl_var_defs, - component_names_ptr); - - g_free(xkl_var_defs.layout); - g_free(xkl_var_defs.variant); - g_free(xkl_var_defs.options); - - if (!got_components) { - xkl_last_error_message = - "Could not translate rules into components"; - /* Just cleanup the stuff in case of failure */ - xkl_xkb_config_native_cleanup(engine, component_names_ptr); - - return FALSE; - } - - if (xkl_debug_level >= 200) { - xkl_debug(200, "keymap: %s\n", - component_names_ptr->keymap); - xkl_debug(200, "keycodes: %s\n", - component_names_ptr->keycodes); - xkl_debug(200, "compat: %s\n", - component_names_ptr->compat); - xkl_debug(200, "types: %s\n", component_names_ptr->types); - xkl_debug(200, "symbols: %s\n", - component_names_ptr->symbols); - xkl_debug(200, "geometry: %s\n", - component_names_ptr->geometry); - } - return TRUE; + XkbRF_VarDefsRec _xklVarDefs; + Bool gotComponents; + + memset( &_xklVarDefs, 0, sizeof( _xklVarDefs ) ); + + _xklRules = _XklLoadRulesSet(); + if( !_xklRules ) + { + return False; + } + + _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 ); + + gotComponents = XkbRF_GetComponents( _xklRules, &_xklVarDefs, componentNamesPtr ); + + free( _xklVarDefs.layout ); + free( _xklVarDefs.variant ); + free( _xklVarDefs.options ); + + if( !gotComponents ) + { + _xklLastErrorMsg = "Could not translate rules into components"; + /* Just cleanup the stuff in case of failure */ + _XklXkbConfigCleanupNative( componentNamesPtr ); + + return False; + } + + if ( _xklDebugLevel >= 200 ) + { + XklDebug( 200, "keymap: %s\n", componentNamesPtr->keymap ); + XklDebug( 200, "keycodes: %s\n", componentNamesPtr->keycodes ); + XklDebug( 200, "compat: %s\n", componentNamesPtr->compat ); + XklDebug( 200, "types: %s\n", componentNamesPtr->types ); + XklDebug( 200, "symbols: %s\n", componentNamesPtr->symbols ); + XklDebug( 200, "geometry: %s\n", componentNamesPtr->geometry ); + } + return True; } -void -xkl_xkb_config_native_cleanup(XklEngine * engine, - XkbComponentNamesPtr component_names_ptr) +void _XklXkbConfigCleanupNative( XkbComponentNamesPtr componentNamesPtr ) { - xkl_rules_set_free(); - - g_free(component_names_ptr->keymap); - g_free(component_names_ptr->keycodes); - g_free(component_names_ptr->compat); - g_free(component_names_ptr->types); - g_free(component_names_ptr->symbols); - g_free(component_names_ptr->geometry); + _XklFreeRulesSet(); + + free(componentNamesPtr->keymap); + free(componentNamesPtr->keycodes); + free(componentNamesPtr->compat); + free(componentNamesPtr->types); + free(componentNamesPtr->symbols); + free(componentNamesPtr->geometry); } -static XkbDescPtr -xkl_config_get_keyboard(XklEngine * engine, - XkbComponentNamesPtr component_names_ptr, - gboolean activate) +static XkbDescPtr _XklConfigGetKeyboard( XkbComponentNamesPtr componentNamesPtr, Bool activate ) { - XkbDescPtr xkb = NULL; + XkbDescPtr xkb = NULL; #if 0 - xkb = XkbGetKeyboardByName(_xklDpy, - XkbUseCoreKbd, - &componentNames, - XkbGBN_AllComponentsMask & - (~XkbGBN_GeometryMask), - XkbGBN_AllComponentsMask & - (~XkbGBN_GeometryMask), activate); + xkb = XkbGetKeyboardByName( _xklDpy, + XkbUseCoreKbd, + &componentNames, + XkbGBN_AllComponentsMask & + ( ~XkbGBN_GeometryMask ), + XkbGBN_AllComponentsMask & + ( ~XkbGBN_GeometryMask ), + activate ); #else - char xkm_fn[L_tmpnam]; - char xkb_fn[L_tmpnam]; - FILE *tmpxkm; - XkbFileInfo result; - int xkmloadres; - - Display *display = xkl_engine_get_display(engine); - - if (tmpnam(xkm_fn) != NULL && tmpnam(xkb_fn) != NULL) { - pid_t cpid, pid; - int status = 0; - FILE *tmpxkb; - - xkl_debug(150, "tmp XKB/XKM file names: [%s]/[%s]\n", - xkb_fn, xkm_fn); - if ((tmpxkb = fopen(xkb_fn, "w")) != NULL) { - fprintf(tmpxkb, "xkb_keymap {\n"); - fprintf(tmpxkb, - " xkb_keycodes { include \"%s\" };\n", - component_names_ptr->keycodes); - fprintf(tmpxkb, - " xkb_types { include \"%s\" };\n", - component_names_ptr->types); - fprintf(tmpxkb, - " xkb_compat { include \"%s\" };\n", - component_names_ptr->compat); - fprintf(tmpxkb, - " xkb_symbols { include \"%s\" };\n", - component_names_ptr->symbols); - fprintf(tmpxkb, - " xkb_geometry { include \"%s\" };\n", - component_names_ptr->geometry); - fprintf(tmpxkb, "};\n"); - fclose(tmpxkb); - - xkl_debug(150, "xkb_keymap {\n" - " xkb_keycodes { include \"%s\" };\n" - " xkb_types { include \"%s\" };\n" - " xkb_compat { include \"%s\" };\n" - " xkb_symbols { include \"%s\" };\n" - " xkb_geometry { include \"%s\" };\n};\n", - component_names_ptr->keycodes, - component_names_ptr->types, - component_names_ptr->compat, - component_names_ptr->symbols, - component_names_ptr->geometry); - - cpid = fork(); - switch (cpid) { - case -1: - xkl_debug(0, "Could not fork: %d\n", - errno); - break; - case 0: - /* child */ - xkl_debug(160, "Executing %s\n", XKBCOMP); - xkl_debug(160, "%s %s %s %s %s %s %s\n", - XKBCOMP, XKBCOMP, "-I", - "-I" XKB_BASE, "-xkm", xkb_fn, - xkm_fn); - execl(XKBCOMP, XKBCOMP, "-I", - "-I" XKB_BASE, "-xkm", xkb_fn, - xkm_fn, NULL); - xkl_debug(0, "Could not exec %s: %d\n", - XKBCOMP, errno); - exit(1); - default: - /* parent */ - pid = waitpid(cpid, &status, 0); - xkl_debug(150, - "Return status of %d (well, started %d): %d\n", - pid, cpid, status); - memset((char *) &result, 0, - sizeof(result)); - result.xkb = XkbAllocKeyboard(); - - if (Success == - XkbChangeKbdDisplay(display, - &result)) { - xkl_debug(150, - "Hacked the kbddesc - set the display...\n"); - if ((tmpxkm = - fopen(xkm_fn, "r")) != NULL) { - xkmloadres = - XkmReadFile(tmpxkm, - XkmKeymapLegal, - XkmKeymapLegal, - &result); - xkl_debug(150, - "Loaded %s output as XKM file, got %d (comparing to %d)\n", - XKBCOMP, - (int) xkmloadres, - (int) - XkmKeymapLegal); - if ((int) xkmloadres != - (int) XkmKeymapLegal) { - xkl_debug(150, - "Loaded legal keymap\n"); - if (activate) { - xkl_debug - (150, - "Activating it...\n"); - if (XkbWriteToServer(&result)) { - xkl_debug - (150, - "Updating the keyboard...\n"); - xkb = result.xkb; - } else { - xkl_debug - (0, - "Could not write keyboard description to the server\n"); - } - } else /* no activate, just load */ - xkb = - result. - xkb; - } else { /* could not load properly */ - - xkl_debug(0, - "Could not load %s output as XKM file, got %d (asked %d)\n", - XKBCOMP, - (int) - xkmloadres, - (int) - XkmKeymapLegal); - } - fclose(tmpxkm); - xkl_debug(160, - "Unlinking the temporary xkm file %s\n", - xkm_fn); - if (xkl_debug_level < 500) { /* don't remove on high debug levels! */ - if (remove(xkm_fn) - == -1) - xkl_debug - (0, - "Could not unlink the temporary xkm file %s: %d\n", - xkm_fn, - errno); - } else - xkl_debug(500, - "Well, not really - the debug level is too high: %d\n", - xkl_debug_level); - } else { /* could not open the file */ - - xkl_debug(0, - "Could not open the temporary xkm file %s\n", - xkm_fn); - } - } else { /* could not assign to display */ - - xkl_debug(0, - "Could not change the keyboard description to display\n"); - } - if (xkb == NULL) - XkbFreeKeyboard(result.xkb, - XkbAllComponentsMask, - True); - break; - } - xkl_debug(160, - "Unlinking the temporary xkb file %s\n", - xkb_fn); - if (xkl_debug_level < 500) { /* don't remove on high debug levels! */ - if (remove(xkb_fn) == -1) - xkl_debug(0, - "Could not unlink the temporary xkb file %s: %d\n", - xkb_fn, errno); - } else - xkl_debug(500, - "Well, not really - the debug level is too high: %d\n", - xkl_debug_level); - } else { /* could not open input tmp file */ - - xkl_debug(0, - "Could not open tmp XKB file [%s]: %d\n", - xkb_fn, errno); - } - } else { - xkl_debug(0, "Could not get tmp names\n"); - } + char xkmFN[L_tmpnam]; + char xkbFN[L_tmpnam]; + FILE* tmpxkm; + XkbFileInfo result; + int xkmloadres; + + if ( tmpnam( xkmFN ) != NULL && + tmpnam( xkbFN ) != NULL ) + { + pid_t cpid, pid; + int status = 0; + FILE *tmpxkb; + + XklDebug( 150, "tmp XKB/XKM file names: [%s]/[%s]\n", xkbFN, xkmFN ); + if( (tmpxkb = fopen( xkbFN, "w" )) != NULL ) + { + fprintf( tmpxkb, "xkb_keymap {\n" ); + fprintf( tmpxkb, " xkb_keycodes { include \"%s\" };\n", componentNamesPtr->keycodes ); + fprintf( tmpxkb, " xkb_types { include \"%s\" };\n", componentNamesPtr->types ); + fprintf( tmpxkb, " xkb_compat { include \"%s\" };\n", componentNamesPtr->compat ); + fprintf( tmpxkb, " xkb_symbols { include \"%s\" };\n", componentNamesPtr->symbols ); + fprintf( tmpxkb, " xkb_geometry { include \"%s\" };\n", componentNamesPtr->geometry ); + fprintf( tmpxkb, "};\n" ); + fclose( tmpxkb ); + + XklDebug( 150, "xkb_keymap {\n" + " xkb_keycodes { include \"%s\" };\n" + " xkb_types { include \"%s\" };\n" + " xkb_compat { include \"%s\" };\n" + " xkb_symbols { include \"%s\" };\n" + " xkb_geometry { include \"%s\" };\n};\n", + componentNamesPtr->keycodes, + componentNamesPtr->types, + componentNamesPtr->compat, + componentNamesPtr->symbols, + componentNamesPtr->geometry ); + + XSync( _xklDpy, False ); + /* From this point, ALL errors should be intercepted only by libxklavier*/ + _xklCriticalSection = True; + + cpid=fork(); + switch( cpid ) + { + case -1: + XklDebug( 0, "Could not fork: %d\n", errno ); + break; + case 0: + /* child */ + XklDebug( 160, "Executing %s\n", XKBCOMP ); + XklDebug( 160, "%s %s %s %s %s %s %s\n", + XKBCOMP, XKBCOMP, "-I", "-I" XKB_BASE, "-xkm", xkbFN, xkmFN ); + execl( XKBCOMP, XKBCOMP, "-I", "-I" XKB_BASE, "-xkm", xkbFN, xkmFN, NULL ); + XklDebug( 0, "Could not exec %s: %d\n", XKBCOMP, errno ); + exit( 1 ); + default: + /* parent */ + pid = waitpid( cpid, &status, 0 ); + XklDebug( 150, "Return status of child process %d " + "(well, at least it started as %d): %d\n", + pid, cpid, status ); + + memset( (char *)&result, 0, sizeof(result) ); + result.xkb = XkbAllocKeyboard(); + + if( Success == XkbChangeKbdDisplay( _xklDpy, &result ) ) + { + XklDebug( 150, "Hacked the kbddesc - set the display...\n" ); + if( (tmpxkm = fopen( xkmFN, "r" )) != NULL ) + { + xkmloadres = XkmReadFile( tmpxkm, XkmKeymapLegal, XkmKeymapLegal, &result); + XklDebug( 150, "Loaded %s output as XKM file, got %d (comparing to %d)\n", + XKBCOMP, (int)xkmloadres, (int)XkmKeymapLegal ); + if ( (int)xkmloadres != (int)XkmKeymapLegal ) + { + XklDebug( 150, "Loaded legal keymap\n" ); + if( activate ) + { + XklDebug( 150, "Activating it...\n" ); + if( XkbWriteToServer(&result) ) + { + XklDebug( 150, "Updating the keyboard...\n" ); + xkb = result.xkb; + } else + { + XklDebug( 0, "Could not write keyboard description to the server\n" ); + } + } else /* no activate, just load */ + xkb = result.xkb; + } else /* could not load properly */ + { + XklDebug( 0, "Could not load %s output as XKM file, got %d (asked %d)\n", + XKBCOMP, (int)xkmloadres, (int)XkmKeymapLegal ); + } + fclose( tmpxkm ); + XklDebug( 160, "Unlinking the temporary xkm file %s\n", xkmFN ); + if ( _xklDebugLevel < 500 ) /* don't remove on high debug levels! */ + { + if ( remove( xkmFN ) == -1 ) + XklDebug( 0, "Could not unlink the temporary xkm file %s: %d\n", + xkmFN, errno ); + } else + XklDebug( 500, "Well, not really - the debug level is too high: %d\n", _xklDebugLevel ); + } else /* could not open the file */ + { + XklDebug( 0, "Could not open the temporary xkm file %s\n", xkmFN ); + } + } else /* could not assign to display */ + { + XklDebug( 0, "Could not change the keyboard description to display\n" ); + } + if ( xkb == NULL ) + XkbFreeKeyboard( result.xkb, XkbAllComponentsMask, True ); + break; + } + XSync( _xklDpy, False ); + /* Return to normal X error processing */ + _xklCriticalSection = False; + + XklDebug( 160, "Unlinking the temporary xkb file %s\n", xkbFN ); + if ( _xklDebugLevel < 500 ) /* don't remove on high debug levels! */ + { + if ( remove( xkbFN ) == -1 ) + XklDebug( 0, "Could not unlink the temporary xkb file %s: %d\n", + xkbFN, errno ); + } else + XklDebug( 500, "Well, not really - the debug level is too high: %d\n", _xklDebugLevel ); + } else /* could not open input tmp file */ + { + XklDebug( 0, "Could not open tmp XKB file [%s]: %d\n", xkbFN, errno ); + } + } else + { + XklDebug( 0, "Could not get tmp names\n" ); + } #endif - return xkb; + return xkb; } -#else /* no XKB headers */ -gboolean -xkl_xkb_config_native_prepare(const XklConfigRec * data, - gpointer componentNamesPtr) +#else /* no XKB headers */ +Bool _XklXkbConfigPrepareNative( const XklConfigRecPtr data, void * componentNamesPtr ) { - return FALSE; + return False; } -void -_XklXkbConfigCleanupNative(gpointer componentNamesPtr) +void _XklXkbConfigCleanupNative( void * componentNamesPtr ) { } #endif /* check only client side support */ -gboolean -xkl_xkb_multiple_layouts_supported(XklEngine * engine) +Bool _XklXkbConfigMultipleLayoutsSupported( void ) { - enum { NON_SUPPORTED, SUPPORTED, UNCHECKED }; + enum { NON_SUPPORTED, SUPPORTED, UNCHECKED }; - static int support_state = UNCHECKED; + static int supportState = UNCHECKED; - if (support_state == UNCHECKED) { - XklConfigRec data; - char *layouts[] = { "us", "de", NULL }; - char *variants[] = { NULL, NULL, NULL }; + if( supportState == UNCHECKED ) + { + XklConfigRec data; + char *layouts[] = { "us", "de" }; + char *variants[] = { NULL, NULL }; #ifdef XKB_HEADERS_PRESENT - XkbComponentNamesRec component_names; - memset(&component_names, 0, sizeof(component_names)); + XkbComponentNamesRec componentNames; + memset( &componentNames, 0, sizeof( componentNames ) ); #endif - data.model = "pc105"; - data.layouts = layouts; - data.variants = variants; - data.options = NULL; + data.model = "pc105"; + data.numVariants = + data.numLayouts = 2; + data.numOptions = 0; + data.layouts = layouts; + data.variants = variants; + data.options = NULL; - xkl_debug(100, "!!! Checking multiple layouts support\n"); - support_state = NON_SUPPORTED; + XklDebug( 100, "!!! Checking multiple layouts support\n" ); + supportState = NON_SUPPORTED; #ifdef XKB_HEADERS_PRESENT - if (xkl_xkb_config_native_prepare - (engine, &data, &component_names)) { - xkl_debug(100, - "!!! Multiple layouts ARE supported\n"); - support_state = SUPPORTED; - xkl_xkb_config_native_cleanup(engine, - &component_names); - } else { - xkl_debug(100, - "!!! Multiple layouts ARE NOT supported\n"); - } + if( _XklXkbConfigPrepareNative( &data, &componentNames ) ) + { + XklDebug( 100, "!!! Multiple layouts ARE supported\n" ); + supportState = SUPPORTED; + _XklXkbConfigCleanupNative( &componentNames ); + } else + { + XklDebug( 100, "!!! Multiple layouts ARE NOT supported\n" ); + } #endif - } - return support_state == SUPPORTED; + } + return supportState == SUPPORTED; } -gboolean -xkl_xkb_activate_config_rec(XklEngine * engine, const XklConfigRec * data) +Bool _XklXkbConfigActivate( const XklConfigRecPtr data ) { - gboolean rv = FALSE; + 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]); - } + { + 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 #ifdef XKB_HEADERS_PRESENT - XkbComponentNamesRec component_names; - memset(&component_names, 0, sizeof(component_names)); - - if (xkl_xkb_config_native_prepare(engine, data, &component_names)) { - XkbDescPtr xkb; - xkb = - xkl_config_get_keyboard(engine, &component_names, - TRUE); - if (xkb != NULL) { - if (xkl_config_rec_set_to_root_window_property - (data, - xkl_engine_priv(engine, base_config_atom), - xkl_engine_get_ruleset_name(engine, - XKB_DEFAULT_RULESET), - engine)) - /* We do not need to check the result of _XklGetRulesSetName - - because PrepareBeforeKbd did it for us */ - rv = TRUE; - else - xkl_last_error_message = - "Could not set names property"; - XkbFreeKeyboard(xkb, XkbAllComponentsMask, True); - } else { - xkl_last_error_message = - "Could not load keyboard description"; - } - xkl_xkb_config_native_cleanup(engine, &component_names); - } + XkbComponentNamesRec componentNames; + memset( &componentNames, 0, sizeof( componentNames ) ); + + if( _XklXkbConfigPrepareNative( data, &componentNames ) ) + { + XkbDescPtr xkb; + xkb = _XklConfigGetKeyboard( &componentNames, True ); + if( xkb != NULL ) + { + if( XklSetNamesProp + ( xklVTable->baseConfigAtom, _XklGetRulesSetName( XKB_DEFAULT_RULESET ), data ) ) + /* We do not need to check the result of _XklGetRulesSetName - + because PrepareBeforeKbd did it for us */ + rv = True; + else + _xklLastErrorMsg = "Could not set names property"; + XkbFreeKeyboard( xkb, XkbAllComponentsMask, True ); + } else + { + _xklLastErrorMsg = "Could not load keyboard description"; + } + _XklXkbConfigCleanupNative( &componentNames ); + } #endif - return rv; + return rv; } -gboolean -xkl_xkb_write_config_rec_to_file(XklEngine * engine, const char *file_name, - const XklConfigRec * data, - const gboolean binary) +Bool _XklXkbConfigWriteFile( const char *fileName, + const XklConfigRecPtr data, + const Bool binary ) { - gboolean rv = FALSE; + Bool rv = False; #ifdef XKB_HEADERS_PRESENT - XkbComponentNamesRec component_names; - FILE *output = fopen(file_name, "w"); - XkbFileInfo dump_info; - - if (output == NULL) { - xkl_last_error_message = "Could not open the XKB file"; - return FALSE; - } - - memset(&component_names, 0, sizeof(component_names)); - - if (xkl_xkb_config_native_prepare(engine, data, &component_names)) { - XkbDescPtr xkb; - xkb = - xkl_config_get_keyboard(engine, &component_names, - FALSE); - if (xkb != NULL) { - dump_info.defined = 0; - dump_info.xkb = xkb; - dump_info.type = XkmKeymapFile; - if (binary) - rv = XkbWriteXKMFile(output, &dump_info); - else - rv = XkbWriteXKBFile(output, &dump_info, - True, NULL, NULL); - - XkbFreeKeyboard(xkb, XkbGBN_AllComponentsMask, - True); - } else - xkl_last_error_message = - "Could not load keyboard description"; - xkl_xkb_config_native_cleanup(engine, &component_names); - } - fclose(output); + XkbComponentNamesRec componentNames; + FILE *output = fopen( fileName, "w" ); + XkbFileInfo dumpInfo; + + if( output == NULL ) + { + _xklLastErrorMsg = "Could not open the XKB file"; + return False; + } + + memset( &componentNames, 0, sizeof( componentNames ) ); + + if( _XklXkbConfigPrepareNative( data, &componentNames ) ) + { + XkbDescPtr xkb; + xkb = _XklConfigGetKeyboard( &componentNames, False ); + if( xkb != NULL ) + { + dumpInfo.defined = 0; + dumpInfo.xkb = xkb; + dumpInfo.type = XkmKeymapFile; + if( binary ) + rv = XkbWriteXKMFile( output, &dumpInfo ); + else + rv = XkbWriteXKBFile( output, &dumpInfo, True, NULL, NULL ); + + XkbFreeKeyboard( xkb, XkbGBN_AllComponentsMask, True ); + } else + _xklLastErrorMsg = "Could not load keyboard description"; + _XklXkbConfigCleanupNative( &componentNames ); + } + fclose( output ); #endif - return rv; + return rv; } diff --git a/libxklavier/xklavier_evt.c b/libxklavier/xklavier_evt.c index 40dd41a..785ac72 100644 --- a/libxklavier/xklavier_evt.c +++ b/libxklavier/xklavier_evt.c @@ -1,433 +1,327 @@ -#include #include #include #include #include +#include #include "xklavier_private.h" -gint -xkl_engine_filter_events(XklEngine * engine, XEvent * xev) +int XklFilterEvents( XEvent * xev ) { - XAnyEvent *pe = (XAnyEvent *) xev; - xkl_debug(400, - "**> Filtering event %d of type %d from window %d\n", - pe->serial, pe->type, pe->window); - xkl_engine_ensure_vtable_inited(engine); - if (!xkl_engine_vcall(engine, process_x_event) (engine, xev)) - switch (xev->type) { /* core events */ - case FocusIn: - xkl_engine_process_focus_in_evt(engine, - &xev->xfocus); - break; - case FocusOut: - xkl_engine_process_focus_out_evt(engine, - &xev->xfocus); - break; - case PropertyNotify: - xkl_engine_process_property_evt(engine, - &xev->xproperty); - break; - case CreateNotify: - xkl_engine_process_create_window_evt(engine, - &xev-> - xcreatewindow); - break; - case DestroyNotify: - xkl_debug(150, - "Window " WINID_FORMAT " destroyed\n", - xev->xdestroywindow.window); - break; - case UnmapNotify: - xkl_debug(200, - "Window " WINID_FORMAT " unmapped\n", - xev->xunmap.window); - break; - case MapNotify: - case GravityNotify: - xkl_debug(200, "%s\n", - xkl_event_get_name(xev->type)); - break; /* Ignore these events */ - case ReparentNotify: - xkl_debug(200, - "Window " WINID_FORMAT " reparented to " - WINID_FORMAT "\n", xev->xreparent.window, - xev->xreparent.parent); - break; /* Ignore these events */ - case MappingNotify: - xkl_debug(200, "%s\n", - xkl_event_get_name(xev->type)); - xkl_engine_reset_all_info(engine, - "X event: MappingNotify"); - break; - default: - { - xkl_debug(200, "Unknown event %d [%s]\n", - xev->type, - xkl_event_get_name(xev->type)); - return 1; - } - } - xkl_debug(400, "Filtered event %d of type %d from window %d **>\n", - pe->serial, pe->type, pe->window); - return 1; + XAnyEvent *pe = ( XAnyEvent * ) xev; + XklDebug( 400, "**> Filtering event %d of type %d from window %d\n", + pe->serial, pe->type, pe->window ); + _XklEnsureVTableInited(); + if ( !xklVTable->xklEventHandler( xev ) ) + switch ( xev->type ) + { /* core events */ + case FocusIn: + _XklFocusInEvHandler( &xev->xfocus ); + break; + case FocusOut: + _XklFocusOutEvHandler( &xev->xfocus ); + break; + case PropertyNotify: + _XklPropertyEvHandler( &xev->xproperty ); + break; + case CreateNotify: + _XklCreateEvHandler( &xev->xcreatewindow ); + break; + case DestroyNotify: + XklDebug( 150, "Window " WINID_FORMAT " destroyed\n", + xev->xdestroywindow.window ); + break; + case UnmapNotify: + XklDebug( 200, "Window " WINID_FORMAT " unmapped\n", + xev->xunmap.window ); + break; + case MapNotify: + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); + break; + case MappingNotify: + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); + _XklResetAllInfo( "X event: MappingNotify" ); + break; + case GravityNotify: + XklDebug( 200, "%s\n", _XklGetEventName( xev->type ) ); + break; + case ReparentNotify: + XklDebug( 200, "Window " WINID_FORMAT " reparented to " WINID_FORMAT "\n", + xev->xreparent.window, xev->xreparent.parent ); + break; + default: + { + XklDebug( 200, "Unknown event %d [%s]\n", + xev->type, _XklGetEventName( xev->type ) ); + return 1; + } + } + XklDebug( 400, "Filtered event %d of type %d from window %d **>\n", + pe->serial, pe->type, pe->window ); + return 1; } -/* +/** * FocusIn handler */ -void -xkl_engine_process_focus_in_evt(XklEngine * engine, - XFocusChangeEvent * fev) +void _XklFocusInEvHandler( XFocusChangeEvent * fev ) { - Window win; - Window toplevel_win; - XklState selected_window_state; - - if (! - (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES)) - return; - - win = fev->window; - - switch (fev->mode) { - case NotifyNormal: - case NotifyWhileGrabbed: - break; - default: - xkl_debug(160, - "Window " WINID_FORMAT - " has got focus during special action %d\n", win, - fev->mode); - return; - } - - xkl_debug(150, "Window " WINID_FORMAT ", '%s' has got focus\n", - win, xkl_get_debug_window_title(engine, win)); - - if (!xkl_engine_find_toplevel_window(engine, win, &toplevel_win)) { - return; - } - - xkl_debug(150, "Appwin " WINID_FORMAT ", '%s' has got focus\n", - toplevel_win, xkl_get_debug_window_title(engine, - toplevel_win)); - - if (xkl_engine_get_toplevel_window_state - (engine, toplevel_win, &selected_window_state)) { - if (xkl_engine_priv(engine, curr_toplvl_win) != - toplevel_win) { - gboolean old_win_transparent, new_win_transparent; - XklState tmp_state; - - old_win_transparent = - xkl_engine_is_toplevel_window_transparent - (engine, - xkl_engine_priv(engine, curr_toplvl_win)); - if (old_win_transparent) - xkl_debug(150, - "Leaving transparent window\n"); - - /* - * Reload the current state from the current window. - * Do not do it for transparent window - we keep the state from - * the _previous_ window. - */ - if (!old_win_transparent && - xkl_engine_get_toplevel_window_state(engine, - xkl_engine_priv - (engine, - curr_toplvl_win), - &tmp_state)) - { - xkl_engine_update_current_state(engine, - tmp_state. - group, - tmp_state. - indicators, - "Loading current (previous) state from the current (previous) window"); - } - - xkl_engine_priv(engine, curr_toplvl_win) = - toplevel_win; - xkl_debug(150, - "CurClient:changed to " WINID_FORMAT - ", '%s'\n", xkl_engine_priv(engine, - curr_toplvl_win), - xkl_get_debug_window_title(engine, - xkl_engine_priv - (engine, - curr_toplvl_win))); - - new_win_transparent = - xkl_engine_is_toplevel_window_transparent - (engine, toplevel_win); - if (new_win_transparent) - xkl_debug(150, - "Entering transparent window\n"); - - if (xkl_engine_is_group_per_toplevel_window(engine) - == !new_win_transparent) { - /* We skip restoration only if we return to the same app window */ - gboolean do_skip = FALSE; - if (xkl_engine_priv - (engine, skip_one_restore)) { - xkl_engine_priv(engine, - skip_one_restore) = - FALSE; - if (toplevel_win == - xkl_engine_priv(engine, - prev_toplvl_win)) - do_skip = TRUE; - } - - if (do_skip) { - xkl_debug(150, - "Skipping one restore as requested - instead, " - "saving the current group into the window state\n"); - xkl_engine_save_toplevel_window_state - (engine, toplevel_win, - &xkl_engine_priv(engine, - curr_state)); - } else { - if (xkl_engine_priv - (engine, - curr_state).group != - selected_window_state.group) { - xkl_debug(150, - "Restoring the group from %d to %d after gaining focus\n", - xkl_engine_priv - (engine, - curr_state). - group, - selected_window_state. - group); - /* - * For fast mouse movements - the state is probably not updated yet - * (because of the group change notification being late). - * so we'll enforce the update. But this should only happen in GPA mode - */ - xkl_engine_update_current_state - (engine, - selected_window_state. - group, - selected_window_state. - indicators, - "Enforcing fast update of the current state"); - xkl_engine_lock_group - (engine, - selected_window_state. - group); - } else { - xkl_debug(150, - "Both old and new focused window " - "have group %d so no point restoring it\n", - selected_window_state. - group); - xkl_engine_one_switch_to_secondary_group_performed - (engine); - } - } - - if ((xkl_engine_priv(engine, features) & - XKLF_CAN_TOGGLE_INDICATORS) - && - xkl_engine_get_indicators_handling - (engine)) { - xkl_debug(150, - "Restoring the indicators from %X to %X after gaining focus\n", - xkl_engine_priv(engine, - curr_state). - indicators, - selected_window_state. - indicators); - xkl_engine_ensure_vtable_inited - (engine); - xkl_engine_vcall(engine, - set_indicators) - (engine, - &selected_window_state); - } else - xkl_debug(150, - "Not restoring the indicators %X after gaining focus: indicator handling is not enabled\n", - xkl_engine_priv(engine, - curr_state). - indicators); - } else - xkl_debug(150, - "Not restoring the group %d after gaining focus: global layout (xor transparent window)\n", - xkl_engine_priv(engine, - curr_state). - group); - } else - xkl_debug(150, - "Same app window - just do nothing\n"); - } else { - xkl_debug(150, "But it does not have xklavier_state\n"); - if (xkl_engine_if_window_has_wm_state(engine, win)) { - xkl_debug(150, - "But it does have wm_state so we'll add it\n"); - xkl_engine_priv(engine, curr_toplvl_win) = - toplevel_win; - xkl_debug(150, - "CurClient:changed to " WINID_FORMAT - ", '%s'\n", xkl_engine_priv(engine, - curr_toplvl_win), - xkl_get_debug_window_title(engine, - xkl_engine_priv - (engine, - curr_toplvl_win))); - xkl_engine_add_toplevel_window(engine, - xkl_engine_priv - (engine, - curr_toplvl_win), - (Window) NULL, - FALSE, - &xkl_engine_priv - (engine, - curr_state)); - } else - xkl_debug(150, - "And it does have wm_state either\n"); - } + Window win; + Window appWin; + XklState selectedWindowState; + + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + + win = fev->window; + + switch ( fev->mode ) + { + case NotifyNormal: + case NotifyWhileGrabbed: + break; + default: + XklDebug( 160, + "Window " WINID_FORMAT + " has got focus during special action %d\n", win, fev->mode ); + return; + } + + XklDebug( 150, "Window " WINID_FORMAT ", '%s' has got focus\n", win, + _XklGetDebugWindowTitle( win ) ); + + if( !_XklGetAppWindow( win, &appWin ) ) + { + return; + } + + XklDebug( 150, "Appwin " WINID_FORMAT ", '%s' has got focus\n", appWin, + _XklGetDebugWindowTitle( appWin ) ); + + if( XklGetState( appWin, &selectedWindowState ) ) + { + if( _xklCurClient != appWin ) + { + Bool oldWinTransparent, newWinTransparent; + XklState tmpState; + + oldWinTransparent = _XklIsTransparentAppWindow( _xklCurClient ); + if( oldWinTransparent ) + XklDebug( 150, "Leaving transparent window\n" ); + + /** + * Reload the current state from the current window. + * Do not do it for transparent window - we keep the state from + * the _previous_ window. + */ + if ( !oldWinTransparent && XklGetState ( _xklCurClient, &tmpState ) ) + { + _XklUpdateCurState( tmpState.group, + tmpState.indicators, + "Loading current (previous) state from the current (previous) window" ); + } + + _xklCurClient = appWin; + XklDebug( 150, "CurClient:changed to " WINID_FORMAT ", '%s'\n", + _xklCurClient, _XklGetDebugWindowTitle( _xklCurClient ) ); + + newWinTransparent = _XklIsTransparentAppWindow( appWin ); + if( newWinTransparent ) + XklDebug( 150, "Entering transparent window\n" ); + + if( XklIsGroupPerApp() == !newWinTransparent ) + { + /* We skip restoration only if we return to the same app window */ + Bool doSkip = False; + if( _xklSkipOneRestore ) + { + _xklSkipOneRestore = False; + if( appWin == _xklPrevAppWindow ) + doSkip = True; + } + + if( doSkip ) + { + XklDebug( 150, + "Skipping one restore as requested - instead, saving the current group into the window state\n" ); + _XklSaveAppState( appWin, &_xklCurState ); + } else + { + if( _xklCurState.group != selectedWindowState.group ) + { + XklDebug( 150, + "Restoring the group from %d to %d after gaining focus\n", + _xklCurState.group, selectedWindowState.group ); + /** + * For fast mouse movements - the state is probably not updated yet + * (because of the group change notification being late). + * so we'll enforce the update. But this should only happen in GPA mode + */ + _XklUpdateCurState( selectedWindowState.group, + selectedWindowState.indicators, + "Enforcing fast update of the current state" ); + XklLockGroup( selectedWindowState.group ); + } else + { + XklDebug( 150, + "Both old and new focused window have group %d so no point restoring it\n", + selectedWindowState.group ); + _XklOneSwitchToSecondaryGroupPerformed(); + } + } + + if( ( xklVTable->features & XKLF_CAN_TOGGLE_INDICATORS ) && + XklGetIndicatorsHandling( ) ) + { + XklDebug( 150, + "Restoring the indicators from %X to %X after gaining focus\n", + _xklCurState.indicators, selectedWindowState.indicators ); + _XklEnsureVTableInited(); + (*xklVTable->xklSetIndicatorsHandler)( &selectedWindowState ); + } else + XklDebug( 150, + "Not restoring the indicators %X after gaining focus: indicator handling is not enabled\n", + _xklCurState.indicators ); + } else + XklDebug( 150, + "Not restoring the group %d after gaining focus: global layout (xor transparent window)\n", + _xklCurState.group ); + } else + XklDebug( 150, "Same app window - just do nothing\n" ); + } else + { + XklDebug( 150, "But it does not have xklavier_state\n" ); + if( _XklHasWmState( win ) ) + { + XklDebug( 150, "But it does have wm_state so we'll add it\n" ); + _xklCurClient = appWin; + XklDebug( 150, "CurClient:changed to " WINID_FORMAT ", '%s'\n", + _xklCurClient, _XklGetDebugWindowTitle( _xklCurClient ) ); + _XklAddAppWindow( _xklCurClient, ( Window ) NULL, False, + &_xklCurState ); + } else + XklDebug( 150, "And it does have wm_state either\n" ); + } } -/* +/** * FocusOut handler */ -void -xkl_engine_process_focus_out_evt(XklEngine * engine, - XFocusChangeEvent * fev) +void _XklFocusOutEvHandler( XFocusChangeEvent * fev ) { - if (! - (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES)) - return; - - if (fev->mode != NotifyNormal) { - xkl_debug(200, - "Window " WINID_FORMAT - " has lost focus during special action %d\n", - fev->window, fev->mode); - return; - } - - xkl_debug(160, "Window " WINID_FORMAT ", '%s' has lost focus\n", - fev->window, xkl_get_debug_window_title(engine, - fev->window)); - - if (xkl_engine_is_window_transparent(engine, fev->window)) { - xkl_debug(150, "Leaving transparent window!\n"); -/* + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + + if( fev->mode != NotifyNormal ) + { + XklDebug( 200, + "Window " WINID_FORMAT + " has lost focus during special action %d\n", fev->window, + fev->mode ); + return; + } + + XklDebug( 160, "Window " WINID_FORMAT ", '%s' has lost focus\n", + fev->window, _XklGetDebugWindowTitle( fev->window ) ); + + if( XklIsTransparent( fev->window ) ) + { + + XklDebug( 150, "Leaving transparent window!\n" ); +/** * If we are leaving the transparent window - we skip the restore operation. * This is useful for secondary groups switching from the transparent control * window. */ - xkl_engine_priv(engine, skip_one_restore) = TRUE; - } else { - Window p; - if (xkl_engine_find_toplevel_window - (engine, fev->window, &p)) - xkl_engine_priv(engine, prev_toplvl_win) = p; - } + _xklSkipOneRestore = True; + } else + { + Window p; + if( _XklGetAppWindow( fev->window, &p ) ) + _xklPrevAppWindow = p; + } } -/* +/** * PropertyChange handler * Interested in : * + for XKLL_MANAGE_WINDOW_STATES * - WM_STATE property for all windows * - Configuration property of the root window */ -void -xkl_engine_process_property_evt(XklEngine * engine, XPropertyEvent * pev) +void _XklPropertyEvHandler( XPropertyEvent * pev ) { - if (400 <= xkl_debug_level) { - char *atom_name = - XGetAtomName(xkl_engine_get_display(engine), - pev->atom); - if (atom_name != NULL) { - xkl_debug(400, - "The property '%s' changed for " - WINID_FORMAT "\n", atom_name, - pev->window); - XFree(atom_name); - } else { - xkl_debug(200, - "Some magic property changed for " - WINID_FORMAT "\n", pev->window); - } - } - - if (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES) { - if (pev->atom == xkl_engine_priv(engine, atoms)[WM_STATE]) { - gboolean has_xkl_state = - xkl_engine_get_state(engine, pev->window, - NULL); - - if (pev->state == PropertyNewValue) { - xkl_debug(160, - "New value of WM_STATE on window " - WINID_FORMAT "\n", pev->window); - if (!has_xkl_state) { /* Is this event the first or not? */ - xkl_engine_add_toplevel_window - (engine, pev->window, (Window) - NULL, FALSE, - &xkl_engine_priv(engine, - curr_state)); - } - } else { /* ev->xproperty.state == PropertyDelete, either client or WM can remove it, ICCCM 4.1.3.1 */ - xkl_debug(160, - "Something (%d) happened to WM_STATE of window 0x%x\n", - pev->state, pev->window); - xkl_engine_select_input_merging(engine, - pev-> - window, - PropertyChangeMask); - if (has_xkl_state) { - xkl_engine_delete_state(engine, - pev-> - window); - } - } - } else - if (pev->atom == - xkl_engine_priv(engine, base_config_atom) - && pev->window == xkl_engine_priv(engine, - root_window)) { - if (pev->state == PropertyNewValue) { - /* If root window got new *_NAMES_PROP_ATOM - - it most probably means new keyboard config is loaded by somebody */ - xkl_engine_reset_all_info - (engine, - "New value of *_NAMES_PROP_ATOM on root window"); - } - } - } /* XKLL_MANAGE_WINDOW_STATES */ + if( 400 <= _xklDebugLevel ) + { + char *atomName = XGetAtomName( _xklDpy, pev->atom ); + if( atomName != NULL ) + { + XklDebug( 400, "The property '%s' changed for " WINID_FORMAT "\n", + atomName, pev->window ); + XFree( atomName ); + } else + { + XklDebug( 200, "Some magic property changed for " WINID_FORMAT "\n", + pev->window ); + } + } + + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + { + if( pev->atom == _xklAtoms[WM_STATE] ) + { + Bool hasXklState = XklGetState( pev->window, NULL ); + + if( pev->state == PropertyNewValue ) + { + XklDebug( 160, "New value of WM_STATE on window " WINID_FORMAT "\n", + pev->window ); + if( !hasXklState ) /* Is this event the first or not? */ + { + _XklAddAppWindow( pev->window, ( Window ) NULL, False, + &_xklCurState ); + } + } else + { /* ev->xproperty.state == PropertyDelete, either client or WM can remove it, ICCCM 4.1.3.1 */ + XklDebug( 160, "Something (%d) happened to WM_STATE of window 0x%x\n", + pev->state, pev->window ); + _XklSelectInputMerging( pev->window, PropertyChangeMask ); + if( hasXklState ) + { + XklDelState( pev->window ); + } + } + } else + if( pev->atom == xklVTable->baseConfigAtom + && pev->window == _xklRootWindow ) + { + if( pev->state == PropertyNewValue ) + { + /* If root window got new *_NAMES_PROP_ATOM - + it most probably means new keyboard config is loaded by somebody */ + _XklResetAllInfo( "New value of *_NAMES_PROP_ATOM on root window" ); + } + } + } /* XKLL_MANAGE_WINDOW_STATES */ } -/* +/** * CreateNotify handler. Just interested in properties and focus events... */ -void -xkl_engine_process_create_window_evt(XklEngine * engine, - XCreateWindowEvent * cev) +void _XklCreateEvHandler( XCreateWindowEvent * cev ) { - if (! - (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES)) - return; - - xkl_debug(200, - "Under-root window " WINID_FORMAT - "/%s (%d,%d,%d x %d) is created\n", cev->window, - xkl_get_debug_window_title(engine, cev->window), cev->x, - cev->y, cev->width, cev->height); - - if (!cev->override_redirect) { + if( !( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) ) + return; + + XklDebug( 200, + "Under-root window " WINID_FORMAT + "/%s (%d,%d,%d x %d) is created\n", cev->window, + _XklGetDebugWindowTitle( cev->window ), cev->x, cev->y, + cev->width, cev->height ); + + if( !cev->override_redirect ) + { /* ICCCM 4.1.6: override-redirect is NOT private to * client (and must not be changed - am I right?) * We really need only PropertyChangeMask on this window but even in the case of @@ -435,173 +329,134 @@ xkl_engine_process_create_window_evt(XklEngine * engine, * event + SelectInput request is not zero) and we definitely will (my system DO) * lose FocusIn/Out events after the following call of PropertyNotifyHandler. * So I just decided to purify this extra FocusChangeMask in the FocusIn/OutHandler. */ - xkl_engine_select_input_merging(engine, cev->window, - PropertyChangeMask | - FocusChangeMask); - - if (xkl_engine_if_window_has_wm_state(engine, cev->window)) { - xkl_debug(200, - "Just created window already has WM_STATE - so I'll add it"); - xkl_engine_add_toplevel_window(engine, cev->window, - (Window) NULL, - FALSE, - &xkl_engine_priv - (engine, - curr_state)); - } - } + _XklSelectInputMerging( cev->window, + PropertyChangeMask | FocusChangeMask ); + + if( _XklHasWmState( cev->window ) ) + { + XklDebug( 200, + "Just created window already has WM_STATE - so I'll add it" ); + _XklAddAppWindow( cev->window, ( Window ) NULL, False, &_xklCurState ); + } + } } -/* +/** * Just error handler - sometimes we get BadWindow error for already gone * windows, so we'll just ignore */ -void -xkl_process_error(Display * dpy, XErrorEvent * evt) +void _XklErrHandler( Display * dpy, XErrorEvent * evt ) { - char buf[128] = ""; - XklEngine *engine = xkl_get_the_engine(); - - xkl_engine_priv(engine, last_error_code) = evt->error_code; - switch (xkl_engine_priv(engine, last_error_code)) { - case BadWindow: - case BadAccess: - { - XGetErrorText(xkl_engine_get_display(engine), - evt->error_code, buf, - sizeof(buf)); - /* in most cases this means we are late:) */ - xkl_debug(200, - "ERROR: %p, " WINID_FORMAT ", %d [%s], " - "X11 request: %d, minor code: %d\n", dpy, - (unsigned long) evt->resourceid, - (int) evt->error_code, buf, - (int) evt->request_code, - (int) evt->minor_code); - break; - } - default: - (*xkl_engine_priv(engine, default_error_handler)) (dpy, - evt); - } + char buf[128] = ""; + _xklLastErrorCode = evt->error_code; + switch ( _xklLastErrorCode ) + { + case BadWindow: + case BadAccess: + { + XGetErrorText( dpy, _xklLastErrorCode, buf, sizeof(buf) ); + /* in most cases this means we are late:) */ + XklDebug( 200, "ERROR: %p, " WINID_FORMAT ", %d [%s], " + "X11 request: %d, minor code: %d\n", + dpy, + ( unsigned long ) evt->resourceid, + ( int ) evt->error_code, buf, + ( int ) evt->request_code, + ( int ) evt->minor_code ); + break; + } + default: + XklDebug( 200, "Unexpected by libxklavier X ERROR: %p, " WINID_FORMAT ", %d [%s], " + "X11 request: %d, minor code: %d\n", + dpy, + ( unsigned long ) evt->resourceid, + ( int ) evt->error_code, buf, + ( int ) evt->request_code, + ( int ) evt->minor_code ); + if( !_xklCriticalSection ) + ( *_xklDefaultErrHandler ) ( dpy, evt ); + } } -/* +/** * Some common functionality for Xkb handler */ -void -xkl_engine_process_state_modification(XklEngine * engine, - XklEngineStateChange change_type, - gint grp, guint inds, - gboolean set_inds) +void _XklStateModificationHandler( XklStateChange changeType, + int grp, + unsigned inds, + Bool setInds ) { - Window focused, focused_toplevel; - XklState old_state; - gint revert; - gboolean have_old_state = TRUE; - gboolean set_group = change_type == GROUP_CHANGED; - - XGetInputFocus(xkl_engine_get_display(engine), &focused, &revert); - - if ((focused == None) || (focused == PointerRoot)) { - xkl_debug(160, "Something with focus: " WINID_FORMAT "\n", - focused); - return; - } - - /* - * Only if we manage states - otherwise xkl_engine_priv(engine,curr_toplvl_win) does not make sense - */ - if (!xkl_engine_find_toplevel_window - (engine, focused, &focused_toplevel) - && xkl_engine_priv(engine, - listener_type) & XKLL_MANAGE_WINDOW_STATES) - focused_toplevel = xkl_engine_priv(engine, curr_toplvl_win); /* what else can I do */ - - xkl_debug(150, "Focused window: " WINID_FORMAT ", '%s'\n", - focused_toplevel, - xkl_get_debug_window_title(engine, focused_toplevel)); - if (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES) { - xkl_debug(150, "CurClient: " WINID_FORMAT ", '%s'\n", - xkl_engine_priv(engine, curr_toplvl_win), - xkl_get_debug_window_title(engine, - xkl_engine_priv - (engine, - curr_toplvl_win))); - - if (focused_toplevel != - xkl_engine_priv(engine, curr_toplvl_win)) { - /* - * If not state - we got the new window - */ - if (!xkl_engine_get_toplevel_window_state - (engine, focused_toplevel, &old_state)) { - xkl_engine_update_current_state(engine, - grp, inds, - "Updating the state from new focused window"); - if (xkl_engine_priv(engine, listener_type) - & XKLL_MANAGE_WINDOW_STATES) - xkl_engine_add_toplevel_window - (engine, focused_toplevel, - (Window) NULL, FALSE, - &xkl_engine_priv(engine, - curr_state)); - } - /* - * There is state - just get the state from the window - */ - else { - grp = old_state.group; - inds = old_state.indicators; - } - xkl_engine_priv(engine, curr_toplvl_win) = - focused_toplevel; - xkl_debug(160, - "CurClient:changed to " WINID_FORMAT - ", '%s'\n", xkl_engine_priv(engine, - curr_toplvl_win), - xkl_get_debug_window_title(engine, - xkl_engine_priv - (engine, - curr_toplvl_win))); - } - /* If the window already has this this state - we are just restoring it! - (see the second parameter of stateCallback */ - have_old_state = - xkl_engine_get_toplevel_window_state(engine, - xkl_engine_priv - (engine, - curr_toplvl_win), - &old_state); - } else { /* just tracking the stuff, no smart things */ - - xkl_debug(160, - "Just updating the current state in the tracking mode\n"); - memcpy(&old_state, &xkl_engine_priv(engine, curr_state), - sizeof(XklState)); - } - - if (set_group || have_old_state) { - xkl_engine_update_current_state(engine, - set_group ? grp : - old_state.group, - set_inds ? inds : - old_state.indicators, - "Restoring the state from the window"); - } - - if (have_old_state) - xkl_engine_try_call_state_func(engine, change_type, - &old_state); - - if (xkl_engine_priv(engine, listener_type) & - XKLL_MANAGE_WINDOW_STATES) - xkl_engine_save_toplevel_window_state(engine, - xkl_engine_priv - (engine, - curr_toplvl_win), - &xkl_engine_priv - (engine, - curr_state)); + Window focused, focusedApp; + XklState oldState; + int revert; + Bool haveOldState = True; + Bool setGroup = changeType == GROUP_CHANGED; + + XGetInputFocus( _xklDpy, &focused, &revert ); + + if( ( focused == None ) || ( focused == PointerRoot ) ) + { + XklDebug( 160, "Something with focus: " WINID_FORMAT "\n", focused ); + return; + } + + /** + * Only if we manage states - otherwise _xklCurClient does not make sense + */ + if( !_XklGetAppWindow( focused, &focusedApp ) && + _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + focusedApp = _xklCurClient; /* what else can I do */ + + XklDebug( 150, "Focused window: " WINID_FORMAT ", '%s'\n", focusedApp, + _XklGetDebugWindowTitle( focusedApp ) ); + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + { + XklDebug( 150, "CurClient: " WINID_FORMAT ", '%s'\n", _xklCurClient, + _XklGetDebugWindowTitle( _xklCurClient ) ); + + if( focusedApp != _xklCurClient ) + { + /** + * If not state - we got the new window + */ + if ( !_XklGetAppState( focusedApp, &oldState ) ) + { + _XklUpdateCurState( grp, inds, + "Updating the state from new focused window" ); + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + _XklAddAppWindow( focusedApp, ( Window ) NULL, False, &_xklCurState ); + } + /** + * There is state - just get the state from the window + */ + else + { + grp = oldState.group; + inds = oldState.indicators; + } + _xklCurClient = focusedApp; + XklDebug( 160, "CurClient:changed to " WINID_FORMAT ", '%s'\n", + _xklCurClient, _XklGetDebugWindowTitle( _xklCurClient ) ); + } + /* If the window already has this this state - we are just restoring it! + (see the second parameter of stateCallback */ + haveOldState = _XklGetAppState( _xklCurClient, &oldState ); + } else /* just tracking the stuff, no smart things */ + { + XklDebug( 160, "Just updating the current state in the tracking mode\n" ); + memcpy( &oldState, &_xklCurState, sizeof( XklState ) ); + } + + if( setGroup || haveOldState ) + { + _XklUpdateCurState( setGroup ? grp : oldState.group, + setInds ? inds : oldState.indicators, + "Restoring the state from the window" ); + } + + if( haveOldState ) + _XklTryCallStateCallback( changeType, &oldState ); + + if( _xklListenerType & XKLL_MANAGE_WINDOW_STATES ) + _XklSaveAppState( _xklCurClient, &_xklCurState ); } diff --git a/libxklavier/xklavier_private.h b/libxklavier/xklavier_private.h index 30aef9e..7fbc6f5 100644 --- a/libxklavier/xklavier_private.h +++ b/libxklavier/xklavier_private.h @@ -3,384 +3,352 @@ #include -#include +#include -#include +typedef Bool ( *XklConfigActivateHandler )( const XklConfigRecPtr data ); -enum { WM_NAME, - WM_STATE, - XKLAVIER_STATE, - XKLAVIER_TRANSPARENT, - XKLAVIER_ALLOW_SECONDARY, - TOTAL_ATOMS -}; - -struct _XklEnginePrivate { - - gboolean group_per_toplevel_window; - - gboolean handle_indicators; - - gboolean skip_one_restore; - - gint default_group; - - guint listener_type; - - guint secondary_groups_mask; - - Window root_window; - - Window prev_toplvl_win; - - Window curr_toplvl_win; - - XErrorHandler default_error_handler; - - Status last_error_code; - - XklState curr_state; - - Atom atoms[TOTAL_ATOMS]; - - Display *display; - - /* - * Backend name - */ - const gchar *backend_id; - - /* - * Functions supported by the backend, combination of XKLF_* constants - */ - guint8 features; - - /* - * Activates the configuration. - * xkb: create proper the XkbDescRec and send it to the server - * xmodmap: save the property, init layout #1 - */ - gboolean(*activate_config_rec) (XklEngine * engine, - const XklConfigRec * data); - - /* - * Background-specific initialization. - * xkb: XkbInitAtoms - init internal xkb atoms table - * xmodmap: void. - */ - void (*init_config_registry) (XklConfigRegistry * config); - - /* - * Loads the registry tree into DOM (using whatever path(s)) - * The XklVTConfigFreeRegistry is static - no virtualization necessary. - * xkb: loads xml from XKB_BASE+"/rules/"+ruleset+".xml" - * xmodmap: loads xml from XMODMAP_BASE+"/"+ruleset+".xml" - */ - gboolean(*load_config_registry) (XklConfigRegistry * config); - - /* - * Write the configuration into the file (binary/textual) - * xkb: write xkb or xkm file - * xmodmap: if text requested, just dump XklConfigRec to the - * file - not really useful. If binary - fail (not supported) - */ - gboolean(*write_config_rec_to_file) (XklEngine * engine, - const gchar * file_name, - const XklConfigRec * data, - const gboolean binary); - - /* - * Get the list of the group names - * xkb: return cached list of the group names - * xmodmap: return the list of layouts from the internal XklConfigRec - */ - const gchar **(*get_groups_names) (XklEngine * engine); - - /* - * Get the maximum number of loaded groups - * xkb: returns 1 or XkbNumKbdGroups - * xmodmap: return 0 - */ - guint(*get_max_num_groups) (XklEngine * engine); - - /* - * Get the number of loaded groups - * xkb: return from the cached XkbDesc - * xmodmap: return number of layouts from internal XklConfigRec - */ - guint(*get_num_groups) (XklEngine * engine); - - /* - * Switches the keyboard to the group N - * xkb: simple one-liner to call the XKB function - * xmodmap: changes the root window property - * (listener invokes xmodmap with appropriate config file). - */ - void (*lock_group) (XklEngine * engine, gint group); - - /* - * Handles X events. - * xkb: XkbEvent handling - * xmodmap: keep track on the root window properties. What else can we do? - */ - gint(*process_x_event) (XklEngine * engine, XEvent * xev); - - /* - * Flushes the cached server config info. - * xkb: frees XkbDesc - * xmodmap: frees internal XklConfigRec - */ - void (*free_all_info) (XklEngine * engine); - - /* - * Compares the cached info with the actual one, from the server - * xkb: Compares some parts of XkbDescPtr - * xmodmap: returns False - */ - gboolean(*if_cached_info_equals_actual) (XklEngine * engine); - - /* - * Loads the configuration info from the server - * xkb: loads XkbDesc, names, indicators - * xmodmap: loads internal XklConfigRec from server - */ - gboolean(*load_all_info) (XklEngine * engine); - - /* - * Gets the current state - * xkb: XkbGetState and XkbGetIndicatorState - * xmodmap: check the root window property (regarding the group) - */ - void (*get_server_state) (XklEngine * engine, - XklState * current_state_out); - - /* - * Stop tracking the keyboard-related events - * xkb: XkbSelectEvents(..., 0) - * xmodmap: Ungrab the switching shortcut. - */ - gint(*pause_listen) (XklEngine * engine); - - /* - * Start tracking the keyboard-related events - * xkb: XkbSelectEvents + XkbSelectEventDetails - * xmodmap: Grab the switching shortcut. - */ - gint(*resume_listen) (XklEngine * engine); - - /* - * Set the indicators state from the XklState - * xkb: XklSetIndicator for all indicators - * xmodmap: NULL. Not supported - */ - void (*set_indicators) (XklEngine * engine, - const XklState * window_state); - - /* - * Perform the cleanup - */ - void (*finalize) (XklEngine * engine); - - /* all data is private - no direct access */ - /* - * The base configuration atom. - * xkb: _XKB_RF_NAMES_PROP_ATOM - * xmodmap: "_XMM_NAMES" - */ - Atom base_config_atom; - - /* - * The configuration backup atom - * xkb: "_XKB_RULES_NAMES_BACKUP" - * xmodmap: "_XMM_NAMES_BACKUP" - */ - Atom backup_config_atom; - - /* - * Fallback for missing model - */ - const gchar *default_model; - - /* - * Fallback for missing layout - */ - const gchar *default_layout; - - /* - * Any stuff backend might need to put in here - */ - gpointer backend; -}; - -extern XklEngine *xkl_get_the_engine(void); - -struct _XklConfigRegistryPrivate { - XklEngine *engine; - - xmlDocPtr doc; - - xmlXPathContextPtr xpath_context; -}; - -extern void xkl_engine_ensure_vtable_inited(XklEngine * engine); - -extern void xkl_engine_process_focus_in_evt(XklEngine * engine, - XFocusChangeEvent * fev); -extern void xkl_engine_process_focus_out_evt(XklEngine * engine, - XFocusChangeEvent * fev); -extern void xkl_engine_process_property_evt(XklEngine * engine, - XPropertyEvent * rev); -extern void xkl_engine_process_create_window_evt(XklEngine * engine, - XCreateWindowEvent * cev); - -extern void xkl_process_error(Display * dpy, XErrorEvent * evt); - -extern void xkl_engine_process_state_modification(XklEngine * engine, - XklEngineStateChange - change_type, gint group, - unsigned inds, - gboolean set_indicators); - -extern Window xkl_engine_get_registered_parent(XklEngine * engine, - Window win); -extern void xkl_engine_reset_all_info(XklEngine * engine, - const gchar reason[]); -extern gboolean xkl_engine_load_window_tree(XklEngine * engine); -extern gboolean xkl_engine_load_subtree(XklEngine * engine, Window window, - gint level, XklState * init_state); - -extern gboolean xkl_engine_if_window_has_wm_state(XklEngine * engine, - Window win); - - -/** - * Toplevel window stuff - */ -extern void xkl_engine_add_toplevel_window(XklEngine * engine, Window win, - Window parent, gboolean force, - XklState * init_state); - -extern gboolean xkl_engine_find_toplevel_window_bottom_to_top(XklEngine * - engine, - Window win, - Window * - toplevel_win_out); +typedef void ( *XklConfigInitHandler )( void ); + +typedef Bool ( *XklConfigLoadRegistryHandler )( void ); + +typedef Bool ( *XklConfigWriteFileHandler )( const char *fileName, + const XklConfigRecPtr data, + const Bool binary ); + +typedef int ( *XklEventHandler )( XEvent *xev ); + +typedef void ( *XklFreeAllInfoHandler )( void ); + +typedef const char **( *XklGetGroupNamesHandler )( void ); + +typedef unsigned ( *XklGetMaxNumGroupsHandler )( void ); + +typedef unsigned ( *XklGetNumGroupsHandler )( void ); + +typedef void ( *XklGetRealStateHandler)( XklState * curState_return ); + +typedef Bool ( *XklIfCachedInfoEqualsActualHandler) ( void ); + +typedef Bool ( *XklLoadAllInfoHandler )( void ); + +typedef void ( *XklLockGroupHandler )( int group ); + +typedef int ( *XklPauseResumeListenHandler )( void ); + +typedef void ( *XklSetIndicatorsHandler )( const XklState *windowState ); + +typedef struct +{ + /** + * Backend name + */ + const char *id; + + /** + * Functions supported by the backend, combination of XKLF_* constants + */ + int features; + + /** + * Activates the configuration. + * xkb: create proper the XkbDescRec and send it to the server + * xmodmap: save the property, init layout #1 + */ + XklConfigActivateHandler xklConfigActivateHandler; + + /** + * Background-specific initialization. + * xkb: XkbInitAtoms - init internal xkb atoms table + * xmodmap: void. + */ + XklConfigInitHandler xklConfigInitHandler; /* private */ + + /** + * Loads the registry tree into DOM (using whatever path(s)) + * The XklConfigFreeRegistry is static - no virtualization necessary. + * xkb: loads xml from XKB_BASE+"/rules/"+ruleset+".xml" + * xmodmap: loads xml from XMODMAP_BASE+"/"+ruleset+".xml" + */ + XklConfigLoadRegistryHandler xklConfigLoadRegistryHandler; + + /** + * Write the configuration into the file (binary/textual) + * xkb: write xkb or xkm file + * xmodmap: if text requested, just dump XklConfigRec to the + * file - not really useful. If binary - fail (not supported) + */ + XklConfigWriteFileHandler xklConfigWriteFileHandler; + + /** + * Handles X events. + * xkb: XkbEvent handling + * xmodmap: keep track on the root window properties. What else can we do? + */ + XklEventHandler xklEventHandler; + + /** + * Flushes the cached server config info. + * xkb: frees XkbDesc + * xmodmap: frees internal XklConfigRec + */ + XklFreeAllInfoHandler xklFreeAllInfoHandler; /* private */ + + /** + * Get the list of the group names + * xkb: return cached list of the group names + * xmodmap: return the list of layouts from the internal XklConfigRec + */ + XklGetGroupNamesHandler xklGetGroupNamesHandler; + + /** + * Get the maximum number of loaded groups + * xkb: returns 1 or XkbNumKbdGroups + * xmodmap: return 0 + */ + XklGetMaxNumGroupsHandler xklGetMaxNumGroupsHandler; + + /** + * Get the number of loaded groups + * xkb: return from the cached XkbDesc + * xmodmap: return number of layouts from internal XklConfigRec + */ + XklGetNumGroupsHandler xklGetNumGroupsHandler; + + /** + * Gets the current stateCallback + * xkb: XkbGetState and XkbGetIndicatorState + * xmodmap: check the root window property (regarding the group) + */ + XklGetRealStateHandler xklGetRealStateHandler; + + /** + * Compares the cached info with the actual one, from the server + * xkb: Compares some parts of XkbDescPtr + * xmodmap: returns False + */ + XklIfCachedInfoEqualsActualHandler xklIfCachedInfoEqualsActualHandler; + + /** + * Loads the configuration info from the server + * xkb: loads XkbDesc, names, indicators + * xmodmap: loads internal XklConfigRec from server + */ + XklLoadAllInfoHandler xklLoadAllInfoHandler; /* private */ + + /** + * Switches the keyboard to the group N + * xkb: simple one-liner to call the XKB function + * xmodmap: changes the root window property + * (listener invokes xmodmap with appropriate config file). + */ + XklLockGroupHandler xklLockGroupHandler; + + /** + * Stop tracking the keyboard-related events + * xkb: XkbSelectEvents(..., 0) + * xmodmap: Ungrab the switching shortcut. + */ + XklPauseResumeListenHandler xklPauseListenHandler; + + /** + * Start tracking the keyboard-related events + * xkb: XkbSelectEvents + XkbSelectEventDetails + * xmodmap: Grab the switching shortcut. + */ + XklPauseResumeListenHandler xklResumeListenHandler; + + /** + * Set the indicators state from the XklState + * xkb: _XklSetIndicator for all indicators + * xmodmap: NULL. Not supported + */ + XklSetIndicatorsHandler xklSetIndicatorsHandler; /* private */ + + /* all data is private - no direct access */ + /** + * The base configuration atom. + * xkb: _XKB_RF_NAMES_PROP_ATOM + * xmodmap: "_XMM_NAMES" + */ + Atom baseConfigAtom; + + /** + * The configuration backup atom + * xkb: "_XKB_RULES_NAMES_BACKUP" + * xmodmap: "_XMM_NAMES_BACKUP" + */ + Atom backupConfigAtom; + + /** + * Fallback for missing model + */ + const char* defaultModel; + + /** + * Fallback for missing layout + */ + const char* defaultLayout; + +} XklVTable; + +extern void _XklEnsureVTableInited( void ); + +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 _XklFocusInEvHandler( XFocusChangeEvent * fev ); +extern void _XklFocusOutEvHandler( XFocusChangeEvent * fev ); +extern void _XklPropertyEvHandler( XPropertyEvent * rev ); +extern void _XklCreateEvHandler( XCreateWindowEvent * cev ); + +extern void _XklErrHandler( Display * dpy, XErrorEvent * evt ); + +extern Window _XklGetRegisteredParent( Window win ); +extern Bool _XklLoadAllInfo( void ); +extern void _XklFreeAllInfo( void ); +extern void _XklResetAllInfo( const char reason[] ); +extern Bool _XklLoadWindowTree( void ); +extern Bool _XklLoadSubtree( Window window, int level, XklState * initState ); + +extern Bool _XklHasWmState( Window win ); + +extern Bool _XklGetAppState( Window appWin, XklState * state_return ); +extern void _XklDelAppState( Window appWin ); +extern void _XklSaveAppState( Window appWin, XklState * state ); -extern gboolean xkl_engine_find_toplevel_window(XklEngine * engine, - Window win, - Window * toplevel_win_out); +extern void _XklSelectInputMerging( Window win, long mask ); -extern gboolean xkl_engine_is_toplevel_window_transparent(XklEngine * - engine, - Window - toplevel_win); +extern char *_XklGetDebugWindowTitle( Window win ); -extern void xkl_engine_set_toplevel_window_transparent(XklEngine * engine, - Window toplevel_win, - gboolean - transparent); +extern Status _XklStatusQueryTree( Display * display, + Window w, + Window * root_return, + Window * parent_return, + Window ** children_return, + unsigned int *nchildren_return ); -extern gboolean xkl_engine_get_toplevel_window_state(XklEngine * engine, - Window toplevel_win, - XklState * state_out); +extern Bool _XklSetIndicator( int indicatorNum, Bool set ); -extern void xkl_engine_remove_toplevel_window_state(XklEngine * engine, - Window toplevel_win); -extern void xkl_engine_save_toplevel_window_state(XklEngine * engine, - Window toplevel_win, - XklState * state); -/***/ +extern void _XklTryCallStateCallback( XklStateChange changeType, + XklState * oldState ); -extern void xkl_engine_select_input_merging(XklEngine * engine, Window win, - gulong mask); +extern void _XklI18NInit( ); -extern gchar *xkl_get_debug_window_title(XklEngine * engine, Window win); +extern char *_XklLocaleFromUtf8( const char *utf8string ); -extern Status xkl_engine_query_tree(XklEngine * engine, - Window w, - Window * root_out, - Window * parent_out, - Window ** children_out, - guint * nchildren_out); +extern int _XklGetLanguagePriority( const char *language ); -extern void xkl_engine_try_call_state_func(XklEngine * engine, - XklEngineStateChange - change_type, - XklState * old_state); +extern char* _XklGetRulesSetName( const char defaultRuleset[] ); -extern void xkl_i18n_init(void); +extern Bool _XklConfigGetFullFromServer( char **rulesFileOut, + XklConfigRecPtr data ); -extern gchar *xkl_locale_from_utf8(const gchar * utf8string); +extern char *_XklConfigRecMergeByComma( const char **array, + const int arrayLength ); -extern gint xkl_get_language_priority(const gchar * language); +extern char *_XklConfigRecMergeLayouts( const XklConfigRecPtr data ); -extern gchar *xkl_engine_get_ruleset_name(XklEngine * engine, - const gchar default_ruleset[]); +extern char *_XklConfigRecMergeVariants( const XklConfigRecPtr data ); -extern gboolean xkl_config_rec_get_full_from_server(gchar ** - rules_file_out, - XklConfigRec * data, - XklEngine * engine); +extern char *_XklConfigRecMergeOptions( const XklConfigRecPtr data ); -extern gchar *xkl_strings_concat_comma_separated(gchar ** array); +extern void _XklConfigRecSplitByComma( char ***array, + int *arraySize, const char *merged ); -extern void xkl_strings_split_comma_separated(gchar *** array, - const gchar * merged); +extern void _XklConfigRecSplitLayouts( XklConfigRecPtr data, + const char *merged ); -/** - * XConfigRec - */ -extern gchar *xkl_config_rec_merge_layouts(const XklConfigRec * data); +extern void _XklConfigRecSplitVariants( XklConfigRecPtr data, + const char *merged ); -extern gchar *xkl_config_rec_merge_variants(const XklConfigRec * data); +extern void _XklConfigRecSplitOptions( XklConfigRecPtr data, + const char *merged ); -extern gchar *xkl_config_rec_merge_options(const XklConfigRec * data); +extern void XklConfigDump( FILE* file, + XklConfigRecPtr data ); + +extern const char *_XklGetEventName( int requestId ); -extern void xkl_config_rec_split_layouts(XklConfigRec * data, - const gchar * merged); +extern Bool _XklIsTransparentAppWindow( Window appWin ); -extern void xkl_config_rec_split_variants(XklConfigRec * data, - const gchar * merged); +extern void _XklUpdateCurState( int group, unsigned indicators, const char reason[] ); -extern void xkl_config_rec_split_options(XklConfigRec * data, - const gchar * merged); -/***/ +extern void _XklStateModificationHandler( XklStateChange changeType, + int grp, + unsigned inds, + Bool setInds ); -extern void xkl_config_rec_dump(FILE * file, XklConfigRec * data); +extern int _XklXkbInit( void ); -extern const gchar *xkl_event_get_name(gint type); +extern int _XklXmmInit( void ); -extern void xkl_engine_update_current_state(XklEngine * engine, gint group, - unsigned indicators, - const gchar reason[]); +extern Bool _XklIsOneSwitchToSecondaryGroupAllowed( void ); -extern gint xkl_xkb_init(XklEngine * engine); +extern void _XklOneSwitchToSecondaryGroupPerformed( void ); -extern gint xkl_xmm_init(XklEngine * engine); +extern Display *_xklDpy; -extern gboolean -xkl_engine_is_one_switch_to_secondary_group_allowed(XklEngine * engine); +extern Window _xklRootWindow; -extern void xkl_engine_one_switch_to_secondary_group_performed(XklEngine * - engine); +extern XklState _xklCurState; + +extern Window _xklCurClient; + +extern Status _xklLastErrorCode; + +extern const char *_xklLastErrorMsg; + +extern XErrorHandler _xklDefaultErrHandler; + +extern char *_xklIndicatorNames[]; + +enum { WM_NAME, + WM_STATE, + XKLAVIER_STATE, + XKLAVIER_TRANSPARENT, + XKLAVIER_ALLOW_SECONDARY, + TOTAL_ATOMS }; #define XKLAVIER_STATE_PROP_LENGTH 2 /* taken from XFree86 maprules.c */ -#define XKB_RF_NAMES_PROP_MAXLEN 1024 +#define _XKB_RF_NAMES_PROP_MAXLEN 1024 + +extern Atom _xklAtoms[]; + +extern Bool _xklAllowSecondaryGroupOnce; + +extern int _xklDefaultGroup; + +extern Bool _xklSkipOneRestore; + +extern int _xklSecondaryGroupsMask; + +extern int _xklDebugLevel; + +extern int _xklListenerType; + +extern Window _xklPrevAppWindow; #define WINID_FORMAT "%lx" -#define xkl_engine_priv(engine,member) (engine)->priv->member -#define xkl_engine_backend(engine,type,member) ((type*)((engine)->priv->backend))->member -#define xkl_engine_get_display(engine) (xkl_engine_priv(engine,display)) -#define xkl_engine_vcall(engine,func) (*(engine)->priv->func) +extern XklConfigCallback _xklConfigCallback; -#define xkl_config_registry_priv(config,member) (config)->priv->member -#define xkl_config_registry_get_engine(config) ((config)->priv->engine) +extern void *_xklConfigCallbackData; -extern gint xkl_debug_level; +extern XklVTable *xklVTable; -extern const gchar *xkl_last_error_message; +extern Bool _xklCriticalSection; + +#ifdef __STRICT_ANSI__ +/* these are functions which are NOT in ANSI C. + Probably we should provide the implementation */ +extern int snprintf( char *s, size_t maxlen, + const char *format, ... ); + +extern char *strdup( const char *s ); +#endif #endif -- cgit v1.2.1