diff --git a/plugins/ini.c b/plugins/ini.c index a8696dc..2441e99 100644 --- a/plugins/ini.c +++ b/plugins/ini.c @@ -52,6 +52,9 @@ static int displayPrivateIndex; +/* + * IniFileData + */ typedef struct _IniFileData IniFileData; struct _IniFileData { char *filename; @@ -65,20 +68,9 @@ struct _IniFileData { IniFileData *prev; }; -#define N_ACTION_PARTS 5 -typedef struct _IniActionProxy { - int nSet; - - CompBindingType type; - CompKeyBinding key; - CompButtonBinding button; - - Bool bell; - - unsigned int edgeMask; - int edgeButton; -} IniActionProxy; - +/* + * IniDisplay + */ typedef struct _IniDisplay { int screenPrivateIndex; @@ -91,30 +83,60 @@ typedef struct _IniDisplay { IniFileData *fileData; } IniDisplay; +/* + * IniScreeen + */ typedef struct _IniScreen { InitPluginForScreenProc initPluginForScreen; SetScreenOptionProc setScreenOption; SetScreenOptionForPluginProc setScreenOptionForPlugin; } IniScreen; -static void -initActionProxy (IniActionProxy *a) -{ - a->type = 0; - - a->nSet = 0; - - a->key.keycode = 0; - a->key.modifiers = 0; +/* + * IniAction + */ +static char * validActionTypes[] = { + "key", + "button", + "bell", + "edge", + "edgebutton"}; + +#define ACTION_VALUE_KEY (1 << 0) +#define ACTION_VALUE_BUTTON (1 << 1) +#define ACTION_VALUE_BELL (1 << 2) +#define ACTION_VALUE_EDGE (1 << 3) +#define ACTION_VALUE_EDGEBUTTON (1 << 4) +#define ACTION_VALUES_ALL \ + ( ACTION_VALUE_KEY \ + | ACTION_VALUE_BUTTON \ + | ACTION_VALUE_BELL \ + | ACTION_VALUE_EDGE \ + | ACTION_VALUE_EDGEBUTTON ) + +static int actionValueMasks[] = { + ACTION_VALUE_KEY, + ACTION_VALUE_BUTTON, + ACTION_VALUE_BELL, + ACTION_VALUE_EDGE, + ACTION_VALUE_EDGEBUTTON +}; - a->button.button = 0; - a->button.modifiers = 0; +enum { + ACTION_TYPE_KEY = 0, + ACTION_TYPE_BUTTON, + ACTION_TYPE_BELL, + ACTION_TYPE_EDGE, + ACTION_TYPE_EDGEBUTTON, + ACTION_TYPES_NUM +}; - a->bell = FALSE; +typedef struct _IniAction { + char *realOptionName; + unsigned int valueMasks; + CompAction a; +} IniAction; - a->edgeMask = 0; - a->edgeButton = 0; -} static IniFileData * iniGetFileDataFromFilename (CompDisplay *d, @@ -471,6 +493,135 @@ iniMakeDirectories (void) } static Bool +findActionType(char *optionName, int *type) +{ + char * optionType = strrchr(optionName, '_'); + if (!optionType) + return FALSE; + + optionType++; // skip the '_' + + int i; + for (i = 0; i < ACTION_TYPES_NUM; i++) + { + if (strcmp(optionType, validActionTypes[i]) == 0) + { + if (type) + *type = i; + return TRUE; + } + } + + return FALSE; +} + +static Bool +parseAction(CompDisplay *d, char *optionName, char *optionValue, IniAction *action) +{ + int type; + if (!findActionType(optionName, &type)) + return FALSE; // no action, exit the loop + + // we have a new action + if (!action->realOptionName) + { + char *optionType = strrchr(optionName, '_'); + // chars until the last "_" + int len = strlen(optionName) - strlen(optionType); + + action->realOptionName = malloc(sizeof(char)*(len+1)); + strncpy(action->realOptionName, optionName, len); + action->realOptionName[len] = '\0'; + + // make sure all defaults are set + action->a.type = 0; + action->a.key.keycode = 0; + action->a.key.modifiers = 0; + action->a.button.button = 0; + action->a.button.modifiers = 0; + action->a.bell = FALSE; + action->a.edgeMask = 0; + action->a.edgeButton = 0; + } + // detect a new option (might happen when the options are incomplete) + else if (action->valueMasks != ACTION_VALUES_ALL) + { + char *optionType = strrchr(optionName, '_'); + // chars until the last "_" + int len = strlen(optionName) - strlen(optionType); + + char *realOptionName = malloc(sizeof(char)*(len+1)); + strncpy(realOptionName, optionName, len); + realOptionName[len] = '\0'; + + if (strcmp(action->realOptionName, realOptionName) != 0) { + free(realOptionName); + return FALSE; + } + + free(realOptionName); + } + + int i, j; + CompListValue edges; + switch (type) + { + case ACTION_TYPE_KEY: + if (optionValue[0] != '\0' && + strcasecmp(optionValue, "disabled") != 0 && + stringToKeyBinding (d, optionValue, &action->a.key)) + action->a.type |= CompBindingTypeKey; + break; + + case ACTION_TYPE_BUTTON: + if (optionValue[0] != '\0' && + strcasecmp(optionValue, "disabled") != 0 && + stringToButtonBinding (d, optionValue, &action->a.button)) + action->a.type |= CompBindingTypeButton; + break; + + case ACTION_TYPE_BELL: + action->a.bell = (Bool) atoi(optionValue); + break; + + case ACTION_TYPE_EDGE: + if (optionValue[0] != '\0' && + csvToList (optionValue, &edges, CompOptionTypeString)) + { + for (i = 0; i < edges.nValue; i++) { + for (j = 0; j < SCREEN_EDGE_NUM; j++) { + if (strcasecmp (edges.value[i].s, edgeToString(j)) == 0) + { + action->a.edgeMask |= (1 << j); + + // found corresponding mask, next value + break; + } + } + } + } + break; + + case ACTION_TYPE_EDGEBUTTON: + action->a.edgeButton = atoi(optionValue); + if (action->a.edgeButton != 0) + action->a.type |= CompBindingTypeEdgeButton; + break; + + default: + break; + } + + action->valueMasks |= actionValueMasks[type]; + + // no need to read any further since all value are set + if (action->valueMasks == ACTION_VALUES_ALL) + return FALSE; + + return TRUE; // continue loop, not finished parsing yet +} + +static Bool iniLoadOptionsFromFile (CompDisplay *d, FILE *optionFile, char *plugin, @@ -478,9 +629,6 @@ iniLoadOptionsFromFile (CompDisplay *d, { char *optionName = NULL; char *optionValue = NULL; - char *actionTest = NULL; - char *actionTmp = NULL; - char *realOption = NULL; char tmp[MAX_OPTION_LENGTH]; CompOption *option = NULL, *o; int nOption; @@ -534,10 +682,9 @@ iniLoadOptionsFromFile (CompDisplay *d, option = compGetDisplayOptions (d, &nOption); } - IniActionProxy actionProxy; - - initActionProxy (&actionProxy); - + IniAction action; + action.realOptionName = NULL; + Bool continueReading = FALSE; while (fgets (&tmp[0], MAX_OPTION_LENGTH, optionFile) != NULL) { status = FALSE; @@ -554,42 +701,6 @@ iniLoadOptionsFromFile (CompDisplay *d, o = compFindOption (option, nOption, optionName, 0); if (o) { - if (actionProxy.nSet != 0) - { - /* there is an action where a line is - missing / out of order. realOption - should still be set from the last loop */ - - value.action.type = actionProxy.type; - value.action.key = actionProxy.key; - value.action.button = actionProxy.button; - value.action.bell = actionProxy.bell; - value.action.edgeMask = actionProxy.edgeMask; - value.action.edgeButton = actionProxy.edgeButton; - - if (plugin && p) - { - if (s) - status = (*s->setScreenOptionForPlugin) (s, - plugin, - realOption, - &value); - else - status = (*d->setDisplayOptionForPlugin) (d, plugin, - realOption, - &value); - } - else - { - if (s) - status = (*s->setScreenOption) (s, realOption, &value); - else - status = (*d->setDisplayOption) (d, realOption, &value); - } - - initActionProxy (&actionProxy); - } - value = o->value; switch (o->type) @@ -656,147 +767,61 @@ iniLoadOptionsFromFile (CompDisplay *d, } else { - /* option not found, it might be an action option */ - actionTmp = strchr (optionName, '_'); - if (actionTmp) + // an action has several values, so we need + // to read more then one line into our buffer + continueReading = parseAction(d, optionName, optionValue, &action); + } + + // parsing action finished, write it + if (action.realOptionName && + !continueReading) + { + o = compFindOption (option, nOption, action.realOptionName, 0); + value = o->value; + + value.action.type = action.a.type; + value.action.key = action.a.key; + value.action.button = action.a.button; + value.action.bell = action.a.bell; + value.action.edgeMask = action.a.edgeMask; + value.action.edgeButton = action.a.edgeButton; + + if (plugin) { - actionTmp++; /* skip the _ */ - actionTest = strchr (actionTmp, '_'); - while (actionTest) - { - actionTmp++; - actionTest = strchr (actionTmp, '_'); - if (actionTest) - actionTmp = strchr (actionTmp, '_'); - } + if (s) + status = (*s->setScreenOptionForPlugin) (s, plugin, action.realOptionName, &value); + else + status = (*d->setDisplayOptionForPlugin) (d, plugin, action.realOptionName, &value); + } + else + { + if (s) + status = (*s->setScreenOption) (s, action.realOptionName, &value); + else + status = (*d->setDisplayOption) (d, action.realOptionName, &value); + } - if (actionTmp) - { - /* find the real option */ - int len = strlen (optionName) - strlen (actionTmp) - 1; - realOption = realloc (realOption, sizeof (char) * len); - strncpy (realOption, optionName, len); - realOption[len] = '\0'; - o = compFindOption (option, nOption, realOption, 0); - - if (o) - { - value = o->value; - - if (strcmp (actionTmp, "key") == 0) - { - if (!*optionValue || - strcasecmp (optionValue, "disabled") == 0) - { - actionProxy.type &= ~CompBindingTypeKey; - } - else - { - if (stringToKeyBinding (d, - optionValue, - &actionProxy.key)) - actionProxy.type |= CompBindingTypeKey; - } - actionProxy.nSet++; - } - else if (strcmp (actionTmp, "button") == 0) - { - if (!*optionValue || - strcasecmp (optionValue, "disabled") == 0) - { - actionProxy.type &= ~CompBindingTypeButton; - } - else - { - if (stringToButtonBinding (d, optionValue, - &actionProxy.button)) - actionProxy.type |= CompBindingTypeButton; - } - actionProxy.nSet++; - } - else if (strcmp (actionTmp, "edge") == 0) - { - actionProxy.edgeMask = 0; - if (optionValue[0] != '\0') - { - int i, e; - CompListValue edges; - - if (csvToList (optionValue, &edges, CompOptionTypeString)) - { - for (i = 0; i < SCREEN_EDGE_NUM; i++) - { - for (e=0; e= N_ACTION_PARTS) - { - value.action.type = actionProxy.type; - value.action.key = actionProxy.key; - value.action.button = actionProxy.button; - value.action.bell = actionProxy.bell; - value.action.edgeMask = actionProxy.edgeMask; - value.action.edgeButton = actionProxy.edgeButton; - - if (plugin) - { - if (s) - status = (*s->setScreenOptionForPlugin) (s, - plugin, - realOption, - &value); - else - status = (*d->setDisplayOptionForPlugin) (d, plugin, - realOption, - &value); - } - else - { - if (s) - status = (*s->setScreenOption) (s, realOption, &value); - else - status = (*d->setDisplayOption) (d, realOption, &value); - } - - initActionProxy (&actionProxy); - } - } - } + // clear the buffer + free(action.realOptionName); + action.realOptionName = NULL; + + // we missed the current line because we exited it in the first call + if (!o && action.valueMasks == ACTION_VALUES_ALL) { + action.valueMasks = 0; + parseAction(d, optionName, optionValue, &action); + } else { + action.valueMasks = 0; } } } - } - if (optionName) - free (optionName); - if (optionValue) - free (optionValue); - if (realOption) - free (realOption); + // clear up + if (optionName) + free (optionName); + if (optionValue) + free (optionValue); + continueReading = FALSE; + } return TRUE; }