You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1153 lines
24 KiB

/*
* Copyright © 2007 Mike Dransfield
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Mike Dransfield not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
* Mike Dransfield makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* MIKE DRANSFIELD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL MIKE DRANSFIELD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Mike Dransfield <mike@blueroot.co.uk>
*
* Some code taken from gconf.c by :
* David Reveman <davidr@novell.com>
*/
#define _GNU_SOURCE /* for asprintf */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <compiz-core.h>
#define DEFAULT_PLUGINS "ini,inotify,png,decoration,move,resize,switcher"
#define NUM_DEFAULT_PLUGINS 7
#define MAX_OPTION_LENGTH 1024
#define HOME_OPTIONDIR ".compiz/options"
#define CORE_NAME "general"
#define FILE_SUFFIX ".conf"
#define GET_INI_CORE(c) \
((IniCore *) (c)->base.privates[corePrivateIndex].ptr)
#define INI_CORE(c) \
IniCore *ic = GET_INI_CORE (c)
#define NUM_OPTIONS(s) (sizeof ((s)->opt) / sizeof (CompOption))
static int corePrivateIndex;
static CompMetadata iniMetadata;
static Bool iniSaveOptions (CompObject *object,
const char *plugin);
/*
* IniFileData
*/
typedef struct _IniFileData IniFileData;
struct _IniFileData {
char *filename;
char *plugin;
int screen;
Bool blockWrites;
Bool blockReads;
IniFileData *next;
IniFileData *prev;
};
/*
* IniCore
*/
typedef struct _IniCore {
CompFileWatchHandle directoryWatch;
IniFileData *fileData;
InitPluginForObjectProc initPluginForObject;
SetOptionForPluginProc setOptionForPlugin;
} IniCore;
static IniFileData *
iniGetFileDataFromFilename (const char *filename)
{
int len, i;
int pluginSep = 0, screenSep = 0;
char *pluginStr, *screenStr;
IniFileData *fd;
INI_CORE (&core);
if (!filename)
return NULL;
len = strlen (filename);
if (len < (strlen(FILE_SUFFIX) + 2))
return NULL;
if ((filename[0]=='.') || (filename[len-1]=='~'))
return NULL;
for (fd = ic->fileData; fd; fd = fd->next)
if (strcmp (fd->filename, filename) == 0)
return fd;
for (i=0; i<len; i++)
{
if (filename[i] == '-')
{
if (!pluginSep)
pluginSep = i-1;
else
return NULL; /*found a second dash */
}
else if (filename[i] == '.')
{
if (!screenSep)
screenSep = i-1;
else
return NULL; /*found a second dot */
}
}
if (!pluginSep || !screenSep)
return NULL;
/* If we get here then there is no fd in the display variable */
IniFileData *newFd = malloc (sizeof (IniFileData));
if (!newFd)
return NULL;
/* fd is NULL here, see condition "fd" in first for-loop */
/* if (fd)
fd->next = newFd;
else
*/
ic->fileData = newFd;
newFd->prev = fd;
newFd->next = NULL;
newFd->filename = strdup (filename);
pluginStr = calloc (1, sizeof (char) * pluginSep + 2);
if (!pluginStr)
return NULL;
screenStr = calloc (1, sizeof (char) * (screenSep - pluginSep));
if (!screenStr) {
free(pluginStr);
return NULL;
}
strncpy (pluginStr, filename, pluginSep + 1);
strncpy (screenStr, &filename[pluginSep+2], (screenSep - pluginSep) - 1);
if (strcmp (pluginStr, CORE_NAME) == 0)
newFd->plugin = NULL;
else
newFd->plugin = strdup (pluginStr);
if (strcmp (screenStr, "allscreens") == 0)
newFd->screen = -1;
else
newFd->screen = atoi (&screenStr[6]);
newFd->blockReads = FALSE;
newFd->blockWrites = FALSE;
free (pluginStr);
free (screenStr);
return newFd;
}
static char *
iniOptionValueToString (CompDisplay *d, CompOptionValue *value, CompOptionType type)
{
char tmp[MAX_OPTION_LENGTH];
tmp[0] = '\0';
switch (type)
{
case CompOptionTypeBool:
case CompOptionTypeInt:
snprintf(tmp, 256, "%i", (int)value->i);
break;
case CompOptionTypeFloat:
snprintf(tmp, 256, "%f", value->f);
break;
case CompOptionTypeString:
snprintf (tmp, MAX_OPTION_LENGTH, "%s", strdup (value->s));
break;
case CompOptionTypeColor:
snprintf (tmp, 10, "%s", colorToString (value->c));
break;
case CompOptionTypeKey:
return keyActionToString (d, &value->action);
break;
case CompOptionTypeButton:
return buttonActionToString (d, &value->action);
break;
case CompOptionTypeEdge:
return edgeMaskToString (value->action.edgeMask);
break;
case CompOptionTypeBell:
snprintf (tmp, 256, "%i", (int) value->action.bell);
break;
case CompOptionTypeMatch:
{
char *s = matchToString (&value->match);
snprintf (tmp, MAX_OPTION_LENGTH, "%s", s);
free(s);
}
break;
default:
break;
}
return strdup (tmp);
}
static Bool
iniGetHomeDir (char **homeDir)
{
char *home = NULL, *tmp;
home = getenv ("HOME");
if (home)
{
tmp = malloc (strlen (home) + strlen (HOME_OPTIONDIR) + 2);
if (tmp)
{
sprintf (tmp, "%s/%s", home, HOME_OPTIONDIR);
(*homeDir) = strdup (tmp);
free (tmp);
return TRUE;
}
}
return FALSE;
}
static Bool
iniGetFilename (CompObject *object,
const char *plugin,
char **filename)
{
int len;
char *fn = NULL, *screenStr;
screenStr = malloc (sizeof(char) * 12);
if (!screenStr)
return FALSE;
if (object->type == COMP_OBJECT_TYPE_SCREEN)
{
CORE_SCREEN (object);
snprintf (screenStr, 12, "screen%d", s->screenNum);
}
else
{
strncpy (screenStr, "allscreens", 12);
}
len = strlen (screenStr) + strlen (FILE_SUFFIX) + 2;
if (plugin)
len += strlen (plugin);
else
len += strlen (CORE_NAME);
fn = malloc (sizeof (char) * len);
if (fn)
{
sprintf (fn, "%s-%s%s",
plugin ? plugin : CORE_NAME, screenStr, FILE_SUFFIX);
*filename = strdup (fn);
free (screenStr);
free (fn);
return TRUE;
}
free (screenStr);
return FALSE;
}
static Bool
iniParseLine (char *line, char **optionName, char **optionValue)
{
char *splitPos;
int length, optionLength;
if (line[0] == '\0' || line[0] == '\n')
return FALSE;
splitPos = strchr (line, '=');
if (!splitPos)
return FALSE;
length = strlen (line) - strlen (splitPos);
*optionName = malloc (sizeof (char) * (length + 1));
if (*optionName)
{
strncpy (*optionName, line, length);
(*optionName)[length] = 0;
}
splitPos++;
optionLength = strlen (splitPos);
if (splitPos[optionLength-1] == '\n')
optionLength--;
*optionValue = malloc (sizeof (char) * (optionLength + 1));
if (*optionValue)
{
strncpy (*optionValue, splitPos, optionLength);
(*optionValue)[optionLength] = 0;
}
return TRUE;
}
static Bool
csvToList (CompDisplay *d, char *csv, CompListValue *list, CompOptionType type)
{
char *splitStart = NULL;
char *splitEnd = NULL;
char *item = NULL;
int itemLength, count, i;
if (csv[0] == '\0')
{
list->nValue = 0;
return FALSE;
}
int length = strlen (csv);
count = 1;
for (i = 0; csv[i] != '\0'; i++)
if (csv[i] == ',' && i != length-1)
count++;
splitStart = csv;
list->value = malloc (sizeof (CompOptionValue) * count);
list->nValue = count;
if (list->value)
{
for (i = 0; i < count; i++)
{
splitEnd = strchr (splitStart, ',');
if (splitEnd)
{
itemLength = strlen (splitStart) - strlen (splitEnd);
item = malloc (sizeof (char) * (itemLength + 1));
if (item)
{
strncpy (item, splitStart, itemLength);
item[itemLength] = 0;
}
}
else // last value
{
item = strdup (splitStart);
}
if (!item) {
compLogMessage ("ini", CompLogLevelError, "Not enough memory");
list->nValue = 0;
return FALSE;
}
switch (type)
{
case CompOptionTypeString:
list->value[i].s = strdup (item);
break;
case CompOptionTypeBool:
list->value[i].b = item[0] ? (Bool) atoi (item) : FALSE;
break;
case CompOptionTypeInt:
list->value[i].i = item[0] ? atoi (item) : 0;
break;
case CompOptionTypeFloat:
list->value[i].f = item[0] ? atof (item) : 0.0f;
break;
case CompOptionTypeKey:
stringToKeyAction (d, item, &list->value[i].action);
break;
case CompOptionTypeButton:
stringToButtonAction (d, item, &list->value[i].action);
break;
case CompOptionTypeEdge:
list->value[i].action.edgeMask = stringToEdgeMask (item);
break;
case CompOptionTypeBell:
list->value[i].action.bell = (Bool) atoi (item);
break;
case CompOptionTypeMatch:
matchInit (&list->value[i].match);
matchAddFromString (&list->value[i].match, item);
break;
default:
break;
}
splitStart = ++splitEnd;
if (item)
{
free (item);
item = NULL;
}
}
}
return TRUE;
}
static Bool
iniMakeDirectories (void)
{
char *homeDir;
if (iniGetHomeDir (&homeDir))
{
mkdir (homeDir, 0700);
free (homeDir);
return TRUE;
}
else
{
compLogMessage ("ini", CompLogLevelWarn,
"Could not get HOME environmental variable");
return FALSE;
}
}
static Bool
iniLoadOptionsFromFile (FILE *optionFile,
CompObject *object,
const char *plugin,
Bool *reSave)
{
CompOption *option = NULL, *o;
CompPlugin *p = NULL;
CompOptionValue value;
char *optionName = NULL, *optionValue = NULL;
char tmp[MAX_OPTION_LENGTH];
int nOption, nOptionRead = 0;
Bool status = FALSE, hasValue = FALSE;
if (plugin)
{
p = findActivePlugin (plugin);
if (!p)
{
compLogMessage ("ini", CompLogLevelWarn,
"Could not find running plugin " \
"%s (iniLoadOptionsFromFile)", plugin);
return FALSE;
}
}
else
{
return FALSE;
}
if (p->vTable->getObjectOptions)
option = (*p->vTable->getObjectOptions) (p, object, &nOption);
while (fgets (tmp, MAX_OPTION_LENGTH, optionFile) != NULL)
{
status = FALSE;
if (!iniParseLine (tmp, &optionName, &optionValue))
{
compLogMessage ("ini", CompLogLevelWarn,
"Ignoring line '%s' in %s", tmp, plugin);
continue;
}
if (option)
{
o = compFindOption (option, nOption, optionName, 0);
if (o)
{
value = o->value;
switch (o->type)
{
case CompOptionTypeBool:
hasValue = TRUE;
value.b = (Bool) atoi (optionValue);
break;
case CompOptionTypeInt:
hasValue = TRUE;
value.i = atoi (optionValue);
break;
case CompOptionTypeFloat:
hasValue = TRUE;
value.f = atof (optionValue);
break;
case CompOptionTypeString:
hasValue = TRUE;
value.s = strdup (optionValue);
break;
case CompOptionTypeColor:
hasValue = stringToColor (optionValue, value.c);
break;
case CompOptionTypeKey:
hasValue = TRUE;
stringToKeyAction (GET_CORE_DISPLAY (object),
optionValue, &value.action);
break;
case CompOptionTypeButton:
hasValue = TRUE;
stringToButtonAction (GET_CORE_DISPLAY (object),
optionValue, &value.action);
break;
case CompOptionTypeEdge:
hasValue = TRUE;
value.action.edgeMask = stringToEdgeMask (optionValue);
break;
case CompOptionTypeBell:
hasValue = TRUE;
value.action.bell = (Bool) atoi (optionValue);
break;
case CompOptionTypeList:
hasValue = csvToList (GET_CORE_DISPLAY (object),
optionValue,
&value.list, value.list.type);
break;
case CompOptionTypeMatch:
hasValue = TRUE;
matchInit (&value.match);
matchAddFromString (&value.match, optionValue);
break;
default:
break;
}
if (hasValue)
{
status = (*core.setOptionForPlugin) (object,
plugin,
optionName,
&value);
if (o->type == CompOptionTypeMatch)
{
matchFini (&value.match);
}
}
nOptionRead++;
}
}
/* clear up */
if (optionName)
free (optionName);
if (optionValue)
free (optionValue);
}
if (nOption != nOptionRead)
{
*reSave = TRUE;
}
return TRUE;
}
static Bool
iniSaveOptions (CompObject *object,
const char *plugin)
{
CompOption *option = NULL;
int nOption = 0;
char *filename, *directory, *fullPath, *strVal = NULL;
if (plugin)
{
CompPlugin *p;
p = findActivePlugin (plugin);
if (!p)
return FALSE;
option = (*p->vTable->getObjectOptions) (p, object, &nOption);
}
else
{
return FALSE;
}
if (!option)
return FALSE;
if (!iniGetFilename (object, plugin, &filename))
return FALSE;
IniFileData *fileData;
fileData = iniGetFileDataFromFilename (filename);
if (!fileData || (fileData && fileData->blockWrites))
{
free (filename);
return FALSE;
}
if (!iniGetHomeDir (&directory))
return FALSE;
fullPath = malloc (sizeof (char) * (strlen (filename) + strlen (directory) + 2));
if (!fullPath)
{
free (filename);
free (directory);
return FALSE;
}
sprintf (fullPath, "%s/%s", directory, filename);
FILE *optionFile = fopen (fullPath, "w");
if (!optionFile && iniMakeDirectories ())
optionFile = fopen (fullPath, "w");
if (!optionFile)
{
compLogMessage ("ini", CompLogLevelError,
"Failed to write to %s, check you " \
"have the correct permissions", fullPath);
free (filename);
free (directory);
free (fullPath);
return FALSE;
}
fileData->blockReads = TRUE;
Bool status, firstInList;
while (nOption--)
{
status = FALSE;
int i;
switch (option->type)
{
case CompOptionTypeBool:
case CompOptionTypeInt:
case CompOptionTypeFloat:
case CompOptionTypeString:
case CompOptionTypeColor:
case CompOptionTypeKey:
case CompOptionTypeButton:
case CompOptionTypeEdge:
case CompOptionTypeBell:
case CompOptionTypeMatch:
strVal = iniOptionValueToString (GET_CORE_DISPLAY (object),
&option->value, option->type);
if (strVal)
{
fprintf (optionFile, "%s=%s\n", option->name, strVal);
free (strVal);
}
else
fprintf (optionFile, "%s=\n", option->name);
break;
case CompOptionTypeList:
firstInList = TRUE;
switch (option->value.list.type)
{
case CompOptionTypeBool:
case CompOptionTypeInt:
case CompOptionTypeFloat:
case CompOptionTypeString:
case CompOptionTypeColor:
case CompOptionTypeMatch:
{
int stringLen = MAX_OPTION_LENGTH * option->value.list.nValue;
char *itemVal;
strVal = malloc (sizeof(char) * stringLen);
if (!strVal) {
fclose(optionFile);
free(fullPath);
return FALSE;
}
strcpy (strVal, "");
firstInList = TRUE;
for (i = 0; i < option->value.list.nValue; i++)
{
itemVal =
iniOptionValueToString (GET_CORE_DISPLAY (object),
&option->value.list.value[i],
option->value.list.type);
if (!firstInList)
strncat (strVal, ",", stringLen);
firstInList = FALSE;
if (itemVal)
{
strncat (strVal, itemVal, stringLen);
free (itemVal);
}
}
fprintf (optionFile, "%s=%s\n", option->name, strVal);
free (strVal);
break;
}
default:
compLogMessage ("ini", CompLogLevelWarn,
"Unknown list option type %d, %s\n",
option->value.list.type,
optionTypeToString (option->value.list.type));
break;
}
break;
default:
break;
}
option++;
}
fileData->blockReads = FALSE;
fclose (optionFile);
free (filename);
free (directory);
free (fullPath);
return TRUE;
}
static Bool
iniLoadOptions (CompObject *object,
const char *plugin)
{
char *filename, *directory, *fullPath;
FILE *optionFile;
Bool loadRes, reSave = FALSE;
IniFileData *fileData;
filename = directory = fullPath = NULL;
optionFile = NULL;
fileData = NULL;
if (!iniGetFilename (object, plugin, &filename))
return FALSE;
fileData = iniGetFileDataFromFilename (filename);
if (!fileData || (fileData && fileData->blockReads))
{
free(filename);
return FALSE;
}
if (!iniGetHomeDir (&directory))
{
free (filename);
return FALSE;
}
fullPath = malloc (sizeof (char) * (strlen (filename) + strlen (directory) + 2));
if (!fullPath)
{
free (filename);
free (directory);
return FALSE;
}
sprintf(fullPath, "%s/%s", directory, filename);
optionFile = fopen (fullPath, "r");
if (!optionFile && iniMakeDirectories ())
optionFile = fopen (fullPath, "r");
if (!optionFile)
{
if (!plugin && object->type == COMP_OBJECT_TYPE_DISPLAY)
{
CompOptionValue value;
value.list.value = malloc (NUM_DEFAULT_PLUGINS * sizeof (CompListValue));
if (!value.list.value)
{
free (filename);
free (directory);
free (fullPath);
return FALSE;
}
if (!csvToList (GET_CORE_DISPLAY (object), DEFAULT_PLUGINS,
&value.list,
CompOptionTypeString))
{
free (filename);
free (directory);
free (fullPath);
return FALSE;
}
value.list.type = CompOptionTypeString;
compLogMessage ("ini", CompLogLevelWarn,
"Could not open main display config file %s",
fullPath);
compLogMessage ("ini", CompLogLevelWarn,
"Loading default plugins (%s)", DEFAULT_PLUGINS);
(*core.setOptionForPlugin) (object,
"core", "active_plugins",
&value);
free (value.list.value);
fileData->blockWrites = FALSE;
iniSaveOptions (object, plugin);
fileData->blockWrites = TRUE;
optionFile = fopen (fullPath, "r");
if (!optionFile)
{
free (filename);
free (directory);
free (fullPath);
return FALSE;
}
}
else
{
compLogMessage ("ini", CompLogLevelWarn,
"Could not open config file %s - "
"using defaults for %s",
fullPath, plugin ? plugin : "core");
fileData->blockWrites = FALSE;
iniSaveOptions (object, plugin);
fileData->blockWrites = TRUE;
optionFile = fopen (fullPath, "r");
if (!optionFile)
{
free (filename);
free (directory);
free (fullPath);
return FALSE;
}
}
}
fileData->blockWrites = TRUE;
loadRes = iniLoadOptionsFromFile (optionFile, object, plugin, &reSave);
fileData->blockWrites = FALSE;
fclose (optionFile);
if (loadRes && reSave)
{
fileData->blockReads = TRUE;
iniSaveOptions (object, plugin);
fileData->blockReads = FALSE;
}
free (filename);
free (directory);
free (fullPath);
return TRUE;
}
/* MULTIDPYERROR: only works with one or less displays present */
/* OBJECTOPTION: only display and screen options are supported */
static void
iniFileModified (const char *name,
void *closure)
{
IniFileData *fd;
fd = iniGetFileDataFromFilename (name);
if (fd && core.displays)
{
if (fd->screen < 0)
{
iniLoadOptions (&core.displays->base, fd->plugin);
}
else
{
CompScreen *s;
for (s = core.displays->screens; s; s = s->next)
if (s->screenNum == fd->screen)
break;
if (s)
iniLoadOptions (&s->base, fd->plugin);
}
}
}
static void
iniFreeFileData (void)
{
IniFileData *fd, *tmp;
INI_CORE (&core);
fd = ic->fileData;
while (fd)
{
tmp = fd;
fd = fd->next;
free (tmp);
}
}
/*
CORE FUNCTIONS
*/
static Bool
iniInitPluginForDisplay (CompPlugin *p,
CompDisplay *d)
{
iniLoadOptions (&d->base, p->vTable->name);
return TRUE;
}
static Bool
iniInitPluginForScreen (CompPlugin *p,
CompScreen *s)
{
iniLoadOptions (&s->base, p->vTable->name);
return TRUE;
}
static CompBool
iniInitPluginForObject (CompPlugin *p,
CompObject *o)
{
CompBool status;
INI_CORE (&core);
UNWRAP (ic, &core, initPluginForObject);
status = (*core.initPluginForObject) (p, o);
WRAP (ic, &core, initPluginForObject, iniInitPluginForObject);
if (status && p->vTable->getObjectOptions)
{
static InitPluginForObjectProc dispTab[] = {
(InitPluginForObjectProc) 0, /* InitPluginForCore */
(InitPluginForObjectProc) iniInitPluginForDisplay,
(InitPluginForObjectProc) iniInitPluginForScreen
};
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
}
return status;
}
static CompBool
iniSetOptionForPlugin (CompObject *object,
const char *plugin,
const char *name,
CompOptionValue *value)
{
CompBool status;
INI_CORE (&core);
UNWRAP (ic, &core, setOptionForPlugin);
status = (*core.setOptionForPlugin) (object, plugin, name, value);
WRAP (ic, &core, setOptionForPlugin, iniSetOptionForPlugin);
if (status)
{
CompPlugin *p;
p = findActivePlugin (plugin);
if (p && p->vTable->getObjectOptions)
iniSaveOptions (object, plugin);
}
return status;
}
static Bool
iniInitCore (CompPlugin *p,
CompCore *c)
{
IniCore *ic;
char *homeDir;
if (!checkPluginABI ("core", CORE_ABIVERSION))
return FALSE;
ic = malloc (sizeof (IniCore));
if (!ic)
return FALSE;
ic->fileData = NULL;
ic->directoryWatch = 0;
if (iniGetHomeDir (&homeDir))
{
ic->directoryWatch = addFileWatch (homeDir,
NOTIFY_DELETE_MASK |
NOTIFY_CREATE_MASK |
NOTIFY_MODIFY_MASK,
iniFileModified, 0);
free (homeDir);
}
WRAP (ic, c, initPluginForObject, iniInitPluginForObject);
WRAP (ic, c, setOptionForPlugin, iniSetOptionForPlugin);
c->base.privates[corePrivateIndex].ptr = ic;
return TRUE;
}
static void
iniFiniCore (CompPlugin *p,
CompCore *c)
{
INI_CORE (c);
UNWRAP (ic, c, initPluginForObject);
UNWRAP (ic, c, setOptionForPlugin);
if (ic->directoryWatch)
removeFileWatch (ic->directoryWatch);
iniFreeFileData ();
free (ic);
}
static Bool
iniInitDisplay (CompPlugin *p, CompDisplay *d)
{
iniLoadOptions (&d->base, NULL);
return TRUE;
}
static Bool
iniInitScreen (CompPlugin *p, CompScreen *s)
{
iniLoadOptions (&s->base, NULL);
return TRUE;
}
static CompBool
iniInitObject (CompPlugin *p,
CompObject *o)
{
static InitPluginObjectProc dispTab[] = {
(InitPluginObjectProc) iniInitCore,
(InitPluginObjectProc) iniInitDisplay,
(InitPluginObjectProc) iniInitScreen
};
RETURN_DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), TRUE, (p, o));
}
static void
iniFiniObject (CompPlugin *p,
CompObject *o)
{
static FiniPluginObjectProc dispTab[] = {
(FiniPluginObjectProc) iniFiniCore
};
DISPATCH (o, dispTab, ARRAY_SIZE (dispTab), (p, o));
}
static Bool
iniInit (CompPlugin *p)
{
if (!compInitPluginMetadataFromInfo (&iniMetadata, p->vTable->name,
0, 0, 0, 0))
return FALSE;
corePrivateIndex = allocateCorePrivateIndex ();
if (corePrivateIndex < 0)
{
compFiniMetadata (&iniMetadata);
return FALSE;
}
compAddMetadataFromFile (&iniMetadata, p->vTable->name);
return TRUE;
}
static void
iniFini (CompPlugin *p)
{
freeCorePrivateIndex (corePrivateIndex);
}
static CompMetadata *
iniGetMetadata (CompPlugin *plugin)
{
return &iniMetadata;
}
CompPluginVTable iniVTable = {
"ini",
iniGetMetadata,
iniInit,
iniFini,
iniInitObject,
iniFiniObject,
0, /* GetObjectOptions */
0 /* SetObjectOption */
};
CompPluginVTable *
getCompPluginInfo20070830 (void)
{
return &iniVTable;
}