2
* Copyright © 2008 Dennis Kasprzyk
3
* Copyright © 2007 Novell, Inc.
5
* Permission to use, copy, modify, distribute, and sell this software
6
* and its documentation for any purpose is hereby granted without
7
* fee, provided that the above copyright notice appear in all copies
8
* and that both that copyright notice and this permission notice
9
* appear in supporting documentation, and that the name of
10
* Dennis Kasprzyk not be used in advertising or publicity pertaining to
11
* distribution of the software without specific, written prior permission.
12
* Dennis Kasprzyk makes no representations about the suitability of this
13
* software for any purpose. It is provided "as is" without express or
16
* DENNIS KASPRZYK DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
18
* NO EVENT SHALL DENNIS KASPRZYK BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
20
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
* Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
25
* David Reveman <davidr@novell.com>
29
#include <libxml/tree.h>
30
#include <libxml/xpath.h>
31
#include <libxml/xpathInternals.h>
34
#include <boost/foreach.hpp>
35
#define foreach BOOST_FOREACH
38
#include <core/metadata.h>
39
#include <core/screen.h>
40
#include "privatescreen.h"
41
#include "privatemetadata.h"
43
#define HOME_METADATADIR ".compiz/metadata"
44
#define EXTENSION ".xml"
47
readXmlFile (CompString name,
55
file = compPrintf ("%s/%s%s", path.c_str (), name.c_str (), EXTENSION);
57
file = compPrintf ("%s%s", name.c_str (), EXTENSION);
59
fp = fopen (file.c_str (), "r");
67
doc = xmlReadFile (file.c_str (), NULL, 0);
72
typedef struct _CompIOCtx {
75
const CompMetadata::OptionInfo *oInfo;
79
typedef struct _CompXPath {
80
xmlXPathObjectPtr obj;
81
xmlXPathContextPtr ctx;
87
readPluginXmlCallback (void *context,
91
CompIOCtx *ctx = (CompIOCtx *) context;
92
unsigned int offset = ctx->offset;
95
i = CompMetadata::readXmlChunk ("<compiz><plugin name=\"", &offset,
97
i += CompMetadata::readXmlChunk (ctx->name, &offset, buffer + i,
99
i += CompMetadata::readXmlChunk ("\">", &offset, buffer + i, length - i);
103
i += CompMetadata::readXmlChunk ("<options>", &offset, buffer + i,
106
for (j = 0; j < ctx->nOInfo; j++)
107
i += CompMetadata::readXmlChunkFromOptionInfo (
108
&ctx->oInfo[j], &offset, buffer + i, length - i);
110
i += CompMetadata::readXmlChunk ("</options>", &offset, buffer + i,
114
i += CompMetadata::readXmlChunk ("</plugin></compiz>", &offset, buffer + i,
117
if (!offset && length > (int)i)
126
initXPathFromMetadataPath (CompXPath *xPath,
127
CompMetadata *metadata,
130
xmlXPathObjectPtr obj;
131
xmlXPathContextPtr ctx;
133
foreach (xmlDoc *doc, metadata->doc ())
135
ctx = xmlXPathNewContext (doc);
138
obj = xmlXPathEvalExpression (path, ctx);
141
if (obj->nodesetval && obj->nodesetval->nodeNr)
150
xmlXPathFreeObject (obj);
153
xmlXPathFreeContext (ctx);
161
initXPathFromMetadataPathElement (CompXPath *xPath,
162
CompMetadata *metadata,
164
const xmlChar *element)
168
snprintf (str, 1024, "%s/%s", path, element);
170
return initXPathFromMetadataPath (xPath, metadata, BAD_CAST str);
174
finiXPath (CompXPath *xPath)
176
xmlXPathFreeObject (xPath->obj);
177
xmlXPathFreeContext (xPath->ctx);
180
static CompOption::Type
181
getOptionType (const char *name)
183
static struct _TypeMap {
185
CompOption::Type type;
187
{ "int", CompOption::TypeInt },
188
{ "float", CompOption::TypeFloat },
189
{ "string", CompOption::TypeString },
190
{ "color", CompOption::TypeColor },
191
{ "action", CompOption::TypeAction },
192
{ "key", CompOption::TypeKey },
193
{ "button", CompOption::TypeButton },
194
{ "edge", CompOption::TypeEdge },
195
{ "bell", CompOption::TypeBell },
196
{ "match", CompOption::TypeMatch },
197
{ "list", CompOption::TypeList }
201
for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
202
if (strcasecmp (name, map[i].name) == 0)
205
return CompOption::TypeBool;
209
initBoolValue (CompOption::Value &v,
220
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
223
if (strcasecmp ((char *) value, "true") == 0)
231
initIntValue (CompOption::Value &v,
232
CompOption::Restriction &r,
238
v.set ((r.iMin () + r.iMax ()) / 2);
243
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
246
int i = strtol ((char *) value, NULL, 0);
256
initFloatValue (CompOption::Value &v,
257
CompOption::Restriction &r,
264
v.set ((r.fMin () + r.fMax ()) / 2);
269
loc = setlocale (LC_NUMERIC, NULL);
270
setlocale (LC_NUMERIC, "C");
271
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
274
float f = strtod ((char *) value, NULL);
281
setlocale (LC_NUMERIC, loc);
285
initStringValue (CompOption::Value &v,
286
CompOption::Restriction &r,
297
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
300
v.set (CompString ((char *) value));
306
initColorValue (CompOption::Value &v,
312
unsigned short c[4] = { 0x0000, 0x0000, 0x0000, 0xffff};
318
for (child = node->xmlChildrenNode; child; child = child->next)
323
if (!xmlStrcmp (child->name, BAD_CAST "red"))
325
else if (!xmlStrcmp (child->name, BAD_CAST "green"))
327
else if (!xmlStrcmp (child->name, BAD_CAST "blue"))
329
else if (!xmlStrcmp (child->name, BAD_CAST "alpha"))
334
value = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
337
int color = strtol ((char *) value, NULL , 0);
339
c[index] = MAX (0, MIN (0xffff, color));
348
initActionValue (CompOption::Value &v,
349
CompAction::State state,
353
v.set (CompAction ());
354
v.action ().setState (state);
358
initKeyValue (CompOption::Value &v,
359
CompAction::State state,
366
action.setState (state | CompAction::StateInitKey);
370
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
373
char *binding = (char *) value;
375
if (strcasecmp (binding, "disabled") && *binding)
376
action.keyFromString (binding);
383
if (state & CompAction::StateAutoGrab)
384
screen->addAction (&v.action ());
391
initButtonValue (CompOption::Value &v,
392
CompAction::State state,
399
action.setState (state | CompAction::StateInitButton |
400
CompAction::StateInitEdge);
404
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
407
char *binding = (char *) value;
409
if (strcasecmp (binding, "disabled") && *binding)
410
action.buttonFromString (binding);
417
if (state & CompAction::StateAutoGrab)
418
screen->addAction (&v.action ());
425
initEdgeValue (CompOption::Value &v,
426
CompAction::State state,
433
unsigned int edge = 0;
435
action.setState (state | CompAction::StateInitEdge);
439
for (child = node->xmlChildrenNode; child; child = child->next)
441
value = xmlGetProp (child, BAD_CAST "name");
446
for (i = 0; i < SCREEN_EDGE_NUM; i++)
447
if (strcasecmp ((char *) value,
448
CompAction::edgeToString (i).c_str ()) == 0)
455
action.setEdgeMask (edge);
458
if (state & CompAction::StateAutoGrab)
459
screen->addAction (&v.action ());
463
action.setEdgeMask (edge);
469
initBellValue (CompOption::Value &v,
470
CompAction::State state,
477
action.setState (state | CompAction::StateInitBell);
481
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
484
if (strcasecmp ((char *) value, "true") == 0)
485
action.setBell (true);
494
initMatchValue (CompOption::Value &v,
501
v.set (CompMatch ());
506
value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
509
v.match () = (char *) value;
514
v.match ().update ();
518
initListValue (CompOption::Value &v,
519
CompOption::Restriction &r,
520
CompAction::State state,
532
for (child = node->xmlChildrenNode; child; child = child->next)
534
CompOption::Value value;
536
if (xmlStrcmp (child->name, BAD_CAST "value"))
539
switch (v.listType ()) {
540
case CompOption::TypeBool:
541
initBoolValue (value, doc, child);
543
case CompOption::TypeInt:
544
initIntValue (value, r, doc, child);
546
case CompOption::TypeFloat:
547
initFloatValue (value, r, doc, child);
549
case CompOption::TypeString:
550
initStringValue (value, r, doc, child);
552
case CompOption::TypeColor:
553
initColorValue (value, doc, child);
555
case CompOption::TypeAction:
556
initActionValue (value, state, doc, child);
558
case CompOption::TypeKey:
559
initKeyValue (value, state, doc, child);
561
case CompOption::TypeButton:
562
initButtonValue (value, state, doc, child);
564
case CompOption::TypeEdge:
565
initEdgeValue (value, state, doc, child);
567
case CompOption::TypeBell:
568
initBellValue (value, state, doc, child);
570
case CompOption::TypeMatch:
571
initMatchValue (value, helper, doc, child);
576
v.list ().push_back (value);
581
stringFromMetadataPathElement (CompMetadata *metadata,
585
return metadata->getStringFromPath (compPrintf ("%s/%s", path, element));
589
boolFromMetadataPathElement (CompMetadata *metadata,
597
str = stringFromMetadataPathElement (metadata, path, element);
599
if (strcasecmp (str.c_str (), "true") == 0)
606
initIntRestriction (CompMetadata *metadata,
607
CompOption::Restriction &r,
611
int min = MINSHORT, max = MAXSHORT;
613
value = stringFromMetadataPathElement (metadata, path, "min");
615
min = strtol (value.c_str (), NULL, 0);
617
value = stringFromMetadataPathElement (metadata, path, "max");
619
max = strtol (value.c_str (), NULL, 0);
625
initFloatRestriction (CompMetadata *metadata,
626
CompOption::Restriction &r,
632
float min = MINSHORT;
633
float max = MAXSHORT;
634
float precision = 0.1f;
636
loc = setlocale (LC_NUMERIC, NULL);
637
setlocale (LC_NUMERIC, "C");
638
value = stringFromMetadataPathElement (metadata, path, "min");
640
min = strtod (value.c_str (), NULL);
642
value = stringFromMetadataPathElement (metadata, path, "max");
644
max = strtod (value.c_str (), NULL);
646
value = stringFromMetadataPathElement (metadata, path, "precision");
648
precision = strtod (value.c_str (), NULL);
650
r.set (min, max, precision);
652
setlocale (LC_NUMERIC, loc);
656
initActionState (CompMetadata *metadata,
657
CompOption::Type type,
658
CompAction::State *state,
661
static struct _StateMap {
663
CompAction::State state;
665
{ "key", CompAction::StateInitKey },
666
{ "button", CompAction::StateInitButton },
667
{ "bell", CompAction::StateInitBell },
668
{ "edge", CompAction::StateInitEdge },
669
{ "edgednd", CompAction::StateInitEdgeDnd }
675
*state = CompAction::StateAutoGrab;
677
value = stringFromMetadataPathElement (metadata, path, "passive_grab");
679
if (value == "false")
682
if (type == CompOption::TypeEdge)
684
value = stringFromMetadataPathElement (metadata, path, "nodelay");
687
*state |= CompAction::StateNoEdgeDelay;
690
if (!initXPathFromMetadataPathElement (&xPath, metadata, BAD_CAST path,
694
for (unsigned int i = 0; i < sizeof (map) / sizeof (map[0]); i++)
698
value = xmlGetProp (*xPath.obj->nodesetval->nodeTab,
699
BAD_CAST map[i].name);
702
if (xmlStrcmp (value, BAD_CAST "true") == 0)
703
*state |= map[i].state;
712
initOptionFromMetadataPath (CompMetadata *metadata,
716
CompXPath xPath, xDefaultPath;
717
xmlNodePtr node, defaultNode;
718
xmlDocPtr defaultDoc;
719
xmlChar *name, *type;
721
CompAction::State state = 0;
723
CompOption::Type oType = CompOption::TypeBool;
725
CompOption::Value::Vector emptyList (0);
727
if (!initXPathFromMetadataPath (&xPath, metadata, path))
730
node = *xPath.obj->nodesetval->nodeTab;
732
type = xmlGetProp (node, BAD_CAST "type");
735
oType = getOptionType ((char *) type);
739
name = xmlGetProp (node, BAD_CAST "name");
740
option->setName ((char *) name, oType);
743
if (initXPathFromMetadataPathElement (&xDefaultPath, metadata, path,
746
defaultDoc = xDefaultPath.doc;
747
defaultNode = *xDefaultPath.obj->nodesetval->nodeTab;
755
switch (option->type ()) {
756
case CompOption::TypeBool:
757
initBoolValue (option->value (), defaultDoc, defaultNode);
759
case CompOption::TypeInt:
760
initIntRestriction (metadata, option->rest (), (char *) path);
761
initIntValue (option->value (), option->rest (),
762
defaultDoc, defaultNode);
764
case CompOption::TypeFloat:
765
initFloatRestriction (metadata, option->rest (), (char *) path);
766
initFloatValue (option->value (), option->rest (),
767
defaultDoc, defaultNode);
769
case CompOption::TypeString:
770
initStringValue (option->value (), option->rest (),
771
defaultDoc, defaultNode);
773
case CompOption::TypeColor:
774
initColorValue (option->value (), defaultDoc, defaultNode);
776
case CompOption::TypeAction:
777
initActionState (metadata, option->type (), &state, (char *) path);
778
initActionValue (option->value (), state,
779
defaultDoc, defaultNode);
781
case CompOption::TypeKey:
782
initActionState (metadata, option->type (), &state, (char *) path);
783
initKeyValue (option->value (), state,
784
defaultDoc, defaultNode);
786
case CompOption::TypeButton:
787
initActionState (metadata, option->type (), &state, (char *) path);
788
initButtonValue (option->value (), state,
789
defaultDoc, defaultNode);
791
case CompOption::TypeEdge:
792
initActionState (metadata, option->type (), &state, (char *) path);
793
initEdgeValue (option->value (), state,
794
defaultDoc, defaultNode);
796
case CompOption::TypeBell:
797
initActionState (metadata, option->type (), &state, (char *) path);
798
initBellValue (option->value (), state,
799
defaultDoc, defaultNode);
801
case CompOption::TypeMatch:
802
helper = boolFromMetadataPathElement (metadata, (char *) path,
804
initMatchValue (option->value (), helper,
805
defaultDoc, defaultNode);
807
case CompOption::TypeList:
808
value = stringFromMetadataPathElement (metadata, (char *) path,
811
option->value ().set (getOptionType (value.c_str ()), emptyList);
813
option->value ().set (CompOption::TypeBool, emptyList);
815
switch (option->value ().listType ()) {
816
case CompOption::TypeInt:
817
initIntRestriction (metadata, option->rest (),
820
case CompOption::TypeFloat:
821
initFloatRestriction (metadata, option->rest (),
824
case CompOption::TypeAction:
825
case CompOption::TypeKey:
826
case CompOption::TypeButton:
827
case CompOption::TypeEdge:
828
case CompOption::TypeBell:
829
initActionState (metadata, option->value ().listType (),
830
&state, (char *) path);
832
case CompOption::TypeMatch:
833
helper = boolFromMetadataPathElement (metadata,
840
initListValue (option->value (), option->rest (), state, helper,
841
defaultDoc, defaultNode);
846
finiXPath (&xDefaultPath);
853
CompMetadata::CompMetadata (CompString plugin,
854
const OptionInfo *optionInfo,
855
unsigned int nOptionInfo)
857
priv = new PrivateMetadata (plugin, compPrintf ("plugin[@name=\"%s\"]",
864
ctx.name = plugin.c_str ();
865
ctx.oInfo = optionInfo;
866
ctx.nOInfo = nOptionInfo;
868
addFromIO (readPluginXmlCallback, NULL, (void *) &ctx);
872
CompMetadata::~CompMetadata ()
877
std::vector<xmlDoc *> &
885
CompMetadata::addFromFile (CompString file, bool prepend)
888
CompString home (getenv ("HOME"));
891
home = getenv ("HOME");
894
CompString path = compPrintf ("%s/%s", home.c_str (), HOME_METADATADIR);
895
doc = readXmlFile (file, path);
899
priv->mDoc.insert (priv->mDoc.begin (), doc);
901
priv->mDoc.push_back (doc);
907
doc = readXmlFile (file, CompString (METADATADIR));
911
priv->mDoc.insert (priv->mDoc.begin (), doc);
913
priv->mDoc.push_back (doc);
920
compLogMessage ("core", CompLogLevelWarn,
921
"Unable to parse XML metadata from file \"%s%s\"",
922
file.c_str (), EXTENSION);
931
CompMetadata::addFromString (CompString string, bool prepend)
935
doc = xmlReadMemory (string.c_str (), string.size (), NULL, NULL, 0);
938
compLogMessage ("core", CompLogLevelWarn,
939
"Unable to parse XML metadata");
945
priv->mDoc.insert (priv->mDoc.begin (), doc);
947
priv->mDoc.push_back (doc);
953
CompMetadata::addFromIO (xmlInputReadCallback ioread,
954
xmlInputCloseCallback ioclose,
960
doc = xmlReadIO (ioread, ioclose, ioctx, NULL, NULL, 0);
963
compLogMessage ("core", CompLogLevelWarn,
964
"Unable to parse XML metadata");
970
priv->mDoc.insert (priv->mDoc.begin (), doc);
972
priv->mDoc.push_back (doc);
978
CompMetadata::addFromOptionInfo (const OptionInfo *optionInfo,
979
unsigned int nOptionInfo,
987
ctx.name = priv->mPlugin.c_str ();
988
ctx.oInfo = optionInfo;
989
ctx.nOInfo = nOptionInfo;
991
return addFromIO (readPluginXmlCallback, NULL, (void *) &ctx, prepend);
998
CompMetadata::initOption (CompOption *option,
1003
sprintf (str, "/compiz/%s/options//option[@name=\"%s\"]",
1004
priv->mPath.c_str (), name.c_str ());
1006
return initOptionFromMetadataPath (this, option, BAD_CAST str);
1010
CompMetadata::initOptions (const OptionInfo *info,
1011
unsigned int nOptions,
1012
CompOption::Vector &opt)
1014
if (opt.size () < nOptions)
1015
opt.resize (nOptions);
1017
for (unsigned int i = 0; i < nOptions; i++)
1019
if (!initOption (&opt[i], info[i].name))
1024
if (info[i].initiate)
1025
opt[i].value ().action ().setInitiate (info[i].initiate);
1027
if (info[i].terminate)
1028
opt[i].value ().action ().setTerminate (info[i].terminate);
1035
CompMetadata::getShortPluginDescription ()
1037
return getStringFromPath (
1038
compPrintf ("/compiz/%s/short/child::text()", priv->mPath.c_str ()));
1042
CompMetadata::getLongPluginDescription ()
1044
return getStringFromPath (
1045
compPrintf ("/compiz/%s/long/child::text()", priv->mPath.c_str ()));
1049
CompMetadata::getShortOptionDescription (CompOption *option)
1051
return getStringFromPath (
1053
"/compiz/%s/options//option[@name=\"%s\"]/short/child::text()",
1054
priv->mPath.c_str (), option->name ().c_str ()));
1058
CompMetadata::getLongOptionDescription (CompOption *option)
1060
return getStringFromPath (
1062
"/compiz/%s/options//option[@name=\"%s\"]/long/child::text()",
1063
priv->mPath.c_str (), option->name ().c_str ()));
1069
CompMetadata::getStringFromPath (CompString path)
1074
if (!initXPathFromMetadataPath (&xPath, this, BAD_CAST path.c_str ()))
1077
xPath.obj = xmlXPathConvertString (xPath.obj);
1079
if (xPath.obj->type == XPATH_STRING && xPath.obj->stringval)
1080
v = (char *) xPath.obj->stringval;
1088
CompMetadata::readXmlChunk (const char *src,
1089
unsigned int *offset,
1091
unsigned int length)
1093
unsigned int srcLength = strlen (src);
1094
unsigned int srcOffset = *offset;
1096
if (srcOffset > srcLength)
1097
srcOffset = srcLength;
1099
*offset -= srcOffset;
1102
srcLength -= srcOffset;
1104
if (srcLength > 0 && length > 0)
1106
if (srcLength < length)
1109
memcpy (buffer, src, length);
1118
CompMetadata::readXmlChunkFromOptionInfo (const CompMetadata::OptionInfo *info,
1119
unsigned int *offset,
1121
unsigned int length)
1125
i = readXmlChunk ("<option name=\"", offset, buffer, length);
1126
i += readXmlChunk (info->name, offset, buffer + i, length - i);
1130
i += readXmlChunk ("\" type=\"", offset, buffer + i, length - i);
1131
i += readXmlChunk (info->type, offset, buffer + i, length - i);
1136
i += readXmlChunk ("\">", offset, buffer + i, length - i);
1137
i += readXmlChunk (info->data, offset, buffer + i, length - i);
1138
i += readXmlChunk ("</option>", offset, buffer + i, length - i);
1142
i += readXmlChunk ("\"/>", offset, buffer + i, length - i);
1148
PrivateMetadata::PrivateMetadata (CompString plugin, CompString path) :
1155
PrivateMetadata::~PrivateMetadata ()
1157
foreach (xmlDoc *d, mDoc)