1 /*
2 * Copyright © 2007 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@deltatauchi.de>
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 <compiz-core.h>
35
36 #define HOME_METADATADIR ".compiz/metadata"
37 #define EXTENSION ".xml"
38
39 Bool
compInitMetadata(CompMetadata * metadata)40 compInitMetadata (CompMetadata *metadata)
41 {
42 metadata->path = strdup ("core");
43 if (!metadata->path)
44 return FALSE;
45
46 metadata->doc = NULL;
47 metadata->nDoc = 0;
48
49 return TRUE;
50 }
51
52 Bool
compInitPluginMetadata(CompMetadata * metadata,const char * plugin)53 compInitPluginMetadata (CompMetadata *metadata,
54 const char *plugin)
55 {
56 char str[1024];
57
58 snprintf (str, 1024, "plugin[@name=\"%s\"]", plugin);
59
60 metadata->path = strdup (str);
61 if (!metadata->path)
62 return FALSE;
63
64 metadata->doc = NULL;
65 metadata->nDoc = 0;
66
67 return TRUE;
68 }
69
70 void
compFiniMetadata(CompMetadata * metadata)71 compFiniMetadata (CompMetadata *metadata)
72 {
73 int i;
74
75 for (i = 0; i < metadata->nDoc; i++)
76 xmlFreeDoc (metadata->doc[i]);
77
78 if (metadata->doc)
79 free (metadata->doc);
80
81 free (metadata->path);
82 }
83
84 static xmlDoc *
readXmlFile(const char * path,const char * name)85 readXmlFile (const char *path,
86 const char *name)
87 {
88 char *file;
89 int length = strlen (name) + strlen (EXTENSION) + 1;
90 xmlDoc *doc = NULL;
91 FILE *fp;
92
93 if (path)
94 length += strlen (path) + 1;
95
96 file = malloc (length);
97 if (!file)
98 return NULL;
99
100 if (path)
101 sprintf (file, "%s/%s%s", path, name, EXTENSION);
102 else
103 sprintf (file, "%s%s", name, EXTENSION);
104
105 fp = fopen (file, "r");
106 if (!fp)
107 {
108 free (file);
109 return NULL;
110 }
111
112 fclose (fp);
113
114 doc = xmlReadFile (file, NULL, 0);
115
116 free (file);
117
118 return doc;
119 }
120
121 static Bool
addMetadataFromFilename(CompMetadata * metadata,const char * path,const char * file)122 addMetadataFromFilename (CompMetadata *metadata,
123 const char *path,
124 const char *file)
125 {
126 xmlDoc **d, *doc;
127
128 doc = readXmlFile (path, file);
129 if (!doc)
130 return FALSE;
131
132 d = realloc (metadata->doc, (metadata->nDoc + 1) * sizeof (xmlDoc *));
133 if (!d)
134 {
135 xmlFreeDoc (doc);
136 return FALSE;
137 }
138
139 d[metadata->nDoc++] = doc;
140 metadata->doc = d;
141
142 return TRUE;
143 }
144
145 Bool
compAddMetadataFromFile(CompMetadata * metadata,const char * file)146 compAddMetadataFromFile (CompMetadata *metadata,
147 const char *file)
148 {
149 char *home;
150 Bool status = FALSE;
151
152 home = getenv ("HOME");
153 if (home)
154 {
155 char *path;
156
157 path = malloc (strlen (home) + strlen (HOME_METADATADIR) + 2);
158 if (path)
159 {
160 sprintf (path, "%s/%s", home, HOME_METADATADIR);
161 status |= addMetadataFromFilename (metadata, path, file);
162 free (path);
163 }
164 }
165
166 status |= addMetadataFromFilename (metadata, METADATADIR, file);
167 if (!status)
168 {
169 compLogMessage ("core", CompLogLevelWarn,
170 "Unable to parse XML metadata from file \"%s%s\"",
171 file, EXTENSION);
172
173 return FALSE;
174 }
175
176 return TRUE;
177 }
178
179 Bool
compAddMetadataFromString(CompMetadata * metadata,const char * string)180 compAddMetadataFromString (CompMetadata *metadata,
181 const char *string)
182 {
183 xmlDoc **d, *doc;
184
185 doc = xmlReadMemory (string, strlen (string), NULL, NULL, 0);
186 if (!doc)
187 {
188 compLogMessage ("core", CompLogLevelWarn,
189 "Unable to parse XML metadata");
190
191 return FALSE;
192 }
193
194 d = realloc (metadata->doc, (metadata->nDoc + 1) * sizeof (xmlDoc *));
195 if (!d)
196 {
197 xmlFreeDoc (doc);
198 return FALSE;
199 }
200
201 d[metadata->nDoc++] = doc;
202 metadata->doc = d;
203
204 return TRUE;
205 }
206
207 Bool
compAddMetadataFromIO(CompMetadata * metadata,xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx)208 compAddMetadataFromIO (CompMetadata *metadata,
209 xmlInputReadCallback ioread,
210 xmlInputCloseCallback ioclose,
211 void *ioctx)
212 {
213 xmlDoc **d, *doc;
214
215 doc = xmlReadIO (ioread, ioclose, ioctx, NULL, NULL, 0);
216 if (!doc)
217 {
218 compLogMessage ("core", CompLogLevelWarn,
219 "Unable to parse XML metadata");
220
221 return FALSE;
222 }
223
224 d = realloc (metadata->doc, (metadata->nDoc + 1) * sizeof (xmlDoc *));
225 if (!d)
226 {
227 xmlFreeDoc (doc);
228 return FALSE;
229 }
230
231 d[metadata->nDoc++] = doc;
232 metadata->doc = d;
233
234 return TRUE;
235 }
236
237 typedef struct _CompIOCtx {
238 int offset;
239 const char *name;
240 const CompMetadataOptionInfo *displayOInfo;
241 int nDisplayOInfo;
242 const CompMetadataOptionInfo *screenOInfo;
243 int nScreenOInfo;
244 } CompIOCtx;
245
246 static int
readPluginXmlCallback(void * context,char * buffer,int length)247 readPluginXmlCallback (void *context,
248 char *buffer,
249 int length)
250 {
251 CompIOCtx *ctx = (CompIOCtx *) context;
252 int offset = ctx->offset;
253 int i, j;
254
255 i = compReadXmlChunk ("<compiz><plugin name=\"", &offset, buffer, length);
256 i += compReadXmlChunk (ctx->name, &offset, buffer + i, length - i);
257 i += compReadXmlChunk ("\">", &offset, buffer + i, length - i);
258
259 if (ctx->nDisplayOInfo)
260 {
261 i += compReadXmlChunk ("<display>", &offset, buffer + i, length - i);
262
263 for (j = 0; j < ctx->nDisplayOInfo; j++)
264 i += compReadXmlChunkFromMetadataOptionInfo (&ctx->displayOInfo[j],
265 &offset,
266 buffer + i,
267 length - i);
268
269 i += compReadXmlChunk ("</display>", &offset, buffer + i, length - i);
270 }
271
272 if (ctx->nScreenOInfo)
273 {
274 i += compReadXmlChunk ("<screen>", &offset, buffer + i, length - i);
275
276 for (j = 0; j < ctx->nScreenOInfo; j++)
277 i += compReadXmlChunkFromMetadataOptionInfo (&ctx->screenOInfo[j],
278 &offset,
279 buffer + i,
280 length - i);
281
282 i += compReadXmlChunk ("</screen>", &offset, buffer + i, length - i);
283 }
284
285 i += compReadXmlChunk ("</plugin></compiz>", &offset, buffer + i,
286 length - i);
287
288 if (!offset && length > i)
289 buffer[i++] = '\0';
290
291 ctx->offset += i;
292
293 return i;
294 }
295
296 Bool
compInitPluginMetadataFromInfo(CompMetadata * metadata,const char * plugin,const CompMetadataOptionInfo * displayOptionInfo,int nDisplayOptionInfo,const CompMetadataOptionInfo * screenOptionInfo,int nScreenOptionInfo)297 compInitPluginMetadataFromInfo (CompMetadata *metadata,
298 const char *plugin,
299 const CompMetadataOptionInfo *displayOptionInfo,
300 int nDisplayOptionInfo,
301 const CompMetadataOptionInfo *screenOptionInfo,
302 int nScreenOptionInfo)
303 {
304 if (!compInitPluginMetadata (metadata, plugin))
305 return FALSE;
306
307 if (nDisplayOptionInfo || nScreenOptionInfo)
308 {
309 CompIOCtx ctx;
310
311 ctx.offset = 0;
312 ctx.name = plugin;
313 ctx.displayOInfo = displayOptionInfo;
314 ctx.nDisplayOInfo = nDisplayOptionInfo;
315 ctx.screenOInfo = screenOptionInfo;
316 ctx.nScreenOInfo = nScreenOptionInfo;
317
318 if (!compAddMetadataFromIO (metadata,
319 readPluginXmlCallback, NULL,
320 (void *) &ctx))
321 {
322 compFiniMetadata (metadata);
323 return FALSE;
324 }
325 }
326
327 return TRUE;
328 }
329
330 typedef struct _CompXPath {
331 xmlXPathObjectPtr obj;
332 xmlXPathContextPtr ctx;
333 xmlDocPtr doc;
334 } CompXPath;
335
336 static Bool
initXPathFromMetadataPath(CompXPath * xPath,CompMetadata * metadata,const xmlChar * path)337 initXPathFromMetadataPath (CompXPath *xPath,
338 CompMetadata *metadata,
339 const xmlChar *path)
340 {
341 xmlXPathObjectPtr obj;
342 xmlXPathContextPtr ctx;
343 int i;
344
345 for (i = 0; i < metadata->nDoc; i++)
346 {
347 ctx = xmlXPathNewContext (metadata->doc[i]);
348 if (ctx)
349 {
350 obj = xmlXPathEvalExpression (path, ctx);
351 if (obj)
352 {
353 if (obj->nodesetval && obj->nodesetval->nodeNr)
354 {
355 xPath->ctx = ctx;
356 xPath->obj = obj;
357 xPath->doc = metadata->doc[i];
358
359 return TRUE;
360 }
361
362 xmlXPathFreeObject (obj);
363 }
364
365 xmlXPathFreeContext (ctx);
366 }
367 }
368
369 return FALSE;
370 }
371
372 static Bool
initXPathFromMetadataPathElement(CompXPath * xPath,CompMetadata * metadata,const xmlChar * path,const xmlChar * element)373 initXPathFromMetadataPathElement (CompXPath *xPath,
374 CompMetadata *metadata,
375 const xmlChar *path,
376 const xmlChar *element)
377 {
378 char str[1024];
379
380 snprintf (str, 1024, "%s/%s", path, element);
381
382 return initXPathFromMetadataPath (xPath, metadata, BAD_CAST str);
383 }
384
385 static void
finiXPath(CompXPath * xPath)386 finiXPath (CompXPath *xPath)
387 {
388 xmlXPathFreeObject (xPath->obj);
389 xmlXPathFreeContext (xPath->ctx);
390 }
391
392 static CompOptionType
getOptionType(char * name)393 getOptionType (char *name)
394 {
395 static struct _TypeMap {
396 char *name;
397 CompOptionType type;
398 } map[] = {
399 { "int", CompOptionTypeInt },
400 { "float", CompOptionTypeFloat },
401 { "string", CompOptionTypeString },
402 { "color", CompOptionTypeColor },
403 { "action", CompOptionTypeAction },
404 { "key", CompOptionTypeKey },
405 { "button", CompOptionTypeButton },
406 { "edge", CompOptionTypeEdge },
407 { "bell", CompOptionTypeBell },
408 { "match", CompOptionTypeMatch },
409 { "list", CompOptionTypeList }
410 };
411 int i;
412
413 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
414 if (strcasecmp (name, map[i].name) == 0)
415 return map[i].type;
416
417 return CompOptionTypeBool;
418 }
419
420 static void
initBoolValue(CompOptionValue * v,xmlDocPtr doc,xmlNodePtr node)421 initBoolValue (CompOptionValue *v,
422 xmlDocPtr doc,
423 xmlNodePtr node)
424 {
425 xmlChar *value;
426
427 v->b = FALSE;
428
429 if (!doc)
430 return;
431
432 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
433 if (value)
434 {
435 if (strcasecmp ((char *) value, "true") == 0)
436 v->b = TRUE;
437
438 xmlFree (value);
439 }
440 }
441
442 static void
initIntValue(CompOptionValue * v,CompOptionRestriction * r,xmlDocPtr doc,xmlNodePtr node)443 initIntValue (CompOptionValue *v,
444 CompOptionRestriction *r,
445 xmlDocPtr doc,
446 xmlNodePtr node)
447 {
448 xmlChar *value;
449
450 v->i = (r->i.min + r->i.max) / 2;
451
452 if (!doc)
453 return;
454
455 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
456 if (value)
457 {
458 int i = strtol ((char *) value, NULL, 0);
459
460 if (i >= r->i.min && i <= r->i.max)
461 v->i = i;
462
463 xmlFree (value);
464 }
465 }
466
467 static void
initFloatValue(CompOptionValue * v,CompOptionRestriction * r,xmlDocPtr doc,xmlNodePtr node)468 initFloatValue (CompOptionValue *v,
469 CompOptionRestriction *r,
470 xmlDocPtr doc,
471 xmlNodePtr node)
472 {
473 xmlChar *value;
474 char *loc;
475
476 v->f = (r->f.min + r->f.max) / 2;
477
478 if (!doc)
479 return;
480
481 loc = setlocale (LC_NUMERIC, "C");
482 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
483 if (value)
484 {
485 float f = strtod ((char *) value, NULL);
486
487 if (f >= r->f.min && f <= r->f.max)
488 v->f = f;
489
490 xmlFree (value);
491 }
492 setlocale (LC_NUMERIC, loc);
493 }
494
495 static void
initStringValue(CompOptionValue * v,CompOptionRestriction * r,xmlDocPtr doc,xmlNodePtr node)496 initStringValue (CompOptionValue *v,
497 CompOptionRestriction *r,
498 xmlDocPtr doc,
499 xmlNodePtr node)
500 {
501 xmlChar *value;
502
503 v->s = strdup ("");
504
505 if (!doc)
506 return;
507
508 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
509 if (value)
510 {
511 free (v->s);
512 v->s = strdup ((char *) value);
513
514 xmlFree (value);
515 }
516 }
517
518 static void
initColorValue(CompOptionValue * v,xmlDocPtr doc,xmlNodePtr node)519 initColorValue (CompOptionValue *v,
520 xmlDocPtr doc,
521 xmlNodePtr node)
522 {
523 xmlNodePtr child;
524
525 v->c[0] = 0x0000;
526 v->c[1] = 0x0000;
527 v->c[2] = 0x0000;
528 v->c[3] = 0xffff;
529
530 if (!doc)
531 return;
532
533 for (child = node->xmlChildrenNode; child; child = child->next)
534 {
535 xmlChar *value;
536 int index;
537
538 if (!xmlStrcmp (child->name, BAD_CAST "red"))
539 index = 0;
540 else if (!xmlStrcmp (child->name, BAD_CAST "green"))
541 index = 1;
542 else if (!xmlStrcmp (child->name, BAD_CAST "blue"))
543 index = 2;
544 else if (!xmlStrcmp (child->name, BAD_CAST "alpha"))
545 index = 3;
546 else
547 continue;
548
549 value = xmlNodeListGetString (child->doc, child->xmlChildrenNode, 1);
550 if (value)
551 {
552 int color = strtol ((char *) value, NULL , 0);
553
554 v->c[index] = MAX (0, MIN (0xffff, color));
555
556 xmlFree (value);
557 }
558 }
559 }
560
561 static void
initActionValue(CompDisplay * d,CompOptionValue * v,CompActionState state,xmlDocPtr doc,xmlNodePtr node)562 initActionValue (CompDisplay *d,
563 CompOptionValue *v,
564 CompActionState state,
565 xmlDocPtr doc,
566 xmlNodePtr node)
567 {
568 memset (&v->action, 0, sizeof (v->action));
569
570 v->action.state = state;
571 }
572
573 static void
initKeyValue(CompDisplay * d,CompOptionValue * v,CompActionState state,xmlDocPtr doc,xmlNodePtr node)574 initKeyValue (CompDisplay *d,
575 CompOptionValue *v,
576 CompActionState state,
577 xmlDocPtr doc,
578 xmlNodePtr node)
579 {
580 xmlChar *value;
581
582 memset (&v->action, 0, sizeof (v->action));
583
584 v->action.state = state | CompActionStateInitKey;
585
586 if (!doc)
587 return;
588
589 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
590 if (value)
591 {
592 char *binding = (char *) value;
593
594 if (strcasecmp (binding, "disabled") && *binding)
595 stringToKeyAction (d, binding, &v->action);
596
597 xmlFree (value);
598 }
599
600 if (state & CompActionStateAutoGrab)
601 {
602 CompScreen *s;
603
604 for (s = d->screens; s; s = s->next)
605 addScreenAction (s, &v->action);
606 }
607 }
608
609 static void
initButtonValue(CompDisplay * d,CompOptionValue * v,CompActionState state,xmlDocPtr doc,xmlNodePtr node)610 initButtonValue (CompDisplay *d,
611 CompOptionValue *v,
612 CompActionState state,
613 xmlDocPtr doc,
614 xmlNodePtr node)
615 {
616 xmlChar *value;
617
618 memset (&v->action, 0, sizeof (v->action));
619
620 v->action.state = state | CompActionStateInitButton |
621 CompActionStateInitEdge;
622
623 if (!doc)
624 return;
625
626 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
627 if (value)
628 {
629 char *binding = (char *) value;
630
631 if (strcasecmp (binding, "disabled") && *binding)
632 stringToButtonAction (d, binding, &v->action);
633
634 xmlFree (value);
635 }
636
637 if (state & CompActionStateAutoGrab)
638 {
639 CompScreen *s;
640
641 for (s = d->screens; s; s = s->next)
642 addScreenAction (s, &v->action);
643 }
644 }
645
646 static void
initEdgeValue(CompDisplay * d,CompOptionValue * v,CompActionState state,xmlDocPtr doc,xmlNodePtr node)647 initEdgeValue (CompDisplay *d,
648 CompOptionValue *v,
649 CompActionState state,
650 xmlDocPtr doc,
651 xmlNodePtr node)
652 {
653 xmlNodePtr child;
654 xmlChar *value;
655
656 memset (&v->action, 0, sizeof (v->action));
657
658 v->action.state = state | CompActionStateInitEdge;
659
660 if (!doc)
661 return;
662
663 for (child = node->xmlChildrenNode; child; child = child->next)
664 {
665 value = xmlGetProp (child, BAD_CAST "name");
666 if (value)
667 {
668 int i;
669
670 for (i = 0; i < SCREEN_EDGE_NUM; i++)
671 if (strcasecmp ((char *) value, edgeToString (i)) == 0)
672 v->action.edgeMask |= (1 << i);
673
674 xmlFree (value);
675 }
676 }
677
678 if (state & CompActionStateAutoGrab)
679 {
680 CompScreen *s;
681
682 for (s = d->screens; s; s = s->next)
683 addScreenAction (s, &v->action);
684 }
685 }
686
687 static void
initBellValue(CompDisplay * d,CompOptionValue * v,CompActionState state,xmlDocPtr doc,xmlNodePtr node)688 initBellValue (CompDisplay *d,
689 CompOptionValue *v,
690 CompActionState state,
691 xmlDocPtr doc,
692 xmlNodePtr node)
693 {
694 xmlChar *value;
695
696 memset (&v->action, 0, sizeof (v->action));
697
698 v->action.state = state | CompActionStateInitBell;
699
700 if (!doc)
701 return;
702
703 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
704 if (value)
705 {
706 if (strcasecmp ((char *) value, "true") == 0)
707 v->action.bell = TRUE;
708
709 xmlFree (value);
710 }
711 }
712
713 static void
initMatchValue(CompDisplay * d,CompOptionValue * v,Bool helper,xmlDocPtr doc,xmlNodePtr node)714 initMatchValue (CompDisplay *d,
715 CompOptionValue *v,
716 Bool helper,
717 xmlDocPtr doc,
718 xmlNodePtr node)
719 {
720 xmlChar *value;
721
722 matchInit (&v->match);
723
724 if (!doc)
725 return;
726
727 value = xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
728 if (value)
729 {
730 matchAddFromString (&v->match, (char *) value);
731 xmlFree (value);
732 }
733
734 if (!helper)
735 matchUpdate (d, &v->match);
736 }
737
738 static void
initListValue(CompDisplay * d,CompOptionValue * v,CompOptionRestriction * r,CompActionState state,Bool helper,xmlDocPtr doc,xmlNodePtr node)739 initListValue (CompDisplay *d,
740 CompOptionValue *v,
741 CompOptionRestriction *r,
742 CompActionState state,
743 Bool helper,
744 xmlDocPtr doc,
745 xmlNodePtr node)
746 {
747 xmlNodePtr child;
748
749 v->list.value = NULL;
750 v->list.nValue = 0;
751
752 if (!doc)
753 return;
754
755 for (child = node->xmlChildrenNode; child; child = child->next)
756 {
757 CompOptionValue *value;
758
759 if (xmlStrcmp (child->name, BAD_CAST "value"))
760 continue;
761
762 value = realloc (v->list.value,
763 sizeof (CompOptionValue) * (v->list.nValue + 1));
764 if (value)
765 {
766 switch (v->list.type) {
767 case CompOptionTypeBool:
768 initBoolValue (&value[v->list.nValue], doc, child);
769 break;
770 case CompOptionTypeInt:
771 initIntValue (&value[v->list.nValue], r, doc, child);
772 break;
773 case CompOptionTypeFloat:
774 initFloatValue (&value[v->list.nValue], r, doc, child);
775 break;
776 case CompOptionTypeString:
777 initStringValue (&value[v->list.nValue], r, doc, child);
778 break;
779 case CompOptionTypeColor:
780 initColorValue (&value[v->list.nValue], doc, child);
781 break;
782 case CompOptionTypeAction:
783 initActionValue (d, &value[v->list.nValue], state, doc, child);
784 break;
785 case CompOptionTypeKey:
786 initKeyValue (d, &value[v->list.nValue], state, doc, child);
787 break;
788 case CompOptionTypeButton:
789 initButtonValue (d, &value[v->list.nValue], state, doc, child);
790 break;
791 case CompOptionTypeEdge:
792 initEdgeValue (d, &value[v->list.nValue], state, doc, child);
793 break;
794 case CompOptionTypeBell:
795 initBellValue (d, &value[v->list.nValue], state, doc, child);
796 break;
797 case CompOptionTypeMatch:
798 initMatchValue (d, &value[v->list.nValue], helper, doc, child);
799 default:
800 break;
801 }
802
803 v->list.value = value;
804 v->list.nValue++;
805 }
806 }
807 }
808
809 static char *
stringFromMetadataPathElement(CompMetadata * metadata,const char * path,const char * element)810 stringFromMetadataPathElement (CompMetadata *metadata,
811 const char *path,
812 const char *element)
813 {
814 char str[1024];
815
816 snprintf (str, 1024, "%s/%s", path, element);
817
818 return compGetStringFromMetadataPath (metadata, str);
819 }
820
821 static Bool
boolFromMetadataPathElement(CompMetadata * metadata,const char * path,const char * element,Bool defaultValue)822 boolFromMetadataPathElement (CompMetadata *metadata,
823 const char *path,
824 const char *element,
825 Bool defaultValue)
826 {
827 Bool value = FALSE;
828 char *str;
829
830 str = stringFromMetadataPathElement (metadata, path, element);
831 if (!str)
832 return defaultValue;
833
834 if (strcasecmp (str, "true") == 0)
835 value = TRUE;
836
837 free (str);
838
839 return value;
840 }
841
842 static void
initIntRestriction(CompMetadata * metadata,CompOptionRestriction * r,const char * path)843 initIntRestriction (CompMetadata *metadata,
844 CompOptionRestriction *r,
845 const char *path)
846 {
847 char *value;
848
849 r->i.min = MINSHORT;
850 r->i.max = MAXSHORT;
851
852 value = stringFromMetadataPathElement (metadata, path, "min");
853 if (value)
854 {
855 r->i.min = strtol ((char *) value, NULL, 0);
856 free (value);
857 }
858
859 value = stringFromMetadataPathElement (metadata, path, "max");
860 if (value)
861 {
862 r->i.max = strtol ((char *) value, NULL, 0);
863 free (value);
864 }
865 }
866
867 static void
initFloatRestriction(CompMetadata * metadata,CompOptionRestriction * r,const char * path)868 initFloatRestriction (CompMetadata *metadata,
869 CompOptionRestriction *r,
870 const char *path)
871 {
872 char *value;
873 char *loc;
874
875 r->f.min = MINSHORT;
876 r->f.max = MAXSHORT;
877 r->f.precision = 0.1f;
878
879 loc = setlocale (LC_NUMERIC, "C");
880 value = stringFromMetadataPathElement (metadata, path, "min");
881 if (value)
882 {
883 r->f.min = strtod ((char *) value, NULL);
884 free (value);
885 }
886
887 value = stringFromMetadataPathElement (metadata, path, "max");
888 if (value)
889 {
890 r->f.max = strtod ((char *) value, NULL);
891 free (value);
892 }
893
894 value = stringFromMetadataPathElement (metadata, path, "precision");
895 if (value)
896 {
897 r->f.precision = strtod ((char *) value, NULL);
898 free (value);
899 }
900
901 setlocale (LC_NUMERIC, loc);
902 }
903
904 static void
initActionState(CompMetadata * metadata,CompOptionType type,CompActionState * state,const char * path)905 initActionState (CompMetadata *metadata,
906 CompOptionType type,
907 CompActionState *state,
908 const char *path)
909 {
910 static struct _StateMap {
911 char *name;
912 CompActionState state;
913 } map[] = {
914 { "key", CompActionStateInitKey },
915 { "button", CompActionStateInitButton },
916 { "bell", CompActionStateInitBell },
917 { "edge", CompActionStateInitEdge },
918 { "edgednd", CompActionStateInitEdgeDnd }
919 };
920 int i;
921 CompXPath xPath;
922 char *grab;
923
924 *state = CompActionStateAutoGrab;
925
926 grab = stringFromMetadataPathElement (metadata, path, "passive_grab");
927 if (grab)
928 {
929 if (strcmp (grab, "false") == 0)
930 *state = 0;
931
932 free (grab);
933 }
934
935 if (type == CompOptionTypeEdge)
936 {
937 char *noEdgeDelay;
938
939 noEdgeDelay = stringFromMetadataPathElement (metadata, path, "nodelay");
940 if (noEdgeDelay)
941 {
942 if (strcmp (noEdgeDelay, "true") == 0)
943 *state |= CompActionStateNoEdgeDelay;
944
945 free (noEdgeDelay);
946 }
947 }
948
949 if (!initXPathFromMetadataPathElement (&xPath, metadata, BAD_CAST path,
950 BAD_CAST "allowed"))
951 return;
952
953 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
954 {
955 xmlChar *value;
956
957 value = xmlGetProp (*xPath.obj->nodesetval->nodeTab,
958 BAD_CAST map[i].name);
959 if (value)
960 {
961 if (xmlStrcmp (value, BAD_CAST "true") == 0)
962 *state |= map[i].state;
963 xmlFree (value);
964 }
965 }
966
967 finiXPath (&xPath);
968 }
969
970 static Bool
initOptionFromMetadataPath(CompDisplay * d,CompMetadata * metadata,CompOption * option,const xmlChar * path)971 initOptionFromMetadataPath (CompDisplay *d,
972 CompMetadata *metadata,
973 CompOption *option,
974 const xmlChar *path)
975 {
976 CompXPath xPath, xDefaultPath;
977 xmlNodePtr node, defaultNode;
978 xmlDocPtr defaultDoc;
979 xmlChar *name, *type;
980 char *value;
981 CompActionState state = 0;
982 Bool helper = FALSE;
983
984 if (!initXPathFromMetadataPath (&xPath, metadata, path))
985 return FALSE;
986
987 node = *xPath.obj->nodesetval->nodeTab;
988
989 type = xmlGetProp (node, BAD_CAST "type");
990 if (type)
991 {
992 option->type = getOptionType ((char *) type);
993 xmlFree (type);
994 }
995 else
996 {
997 option->type = CompOptionTypeBool;
998 }
999
1000 name = xmlGetProp (node, BAD_CAST "name");
1001 option->name = strdup ((char *) name);
1002 xmlFree (name);
1003
1004 if (initXPathFromMetadataPathElement (&xDefaultPath, metadata, path,
1005 BAD_CAST "default"))
1006 {
1007 defaultDoc = xDefaultPath.doc;
1008 defaultNode = *xDefaultPath.obj->nodesetval->nodeTab;
1009 }
1010 else
1011 {
1012 defaultDoc = NULL;
1013 defaultNode = NULL;
1014 }
1015
1016 switch (option->type) {
1017 case CompOptionTypeBool:
1018 initBoolValue (&option->value, defaultDoc, defaultNode);
1019 break;
1020 case CompOptionTypeInt:
1021 initIntRestriction (metadata, &option->rest, (char *) path);
1022 initIntValue (&option->value, &option->rest, defaultDoc, defaultNode);
1023 break;
1024 case CompOptionTypeFloat:
1025 initFloatRestriction (metadata, &option->rest, (char *) path);
1026 initFloatValue (&option->value, &option->rest, defaultDoc, defaultNode);
1027 break;
1028 case CompOptionTypeString:
1029 initStringValue (&option->value, &option->rest,
1030 defaultDoc, defaultNode);
1031 break;
1032 case CompOptionTypeColor:
1033 initColorValue (&option->value, defaultDoc, defaultNode);
1034 break;
1035 case CompOptionTypeAction:
1036 initActionState (metadata, option->type, &state, (char *) path);
1037 initActionValue (d, &option->value, state, defaultDoc, defaultNode);
1038 break;
1039 case CompOptionTypeKey:
1040 initActionState (metadata, option->type, &state, (char *) path);
1041 initKeyValue (d, &option->value, state, defaultDoc, defaultNode);
1042 break;
1043 case CompOptionTypeButton:
1044 initActionState (metadata, option->type, &state, (char *) path);
1045 initButtonValue (d, &option->value, state, defaultDoc, defaultNode);
1046 break;
1047 case CompOptionTypeEdge:
1048 initActionState (metadata, option->type, &state, (char *) path);
1049 initEdgeValue (d, &option->value, state, defaultDoc, defaultNode);
1050 break;
1051 case CompOptionTypeBell:
1052 initActionState (metadata, option->type, &state, (char *) path);
1053 initBellValue (d, &option->value, state, defaultDoc, defaultNode);
1054 break;
1055 case CompOptionTypeMatch:
1056 helper = boolFromMetadataPathElement (metadata, (char *) path, "helper",
1057 FALSE);
1058 initMatchValue (d, &option->value, helper, defaultDoc, defaultNode);
1059 break;
1060 case CompOptionTypeList:
1061 value = stringFromMetadataPathElement (metadata, (char *) path, "type");
1062 if (value)
1063 {
1064 option->value.list.type = getOptionType ((char *) value);
1065 free (value);
1066 }
1067 else
1068 {
1069 option->value.list.type = CompOptionTypeBool;
1070 }
1071
1072 switch (option->value.list.type) {
1073 case CompOptionTypeInt:
1074 initIntRestriction (metadata, &option->rest, (char *) path);
1075 break;
1076 case CompOptionTypeFloat:
1077 initFloatRestriction (metadata, &option->rest, (char *) path);
1078 break;
1079 case CompOptionTypeAction:
1080 case CompOptionTypeKey:
1081 case CompOptionTypeButton:
1082 case CompOptionTypeEdge:
1083 case CompOptionTypeBell:
1084 initActionState (metadata, option->value.list.type,
1085 &state, (char *) path);
1086 break;
1087 case CompOptionTypeMatch:
1088 helper = boolFromMetadataPathElement (metadata, (char *) path,
1089 "helper", FALSE);
1090 default:
1091 break;
1092 }
1093
1094 initListValue (d, &option->value, &option->rest, state, helper,
1095 defaultDoc, defaultNode);
1096 break;
1097 }
1098
1099 if (defaultDoc)
1100 finiXPath (&xDefaultPath);
1101
1102 finiXPath (&xPath);
1103
1104 return TRUE;
1105 }
1106
1107 Bool
compInitScreenOptionFromMetadata(CompScreen * s,CompMetadata * m,CompOption * o,const char * name)1108 compInitScreenOptionFromMetadata (CompScreen *s,
1109 CompMetadata *m,
1110 CompOption *o,
1111 const char *name)
1112 {
1113 char str[1024];
1114
1115 sprintf (str, "/compiz/%s/screen//option[@name=\"%s\"]", m->path, name);
1116
1117 return initOptionFromMetadataPath (s->display, m, o, BAD_CAST str);
1118 }
1119
1120 static void
finiScreenOptionValue(CompScreen * s,CompOptionValue * v,CompOptionType type)1121 finiScreenOptionValue (CompScreen *s,
1122 CompOptionValue *v,
1123 CompOptionType type)
1124 {
1125 int i;
1126
1127 switch (type) {
1128 case CompOptionTypeAction:
1129 case CompOptionTypeKey:
1130 case CompOptionTypeButton:
1131 case CompOptionTypeEdge:
1132 case CompOptionTypeBell:
1133 if (v->action.state & CompActionStateAutoGrab)
1134 removeScreenAction (s, &v->action);
1135 break;
1136 case CompOptionTypeList:
1137 for (i = 0; i < v->list.nValue; i++)
1138 finiScreenOptionValue (s, &v->list.value[i], v->list.type);
1139 default:
1140 break;
1141 }
1142 }
1143
1144 void
compFiniScreenOption(CompScreen * s,CompOption * o)1145 compFiniScreenOption (CompScreen *s,
1146 CompOption *o)
1147 {
1148 finiScreenOptionValue (s, &o->value, o->type);
1149 compFiniOption (o);
1150 free (o->name);
1151 }
1152
1153 Bool
compInitScreenOptionsFromMetadata(CompScreen * s,CompMetadata * m,const CompMetadataOptionInfo * info,CompOption * opt,int n)1154 compInitScreenOptionsFromMetadata (CompScreen *s,
1155 CompMetadata *m,
1156 const CompMetadataOptionInfo *info,
1157 CompOption *opt,
1158 int n)
1159 {
1160 int i;
1161
1162 for (i = 0; i < n; i++)
1163 {
1164 if (!compInitScreenOptionFromMetadata (s, m, &opt[i], info[i].name))
1165 {
1166 compFiniScreenOptions (s, opt, i);
1167 return FALSE;
1168 }
1169
1170 if (info[i].initiate)
1171 opt[i].value.action.initiate = info[i].initiate;
1172
1173 if (info[i].terminate)
1174 opt[i].value.action.terminate = info[i].terminate;
1175 }
1176
1177 return TRUE;
1178 }
1179
1180 void
compFiniScreenOptions(CompScreen * s,CompOption * opt,int n)1181 compFiniScreenOptions (CompScreen *s,
1182 CompOption *opt,
1183 int n)
1184 {
1185 int i;
1186
1187 for (i = 0; i < n; i++)
1188 compFiniScreenOption (s, &opt[i]);
1189 }
1190
1191 Bool
compSetScreenOption(CompScreen * s,CompOption * o,CompOptionValue * value)1192 compSetScreenOption (CompScreen *s,
1193 CompOption *o,
1194 CompOptionValue *value)
1195 {
1196 if (compSetOption (o, value))
1197 return TRUE;
1198
1199 return FALSE;
1200 }
1201
1202 Bool
compInitDisplayOptionFromMetadata(CompDisplay * d,CompMetadata * m,CompOption * o,const char * name)1203 compInitDisplayOptionFromMetadata (CompDisplay *d,
1204 CompMetadata *m,
1205 CompOption *o,
1206 const char *name)
1207 {
1208 char str[1024];
1209
1210 sprintf (str, "/compiz/%s/display//option[@name=\"%s\"]", m->path, name);
1211
1212 return initOptionFromMetadataPath (d, m, o, BAD_CAST str);
1213 }
1214
1215 static void
finiDisplayOptionValue(CompDisplay * d,CompOptionValue * v,CompOptionType type)1216 finiDisplayOptionValue (CompDisplay *d,
1217 CompOptionValue *v,
1218 CompOptionType type)
1219 {
1220 CompScreen *s;
1221 int i;
1222
1223 switch (type) {
1224 case CompOptionTypeAction:
1225 case CompOptionTypeKey:
1226 case CompOptionTypeButton:
1227 case CompOptionTypeEdge:
1228 case CompOptionTypeBell:
1229 if (v->action.state & CompActionStateAutoGrab)
1230 for (s = d->screens; s; s = s->next)
1231 removeScreenAction (s, &v->action);
1232 break;
1233 case CompOptionTypeList:
1234 for (i = 0; i < v->list.nValue; i++)
1235 finiDisplayOptionValue (d, &v->list.value[i], v->list.type);
1236 default:
1237 break;
1238 }
1239 }
1240
1241 void
compFiniDisplayOption(CompDisplay * d,CompOption * o)1242 compFiniDisplayOption (CompDisplay *d,
1243 CompOption *o)
1244 {
1245 finiDisplayOptionValue (d, &o->value, o->type);
1246 compFiniOption (o);
1247 free (o->name);
1248 }
1249
1250 Bool
compInitDisplayOptionsFromMetadata(CompDisplay * d,CompMetadata * m,const CompMetadataOptionInfo * info,CompOption * opt,int n)1251 compInitDisplayOptionsFromMetadata (CompDisplay *d,
1252 CompMetadata *m,
1253 const CompMetadataOptionInfo *info,
1254 CompOption *opt,
1255 int n)
1256 {
1257 int i;
1258
1259 for (i = 0; i < n; i++)
1260 {
1261 if (!compInitDisplayOptionFromMetadata (d, m, &opt[i], info[i].name))
1262 {
1263 compFiniDisplayOptions (d, opt, i);
1264 return FALSE;
1265 }
1266
1267 if (info[i].initiate)
1268 opt[i].value.action.initiate = info[i].initiate;
1269
1270 if (info[i].terminate)
1271 opt[i].value.action.terminate = info[i].terminate;
1272 }
1273
1274 return TRUE;
1275 }
1276
1277 void
compFiniDisplayOptions(CompDisplay * d,CompOption * opt,int n)1278 compFiniDisplayOptions (CompDisplay *d,
1279 CompOption *opt,
1280 int n)
1281 {
1282 int i;
1283
1284 for (i = 0; i < n; i++)
1285 compFiniDisplayOption (d, &opt[i]);
1286 }
1287
1288 Bool
compSetDisplayOption(CompDisplay * d,CompOption * o,CompOptionValue * value)1289 compSetDisplayOption (CompDisplay *d,
1290 CompOption *o,
1291 CompOptionValue *value)
1292 {
1293 if (isActionOption (o))
1294 {
1295 if (o->value.action.state & CompActionStateAutoGrab)
1296 {
1297 if (setDisplayAction (d, o, value))
1298 return TRUE;
1299 }
1300 else
1301 {
1302 if (compSetActionOption (o, value))
1303 return TRUE;
1304 }
1305 }
1306 else
1307 {
1308 if (compSetOption (o, value))
1309 return TRUE;
1310 }
1311
1312 return FALSE;
1313 }
1314
1315 char *
compGetStringFromMetadataPath(CompMetadata * metadata,const char * path)1316 compGetStringFromMetadataPath (CompMetadata *metadata,
1317 const char *path)
1318 {
1319 CompXPath xPath;
1320 char *v = NULL;
1321
1322 if (!initXPathFromMetadataPath (&xPath, metadata, BAD_CAST path))
1323 return NULL;
1324
1325 xPath.obj = xmlXPathConvertString (xPath.obj);
1326
1327 if (xPath.obj->type == XPATH_STRING && xPath.obj->stringval)
1328 v = strdup ((char *) xPath.obj->stringval);
1329
1330 finiXPath (&xPath);
1331
1332 return v;
1333 }
1334
1335 char *
compGetShortPluginDescription(CompMetadata * m)1336 compGetShortPluginDescription (CompMetadata *m)
1337 {
1338 char str[1024];
1339
1340 sprintf (str, "/compiz/%s/short/child::text()", m->path);
1341
1342 return compGetStringFromMetadataPath (m, str);
1343 }
1344
1345 char *
compGetLongPluginDescription(CompMetadata * m)1346 compGetLongPluginDescription (CompMetadata *m)
1347 {
1348 char str[1024];
1349
1350 sprintf (str, "/compiz/%s/long/child::text()", m->path);
1351
1352 return compGetStringFromMetadataPath (m, str);
1353 }
1354
1355 char *
compGetShortScreenOptionDescription(CompMetadata * m,CompOption * o)1356 compGetShortScreenOptionDescription (CompMetadata *m,
1357 CompOption *o)
1358 {
1359 char str[1024];
1360
1361 sprintf (str, "/compiz/%s/screen//option[@name=\"%s\"]/short/child::text()",
1362 m->path, o->name);
1363
1364 return compGetStringFromMetadataPath (m, str);
1365 }
1366
1367 char *
compGetLongScreenOptionDescription(CompMetadata * m,CompOption * o)1368 compGetLongScreenOptionDescription (CompMetadata *m,
1369 CompOption *o)
1370 {
1371 char str[1024];
1372
1373 sprintf (str, "/compiz/%s/screen//option[@name=\"%s\"]/long/child::text()",
1374 m->path, o->name);
1375
1376 return compGetStringFromMetadataPath (m, str);
1377 }
1378
1379
1380 char *
compGetShortDisplayOptionDescription(CompMetadata * m,CompOption * o)1381 compGetShortDisplayOptionDescription (CompMetadata *m,
1382 CompOption *o)
1383 {
1384 char str[1024];
1385
1386 sprintf (str,
1387 "/compiz/%s/display//option[@name=\"%s\"]/short/child::text()",
1388 m->path, o->name);
1389
1390 return compGetStringFromMetadataPath (m, str);
1391 }
1392
1393
1394 char *
compGetLongDisplayOptionDescription(CompMetadata * m,CompOption * o)1395 compGetLongDisplayOptionDescription (CompMetadata *m,
1396 CompOption *o)
1397 {
1398 char str[1024];
1399
1400 sprintf (str, "/compiz/%s/display//option[@name=\"%s\"]/long/child::text()",
1401 m->path, o->name);
1402
1403 return compGetStringFromMetadataPath (m, str);
1404 }
1405
1406 int
compReadXmlChunk(const char * src,int * offset,char * buffer,int length)1407 compReadXmlChunk (const char *src,
1408 int *offset,
1409 char *buffer,
1410 int length)
1411 {
1412 int srcLength = strlen (src);
1413 int srcOffset = *offset;
1414
1415 if (srcOffset > srcLength)
1416 srcOffset = srcLength;
1417
1418 *offset -= srcOffset;
1419
1420 src += srcOffset;
1421 srcLength -= srcOffset;
1422
1423 if (srcLength > 0 && length > 0)
1424 {
1425 if (srcLength < length)
1426 length = srcLength;
1427
1428 memcpy (buffer, src, length);
1429
1430 return length;
1431 }
1432
1433 return 0;
1434 }
1435
1436 int
compReadXmlChunkFromMetadataOptionInfo(const CompMetadataOptionInfo * info,int * offset,char * buffer,int length)1437 compReadXmlChunkFromMetadataOptionInfo (const CompMetadataOptionInfo *info,
1438 int *offset,
1439 char *buffer,
1440 int length)
1441 {
1442 int i;
1443
1444 i = compReadXmlChunk ("<option name=\"", offset, buffer, length);
1445 i += compReadXmlChunk (info->name, offset, buffer + i, length - i);
1446
1447 if (info->type)
1448 {
1449 i += compReadXmlChunk ("\" type=\"", offset, buffer + i, length - i);
1450 i += compReadXmlChunk (info->type, offset, buffer + i, length - i);
1451 }
1452
1453 if (info->data)
1454 {
1455 i += compReadXmlChunk ("\">", offset, buffer + i, length - i);
1456 i += compReadXmlChunk (info->data, offset, buffer + i, length - i);
1457 i += compReadXmlChunk ("</option>", offset, buffer + i, length - i);
1458 }
1459 else
1460 {
1461 i += compReadXmlChunk ("\"/>", offset, buffer + i, length - i);
1462 }
1463
1464 return i;
1465 }
1466