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.

1468 lines
31 KiB

/*
* Copyright © 2007 Dennis Kasprzyk
* Copyright © 2007 Novell, Inc.
*
* 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
* Dennis Kasprzyk not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior permission.
* Dennis Kasprzyk makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
* DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
* NO EVENT SHALL DENNIS KASPRZYK 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.
*
* Authors: Dennis Kasprzyk <onestone@deltatauchi.de>
* David Reveman <davidr@novell.com>
*/
#include <string.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <locale.h>
#include <compiz-core.h>
#define HOME_METADATADIR ".compiz/metadata"
#define EXTENSION ".xml"
Bool
compInitMetadata (CompMetadata *metadata)
{
metadata->path = strdup ("core");
if (!metadata->path)
return FALSE;
metadata->doc = NULL;
metadata->nDoc = 0;
return TRUE;
}
Bool
compInitPluginMetadata (CompMetadata *metadata,
const char *plugin)
{
char str[1024];
snprintf (str, 1024, "plugin[@name=\"%s\"]", plugin);
metadata->path = strdup (str);
if (!metadata->path)
return FALSE;
metadata->doc = NULL;
metadata->nDoc = 0;
return TRUE;
}
void
compFiniMetadata (CompMetadata *metadata)
{
int i;
for (i = 0; i < metadata->nDoc; i++)
xmlFreeDoc (metadata->doc[i]);
if (metadata->doc)
free (metadata->doc);
free (metadata->path);
}
static xmlDoc *
readXmlFile (const char *path,
const char *name)
{
char *file;
int length = strlen (name) + strlen (EXTENSION) + 1;
xmlDoc *doc = NULL;
FILE *fp;
if (path)
length += strlen (path) + 1;
file = malloc (length);
if (!file)
return NULL;
if (path)
sprintf (file, "%s/%s%s", path, name, EXTENSION);
else
sprintf (file, "%s%s", name, EXTENSION);
fp = fopen (file, "r");
if (!fp)
{
free (file);
return NULL;
}
fclose (fp);
doc = xmlReadFile (file, NULL, 0);
free (file);
return doc;
}
static Bool
addMetadataFromFilename (CompMetadata *metadata,
const char *path,
const char *file)
{
xmlDoc **d, *doc;
doc = readXmlFile (path, file);
if (!doc)
return FALSE;
d = realloc (metadata->doc, (metadata->nDoc + 1) * sizeof (xmlDoc *));
if (!d)
{
xmlFreeDoc (doc);
return FALSE;
}
d[metadata->nDoc++] = doc;
metadata->doc = d;
return TRUE;
}
Bool
compAddMetadataFromFile (CompMetadata *metadata,
const char *file)
{
char *home;
Bool status = FALSE;
home = getenv ("HOME");
if (home)
{
char *path;
path = malloc (strlen (home) + strlen (HOME_METADATADIR) + 2);
if (path)
{
sprintf (path, "%s/%s", home, HOME_METADATADIR);
status |= addMetadataFromFilename (metadata, path, file);
free (path);
}
}
status |= addMetadataFromFilename (metadata, METADATADIR, file);
if (!status)
{
compLogMessage ("core", CompLogLevelWarn,
"Unable to parse XML metadata from file \"%s%s\"",
file, EXTENSION);
return FALSE;
}
return TRUE;
}
Bool
compAddMetadataFromString (CompMetadata *metadata,
const char *string)
{
xmlDoc **d, *doc;
doc = xmlReadMemory (string, strlen (string), NULL, NULL, 0);
if (!doc)
{
compLogMessage ("core", CompLogLevelWarn,
"Unable to parse XML metadata");
return FALSE;
}
d = realloc (metadata->doc, (metadata->nDoc + 1) * sizeof (xmlDoc *));
if (!d)
{
xmlFreeDoc (doc);
return FALSE;
}
d[metadata->nDoc++] = doc;
metadata->doc = d;
return TRUE;
}
Bool
compAddMetadataFromIO (CompMetadata *metadata,
xmlInputReadCallback ioread,
xmlInputCloseCallback ioclose,
void *ioctx)
{
xmlDoc **d, *doc;
doc = xmlReadIO (ioread, ioclose, ioctx, NULL, NULL, 0);
if (!doc)
{
compLogMessage ("core", CompLogLevelWarn,
"Unable to parse XML metadata");
return FALSE;
}
d = realloc (metadata->doc, (metadata->nDoc + 1) * sizeof (xmlDoc *));
if (!d)
{
xmlFreeDoc (doc);
return FALSE;
}
d[metadata->nDoc++] = doc;
metadata->doc = d;
return TRUE;
}
typedef struct _CompIOCtx {
int offset;
const char *name;
const CompMetadataOptionInfo *displayOInfo;
int nDisplayOInfo;
const CompMetadataOptionInfo *screenOInfo;
int nScreenOInfo;
} CompIOCtx;
static int
readPluginXmlCallback (void *context,
char *buffer,
int length)
{
CompIOCtx *ctx = (CompIOCtx *) context;
int offset = ctx->offset;
int i, j;
i = compReadXmlChunk ("<compiz><plugin name=\"", &offset, buffer, length);
i += compReadXmlChunk (ctx->name, &offset, buffer + i, length - i);
i += compReadXmlChunk ("\">", &offset, buffer + i, length - i);
if (ctx->nDisplayOInfo)
{
i += compReadXmlChunk ("<display>", &offset, buffer + i, length - i);
for (j = 0; j < ctx->nDisplayOInfo; j++)
i += compReadXmlChunkFromMetadataOptionInfo (&ctx->displayOInfo[j],
&offset,
buffer + i,
length - i);
i += compReadXmlChunk ("</display>", &offset, buffer + i, length - i);
}
if (ctx->nScreenOInfo)
{
i += compReadXmlChunk ("<screen>", &offset, buffer + i, length - i);
for (j = 0; j < ctx->nScreenOInfo; j++)
i += compReadXmlChunkFromMetadataOptionInfo (&ctx->screenOInfo[j],
&offset,
buffer + i,
length - i);
i += compReadXmlChunk ("</screen>", &offset, buffer + i, length - i);
}
i += compReadXmlChunk ("</plugin></compiz>", &offset, buffer + i,
length - i);
if (!offset && length > i)
buffer[i++] = '\0';
ctx->offset += i;
return i;
}
Bool
compInitPluginMetadataFromInfo (CompMetadata *metadata,
const char *plugin,
const CompMetadataOptionInfo *displayOptionInfo,
int nDisplayOptionInfo,
const CompMetadataOptionInfo *screenOptionInfo,
int nScreenOptionInfo)
{
if (!compInitPluginMetadata (metadata, plugin))
return FALSE;
if (nDisplayOptionInfo || nScreenOptionInfo)
{
CompIOCtx ctx;
ctx.offset = 0;
ctx.name = plugin;
ctx.displayOInfo = displayOptionInfo;
ctx.nDisplayOInfo = nDisplayOptionInfo;
ctx.screenOInfo = screenOptionInfo;
ctx.nScreenOInfo = nScreenOptionInfo;
if (!compAddMetadataFromIO (metadata,
readPluginXmlCallback, NULL,
(void *) &ctx))
{
compFiniMetadata (metadata);
return FALSE;
}
}
return TRUE;
}
typedef struct _CompXPath {
xmlXPathObjectPtr obj;
xmlXPathContextPtr ctx;
xmlDocPtr doc;
} CompXPath;
static Bool
initXPathFromMetadataPath (CompXPath *xPath,
CompMetadata *metadata,
const xmlChar *path)
{
xmlXPathObjectPtr obj;
xmlXPathContextPtr ctx;
int i;
for (i = 0; i < metadata->nDoc; i++)
{
ctx = xmlXPathNewContext (metadata->doc[i]);
if (ctx)
{
obj = xmlXPathEvalExpression (path, ctx);
if (obj)
{
if (obj->nodesetval && obj->nodesetval->nodeNr)
{
xPath->ctx = ctx;
xPath->obj = obj;
xPath->doc = metadata->doc[i];
return TRUE;
}
xmlXPathFreeObject (obj);
}
xmlXPathFreeContext (ctx);
}
}
return FALSE;
}
static Bool
initXPathFromMetadataPathElement (CompXPath *xPath,
CompMetadata *metadata,
const xmlChar *path,
const xmlChar *element)
{
char str[1024];
snprintf (str, 1024, "%s/%s", path, element);
return initXPathFromMetadataPath (xPath, metadata, BAD_CAST str);
}
static void
finiXPath (CompXPath *xPath)
{
xmlXPathFreeObject (xPath->obj);
xmlXPathFreeContext (xPath->ctx);
}
static CompOptionType
getOptionType (char *name)
{
static struct _TypeMap {
char *name;
CompOptionType type;
} map[] = {
{ "int", CompOptionTypeInt },
{ "float", CompOptionTypeFloat },
{ "string", CompOptionTypeString },
{ "color", CompOptionTypeColor },
{ "action", CompOptionTypeAction },
{ "key", CompOptionTypeKey },
{ "button", CompOptionTypeButton },
{ "edge", CompOptionTypeEdge },
{ "bell", CompOptionTypeBell },
{ "match", CompOptionTypeMatch },
{ "list", CompOptionTypeList }
};
int i;
for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
if (strcasecmp (name, map[i].name) == 0)
return map[i].type;
return CompOptionTypeBool;
}
static void
initBoolValue (CompOptionValue *v,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
v->b = FALSE;
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
if (strcasecmp ((char *) value, "true") == 0)
v->b = TRUE;
xmlFree (value);
}
}
static void
initIntValue (CompOptionValue *v,
CompOptionRestriction *r,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
v->i = (r->i.min + r->i.max) / 2;
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
int i = strtol ((char *) value, NULL, 0);
if (i >= r->i.min && i <= r->i.max)
v->i = i;
xmlFree (value);
}
}
static void
initFloatValue (CompOptionValue *v,
CompOptionRestriction *r,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
char *loc;
v->f = (r->f.min + r->f.max) / 2;
if (!doc)
return;
loc = setlocale (LC_NUMERIC, NULL);
setlocale (LC_NUMERIC, "C");
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
float f = strtod ((char *) value, NULL);
if (f >= r->f.min && f <= r->f.max)
v->f = f;
xmlFree (value);
}
setlocale (LC_NUMERIC, loc);
}
static void
initStringValue (CompOptionValue *v,
CompOptionRestriction *r,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
v->s = strdup ("");
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
free (v->s);
v->s = strdup ((char *) value);
xmlFree (value);
}
}
static void
initColorValue (CompOptionValue *v,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlNodePtr child;
v->c[0] = 0x0000;
v->c[1] = 0x0000;
v->c[2] = 0x0000;
v->c[3] = 0xffff;
if (!doc)
return;
for (child = node->xmlChildrenNode; child; child = child->next)
{
xmlChar *value;
int index;
if (!xmlStrcmp (child->name, BAD_CAST "red"))
index = 0;
else if (!xmlStrcmp (child->name, BAD_CAST "green"))
index = 1;
else if (!xmlStrcmp (child->name, BAD_CAST "blue"))
index = 2;
else if (!xmlStrcmp (child->name, BAD_CAST "alpha"))
index = 3;
else
continue;
value = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
if (value)
{
int color = strtol ((char *) value, NULL , 0);
v->c[index] = MAX (0, MIN (0xffff, color));
xmlFree (value);
}
}
}
static void
initActionValue (CompDisplay *d,
CompOptionValue *v,
CompActionState state,
xmlDocPtr doc,
xmlNodePtr node)
{
memset (&v->action, 0, sizeof (v->action));
v->action.state = state;
}
static void
initKeyValue (CompDisplay *d,
CompOptionValue *v,
CompActionState state,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
memset (&v->action, 0, sizeof (v->action));
v->action.state = state | CompActionStateInitKey;
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
char *binding = (char *) value;
if (strcasecmp (binding, "disabled") && *binding)
stringToKeyAction (d, binding, &v->action);
xmlFree (value);
}
if (state & CompActionStateAutoGrab)
{
CompScreen *s;
for (s = d->screens; s; s = s->next)
addScreenAction (s, &v->action);
}
}
static void
initButtonValue (CompDisplay *d,
CompOptionValue *v,
CompActionState state,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
memset (&v->action, 0, sizeof (v->action));
v->action.state = state | CompActionStateInitButton |
CompActionStateInitEdge;
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
char *binding = (char *) value;
if (strcasecmp (binding, "disabled") && *binding)
stringToButtonAction (d, binding, &v->action);
xmlFree (value);
}
if (state & CompActionStateAutoGrab)
{
CompScreen *s;
for (s = d->screens; s; s = s->next)
addScreenAction (s, &v->action);
}
}
static void
initEdgeValue (CompDisplay *d,
CompOptionValue *v,
CompActionState state,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlNodePtr child;
xmlChar *value;
memset (&v->action, 0, sizeof (v->action));
v->action.state = state | CompActionStateInitEdge;
if (!doc)
return;
for (child = node->xmlChildrenNode; child; child = child->next)
{
value = xmlGetProp (child, BAD_CAST "name");
if (value)
{
int i;
for (i = 0; i < SCREEN_EDGE_NUM; i++)
if (strcasecmp ((char *) value, edgeToString (i)) == 0)
v->action.edgeMask |= (1 << i);
xmlFree (value);
}
}
if (state & CompActionStateAutoGrab)
{
CompScreen *s;
for (s = d->screens; s; s = s->next)
addScreenAction (s, &v->action);
}
}
static void
initBellValue (CompDisplay *d,
CompOptionValue *v,
CompActionState state,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
memset (&v->action, 0, sizeof (v->action));
v->action.state = state | CompActionStateInitBell;
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
if (strcasecmp ((char *) value, "true") == 0)
v->action.bell = TRUE;
xmlFree (value);
}
}
static void
initMatchValue (CompDisplay *d,
CompOptionValue *v,
Bool helper,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlChar *value;
matchInit (&v->match);
if (!doc)
return;
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
if (value)
{
matchAddFromString (&v->match, (char *) value);
xmlFree (value);
}
if (!helper)
matchUpdate (d, &v->match);
}
static void
initListValue (CompDisplay *d,
CompOptionValue *v,
CompOptionRestriction *r,
CompActionState state,
Bool helper,
xmlDocPtr doc,
xmlNodePtr node)
{
xmlNodePtr child;
v->list.value = NULL;
v->list.nValue = 0;
if (!doc)
return;
for (child = node->xmlChildrenNode; child; child = child->next)
{
CompOptionValue *value;
if (xmlStrcmp (child->name, BAD_CAST "value"))
continue;
value = realloc (v->list.value,
sizeof (CompOptionValue) * (v->list.nValue + 1));
if (value)
{
switch (v->list.type) {
case CompOptionTypeBool:
initBoolValue (&value[v->list.nValue], doc, child);
break;
case CompOptionTypeInt:
initIntValue (&value[v->list.nValue], r, doc, child);
break;
case CompOptionTypeFloat:
initFloatValue (&value[v->list.nValue], r, doc, child);
break;
case CompOptionTypeString:
initStringValue (&value[v->list.nValue], r, doc, child);
break;
case CompOptionTypeColor:
initColorValue (&value[v->list.nValue], doc, child);
break;
case CompOptionTypeAction:
initActionValue (d, &value[v->list.nValue], state, doc, child);
break;
case CompOptionTypeKey:
initKeyValue (d, &value[v->list.nValue], state, doc, child);
break;
case CompOptionTypeButton:
initButtonValue (d, &value[v->list.nValue], state, doc, child);
break;
case CompOptionTypeEdge:
initEdgeValue (d, &value[v->list.nValue], state, doc, child);
break;
case CompOptionTypeBell:
initBellValue (d, &value[v->list.nValue], state, doc, child);
break;
case CompOptionTypeMatch:
initMatchValue (d, &value[v->list.nValue], helper, doc, child);
default:
break;
}
v->list.value = value;
v->list.nValue++;
}
}
}
static char *
stringFromMetadataPathElement (CompMetadata *metadata,
const char *path,
const char *element)
{
char str[1024];
snprintf (str, 1024, "%s/%s", path, element);
return compGetStringFromMetadataPath (metadata, str);
}
static Bool
boolFromMetadataPathElement (CompMetadata *metadata,
const char *path,
const char *element,
Bool defaultValue)
{
Bool value = FALSE;
char *str;
str = stringFromMetadataPathElement (metadata, path, element);
if (!str)
return defaultValue;
if (strcasecmp (str, "true") == 0)
value = TRUE;
free (str);
return value;
}
static void
initIntRestriction (CompMetadata *metadata,
CompOptionRestriction *r,
const char *path)
{
char *value;
r->i.min = MINSHORT;
r->i.max = MAXSHORT;
value = stringFromMetadataPathElement (metadata, path, "min");
if (value)
{
r->i.min = strtol ((char *) value, NULL, 0);
free (value);
}
value = stringFromMetadataPathElement (metadata, path, "max");
if (value)
{
r->i.max = strtol ((char *) value, NULL, 0);
free (value);
}
}
static void
initFloatRestriction (CompMetadata *metadata,
CompOptionRestriction *r,
const char *path)
{
char *value;
char *loc;
r->f.min = MINSHORT;
r->f.max = MAXSHORT;
r->f.precision = 0.1f;
loc = setlocale (LC_NUMERIC, NULL);
setlocale (LC_NUMERIC, "C");
value = stringFromMetadataPathElement (metadata, path, "min");
if (value)
{
r->f.min = strtod ((char *) value, NULL);
free (value);
}
value = stringFromMetadataPathElement (metadata, path, "max");
if (value)
{
r->f.max = strtod ((char *) value, NULL);
free (value);
}
value = stringFromMetadataPathElement (metadata, path, "precision");
if (value)
{
r->f.precision = strtod ((char *) value, NULL);
free (value);
}
setlocale (LC_NUMERIC, loc);
}
static void
initActionState (CompMetadata *metadata,
CompOptionType type,
CompActionState *state,
const char *path)
{
static struct _StateMap {
char *name;
CompActionState state;
} map[] = {
{ "key", CompActionStateInitKey },
{ "button", CompActionStateInitButton },
{ "bell", CompActionStateInitBell },
{ "edge", CompActionStateInitEdge },
{ "edgednd", CompActionStateInitEdgeDnd }
};
int i;
CompXPath xPath;
char *grab;
*state = CompActionStateAutoGrab;
grab = stringFromMetadataPathElement (metadata, path, "passive_grab");
if (grab)
{
if (strcmp (grab, "false") == 0)
*state = 0;
free (grab);
}
if (type == CompOptionTypeEdge)
{
char *noEdgeDelay;
noEdgeDelay = stringFromMetadataPathElement (metadata, path, "nodelay");
if (noEdgeDelay)
{
if (strcmp (noEdgeDelay, "true") == 0)
*state |= CompActionStateNoEdgeDelay;
free (noEdgeDelay);
}
}
if (!initXPathFromMetadataPathElement (&xPath, metadata, BAD_CAST path,
BAD_CAST "allowed"))
return;
for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
{
xmlChar *value;
value = xmlGetProp (*xPath.obj->nodesetval->nodeTab,
BAD_CAST map[i].name);
if (value)
{
if (xmlStrcmp (value, BAD_CAST "true") == 0)
*state |= map[i].state;
xmlFree (value);
}
}
finiXPath (&xPath);
}
static Bool
initOptionFromMetadataPath (CompDisplay *d,
CompMetadata *metadata,
CompOption *option,
const xmlChar *path)
{
CompXPath xPath, xDefaultPath;
xmlNodePtr node, defaultNode;
xmlDocPtr defaultDoc;
xmlChar *name, *type;
char *value;
CompActionState state = 0;
Bool helper = FALSE;
if (!initXPathFromMetadataPath (&xPath, metadata, path))
return FALSE;
node = *xPath.obj->nodesetval->nodeTab;
type = xmlGetProp (node, BAD_CAST "type");
if (type)
{
option->type = getOptionType ((char *) type);
xmlFree (type);
}
else
{
option->type = CompOptionTypeBool;
}
name = xmlGetProp (node, BAD_CAST "name");
option->name = strdup ((char *) name);
xmlFree (name);
if (initXPathFromMetadataPathElement (&xDefaultPath, metadata, path,
BAD_CAST "default"))
{
defaultDoc = xDefaultPath.doc;
defaultNode = *xDefaultPath.obj->nodesetval->nodeTab;
}
else
{
defaultDoc = NULL;
defaultNode = NULL;
}
switch (option->type) {
case CompOptionTypeBool:
initBoolValue (&option->value, defaultDoc, defaultNode);
break;
case CompOptionTypeInt:
initIntRestriction (metadata, &option->rest, (char *) path);
initIntValue (&option->value, &option->rest, defaultDoc, defaultNode);
break;
case CompOptionTypeFloat:
initFloatRestriction (metadata, &option->rest, (char *) path);
initFloatValue (&option->value, &option->rest, defaultDoc, defaultNode);
break;
case CompOptionTypeString:
initStringValue (&option->value, &option->rest,
defaultDoc, defaultNode);
break;
case CompOptionTypeColor:
initColorValue (&option->value, defaultDoc, defaultNode);
break;
case CompOptionTypeAction:
initActionState (metadata, option->type, &state, (char *) path);
initActionValue (d, &option->value, state, defaultDoc, defaultNode);
break;
case CompOptionTypeKey:
initActionState (metadata, option->type, &state, (char *) path);
initKeyValue (d, &option->value, state, defaultDoc, defaultNode);
break;
case CompOptionTypeButton:
initActionState (metadata, option->type, &state, (char *) path);
initButtonValue (d, &option->value, state, defaultDoc, defaultNode);
break;
case CompOptionTypeEdge:
initActionState (metadata, option->type, &state, (char *) path);
initEdgeValue (d, &option->value, state, defaultDoc, defaultNode);
break;
case CompOptionTypeBell:
initActionState (metadata, option->type, &state, (char *) path);
initBellValue (d, &option->value, state, defaultDoc, defaultNode);
break;
case CompOptionTypeMatch:
helper = boolFromMetadataPathElement (metadata, (char *) path, "helper",
FALSE);
initMatchValue (d, &option->value, helper, defaultDoc, defaultNode);
break;
case CompOptionTypeList:
value = stringFromMetadataPathElement (metadata, (char *) path, "type");
if (value)
{
option->value.list.type = getOptionType ((char *) value);
free (value);
}
else
{
option->value.list.type = CompOptionTypeBool;
}
switch (option->value.list.type) {
case CompOptionTypeInt:
initIntRestriction (metadata, &option->rest, (char *) path);
break;
case CompOptionTypeFloat:
initFloatRestriction (metadata, &option->rest, (char *) path);
break;
case CompOptionTypeAction:
case CompOptionTypeKey:
case CompOptionTypeButton:
case CompOptionTypeEdge:
case CompOptionTypeBell:
initActionState (metadata, option->value.list.type,
&state, (char *) path);
break;
case CompOptionTypeMatch:
helper = boolFromMetadataPathElement (metadata, (char *) path,
"helper", FALSE);
default:
break;
}
initListValue (d, &option->value, &option->rest, state, helper,
defaultDoc, defaultNode);
break;
}
if (defaultDoc)
finiXPath (&xDefaultPath);
finiXPath (&xPath);
return TRUE;
}
Bool
compInitScreenOptionFromMetadata (CompScreen *s,
CompMetadata *m,
CompOption *o,
const char *name)
{
char str[1024];
sprintf (str, "/compiz/%s/screen//option[@name=\"%s\"]", m->path, name);
return initOptionFromMetadataPath (s->display, m, o, BAD_CAST str);
}
static void
finiScreenOptionValue (CompScreen *s,
CompOptionValue *v,
CompOptionType type)
{
int i;
switch (type) {
case CompOptionTypeAction:
case CompOptionTypeKey:
case CompOptionTypeButton:
case CompOptionTypeEdge:
case CompOptionTypeBell:
if (v->action.state & CompActionStateAutoGrab)
removeScreenAction (s, &v->action);
break;
case CompOptionTypeList:
for (i = 0; i < v->list.nValue; i++)
finiScreenOptionValue (s, &v->list.value[i], v->list.type);
default:
break;
}
}
void
compFiniScreenOption (CompScreen *s,
CompOption *o)
{
finiScreenOptionValue (s, &o->value, o->type);
compFiniOption (o);
free (o->name);
}
Bool
compInitScreenOptionsFromMetadata (CompScreen *s,
CompMetadata *m,
const CompMetadataOptionInfo *info,
CompOption *opt,
int n)
{
int i;
for (i = 0; i < n; i++)
{
if (!compInitScreenOptionFromMetadata (s, m, &opt[i], info[i].name))
{
compFiniScreenOptions (s, opt, i);
return FALSE;
}
if (info[i].initiate)
opt[i].value.action.initiate = info[i].initiate;
if (info[i].terminate)
opt[i].value.action.terminate = info[i].terminate;
}
return TRUE;
}
void
compFiniScreenOptions (CompScreen *s,
CompOption *opt,
int n)
{
int i;
for (i = 0; i < n; i++)
compFiniScreenOption (s, &opt[i]);
}
Bool
compSetScreenOption (CompScreen *s,
CompOption *o,
CompOptionValue *value)
{
if (compSetOption (o, value))
return TRUE;
return FALSE;
}
Bool
compInitDisplayOptionFromMetadata (CompDisplay *d,
CompMetadata *m,
CompOption *o,
const char *name)
{
char str[1024];
sprintf (str, "/compiz/%s/display//option[@name=\"%s\"]", m->path, name);
return initOptionFromMetadataPath (d, m, o, BAD_CAST str);
}
static void
finiDisplayOptionValue (CompDisplay *d,
CompOptionValue *v,
CompOptionType type)
{
CompScreen *s;
int i;
switch (type) {
case CompOptionTypeAction:
case CompOptionTypeKey:
case CompOptionTypeButton:
case CompOptionTypeEdge:
case CompOptionTypeBell:
if (v->action.state & CompActionStateAutoGrab)
for (s = d->screens; s; s = s->next)
removeScreenAction (s, &v->action);
break;
case CompOptionTypeList:
for (i = 0; i < v->list.nValue; i++)
finiDisplayOptionValue (d, &v->list.value[i], v->list.type);
default:
break;
}
}
void
compFiniDisplayOption (CompDisplay *d,
CompOption *o)
{
finiDisplayOptionValue (d, &o->value, o->type);
compFiniOption (o);
free (o->name);
}
Bool
compInitDisplayOptionsFromMetadata (CompDisplay *d,
CompMetadata *m,
const CompMetadataOptionInfo *info,
CompOption *opt,
int n)
{
int i;
for (i = 0; i < n; i++)
{
if (!compInitDisplayOptionFromMetadata (d, m, &opt[i], info[i].name))
{
compFiniDisplayOptions (d, opt, i);
return FALSE;
}
if (info[i].initiate)
opt[i].value.action.initiate = info[i].initiate;
if (info[i].terminate)
opt[i].value.action.terminate = info[i].terminate;
}
return TRUE;
}
void
compFiniDisplayOptions (CompDisplay *d,
CompOption *opt,
int n)
{
int i;
for (i = 0; i < n; i++)
compFiniDisplayOption (d, &opt[i]);
}
Bool
compSetDisplayOption (CompDisplay *d,
CompOption *o,
CompOptionValue *value)
{
if (isActionOption (o))
{
if (o->value.action.state & CompActionStateAutoGrab)
{
if (setDisplayAction (d, o, value))
return TRUE;
}
else
{
if (compSetActionOption (o, value))
return TRUE;
}
}
else
{
if (compSetOption (o, value))
return TRUE;
}
return FALSE;
}
char *
compGetStringFromMetadataPath (CompMetadata *metadata,
const char *path)
{
CompXPath xPath;
char *v = NULL;
if (!initXPathFromMetadataPath (&xPath, metadata, BAD_CAST path))
return NULL;
xPath.obj = xmlXPathConvertString (xPath.obj);
if (xPath.obj->type == XPATH_STRING && xPath.obj->stringval)
v = strdup ((char *) xPath.obj->stringval);
finiXPath (&xPath);
return v;
}
char *
compGetShortPluginDescription (CompMetadata *m)
{
char str[1024];
sprintf (str, "/compiz/%s/short/child::text()", m->path);
return compGetStringFromMetadataPath (m, str);
}
char *
compGetLongPluginDescription (CompMetadata *m)
{
char str[1024];
sprintf (str, "/compiz/%s/long/child::text()", m->path);
return compGetStringFromMetadataPath (m, str);
}
char *
compGetShortScreenOptionDescription (CompMetadata *m,
CompOption *o)
{
char str[1024];
sprintf (str, "/compiz/%s/screen//option[@name=\"%s\"]/short/child::text()",
m->path, o->name);
return compGetStringFromMetadataPath (m, str);
}
char *
compGetLongScreenOptionDescription (CompMetadata *m,
CompOption *o)
{
char str[1024];
sprintf (str, "/compiz/%s/screen//option[@name=\"%s\"]/long/child::text()",
m->path, o->name);
return compGetStringFromMetadataPath (m, str);
}
char *
compGetShortDisplayOptionDescription (CompMetadata *m,
CompOption *o)
{
char str[1024];
sprintf (str,
"/compiz/%s/display//option[@name=\"%s\"]/short/child::text()",
m->path, o->name);
return compGetStringFromMetadataPath (m, str);
}
char *
compGetLongDisplayOptionDescription (CompMetadata *m,
CompOption *o)
{
char str[1024];
sprintf (str, "/compiz/%s/display//option[@name=\"%s\"]/long/child::text()",
m->path, o->name);
return compGetStringFromMetadataPath (m, str);
}
int
compReadXmlChunk (const char *src,
int *offset,
char *buffer,
int length)
{
int srcLength = strlen (src);
int srcOffset = *offset;
if (srcOffset > srcLength)
srcOffset = srcLength;
*offset -= srcOffset;
src += srcOffset;
srcLength -= srcOffset;
if (srcLength > 0 && length > 0)
{
if (srcLength < length)
length = srcLength;
memcpy (buffer, src, length);
return length;
}
return 0;
}
int
compReadXmlChunkFromMetadataOptionInfo (const CompMetadataOptionInfo *info,
int *offset,
char *buffer,
int length)
{
int i;
i = compReadXmlChunk ("<option name=\"", offset, buffer, length);
i += compReadXmlChunk (info->name, offset, buffer + i, length - i);
if (info->type)
{
i += compReadXmlChunk ("\" type=\"", offset, buffer + i, length - i);
i += compReadXmlChunk (info->type, offset, buffer + i, length - i);
}
if (info->data)
{
i += compReadXmlChunk ("\">", offset, buffer + i, length - i);
i += compReadXmlChunk (info->data, offset, buffer + i, length - i);
i += compReadXmlChunk ("</option>", offset, buffer + i, length - i);
}
else
{
i += compReadXmlChunk ("\"/>", offset, buffer + i, length - i);
}
return i;
}