~compiz-team/compiz-core/compiz-core.fix_882826

« back to all changes in this revision

Viewing changes to legacy/metadata.cpp

  • Committer: Dennis kasprzyk
  • Author(s): Dennis Kasprzyk
  • Date: 2009-03-15 23:01:28 UTC
  • Revision ID: git-v1:aaa1ea1d80873aea6533346199b724550667142b
Drop CompMetadata.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2008 Dennis Kasprzyk
 
3
 * Copyright © 2007 Novell, Inc.
 
4
 *
 
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
 
14
 * implied warranty.
 
15
 *
 
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.
 
23
 *
 
24
 * Authors: Dennis Kasprzyk <onestone@compiz-fusion.org>
 
25
 *          David Reveman <davidr@novell.com>
 
26
 */
 
27
 
 
28
#include <string.h>
 
29
#include <libxml/tree.h>
 
30
#include <libxml/xpath.h>
 
31
#include <libxml/xpathInternals.h>
 
32
#include <locale.h>
 
33
 
 
34
#include <boost/foreach.hpp>
 
35
#define foreach BOOST_FOREACH
 
36
 
 
37
#include <compiz.h>
 
38
#include <core/metadata.h>
 
39
#include <core/screen.h>
 
40
#include "privatescreen.h"
 
41
#include "privatemetadata.h"
 
42
 
 
43
#define HOME_METADATADIR ".compiz/metadata"
 
44
#define EXTENSION ".xml"
 
45
 
 
46
static xmlDoc *
 
47
readXmlFile (CompString name,
 
48
             CompString path = "")
 
49
{
 
50
    CompString file;
 
51
    xmlDoc *doc = NULL;
 
52
    FILE   *fp;
 
53
 
 
54
    if (path.size ())
 
55
        file = compPrintf ("%s/%s%s", path.c_str (), name.c_str (), EXTENSION);
 
56
    else
 
57
        file = compPrintf ("%s%s", name.c_str (), EXTENSION);
 
58
 
 
59
    fp = fopen (file.c_str (), "r");
 
60
    if (!fp)
 
61
    {
 
62
        return NULL;
 
63
    }
 
64
 
 
65
    fclose (fp);
 
66
 
 
67
    doc = xmlReadFile (file.c_str (), NULL, 0);
 
68
 
 
69
    return doc;
 
70
}
 
71
 
 
72
typedef struct _CompIOCtx {
 
73
    unsigned int                   offset;
 
74
    const char                     *name;
 
75
    const CompMetadata::OptionInfo *oInfo;
 
76
    unsigned int                   nOInfo;
 
77
} CompIOCtx;
 
78
 
 
79
typedef struct _CompXPath {
 
80
    xmlXPathObjectPtr  obj;
 
81
    xmlXPathContextPtr ctx;
 
82
    xmlDocPtr          doc;
 
83
} CompXPath;
 
84
 
 
85
 
 
86
static int
 
87
readPluginXmlCallback (void *context,
 
88
                       char *buffer,
 
89
                       int  length)
 
90
{
 
91
    CompIOCtx    *ctx = (CompIOCtx *) context;
 
92
    unsigned int offset = ctx->offset;
 
93
    unsigned int i, j;
 
94
 
 
95
    i = CompMetadata::readXmlChunk ("<compiz><plugin name=\"", &offset,
 
96
                                    buffer, length);
 
97
    i += CompMetadata::readXmlChunk (ctx->name, &offset, buffer + i,
 
98
                                     length - i);
 
99
    i += CompMetadata::readXmlChunk ("\">", &offset, buffer + i, length - i);
 
100
 
 
101
    if (ctx->nOInfo)
 
102
    {
 
103
        i += CompMetadata::readXmlChunk ("<options>", &offset, buffer + i,
 
104
                                         length - i);
 
105
 
 
106
        for (j = 0; j < ctx->nOInfo; j++)
 
107
            i += CompMetadata::readXmlChunkFromOptionInfo (
 
108
                   &ctx->oInfo[j], &offset, buffer + i, length - i);
 
109
 
 
110
        i += CompMetadata::readXmlChunk ("</options>", &offset, buffer + i,
 
111
                                         length - i);
 
112
    }
 
113
 
 
114
    i += CompMetadata::readXmlChunk ("</plugin></compiz>", &offset, buffer + i,
 
115
                                     length - i);
 
116
 
 
117
    if (!offset && length > (int)i)
 
118
        buffer[i++] = '\0';
 
119
 
 
120
    ctx->offset += i;
 
121
 
 
122
    return i;
 
123
}
 
124
 
 
125
static bool
 
126
initXPathFromMetadataPath (CompXPath     *xPath,
 
127
                           CompMetadata  *metadata,
 
128
                           const xmlChar *path)
 
129
{
 
130
    xmlXPathObjectPtr  obj;
 
131
    xmlXPathContextPtr ctx;
 
132
 
 
133
    foreach (xmlDoc *doc, metadata->doc ())
 
134
    {
 
135
        ctx = xmlXPathNewContext (doc);
 
136
        if (ctx)
 
137
        {
 
138
            obj = xmlXPathEvalExpression (path, ctx);
 
139
            if (obj)
 
140
            {
 
141
                if (obj->nodesetval && obj->nodesetval->nodeNr)
 
142
                {
 
143
                    xPath->ctx = ctx;
 
144
                    xPath->obj = obj;
 
145
                    xPath->doc = doc;
 
146
 
 
147
                    return true;
 
148
                }
 
149
 
 
150
                xmlXPathFreeObject (obj);
 
151
            }
 
152
 
 
153
            xmlXPathFreeContext (ctx);
 
154
        }
 
155
    }
 
156
 
 
157
    return false;
 
158
}
 
159
 
 
160
static bool
 
161
initXPathFromMetadataPathElement (CompXPath     *xPath,
 
162
                                  CompMetadata  *metadata,
 
163
                                  const xmlChar *path,
 
164
                                  const xmlChar *element)
 
165
{
 
166
    char str[1024];
 
167
 
 
168
    snprintf (str, 1024, "%s/%s", path, element);
 
169
 
 
170
    return initXPathFromMetadataPath (xPath, metadata, BAD_CAST str);
 
171
}
 
172
 
 
173
static void
 
174
finiXPath (CompXPath *xPath)
 
175
{
 
176
    xmlXPathFreeObject (xPath->obj);
 
177
    xmlXPathFreeContext (xPath->ctx);
 
178
}
 
179
 
 
180
static CompOption::Type
 
181
getOptionType (const char *name)
 
182
{
 
183
    static struct _TypeMap {
 
184
        const char       *name;
 
185
        CompOption::Type type;
 
186
    } map[] = {
 
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   }
 
198
    };
 
199
    unsigned int i;
 
200
 
 
201
    for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
 
202
        if (strcasecmp (name, map[i].name) == 0)
 
203
            return map[i].type;
 
204
 
 
205
    return CompOption::TypeBool;
 
206
}
 
207
 
 
208
static void
 
209
initBoolValue (CompOption::Value &v,
 
210
               xmlDocPtr         doc,
 
211
               xmlNodePtr        node)
 
212
{
 
213
    xmlChar *value;
 
214
 
 
215
    v.set (false);
 
216
 
 
217
    if (!doc)
 
218
        return;
 
219
 
 
220
    value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
221
    if (value)
 
222
    {
 
223
        if (strcasecmp ((char *) value, "true") == 0)
 
224
            v.set (true);
 
225
 
 
226
        xmlFree (value);
 
227
    }
 
228
}
 
229
 
 
230
static void
 
231
initIntValue (CompOption::Value       &v,
 
232
              CompOption::Restriction &r,
 
233
              xmlDocPtr               doc,
 
234
              xmlNodePtr              node)
 
235
{
 
236
    xmlChar *value;
 
237
 
 
238
    v.set ((r.iMin () + r.iMax ()) / 2);
 
239
 
 
240
    if (!doc)
 
241
        return;
 
242
 
 
243
    value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
244
    if (value)
 
245
    {
 
246
        int i = strtol ((char *) value, NULL, 0);
 
247
 
 
248
        if (r.inRange (i))
 
249
            v.set (i);
 
250
 
 
251
        xmlFree (value);
 
252
    }
 
253
}
 
254
 
 
255
static void
 
256
initFloatValue (CompOption::Value       &v,
 
257
                CompOption::Restriction &r,
 
258
                xmlDocPtr               doc,
 
259
                xmlNodePtr              node)
 
260
{
 
261
    xmlChar *value;
 
262
    char *loc;
 
263
 
 
264
    v.set ((r.fMin () + r.fMax ()) / 2);
 
265
 
 
266
    if (!doc)
 
267
        return;
 
268
 
 
269
    loc = setlocale (LC_NUMERIC, NULL);
 
270
    setlocale (LC_NUMERIC, "C");
 
271
    value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
272
    if (value)
 
273
    {
 
274
        float f = strtod ((char *) value, NULL);
 
275
 
 
276
        if (r.inRange (f))
 
277
            v.set (f);
 
278
 
 
279
        xmlFree (value);
 
280
    }
 
281
    setlocale (LC_NUMERIC, loc);
 
282
}
 
283
 
 
284
static void
 
285
initStringValue (CompOption::Value       &v,
 
286
                 CompOption::Restriction &r,
 
287
                 xmlDocPtr               doc,
 
288
                 xmlNodePtr              node)
 
289
{
 
290
    xmlChar *value;
 
291
 
 
292
    v.set ("");
 
293
 
 
294
    if (!doc)
 
295
        return;
 
296
 
 
297
    value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
298
    if (value)
 
299
    {
 
300
        v.set (CompString ((char *) value));
 
301
        xmlFree (value);
 
302
    }
 
303
}
 
304
 
 
305
static void
 
306
initColorValue (CompOption::Value &v,
 
307
                xmlDocPtr         doc,
 
308
                xmlNodePtr        node)
 
309
{
 
310
    xmlNodePtr child;
 
311
 
 
312
    unsigned short c[4] = { 0x0000, 0x0000, 0x0000, 0xffff};
 
313
    v.set (c);
 
314
 
 
315
    if (!doc)
 
316
        return;
 
317
 
 
318
    for (child = node->xmlChildrenNode; child; child = child->next)
 
319
    {
 
320
        xmlChar *value;
 
321
        int     index;
 
322
 
 
323
        if (!xmlStrcmp (child->name, BAD_CAST "red"))
 
324
            index = 0;
 
325
        else if (!xmlStrcmp (child->name, BAD_CAST "green"))
 
326
            index = 1;
 
327
        else if (!xmlStrcmp (child->name, BAD_CAST "blue"))
 
328
            index = 2;
 
329
        else if (!xmlStrcmp (child->name, BAD_CAST "alpha"))
 
330
            index = 3;
 
331
        else
 
332
            continue;
 
333
 
 
334
        value = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
 
335
        if (value)
 
336
        {
 
337
            int color = strtol ((char *) value, NULL , 0);
 
338
 
 
339
            c[index] = MAX (0, MIN (0xffff, color));
 
340
 
 
341
            xmlFree (value);
 
342
        }
 
343
    }
 
344
    v.set (c);
 
345
}
 
346
 
 
347
static void
 
348
initActionValue (CompOption::Value &v,
 
349
                 CompAction::State state,
 
350
                 xmlDocPtr         doc,
 
351
                 xmlNodePtr        node)
 
352
{
 
353
    v.set (CompAction ());
 
354
    v.action ().setState (state);
 
355
}
 
356
 
 
357
static void
 
358
initKeyValue (CompOption::Value &v,
 
359
              CompAction::State state,
 
360
              xmlDocPtr         doc,
 
361
              xmlNodePtr        node)
 
362
{
 
363
    xmlChar    *value;
 
364
    CompAction action;
 
365
 
 
366
    action.setState (state | CompAction::StateInitKey);
 
367
 
 
368
    if (doc)
 
369
    {
 
370
        value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
371
        if (value)
 
372
        {
 
373
            char *binding = (char *) value;
 
374
 
 
375
            if (strcasecmp (binding, "disabled") && *binding)
 
376
                action.keyFromString (binding);
 
377
 
 
378
            xmlFree (value);
 
379
        }
 
380
 
 
381
        v.set (action);
 
382
 
 
383
        if (state & CompAction::StateAutoGrab)
 
384
            screen->addAction (&v.action ());
 
385
    }
 
386
    else
 
387
        v.set (action);
 
388
}
 
389
 
 
390
static void
 
391
initButtonValue (CompOption::Value &v,
 
392
                 CompAction::State state,
 
393
                 xmlDocPtr         doc,
 
394
                 xmlNodePtr        node)
 
395
{
 
396
    xmlChar    *value;
 
397
    CompAction action;
 
398
 
 
399
    action.setState (state | CompAction::StateInitButton |
 
400
                     CompAction::StateInitEdge);
 
401
 
 
402
    if (doc)
 
403
    {
 
404
        value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
405
        if (value)
 
406
        {
 
407
            char *binding = (char *) value;
 
408
 
 
409
            if (strcasecmp (binding, "disabled") && *binding)
 
410
                action.buttonFromString (binding);
 
411
 
 
412
            xmlFree (value);
 
413
        }
 
414
 
 
415
        v.set (action);
 
416
 
 
417
        if (state & CompAction::StateAutoGrab)
 
418
            screen->addAction (&v.action ());
 
419
    }
 
420
    else
 
421
        v.set (action);
 
422
}
 
423
 
 
424
static void
 
425
initEdgeValue (CompOption::Value &v,
 
426
               CompAction::State state,
 
427
               xmlDocPtr         doc,
 
428
               xmlNodePtr        node)
 
429
{
 
430
    xmlNodePtr   child;
 
431
    xmlChar      *value;
 
432
    CompAction   action;
 
433
    unsigned int edge = 0;
 
434
 
 
435
    action.setState (state | CompAction::StateInitEdge);
 
436
 
 
437
    if (doc)
 
438
    {
 
439
        for (child = node->xmlChildrenNode; child; child = child->next)
 
440
        {
 
441
            value = xmlGetProp (child, BAD_CAST "name");
 
442
            if (value)
 
443
            {
 
444
                int i;
 
445
 
 
446
                for (i = 0; i < SCREEN_EDGE_NUM; i++)
 
447
                    if (strcasecmp ((char *) value,
 
448
                                    CompAction::edgeToString (i).c_str ()) == 0)
 
449
                        edge |= (1 << i);
 
450
 
 
451
                xmlFree (value);
 
452
            }
 
453
        }
 
454
 
 
455
        action.setEdgeMask (edge);
 
456
        v.set (action);
 
457
 
 
458
        if (state & CompAction::StateAutoGrab)
 
459
            screen->addAction (&v.action ());
 
460
    }
 
461
    else
 
462
    {
 
463
        action.setEdgeMask (edge);
 
464
        v.set (action);
 
465
    }
 
466
}
 
467
 
 
468
static void
 
469
initBellValue (CompOption::Value &v,
 
470
               CompAction::State state,
 
471
               xmlDocPtr         doc,
 
472
               xmlNodePtr        node)
 
473
{
 
474
    xmlChar    *value;
 
475
    CompAction action;
 
476
 
 
477
    action.setState (state | CompAction::StateInitBell);
 
478
 
 
479
    if (doc)
 
480
    {
 
481
        value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
482
        if (value)
 
483
        {
 
484
            if (strcasecmp ((char *) value, "true") == 0)
 
485
                action.setBell (true);
 
486
 
 
487
            xmlFree (value);
 
488
        }
 
489
    }
 
490
    v.set (action);
 
491
}
 
492
 
 
493
static void
 
494
initMatchValue (CompOption::Value &v,
 
495
                bool              helper,
 
496
                xmlDocPtr         doc,
 
497
                xmlNodePtr        node)
 
498
{
 
499
    xmlChar *value;
 
500
 
 
501
    v.set (CompMatch ());
 
502
 
 
503
    if (!doc)
 
504
        return;
 
505
 
 
506
    value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
 
507
    if (value)
 
508
    {
 
509
        v.match () = (char *) value;
 
510
        xmlFree (value);
 
511
    }
 
512
 
 
513
    if (!helper)
 
514
        v.match ().update ();
 
515
}
 
516
 
 
517
static void
 
518
initListValue (CompOption::Value       &v,
 
519
               CompOption::Restriction &r,
 
520
               CompAction::State       state,
 
521
               bool                    helper,
 
522
               xmlDocPtr               doc,
 
523
               xmlNodePtr              node)
 
524
{
 
525
    xmlNodePtr child;
 
526
 
 
527
    v.list ().clear ();
 
528
 
 
529
    if (!doc)
 
530
        return;
 
531
 
 
532
    for (child = node->xmlChildrenNode; child; child = child->next)
 
533
    {
 
534
        CompOption::Value value;
 
535
 
 
536
        if (xmlStrcmp (child->name, BAD_CAST "value"))
 
537
            continue;
 
538
 
 
539
        switch (v.listType ()) {
 
540
            case CompOption::TypeBool:
 
541
                initBoolValue (value, doc, child);
 
542
                break;
 
543
            case CompOption::TypeInt:
 
544
                initIntValue (value, r, doc, child);
 
545
                break;
 
546
            case CompOption::TypeFloat:
 
547
                initFloatValue (value, r, doc, child);
 
548
                break;
 
549
            case CompOption::TypeString:
 
550
                initStringValue (value, r, doc, child);
 
551
                break;
 
552
            case CompOption::TypeColor:
 
553
                initColorValue (value, doc, child);
 
554
                break;
 
555
            case CompOption::TypeAction:
 
556
                initActionValue (value, state, doc, child);
 
557
                break;
 
558
            case CompOption::TypeKey:
 
559
                initKeyValue (value, state, doc, child);
 
560
                break;
 
561
            case CompOption::TypeButton:
 
562
                initButtonValue (value, state, doc, child);
 
563
                break;
 
564
            case CompOption::TypeEdge:
 
565
                initEdgeValue (value, state, doc, child);
 
566
                break;
 
567
            case CompOption::TypeBell:
 
568
                initBellValue (value, state, doc, child);
 
569
                break;
 
570
            case CompOption::TypeMatch:
 
571
                initMatchValue (value, helper, doc, child);
 
572
            default:
 
573
                break;
 
574
        }
 
575
 
 
576
        v.list ().push_back (value);
 
577
    }
 
578
}
 
579
 
 
580
static CompString
 
581
stringFromMetadataPathElement (CompMetadata *metadata,
 
582
                               const char   *path,
 
583
                               const char   *element)
 
584
{
 
585
    return metadata->getStringFromPath (compPrintf ("%s/%s", path, element));
 
586
}
 
587
 
 
588
static Bool
 
589
boolFromMetadataPathElement (CompMetadata *metadata,
 
590
                             const char   *path,
 
591
                             const char   *element,
 
592
                             Bool         defaultValue)
 
593
{
 
594
    Bool value = FALSE;
 
595
    CompString str;
 
596
 
 
597
    str = stringFromMetadataPathElement (metadata, path, element);
 
598
 
 
599
    if (strcasecmp (str.c_str (), "true") == 0)
 
600
        value = TRUE;
 
601
 
 
602
    return value;
 
603
}
 
604
 
 
605
static void
 
606
initIntRestriction (CompMetadata            *metadata,
 
607
                    CompOption::Restriction &r,
 
608
                    const char              *path)
 
609
{
 
610
    CompString value;
 
611
    int  min = MINSHORT, max = MAXSHORT;
 
612
 
 
613
    value = stringFromMetadataPathElement (metadata, path, "min");
 
614
    if (!value.empty ())
 
615
        min = strtol (value.c_str (), NULL, 0);
 
616
 
 
617
    value = stringFromMetadataPathElement (metadata, path, "max");
 
618
    if (!value.empty ())
 
619
        max = strtol (value.c_str (), NULL, 0);
 
620
 
 
621
    r.set (min, max);
 
622
}
 
623
 
 
624
static void
 
625
initFloatRestriction (CompMetadata            *metadata,
 
626
                      CompOption::Restriction &r,
 
627
                      const char              *path)
 
628
{
 
629
    CompString value;
 
630
    char *loc;
 
631
 
 
632
    float min       = MINSHORT;
 
633
    float max       = MAXSHORT;
 
634
    float precision = 0.1f;
 
635
 
 
636
    loc = setlocale (LC_NUMERIC, NULL);
 
637
    setlocale (LC_NUMERIC, "C");
 
638
    value = stringFromMetadataPathElement (metadata, path, "min");
 
639
    if (!value.empty ())
 
640
        min = strtod (value.c_str (), NULL);
 
641
 
 
642
    value = stringFromMetadataPathElement (metadata, path, "max");
 
643
    if (!value.empty ())
 
644
        max = strtod (value.c_str (), NULL);
 
645
 
 
646
    value = stringFromMetadataPathElement (metadata, path, "precision");
 
647
    if (!value.empty ())
 
648
        precision = strtod (value.c_str (), NULL);
 
649
 
 
650
    r.set (min, max, precision);
 
651
 
 
652
    setlocale (LC_NUMERIC, loc);
 
653
}
 
654
 
 
655
static void
 
656
initActionState (CompMetadata      *metadata,
 
657
                 CompOption::Type  type,
 
658
                 CompAction::State *state,
 
659
                 const char        *path)
 
660
{
 
661
    static struct _StateMap {
 
662
        const char        *name;
 
663
        CompAction::State state;
 
664
    } map[] = {
 
665
        { "key",     CompAction::StateInitKey     },
 
666
        { "button",  CompAction::StateInitButton  },
 
667
        { "bell",    CompAction::StateInitBell    },
 
668
        { "edge",    CompAction::StateInitEdge    },
 
669
        { "edgednd", CompAction::StateInitEdgeDnd }
 
670
    };
 
671
 
 
672
    CompXPath xPath;
 
673
    CompString value;
 
674
 
 
675
    *state = CompAction::StateAutoGrab;
 
676
 
 
677
    value = stringFromMetadataPathElement (metadata, path, "passive_grab");
 
678
    if (!value.empty ())
 
679
        if (value == "false")
 
680
            *state = 0;
 
681
 
 
682
    if (type == CompOption::TypeEdge)
 
683
    {
 
684
        value = stringFromMetadataPathElement (metadata, path, "nodelay");
 
685
        if (!value.empty ())
 
686
            if (value == "true")
 
687
                *state |= CompAction::StateNoEdgeDelay;
 
688
    }
 
689
 
 
690
    if (!initXPathFromMetadataPathElement (&xPath, metadata, BAD_CAST path,
 
691
                                           BAD_CAST "allowed"))
 
692
        return;
 
693
 
 
694
    for (unsigned int i = 0; i < sizeof (map) / sizeof (map[0]); i++)
 
695
    {
 
696
        xmlChar *value;
 
697
 
 
698
        value = xmlGetProp (*xPath.obj->nodesetval->nodeTab,
 
699
                            BAD_CAST map[i].name);
 
700
        if (value)
 
701
        {
 
702
            if (xmlStrcmp (value, BAD_CAST "true") == 0)
 
703
                *state |= map[i].state;
 
704
            xmlFree (value);
 
705
        }
 
706
    }
 
707
 
 
708
    finiXPath (&xPath);
 
709
}
 
710
 
 
711
static bool
 
712
initOptionFromMetadataPath (CompMetadata  *metadata,
 
713
                            CompOption    *option,
 
714
                            const xmlChar *path)
 
715
{
 
716
    CompXPath         xPath, xDefaultPath;
 
717
    xmlNodePtr        node, defaultNode;
 
718
    xmlDocPtr         defaultDoc;
 
719
    xmlChar           *name, *type;
 
720
    CompString        value;
 
721
    CompAction::State state = 0;
 
722
    bool              helper = false;
 
723
    CompOption::Type  oType = CompOption::TypeBool;
 
724
 
 
725
    CompOption::Value::Vector emptyList (0);
 
726
 
 
727
    if (!initXPathFromMetadataPath (&xPath, metadata, path))
 
728
        return FALSE;
 
729
 
 
730
    node = *xPath.obj->nodesetval->nodeTab;
 
731
 
 
732
    type = xmlGetProp (node, BAD_CAST "type");
 
733
    if (type)
 
734
    {
 
735
        oType = getOptionType ((char *) type);
 
736
        xmlFree (type);
 
737
    }
 
738
 
 
739
    name = xmlGetProp (node, BAD_CAST "name");
 
740
    option->setName ((char *) name, oType);
 
741
    xmlFree (name);
 
742
 
 
743
    if (initXPathFromMetadataPathElement (&xDefaultPath, metadata, path,
 
744
                                          BAD_CAST "default"))
 
745
    {
 
746
        defaultDoc  = xDefaultPath.doc;
 
747
        defaultNode = *xDefaultPath.obj->nodesetval->nodeTab;
 
748
    }
 
749
    else
 
750
    {
 
751
        defaultDoc  = NULL;
 
752
        defaultNode = NULL;
 
753
    }
 
754
 
 
755
    switch (option->type ()) {
 
756
        case CompOption::TypeBool:
 
757
            initBoolValue (option->value (), defaultDoc, defaultNode);
 
758
            break;
 
759
        case CompOption::TypeInt:
 
760
            initIntRestriction (metadata, option->rest (), (char *) path);
 
761
            initIntValue (option->value (), option->rest (),
 
762
                          defaultDoc, defaultNode);
 
763
            break;
 
764
        case CompOption::TypeFloat:
 
765
            initFloatRestriction (metadata, option->rest (), (char *) path);
 
766
            initFloatValue (option->value (), option->rest (),
 
767
                            defaultDoc, defaultNode);
 
768
            break;
 
769
        case CompOption::TypeString:
 
770
            initStringValue (option->value (), option->rest (),
 
771
                             defaultDoc, defaultNode);
 
772
            break;
 
773
        case CompOption::TypeColor:
 
774
            initColorValue (option->value (), defaultDoc, defaultNode);
 
775
            break;
 
776
        case CompOption::TypeAction:
 
777
            initActionState (metadata, option->type (), &state, (char *) path);
 
778
            initActionValue (option->value (), state,
 
779
                             defaultDoc, defaultNode);
 
780
            break;
 
781
        case CompOption::TypeKey:
 
782
            initActionState (metadata, option->type (), &state, (char *) path);
 
783
            initKeyValue (option->value (), state,
 
784
                          defaultDoc, defaultNode);
 
785
            break;
 
786
        case CompOption::TypeButton:
 
787
            initActionState (metadata, option->type (), &state, (char *) path);
 
788
            initButtonValue (option->value (), state,
 
789
                             defaultDoc, defaultNode);
 
790
            break;
 
791
        case CompOption::TypeEdge:
 
792
            initActionState (metadata, option->type (), &state, (char *) path);
 
793
            initEdgeValue (option->value (), state,
 
794
                           defaultDoc, defaultNode);
 
795
            break;
 
796
        case CompOption::TypeBell:
 
797
            initActionState (metadata, option->type (), &state, (char *) path);
 
798
            initBellValue (option->value (), state,
 
799
                           defaultDoc, defaultNode);
 
800
            break;
 
801
        case CompOption::TypeMatch:
 
802
            helper = boolFromMetadataPathElement (metadata, (char *) path,
 
803
                                                  "helper", false);
 
804
            initMatchValue (option->value (), helper,
 
805
                            defaultDoc, defaultNode);
 
806
            break;
 
807
        case CompOption::TypeList:
 
808
            value = stringFromMetadataPathElement (metadata, (char *) path,
 
809
                                                   "type");
 
810
            if (!value.empty ())
 
811
                option->value ().set (getOptionType (value.c_str ()), emptyList);
 
812
            else
 
813
                option->value ().set (CompOption::TypeBool, emptyList);
 
814
 
 
815
            switch (option->value ().listType ()) {
 
816
                case CompOption::TypeInt:
 
817
                    initIntRestriction (metadata, option->rest (),
 
818
                                        (char *) path);
 
819
                    break;
 
820
                case CompOption::TypeFloat:
 
821
                    initFloatRestriction (metadata, option->rest (),
 
822
                                          (char *) path);
 
823
                    break;
 
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);
 
831
                    break;
 
832
                case CompOption::TypeMatch:
 
833
                    helper = boolFromMetadataPathElement (metadata,
 
834
                                                          (char *) path,
 
835
                                                          "helper", false);
 
836
                default:
 
837
                    break;
 
838
            }
 
839
 
 
840
            initListValue (option->value (), option->rest (), state, helper,
 
841
                           defaultDoc, defaultNode);
 
842
            break;
 
843
    }
 
844
 
 
845
    if (defaultDoc)
 
846
        finiXPath (&xDefaultPath);
 
847
 
 
848
    finiXPath (&xPath);
 
849
 
 
850
    return TRUE;
 
851
}
 
852
 
 
853
CompMetadata::CompMetadata (CompString       plugin,
 
854
                            const OptionInfo *optionInfo,
 
855
                            unsigned int     nOptionInfo)
 
856
{
 
857
    priv = new PrivateMetadata (plugin, compPrintf ("plugin[@name=\"%s\"]",
 
858
                                                    plugin.c_str ()));
 
859
    if (nOptionInfo)
 
860
    {
 
861
        CompIOCtx ctx;
 
862
 
 
863
        ctx.offset        = 0;
 
864
        ctx.name          = plugin.c_str ();
 
865
        ctx.oInfo  = optionInfo;
 
866
        ctx.nOInfo = nOptionInfo;
 
867
 
 
868
        addFromIO (readPluginXmlCallback, NULL, (void *) &ctx);
 
869
    }
 
870
}
 
871
 
 
872
CompMetadata::~CompMetadata ()
 
873
{
 
874
    delete priv;
 
875
}
 
876
 
 
877
std::vector<xmlDoc *> &
 
878
CompMetadata::doc ()
 
879
{
 
880
    return priv->mDoc;
 
881
}
 
882
 
 
883
 
 
884
bool
 
885
CompMetadata::addFromFile (CompString file, bool prepend)
 
886
{
 
887
    xmlDoc     *doc;
 
888
    CompString home (getenv ("HOME"));
 
889
    bool       status = false;
 
890
 
 
891
    home = getenv ("HOME");
 
892
    if (home.size ())
 
893
    {
 
894
        CompString path = compPrintf ("%s/%s", home.c_str (), HOME_METADATADIR);
 
895
        doc = readXmlFile (file, path);
 
896
        if (doc)
 
897
        {
 
898
            if (prepend)
 
899
                priv->mDoc.insert (priv->mDoc.begin (), doc);
 
900
            else
 
901
                priv->mDoc.push_back (doc);
 
902
 
 
903
            status = true;
 
904
        }
 
905
    }
 
906
 
 
907
    doc = readXmlFile (file, CompString (METADATADIR));
 
908
    if (doc)
 
909
    {
 
910
        if (prepend)
 
911
            priv->mDoc.insert (priv->mDoc.begin (), doc);
 
912
        else
 
913
            priv->mDoc.push_back (doc);
 
914
 
 
915
        status |= true;
 
916
    }
 
917
 
 
918
    if (!status)
 
919
    {
 
920
        compLogMessage ("core", CompLogLevelWarn,
 
921
                        "Unable to parse XML metadata from file \"%s%s\"",
 
922
                        file.c_str (), EXTENSION);
 
923
 
 
924
        return false;
 
925
    }
 
926
 
 
927
    return true;
 
928
}
 
929
 
 
930
bool
 
931
CompMetadata::addFromString (CompString string, bool prepend)
 
932
{
 
933
    xmlDoc *doc;
 
934
 
 
935
    doc = xmlReadMemory (string.c_str (), string.size (), NULL, NULL, 0);
 
936
    if (!doc)
 
937
    {
 
938
        compLogMessage ("core", CompLogLevelWarn,
 
939
                        "Unable to parse XML metadata");
 
940
 
 
941
        return false;
 
942
    }
 
943
 
 
944
    if (prepend)
 
945
        priv->mDoc.insert (priv->mDoc.begin (), doc);
 
946
    else
 
947
        priv->mDoc.push_back (doc);
 
948
 
 
949
    return true;
 
950
}
 
951
 
 
952
bool
 
953
CompMetadata::addFromIO (xmlInputReadCallback  ioread,
 
954
                         xmlInputCloseCallback ioclose,
 
955
                         void                  *ioctx,
 
956
                         bool                  prepend)
 
957
{
 
958
    xmlDoc *doc;
 
959
 
 
960
    doc = xmlReadIO (ioread, ioclose, ioctx, NULL, NULL, 0);
 
961
    if (!doc)
 
962
    {
 
963
        compLogMessage ("core", CompLogLevelWarn,
 
964
                        "Unable to parse XML metadata");
 
965
 
 
966
        return false;
 
967
    }
 
968
 
 
969
    if (prepend)
 
970
        priv->mDoc.insert (priv->mDoc.begin (), doc);
 
971
    else
 
972
        priv->mDoc.push_back (doc);
 
973
 
 
974
    return true;
 
975
}
 
976
 
 
977
bool
 
978
CompMetadata::addFromOptionInfo (const OptionInfo *optionInfo,
 
979
                                 unsigned int     nOptionInfo,
 
980
                                 bool             prepend)
 
981
{
 
982
    if (nOptionInfo)
 
983
    {
 
984
        CompIOCtx ctx;
 
985
 
 
986
        ctx.offset        = 0;
 
987
        ctx.name          = priv->mPlugin.c_str ();
 
988
        ctx.oInfo  = optionInfo;
 
989
        ctx.nOInfo = nOptionInfo;
 
990
 
 
991
        return addFromIO (readPluginXmlCallback, NULL, (void *) &ctx, prepend);
 
992
    }
 
993
    else
 
994
        return false;
 
995
}
 
996
 
 
997
bool
 
998
CompMetadata::initOption (CompOption  *option,
 
999
                          CompString  name)
 
1000
{
 
1001
    char str[1024];
 
1002
 
 
1003
    sprintf (str, "/compiz/%s/options//option[@name=\"%s\"]",
 
1004
             priv->mPath.c_str (), name.c_str ());
 
1005
 
 
1006
    return initOptionFromMetadataPath (this, option, BAD_CAST str);
 
1007
}
 
1008
 
 
1009
bool
 
1010
CompMetadata::initOptions (const OptionInfo   *info,
 
1011
                           unsigned int       nOptions,
 
1012
                           CompOption::Vector &opt)
 
1013
{
 
1014
    if (opt.size () < nOptions)
 
1015
        opt.resize (nOptions);
 
1016
 
 
1017
    for (unsigned int i = 0; i < nOptions; i++)
 
1018
    {
 
1019
        if (!initOption (&opt[i], info[i].name))
 
1020
        {
 
1021
            return false;
 
1022
        }
 
1023
        
 
1024
        if (info[i].initiate)
 
1025
            opt[i].value ().action ().setInitiate  (info[i].initiate);
 
1026
 
 
1027
        if (info[i].terminate)
 
1028
            opt[i].value ().action ().setTerminate (info[i].terminate);
 
1029
    }
 
1030
 
 
1031
    return true;
 
1032
}
 
1033
 
 
1034
CompString
 
1035
CompMetadata::getShortPluginDescription ()
 
1036
{
 
1037
    return getStringFromPath (
 
1038
        compPrintf ("/compiz/%s/short/child::text()", priv->mPath.c_str ()));
 
1039
}
 
1040
 
 
1041
CompString
 
1042
CompMetadata::getLongPluginDescription ()
 
1043
{
 
1044
    return getStringFromPath (
 
1045
        compPrintf ("/compiz/%s/long/child::text()", priv->mPath.c_str ()));
 
1046
}
 
1047
 
 
1048
CompString
 
1049
CompMetadata::getShortOptionDescription (CompOption *option)
 
1050
{
 
1051
    return getStringFromPath (
 
1052
        compPrintf (
 
1053
            "/compiz/%s/options//option[@name=\"%s\"]/short/child::text()",
 
1054
            priv->mPath.c_str (), option->name ().c_str ()));
 
1055
}
 
1056
 
 
1057
CompString
 
1058
CompMetadata::getLongOptionDescription (CompOption *option)
 
1059
{
 
1060
    return getStringFromPath (
 
1061
        compPrintf (
 
1062
            "/compiz/%s/options//option[@name=\"%s\"]/long/child::text()",
 
1063
            priv->mPath.c_str (), option->name ().c_str ()));
 
1064
}
 
1065
 
 
1066
 
 
1067
 
 
1068
CompString
 
1069
CompMetadata::getStringFromPath (CompString path)
 
1070
{
 
1071
    CompXPath  xPath;
 
1072
    CompString v = "";
 
1073
 
 
1074
    if (!initXPathFromMetadataPath (&xPath, this, BAD_CAST path.c_str ()))
 
1075
        return "";
 
1076
 
 
1077
    xPath.obj = xmlXPathConvertString (xPath.obj);
 
1078
 
 
1079
    if (xPath.obj->type == XPATH_STRING && xPath.obj->stringval)
 
1080
        v = (char *) xPath.obj->stringval;
 
1081
 
 
1082
    finiXPath (&xPath);
 
1083
 
 
1084
    return v;
 
1085
}
 
1086
 
 
1087
unsigned int
 
1088
CompMetadata::readXmlChunk (const char   *src,
 
1089
                            unsigned int *offset,
 
1090
                            char         *buffer,
 
1091
                            unsigned int length)
 
1092
{
 
1093
    unsigned int srcLength = strlen (src);
 
1094
    unsigned int srcOffset = *offset;
 
1095
 
 
1096
    if (srcOffset > srcLength)
 
1097
        srcOffset = srcLength;
 
1098
 
 
1099
    *offset -= srcOffset;
 
1100
 
 
1101
    src += srcOffset;
 
1102
    srcLength -= srcOffset;
 
1103
 
 
1104
    if (srcLength > 0 && length > 0)
 
1105
    {
 
1106
        if (srcLength < length)
 
1107
            length = srcLength;
 
1108
 
 
1109
        memcpy (buffer, src, length);
 
1110
 
 
1111
        return length;
 
1112
    }
 
1113
 
 
1114
    return 0;
 
1115
}
 
1116
 
 
1117
unsigned int
 
1118
CompMetadata::readXmlChunkFromOptionInfo (const CompMetadata::OptionInfo *info,
 
1119
                                          unsigned int                   *offset,
 
1120
                                          char                           *buffer,
 
1121
                                          unsigned int                   length)
 
1122
{
 
1123
    unsigned int i;
 
1124
 
 
1125
    i = readXmlChunk ("<option name=\"", offset, buffer, length);
 
1126
    i += readXmlChunk (info->name, offset, buffer + i, length - i);
 
1127
 
 
1128
    if (info->type)
 
1129
    {
 
1130
        i += readXmlChunk ("\" type=\"", offset, buffer + i, length - i);
 
1131
        i += readXmlChunk (info->type, offset, buffer + i, length - i);
 
1132
    }
 
1133
 
 
1134
    if (info->data)
 
1135
    {
 
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);
 
1139
    }
 
1140
    else
 
1141
    {
 
1142
        i += readXmlChunk ("\"/>", offset, buffer + i, length - i);
 
1143
    }
 
1144
 
 
1145
    return i;
 
1146
}
 
1147
 
 
1148
PrivateMetadata::PrivateMetadata (CompString plugin, CompString path) :
 
1149
    mPlugin (plugin),
 
1150
    mPath (path),
 
1151
    mDoc (0)
 
1152
{
 
1153
}
 
1154
 
 
1155
PrivateMetadata::~PrivateMetadata ()
 
1156
{
 
1157
    foreach (xmlDoc *d, mDoc)
 
1158
        xmlFreeDoc (d);
 
1159
}
 
1160