1 /*
2  * Compiz configuration system library
3  *
4  * Copyright (C) 2007  Dennis Kasprzyk <onestone@opencompositing.org>
5  * Copyright (C) 2007  Danny Baumann <maniac@opencompositing.org>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11 
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16 
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #  include "../config.h"
24 #endif
25 
26 #define _GNU_SOURCE
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <libintl.h>
32 #include <dlfcn.h>
33 #include <dirent.h>
34 #include <math.h>
35 
36 #include <ccs.h>
37 
38 #include "ccs-private.h"
39 #include "iniparser.h"
40 
41 Bool basicMetadata = FALSE;
42 
43 void
ccsSetBasicMetadata(Bool value)44 ccsSetBasicMetadata (Bool value)
45 {
46     basicMetadata = value;
47 }
48 
49 static void
initGeneralOptions(CCSContext * context)50 initGeneralOptions (CCSContext * context)
51 {
52     char *val;
53 
54     if (ccsReadConfig (OptionBackend, &val))
55     {
56 	ccsSetBackend (context, val);
57 	free (val);
58     }
59     else
60 	ccsSetBackend (context, "ini");
61 
62     if (ccsReadConfig (OptionProfile, &val))
63     {
64 	ccsSetProfile (context, val);
65 	free (val);
66     }
67     else
68 	ccsSetProfile (context, "");
69 
70     if (ccsReadConfig (OptionIntegration, &val))
71     {
72 	ccsSetIntegrationEnabled (context, !strcasecmp (val, "true"));
73 	free (val);
74     }
75     else
76 	ccsSetIntegrationEnabled (context, TRUE);
77 
78     if (ccsReadConfig (OptionAutoSort, &val))
79     {
80 	ccsSetPluginListAutoSort (context, !strcasecmp (val, "true"));
81 	free (val);
82     }
83     else
84 	ccsSetPluginListAutoSort (context, TRUE);
85 }
86 
87 static void
configChangeNotify(unsigned int watchId,void * closure)88 configChangeNotify (unsigned int watchId, void *closure)
89 {
90     CCSContext *context = (CCSContext *) closure;
91 
92     initGeneralOptions (context);
93     ccsReadSettings (context);
94 }
95 
96 CCSContext *
ccsEmptyContextNew(unsigned int * screens,unsigned int numScreens)97 ccsEmptyContextNew (unsigned int *screens, unsigned int numScreens)
98 {
99     CCSContext *context;
100 
101     context = calloc (1, sizeof (CCSContext));
102     if (!context)
103 	return NULL;
104 
105     context->ccsPrivate = calloc (1, sizeof (CCSContextPrivate));
106     if (!context->ccsPrivate)
107     {
108 	free (context);
109 	return NULL;
110     }
111 
112     CONTEXT_PRIV (context);
113 
114     if (numScreens > 0 && screens)
115     {
116 	int i;
117 
118 	context->screens = calloc (1, sizeof (unsigned int) * numScreens);
119 	if (!context->screens)
120 	{
121 	    free (cPrivate);
122 	    free (context);
123 	    return NULL;
124 	}
125 
126 	context->numScreens = numScreens;
127 
128 	for (i = 0; i < numScreens; i++)
129 	    context->screens[i] = screens[i];
130     }
131     else
132     {
133 	context->screens = calloc (1, sizeof (unsigned int));
134 	if (!context->screens)
135 	{
136 	    free (cPrivate);
137 	    free (context);
138 	    return NULL;
139 	}
140 	context->screens[0] = 0;
141 	context->numScreens = 1;
142     }
143 
144     initGeneralOptions (context);
145     cPrivate->configWatchId = ccsAddConfigWatch (context, configChangeNotify);
146 
147     if (cPrivate->backend)
148 	D (D_NORMAL, "Backend     : %s\n", cPrivate->backend->vTable->name);
149 	D (D_NORMAL, "Integration : %s\n", cPrivate->deIntegration ? "true" : "false");
150 	D (D_NORMAL, "Profile     : %s\n",
151 	    (cPrivate->profile && strlen (cPrivate->profile)) ?
152 	    cPrivate->profile : "default");
153 
154     return context;
155 }
156 
157 static void
ccsSetActivePluginList(CCSContext * context,CCSStringList list)158 ccsSetActivePluginList (CCSContext * context, CCSStringList list)
159 {
160     CCSPluginList l;
161     CCSPlugin     *plugin;
162 
163     for (l = context->plugins; l; l = l->next)
164     {
165 	PLUGIN_PRIV (l->data);
166 	pPrivate->active = FALSE;
167     }
168 
169     for (; list; list = list->next)
170     {
171 	plugin = ccsFindPlugin (context, list->data);
172 
173 	if (plugin)
174 	{
175 	    PLUGIN_PRIV (plugin);
176 	    pPrivate->active = TRUE;
177 	}
178     }
179 
180     /* core plugin is always active */
181     plugin = ccsFindPlugin (context, "core");
182     if (plugin)
183     {
184 	PLUGIN_PRIV (plugin);
185 	pPrivate->active = TRUE;
186     }
187 }
188 
189 CCSContext *
ccsContextNew(unsigned int * screens,unsigned int numScreens)190 ccsContextNew (unsigned int *screens, unsigned int numScreens)
191 {
192     CCSPlugin  *p;
193     CCSContext *context = ccsEmptyContextNew (screens, numScreens);
194     if (!context)
195 	return NULL;
196 
197     ccsLoadPlugins (context);
198 
199     p = ccsFindPlugin (context, "core");
200     if (p)
201     {
202 	CCSSetting    *s;
203 
204 	ccsLoadPluginSettings (p);
205 
206 	/* initialize plugin->active values */
207 	s = ccsFindSetting (p, "active_plugins", FALSE, 0);
208 	if (s)
209 	{
210 	    CCSStringList       list;
211 	    CCSSettingValueList vl;
212 
213 	    ccsGetList (s, &vl);
214 	    list = ccsGetStringListFromValueList (vl);
215 	    ccsSetActivePluginList (context, list);
216 	    ccsStringListFree (list, TRUE);
217 	}
218     }
219 
220     return context;
221 }
222 
223 CCSPlugin *
ccsFindPlugin(CCSContext * context,const char * name)224 ccsFindPlugin (CCSContext * context, const char *name)
225 {
226     if (!name)
227 	name = "";
228 
229     CCSPluginList l = context->plugins;
230     while (l)
231     {
232 	if (!strcmp (l->data->name, name))
233 	    return l->data;
234 
235 	l = l->next;
236     }
237 
238     return NULL;
239 }
240 
241 CCSSetting *
ccsFindSetting(CCSPlugin * plugin,const char * name,Bool isScreen,unsigned int screenNum)242 ccsFindSetting (CCSPlugin * plugin, const char *name,
243 		Bool isScreen, unsigned int screenNum)
244 {
245     if (!plugin)
246 	return NULL;
247 
248     PLUGIN_PRIV (plugin);
249 
250     if (!name)
251 	name = "";
252 
253     if (!pPrivate->loaded)
254 	ccsLoadPluginSettings (plugin);
255 
256     CCSSettingList l = pPrivate->settings;
257 
258     while (l)
259     {
260 	if (!strcmp (l->data->name, name) &&
261 	    ((!l->data->isScreen && !isScreen) ||
262 	     (l->data->isScreen && isScreen)) &&
263 	    (!isScreen || (l->data->screenNum == screenNum)))
264 	    return l->data;
265 
266 	l = l->next;
267     }
268 
269     return NULL;
270 }
271 
272 Bool
ccsPluginIsActive(CCSContext * context,char * name)273 ccsPluginIsActive (CCSContext * context, char *name)
274 {
275     CCSPlugin *plugin;
276 
277     plugin = ccsFindPlugin (context, name);
278     if (!plugin)
279 	return FALSE;
280 
281     PLUGIN_PRIV (plugin);
282 
283     return pPrivate->active;
284 }
285 
286 
287 static void
subGroupAdd(CCSSetting * setting,CCSGroup * group)288 subGroupAdd (CCSSetting * setting, CCSGroup * group)
289 {
290     CCSSubGroupList l = group->subGroups;
291     CCSSubGroup     *subGroup;
292 
293     while (l)
294     {
295 	if (!strcmp (l->data->name, setting->subGroup))
296 	{
297 	    l->data->settings = ccsSettingListAppend (l->data->settings,
298 						      setting);
299 	    return;
300 	}
301 
302 	l = l->next;
303     }
304 
305     subGroup = calloc (1, sizeof (CCSSubGroup));
306     if (subGroup)
307     {
308 	group->subGroups = ccsSubGroupListAppend (group->subGroups, subGroup);
309 	subGroup->name = strdup (setting->subGroup);
310 	subGroup->settings = ccsSettingListAppend (subGroup->settings, setting);
311     }
312 }
313 
314 static void
groupAdd(CCSSetting * setting,CCSPluginPrivate * p)315 groupAdd (CCSSetting * setting, CCSPluginPrivate * p)
316 {
317     CCSGroupList l = p->groups;
318     CCSGroup     *group;
319 
320     while (l)
321     {
322 	if (!strcmp (l->data->name, setting->group))
323 	{
324 	    subGroupAdd (setting, l->data);
325 	    return;
326 	}
327 
328 	l = l->next;
329     }
330 
331     group = calloc (1, sizeof (CCSGroup));
332     if (group)
333     {
334     	p->groups = ccsGroupListAppend (p->groups, group);
335 	group->name = strdup (setting->group);
336 	subGroupAdd (setting, group);
337     }
338 }
339 
340 void
collateGroups(CCSPluginPrivate * p)341 collateGroups (CCSPluginPrivate * p)
342 {
343     CCSSettingList l = p->settings;
344 
345     while (l)
346     {
347 	groupAdd (l->data, p);
348 	l = l->next;
349     }
350 }
351 
352 void
ccsFreeContext(CCSContext * c)353 ccsFreeContext (CCSContext * c)
354 {
355     if (!c)
356 	return;
357 
358     CONTEXT_PRIV (c);
359 
360     if (cPrivate->profile)
361 	free (cPrivate->profile);
362 
363     if (cPrivate->configWatchId)
364 	ccsRemoveFileWatch (cPrivate->configWatchId);
365 
366     if (c->changedSettings)
367 	ccsSettingListFree (c->changedSettings, FALSE);
368 
369     if (c->screens)
370 	free (c->screens);
371 
372     if (c->ccsPrivate)
373 	free (c->ccsPrivate);
374 
375     ccsPluginListFree (c->plugins, TRUE);
376 
377     free (c);
378 }
379 
380 void
ccsFreePlugin(CCSPlugin * p)381 ccsFreePlugin (CCSPlugin * p)
382 {
383     if (!p)
384 	return;
385 
386     free (p->name);
387     free (p->shortDesc);
388     free (p->longDesc);
389     free (p->hints);
390     free (p->category);
391 
392     ccsStringListFree (p->loadAfter, TRUE);
393     ccsStringListFree (p->loadBefore, TRUE);
394     ccsStringListFree (p->requiresPlugin, TRUE);
395     ccsStringListFree (p->conflictPlugin, TRUE);
396     ccsStringListFree (p->conflictFeature, TRUE);
397     ccsStringListFree (p->providesFeature, TRUE);
398     ccsStringListFree (p->requiresFeature, TRUE);
399 
400     PLUGIN_PRIV (p);
401 
402     ccsSettingListFree (pPrivate->settings, TRUE);
403     ccsGroupListFree (pPrivate->groups, TRUE);
404     ccsStrExtensionListFree (pPrivate->stringExtensions, TRUE);
405 
406     if (pPrivate->xmlFile)
407 	free (pPrivate->xmlFile);
408 
409     if (pPrivate->xmlPath)
410 	free (pPrivate->xmlPath);
411 
412 #ifdef USE_PROTOBUF
413     if (pPrivate->pbFilePath)
414 	free (pPrivate->pbFilePath);
415 #endif
416 
417     free (pPrivate);
418     free (p);
419 }
420 
421 void
ccsFreeSetting(CCSSetting * s)422 ccsFreeSetting (CCSSetting * s)
423 {
424     if (!s)
425 	return;
426 
427     free (s->name);
428     free (s->shortDesc);
429     free (s->longDesc);
430     free (s->group);
431     free (s->subGroup);
432     free (s->hints);
433 
434     switch (s->type)
435     {
436     case TypeInt:
437 	ccsIntDescListFree (s->info.forInt.desc, TRUE);
438 	break;
439     case TypeString:
440 	ccsStrRestrictionListFree (s->info.forString.restriction, TRUE);
441 	break;
442     case TypeList:
443 	if (s->info.forList.listType == TypeInt)
444 	    ccsIntDescListFree (s->info.forList.listInfo->
445 				forInt.desc, TRUE);
446 	free (s->info.forList.listInfo);
447 	break;
448     default:
449 	break;
450     }
451 
452     if (&s->defaultValue != s->value)
453 	ccsFreeSettingValue (s->value);
454 
455     ccsFreeSettingValue (&s->defaultValue);
456     free (s);
457 }
458 
459 void
ccsFreeGroup(CCSGroup * g)460 ccsFreeGroup (CCSGroup * g)
461 {
462     if (!g)
463 	return;
464 
465     free (g->name);
466     ccsSubGroupListFree (g->subGroups, TRUE);
467     free (g);
468 }
469 
470 void
ccsFreeSubGroup(CCSSubGroup * s)471 ccsFreeSubGroup (CCSSubGroup * s)
472 {
473     if (!s)
474 	return;
475 
476     free (s->name);
477     ccsSettingListFree (s->settings, FALSE);
478     free (s);
479 }
480 
481 void
ccsFreeSettingValue(CCSSettingValue * v)482 ccsFreeSettingValue (CCSSettingValue * v)
483 {
484     if (!v)
485 	return;
486 
487     if (!v->parent)
488 	return;
489 
490     CCSSettingType type = v->parent->type;
491 
492     if (v->isListChild)
493 	type = v->parent->info.forList.listType;
494 
495     switch (type)
496     {
497     case TypeString:
498 	free (v->value.asString);
499 	break;
500     case TypeMatch:
501 	free (v->value.asMatch);
502 	break;
503     case TypeList:
504 	if (!v->isListChild)
505 	    ccsSettingValueListFree (v->value.asList, TRUE);
506 	break;
507     default:
508 	break;
509     }
510 
511     if (v != &v->parent->defaultValue)
512 	free (v);
513 }
514 
515 void
ccsFreePluginConflict(CCSPluginConflict * c)516 ccsFreePluginConflict (CCSPluginConflict * c)
517 {
518     if (!c)
519 	return;
520 
521     free (c->value);
522 
523     ccsPluginListFree (c->plugins, FALSE);
524 
525     free (c);
526 }
527 
528 void
ccsFreeBackendInfo(CCSBackendInfo * b)529 ccsFreeBackendInfo (CCSBackendInfo * b)
530 {
531     if (!b)
532 	return;
533 
534     if (b->name)
535 	free (b->name);
536 
537     if (b->shortDesc)
538 	free (b->shortDesc);
539 
540     if (b->longDesc)
541 	free (b->longDesc);
542 
543     free (b);
544 }
545 
546 void
ccsFreeIntDesc(CCSIntDesc * i)547 ccsFreeIntDesc (CCSIntDesc * i)
548 {
549     if (!i)
550 	return;
551 
552     if (i->name)
553 	free (i->name);
554 
555     free (i);
556 }
557 
558 void
ccsFreeStrRestriction(CCSStrRestriction * r)559 ccsFreeStrRestriction (CCSStrRestriction * r)
560 {
561     if (!r)
562 	return;
563 
564     if (r->name)
565 	free (r->name);
566 
567     if (r->value)
568 	free (r->value);
569 
570     free (r);
571 }
572 
573 void
ccsFreeStrExtension(CCSStrExtension * e)574 ccsFreeStrExtension (CCSStrExtension *e)
575 {
576     if (!e)
577 	return;
578 
579     if (e->basePlugin)
580 	free (e->basePlugin);
581 
582     ccsStringListFree (e->baseSettings, TRUE);
583     ccsStrRestrictionListFree (e->restriction, TRUE);
584 
585     free (e);
586 }
587 
588 static void *
openBackend(char * backend)589 openBackend (char *backend)
590 {
591     char *home = getenv ("HOME");
592     void *dlhand = NULL;
593     char *dlname = NULL;
594     char *err = NULL;
595 
596     if (home && strlen (home))
597     {
598 	asprintf (&dlname, "%s/.compizconfig/backends/lib%s.so",
599 		  home, backend);
600 	dlerror ();
601 	dlhand = dlopen (dlname, RTLD_NOW | RTLD_LOCAL);
602 	dlopen (dlname, RTLD_NOW | RTLD_LOCAL);
603 	err = dlerror ();
604     }
605 
606     if (!dlhand)
607     {
608         if (dlname) {
609 	        free (dlname);
610         }
611 	asprintf (&dlname, "%s/compizconfig/backends/lib%s.so",
612 		  LIBDIR, backend);
613 	dlhand = dlopen (dlname, RTLD_NOW | RTLD_LOCAL);
614 	dlopen (dlname, RTLD_NOW | RTLD_LOCAL);
615 	err = dlerror ();
616     }
617 
618     free (dlname);
619 
620     if (err)
621     {
622 	fprintf (stderr, "libccs: dlopen: %s\n", err);
623     }
624 
625     return dlhand;
626 }
627 
628 Bool
ccsSetBackend(CCSContext * context,char * name)629 ccsSetBackend (CCSContext * context, char *name)
630 {
631     Bool	 fallbackMode = FALSE;
632     CONTEXT_PRIV (context);
633 
634     if (cPrivate->backend)
635     {
636 	/* no action needed if the backend is the same */
637 
638 	if (strcmp (cPrivate->backend->vTable->name, name) == 0)
639 	    return TRUE;
640 
641 	if (cPrivate->backend->vTable->backendFini)
642 	    cPrivate->backend->vTable->backendFini (context);
643 
644 	dlclose (cPrivate->backend->dlhand);
645 	free (cPrivate->backend);
646 	cPrivate->backend = NULL;
647     }
648 
649     void *dlhand = openBackend (name);
650     if (!dlhand)
651     {
652 	fallbackMode = TRUE;
653 	name = "ini";
654 	dlhand = openBackend (name);
655     }
656 
657     if (!dlhand)
658 	return FALSE;
659 
660     BackendGetInfoProc getInfo = dlsym (dlhand, "getBackendInfo");
661     if (!getInfo)
662     {
663 	dlclose (dlhand);
664 	return FALSE;
665     }
666 
667     CCSBackendVTable *vt = getInfo ();
668     if (!vt)
669     {
670 	dlclose (dlhand);
671 	return FALSE;
672     }
673 
674     cPrivate->backend = calloc (1, sizeof (CCSBackend));
675     if (!cPrivate->backend)
676     {
677 	dlclose (dlhand);
678 	return FALSE;
679     }
680     cPrivate->backend->dlhand = dlhand;
681     cPrivate->backend->vTable = vt;
682 
683     if (cPrivate->backend->vTable->backendInit)
684 	cPrivate->backend->vTable->backendInit (context);
685 
686     ccsDisableFileWatch (cPrivate->configWatchId);
687     if (!fallbackMode)
688 	ccsWriteConfig (OptionBackend, name);
689     ccsEnableFileWatch (cPrivate->configWatchId);
690 
691     return TRUE;
692 }
693 
694 static void
copyValue(CCSSettingValue * from,CCSSettingValue * to)695 copyValue (CCSSettingValue * from, CCSSettingValue * to)
696 {
697     memcpy (to, from, sizeof (CCSSettingValue));
698     CCSSettingType type = from->parent->type;
699 
700     if (from->isListChild)
701 	type = from->parent->info.forList.listType;
702 
703     switch (type)
704     {
705     case TypeString:
706 	to->value.asString = strdup (from->value.asString);
707 	break;
708     case TypeMatch:
709 	to->value.asMatch = strdup (from->value.asMatch);
710 	break;
711     case TypeList:
712 	to->value.asList = NULL;
713 	CCSSettingValueList l = from->value.asList;
714 	while (l)
715 	{
716 	    CCSSettingValue *value = calloc (1, sizeof (CCSSettingValue));
717 	    if (!value)
718 		break;
719 
720 	    copyValue (l->data, value);
721 	    to->value.asList = ccsSettingValueListAppend (to->value.asList,
722 							  value);
723 	    l = l->next;
724 	}
725 	break;
726     default:
727 	break;
728     }
729 }
730 
731 static void
copyFromDefault(CCSSetting * setting)732 copyFromDefault (CCSSetting * setting)
733 {
734     CCSSettingValue *value;
735 
736     if (setting->value != &setting->defaultValue)
737 	ccsFreeSettingValue (setting->value);
738 
739     value = calloc (1, sizeof (CCSSettingValue));
740     if (!value)
741     {
742 	setting->value = &setting->defaultValue;
743 	setting->isDefault = TRUE;
744 	return;
745     }
746 
747     copyValue (&setting->defaultValue, value);
748     setting->value = value;
749     setting->isDefault = FALSE;
750 }
751 
752 void
ccsResetToDefault(CCSSetting * setting)753 ccsResetToDefault (CCSSetting * setting)
754 {
755     if (setting->value != &setting->defaultValue)
756     {
757 	ccsFreeSettingValue (setting->value);
758 
759     	setting->parent->context->changedSettings =
760 	    ccsSettingListAppend (setting->parent->context->changedSettings,
761 				  setting);
762     }
763 
764     setting->value = &setting->defaultValue;
765     setting->isDefault = TRUE;
766 }
767 
768 Bool
ccsSetInt(CCSSetting * setting,int data)769 ccsSetInt (CCSSetting * setting, int data)
770 {
771     if (setting->type != TypeInt)
772 	return FALSE;
773 
774     if (setting->isDefault && (setting->defaultValue.value.asInt == data))
775 	return TRUE;
776 
777     if (!setting->isDefault && (setting->defaultValue.value.asInt == data))
778     {
779 	ccsResetToDefault (setting);
780 	return TRUE;
781     }
782 
783     if (setting->value->value.asInt == data)
784 	return TRUE;
785 
786     if ((data < setting->info.forInt.min) ||
787 	 (data > setting->info.forInt.max))
788 	return FALSE;
789 
790     if (setting->isDefault)
791 	copyFromDefault (setting);
792 
793     setting->value->value.asInt = data;
794 
795     setting->parent->context->changedSettings =
796 	ccsSettingListAppend (setting->parent->context->changedSettings,
797 			      setting);
798 
799     return TRUE;
800 }
801 
802 Bool
ccsSetFloat(CCSSetting * setting,float data)803 ccsSetFloat (CCSSetting * setting, float data)
804 {
805     if (setting->type != TypeFloat)
806 	return FALSE;
807 
808     if (setting->isDefault && (setting->defaultValue.value.asFloat == data))
809 	return TRUE;
810 
811     if (!setting->isDefault && (setting->defaultValue.value.asFloat == data))
812     {
813 	ccsResetToDefault (setting);
814 	return TRUE;
815     }
816 
817     /* allow the values to differ a tiny bit because of
818        possible rounding / precision issues */
819     if (fabs (setting->value->value.asFloat - data) < 1e-5)
820 	return TRUE;
821 
822     if ((data < setting->info.forFloat.min) ||
823 	 (data > setting->info.forFloat.max))
824 	return FALSE;
825 
826     if (setting->isDefault)
827 	copyFromDefault (setting);
828 
829     setting->value->value.asFloat = data;
830 
831     setting->parent->context->changedSettings =
832 	ccsSettingListAppend (setting->parent->context->changedSettings,
833 			      setting);
834 
835     return TRUE;
836 }
837 
838 Bool
ccsSetBool(CCSSetting * setting,Bool data)839 ccsSetBool (CCSSetting * setting, Bool data)
840 {
841     if (setting->type != TypeBool)
842 	return FALSE;
843 
844     if (setting->isDefault
845 	&& ((setting->defaultValue.value.asBool && data)
846 	     || (!setting->defaultValue.value.asBool && !data)))
847 	return TRUE;
848 
849     if (!setting->isDefault
850 	&& ((setting->defaultValue.value.asBool && data)
851 	     || (!setting->defaultValue.value.asBool && !data)))
852     {
853 	ccsResetToDefault (setting);
854 	return TRUE;
855     }
856 
857     if ((setting->value->value.asBool && data)
858 	 || (!setting->value->value.asBool && !data))
859 	return TRUE;
860 
861     if (setting->isDefault)
862 	copyFromDefault (setting);
863 
864     setting->value->value.asBool = data;
865 
866     setting->parent->context->changedSettings =
867 	ccsSettingListAppend (setting->parent->context->changedSettings,
868 			      setting);
869 
870     return TRUE;
871 }
872 
873 Bool
ccsSetString(CCSSetting * setting,const char * data)874 ccsSetString (CCSSetting * setting, const char *data)
875 {
876     if (setting->type != TypeString)
877 	return FALSE;
878 
879     if (!data)
880 	return FALSE;
881 
882     Bool isDefault = strcmp (setting->defaultValue.value.asString, data) == 0;
883 
884     if (setting->isDefault && isDefault)
885 	return TRUE;
886 
887     if (!setting->isDefault && isDefault)
888     {
889 	ccsResetToDefault (setting);
890 	return TRUE;
891     }
892 
893     if (!strcmp (setting->value->value.asString, data))
894 	return TRUE;
895 
896     if (setting->isDefault)
897 	copyFromDefault (setting);
898 
899     free (setting->value->value.asString);
900 
901     setting->value->value.asString = strdup (data);
902 
903     setting->parent->context->changedSettings =
904 	ccsSettingListAppend (setting->parent->context->changedSettings,
905 			      setting);
906 
907     return TRUE;
908 }
909 
910 Bool
ccsSetColor(CCSSetting * setting,CCSSettingColorValue data)911 ccsSetColor (CCSSetting * setting, CCSSettingColorValue data)
912 {
913     if (setting->type != TypeColor)
914 	return FALSE;
915 
916     CCSSettingColorValue defValue = setting->defaultValue.value.asColor;
917 
918     Bool isDefault = ccsIsEqualColor (defValue, data);
919 
920     if (setting->isDefault && isDefault)
921 	return TRUE;
922 
923     if (!setting->isDefault && isDefault)
924     {
925 	ccsResetToDefault (setting);
926 	return TRUE;
927     }
928 
929     if (ccsIsEqualColor (setting->value->value.asColor, data))
930 	return TRUE;
931 
932     if (setting->isDefault)
933 	copyFromDefault (setting);
934 
935     setting->value->value.asColor = data;
936 
937     setting->parent->context->changedSettings =
938 	ccsSettingListAppend (setting->parent->context->changedSettings,
939 			      setting);
940 
941     return TRUE;
942 }
943 
944 Bool
ccsSetMatch(CCSSetting * setting,const char * data)945 ccsSetMatch (CCSSetting * setting, const char *data)
946 {
947     if (setting->type != TypeMatch)
948 	return FALSE;
949 
950     if (!data)
951 	return FALSE;
952 
953     Bool isDefault = strcmp (setting->defaultValue.value.asMatch, data) == 0;
954 
955     if (setting->isDefault && isDefault)
956 	return TRUE;
957 
958     if (!setting->isDefault && isDefault)
959     {
960 	ccsResetToDefault (setting);
961 	return TRUE;
962     }
963 
964     if (!strcmp (setting->value->value.asMatch, data))
965 	return TRUE;
966 
967     if (setting->isDefault)
968 	copyFromDefault (setting);
969 
970     free (setting->value->value.asMatch);
971 
972     setting->value->value.asMatch = strdup (data);
973 
974     setting->parent->context->changedSettings =
975 	ccsSettingListAppend (setting->parent->context->changedSettings,
976 			      setting);
977 
978     return TRUE;
979 }
980 
981 Bool
ccsSetKey(CCSSetting * setting,CCSSettingKeyValue data)982 ccsSetKey (CCSSetting * setting, CCSSettingKeyValue data)
983 {
984     if (setting->type != TypeKey)
985 	return FALSE;
986 
987     CCSSettingKeyValue defValue = setting->defaultValue.value.asKey;
988 
989     Bool isDefault = ccsIsEqualKey (data, defValue);
990 
991     if (setting->isDefault && isDefault)
992 	return TRUE;
993 
994     if (!setting->isDefault && isDefault)
995     {
996 	ccsResetToDefault (setting);
997 	return TRUE;
998     }
999 
1000     if (ccsIsEqualKey (setting->value->value.asKey, data))
1001 	return TRUE;
1002 
1003     if (setting->isDefault)
1004 	copyFromDefault (setting);
1005 
1006     setting->value->value.asKey.keysym = data.keysym;
1007     setting->value->value.asKey.keyModMask = data.keyModMask;
1008 
1009     setting->parent->context->changedSettings =
1010 	ccsSettingListAppend (setting->parent->context->changedSettings,
1011 			      setting);
1012 
1013     return TRUE;
1014 }
1015 
1016 Bool
ccsSetButton(CCSSetting * setting,CCSSettingButtonValue data)1017 ccsSetButton (CCSSetting * setting, CCSSettingButtonValue data)
1018 {
1019     if (setting->type != TypeButton)
1020 	return FALSE;
1021 
1022     CCSSettingButtonValue defValue = setting->defaultValue.value.asButton;
1023 
1024     Bool isDefault = ccsIsEqualButton (data, defValue);
1025 
1026     if (setting->isDefault && isDefault)
1027 	return TRUE;
1028 
1029     if (!setting->isDefault && isDefault)
1030     {
1031 	ccsResetToDefault (setting);
1032 	return TRUE;
1033     }
1034 
1035     if (ccsIsEqualButton (setting->value->value.asButton, data))
1036 	return TRUE;
1037 
1038     if (setting->isDefault)
1039 	copyFromDefault (setting);
1040 
1041     setting->value->value.asButton.button = data.button;
1042     setting->value->value.asButton.buttonModMask = data.buttonModMask;
1043     setting->value->value.asButton.edgeMask = data.edgeMask;
1044 
1045     setting->parent->context->changedSettings =
1046 	ccsSettingListAppend (setting->parent->context->changedSettings,
1047 			      setting);
1048 
1049     return TRUE;
1050 }
1051 
1052 Bool
ccsSetEdge(CCSSetting * setting,unsigned int data)1053 ccsSetEdge (CCSSetting * setting, unsigned int data)
1054 {
1055     if (setting->type != TypeEdge)
1056 	return FALSE;
1057 
1058     Bool isDefault = (data == setting->defaultValue.value.asEdge);
1059 
1060     if (setting->isDefault && isDefault)
1061 	return TRUE;
1062 
1063     if (!setting->isDefault && isDefault)
1064     {
1065 	ccsResetToDefault (setting);
1066 	return TRUE;
1067     }
1068 
1069     if (setting->value->value.asEdge == data)
1070 	return TRUE;
1071 
1072     if (setting->isDefault)
1073 	copyFromDefault (setting);
1074 
1075     setting->value->value.asEdge = data;
1076 
1077     setting->parent->context->changedSettings =
1078 	ccsSettingListAppend (setting->parent->context->changedSettings,
1079 			      setting);
1080 
1081     return TRUE;
1082 }
1083 
1084 Bool
ccsSetBell(CCSSetting * setting,Bool data)1085 ccsSetBell (CCSSetting * setting, Bool data)
1086 {
1087     if (setting->type != TypeBell)
1088 	return FALSE;
1089 
1090     Bool isDefault = (data == setting->defaultValue.value.asBool);
1091 
1092     if (setting->isDefault && isDefault)
1093 	return TRUE;
1094 
1095     if (!setting->isDefault && isDefault)
1096     {
1097 	ccsResetToDefault (setting);
1098 	return TRUE;
1099     }
1100 
1101     if (setting->value->value.asBell == data)
1102 	return TRUE;
1103 
1104     if (setting->isDefault)
1105 	copyFromDefault (setting);
1106 
1107     setting->value->value.asBell = data;
1108 
1109     setting->parent->context->changedSettings =
1110 	ccsSettingListAppend (setting->parent->context->changedSettings,
1111 			      setting);
1112 
1113     return TRUE;
1114 }
1115 
1116 static Bool
ccsCompareLists(CCSSettingValueList l1,CCSSettingValueList l2,CCSSettingListInfo info)1117 ccsCompareLists (CCSSettingValueList l1, CCSSettingValueList l2,
1118 		 CCSSettingListInfo info)
1119 {
1120     while (l1 && l2)
1121     {
1122 	switch (info.listType)
1123 	{
1124 	case TypeInt:
1125 	    if (l1->data->value.asInt != l2->data->value.asInt)
1126 		return FALSE;
1127 	    break;
1128 	case TypeBool:
1129 	    if (l1->data->value.asBool != l2->data->value.asBool)
1130 		return FALSE;
1131 	    break;
1132 	case TypeFloat:
1133 	    if (l1->data->value.asFloat != l2->data->value.asFloat)
1134 		return FALSE;
1135 	    break;
1136 	case TypeString:
1137 	    if (strcmp (l1->data->value.asString, l2->data->value.asString))
1138 		return FALSE;
1139 	    break;
1140 	case TypeMatch:
1141 	    if (strcmp (l1->data->value.asMatch, l2->data->value.asMatch))
1142 		return FALSE;
1143 	    break;
1144 	case TypeKey:
1145 	    if (!ccsIsEqualKey
1146 		(l1->data->value.asKey, l2->data->value.asKey))
1147 		return FALSE;
1148 	    break;
1149 	case TypeButton:
1150 	    if (!ccsIsEqualButton
1151 		(l1->data->value.asButton, l2->data->value.asButton))
1152 		return FALSE;
1153 	    break;
1154 	case TypeEdge:
1155 	    if (l1->data->value.asEdge != l2->data->value.asEdge)
1156 		return FALSE;
1157 	    break;
1158 	case TypeBell:
1159 	    if (l1->data->value.asBell != l2->data->value.asBell)
1160 		return FALSE;
1161 	    break;
1162 	case TypeColor:
1163 	    if (!ccsIsEqualColor
1164 		(l1->data->value.asColor, l2->data->value.asColor))
1165 		return FALSE;
1166 	    break;
1167 	default:
1168 	    return FALSE;
1169 	    break;
1170 	}
1171 
1172 	l1 = l1->next;
1173 	l2 = l2->next;
1174     }
1175 
1176     if ((!l1 && l2) || (l1 && !l2))
1177 	return FALSE;
1178 
1179     return TRUE;
1180 }
1181 
1182 static CCSSettingValueList
ccsCopyList(CCSSettingValueList l1,CCSSetting * setting)1183 ccsCopyList (CCSSettingValueList l1, CCSSetting * setting)
1184 {
1185     CCSSettingValueList l2 = NULL;
1186 
1187     while (l1)
1188     {
1189 	CCSSettingValue *value = calloc (1, sizeof (CCSSettingValue));
1190 	if (!value)
1191 	    return l2;
1192 
1193 	value->parent = setting;
1194 	value->isListChild = TRUE;
1195 
1196 	switch (setting->info.forList.listType)
1197 	{
1198 	case TypeInt:
1199 	    value->value.asInt = l1->data->value.asInt;
1200 	    break;
1201 	case TypeBool:
1202 	    value->value.asBool = l1->data->value.asBool;
1203 	    break;
1204 	case TypeFloat:
1205 	    value->value.asFloat = l1->data->value.asFloat;
1206 	    break;
1207 	case TypeString:
1208 	    value->value.asString = strdup (l1->data->value.asString);
1209 	    break;
1210 	case TypeMatch:
1211 	    value->value.asMatch = strdup (l1->data->value.asMatch);
1212 	    break;
1213 	case TypeKey:
1214 	    memcpy (&value->value.asKey, &l1->data->value.asKey,
1215 		    sizeof (CCSSettingKeyValue));
1216 	    break;
1217 	case TypeButton:
1218 	    memcpy (&value->value.asButton, &l1->data->value.asButton,
1219 		    sizeof (CCSSettingButtonValue));
1220 	    break;
1221 	case TypeEdge:
1222 	    value->value.asEdge = l1->data->value.asEdge;
1223 	    break;
1224 	case TypeBell:
1225 	    value->value.asBell = l1->data->value.asBell;
1226 	    break;
1227 	case TypeColor:
1228 	    memcpy (&value->value.asColor, &l1->data->value.asColor,
1229 		    sizeof (CCSSettingColorValue));
1230 	    break;
1231 	default:
1232 	  /* FIXME If l2 != NULL, we leak l2 */
1233 	    free (value);
1234 	    return FALSE;
1235 	    break;
1236 	}
1237 
1238 	l2 = ccsSettingValueListAppend (l2, value);
1239 	l1 = l1->next;
1240     }
1241 
1242     return l2;
1243 }
1244 
1245 Bool
ccsSetList(CCSSetting * setting,CCSSettingValueList data)1246 ccsSetList (CCSSetting * setting, CCSSettingValueList data)
1247 {
1248     if (setting->type != TypeList)
1249 	return FALSE;
1250 
1251     Bool isDefault = ccsCompareLists (setting->defaultValue.value.asList, data,
1252 				      setting->info.forList);
1253 
1254     if (setting->isDefault && isDefault)
1255 	return TRUE;
1256 
1257     if (!setting->isDefault && isDefault)
1258     {
1259 	ccsResetToDefault (setting);
1260 	return TRUE;
1261     }
1262 
1263     if (ccsCompareLists (setting->value->value.asList, data,
1264 			 setting->info.forList))
1265 	return TRUE;
1266 
1267     if (setting->isDefault)
1268 	copyFromDefault (setting);
1269 
1270     ccsSettingValueListFree (setting->value->value.asList, TRUE);
1271 
1272     setting->value->value.asList = ccsCopyList (data, setting);
1273 
1274     if ((strcmp (setting->name, "active_plugins") == 0) &&
1275 	(strcmp (setting->parent->name, "core") == 0))
1276     {
1277 	CCSStringList list;
1278 
1279 	list = ccsGetStringListFromValueList (setting->value->value.asList);
1280 	ccsSetActivePluginList (setting->parent->context, list);
1281 	ccsStringListFree (list, TRUE);
1282     }
1283 
1284     setting->parent->context->changedSettings =
1285 	ccsSettingListAppend (setting->parent->context->changedSettings,
1286 			      setting);
1287 
1288     return TRUE;
1289 }
1290 
1291 Bool
ccsSetValue(CCSSetting * setting,CCSSettingValue * data)1292 ccsSetValue (CCSSetting * setting, CCSSettingValue * data)
1293 {
1294     switch (setting->type)
1295     {
1296     case TypeInt:
1297 	return ccsSetInt (setting, data->value.asInt);
1298 	break;
1299     case TypeFloat:
1300 	return ccsSetFloat (setting, data->value.asFloat);
1301 	break;
1302     case TypeBool:
1303 	return ccsSetBool (setting, data->value.asBool);
1304 	break;
1305     case TypeColor:
1306 	return ccsSetColor (setting, data->value.asColor);
1307 	break;
1308     case TypeString:
1309 	return ccsSetString (setting, data->value.asString);
1310 	break;
1311     case TypeMatch:
1312 	return ccsSetMatch (setting, data->value.asMatch);
1313 	break;
1314     case TypeKey:
1315 	return ccsSetKey (setting, data->value.asKey);
1316 	break;
1317     case TypeButton:
1318 	return ccsSetButton (setting, data->value.asButton);
1319 	break;
1320     case TypeEdge:
1321 	return ccsSetEdge (setting, data->value.asEdge);
1322 	break;
1323     case TypeBell:
1324 	return ccsSetBell (setting, data->value.asBell);
1325 	break;
1326     case TypeList:
1327 	return ccsSetList (setting, data->value.asList);
1328     default:
1329 	break;
1330     }
1331 
1332     return FALSE;
1333 }
1334 
1335 Bool
ccsGetInt(CCSSetting * setting,int * data)1336 ccsGetInt (CCSSetting * setting, int *data)
1337 {
1338     if (setting->type != TypeInt)
1339 	return FALSE;
1340 
1341     *data = setting->value->value.asInt;
1342     return TRUE;
1343 }
1344 
1345 Bool
ccsGetFloat(CCSSetting * setting,float * data)1346 ccsGetFloat (CCSSetting * setting, float *data)
1347 {
1348     if (setting->type != TypeFloat)
1349 	return FALSE;
1350 
1351     *data = setting->value->value.asFloat;
1352     return TRUE;
1353 }
1354 
1355 Bool
ccsGetBool(CCSSetting * setting,Bool * data)1356 ccsGetBool (CCSSetting * setting, Bool * data)
1357 {
1358     if (setting->type != TypeBool)
1359 	return FALSE;
1360 
1361     *data = setting->value->value.asBool;
1362     return TRUE;
1363 }
1364 
1365 Bool
ccsGetString(CCSSetting * setting,char ** data)1366 ccsGetString (CCSSetting * setting, char **data)
1367 {
1368     if (setting->type != TypeString)
1369 	return FALSE;
1370 
1371     *data = setting->value->value.asString;
1372     return TRUE;
1373 }
1374 
1375 Bool
ccsGetColor(CCSSetting * setting,CCSSettingColorValue * data)1376 ccsGetColor (CCSSetting * setting, CCSSettingColorValue * data)
1377 {
1378     if (setting->type != TypeColor)
1379 	return TRUE;
1380 
1381     *data = setting->value->value.asColor;
1382     return TRUE;
1383 }
1384 
1385 Bool
ccsGetMatch(CCSSetting * setting,char ** data)1386 ccsGetMatch (CCSSetting * setting, char **data)
1387 {
1388     if (setting->type != TypeMatch)
1389 	return FALSE;
1390 
1391     *data = setting->value->value.asMatch;
1392     return TRUE;
1393 }
1394 
1395 Bool
ccsGetKey(CCSSetting * setting,CCSSettingKeyValue * data)1396 ccsGetKey (CCSSetting * setting, CCSSettingKeyValue * data)
1397 {
1398     if (setting->type != TypeKey)
1399 	return FALSE;
1400 
1401     *data = setting->value->value.asKey;
1402     return TRUE;
1403 }
1404 
1405 Bool
ccsGetButton(CCSSetting * setting,CCSSettingButtonValue * data)1406 ccsGetButton (CCSSetting * setting, CCSSettingButtonValue * data)
1407 {
1408     if (setting->type != TypeButton)
1409 	return FALSE;
1410 
1411     *data = setting->value->value.asButton;
1412     return TRUE;
1413 }
1414 
1415 Bool
ccsGetEdge(CCSSetting * setting,unsigned int * data)1416 ccsGetEdge (CCSSetting * setting, unsigned int * data)
1417 {
1418     if (setting->type != TypeEdge)
1419 	return FALSE;
1420 
1421     *data = setting->value->value.asEdge;
1422     return TRUE;
1423 }
1424 
1425 Bool
ccsGetBell(CCSSetting * setting,Bool * data)1426 ccsGetBell (CCSSetting * setting, Bool * data)
1427 {
1428     if (setting->type != TypeBell)
1429 	return FALSE;
1430 
1431     *data = setting->value->value.asBell;
1432     return TRUE;
1433 }
1434 
1435 Bool
ccsGetList(CCSSetting * setting,CCSSettingValueList * data)1436 ccsGetList (CCSSetting * setting, CCSSettingValueList * data)
1437 {
1438     if (setting->type != TypeList)
1439 	return FALSE;
1440 
1441     *data = setting->value->value.asList;
1442     return TRUE;
1443 }
1444 
1445 void
ccsContextDestroy(CCSContext * context)1446 ccsContextDestroy (CCSContext * context)
1447 {
1448     if (!context)
1449 	return;
1450 
1451     CONTEXT_PRIV (context);
1452 
1453     if (cPrivate->backend)
1454     {
1455 	if (cPrivate->backend->vTable->backendFini)
1456 	    cPrivate->backend->vTable->backendFini (context);
1457 
1458 	dlclose (cPrivate->backend->dlhand);
1459 	free (cPrivate->backend);
1460 	cPrivate->backend = NULL;
1461     }
1462 
1463     ccsFreeContext (context);
1464 }
1465 
1466 CCSPluginList
ccsGetActivePluginList(CCSContext * context)1467 ccsGetActivePluginList (CCSContext * context)
1468 {
1469     CCSPluginList rv = NULL;
1470     CCSPluginList l = context->plugins;
1471 
1472     while (l)
1473     {
1474 	PLUGIN_PRIV (l->data);
1475 	if (pPrivate->active && strcmp (l->data->name, "ccp"))
1476 	{
1477 	    rv = ccsPluginListAppend (rv, l->data);
1478 	}
1479 
1480 	l = l->next;
1481     }
1482 
1483     return rv;
1484 }
1485 
1486 static CCSPlugin *
findPluginInList(CCSPluginList list,char * name)1487 findPluginInList (CCSPluginList list, char *name)
1488 {
1489     if (!name || !strlen (name))
1490 	return NULL;
1491 
1492     while (list)
1493     {
1494 	if (!strcmp (list->data->name, name))
1495 	    return list->data;
1496 
1497 	list = list->next;
1498     }
1499 
1500     return NULL;
1501 }
1502 
1503 typedef struct _PluginSortHelper
1504 {
1505     CCSPlugin *plugin;
1506     CCSPluginList after;
1507 } PluginSortHelper;
1508 
1509 CCSStringList
ccsGetSortedPluginStringList(CCSContext * context)1510 ccsGetSortedPluginStringList (CCSContext * context)
1511 {
1512     CCSPluginList ap = ccsGetActivePluginList (context);
1513     CCSPluginList list;
1514     CCSPlugin *p = NULL;
1515     CCSStringList rv = ccsStringListAppend (NULL, strdup ("core"));
1516     PluginSortHelper *ph = NULL;
1517 
1518     p = findPluginInList (ap, "core");
1519     if (p)
1520 	ap = ccsPluginListRemove (ap, p, FALSE);
1521 
1522     int len = ccsPluginListLength (ap);
1523     if (len == 0)
1524     {
1525 	ccsStringListFree (rv, TRUE);
1526 	return NULL;
1527     }
1528     int i, j;
1529     /* TODO: conflict handling */
1530 
1531     PluginSortHelper *plugins = calloc (1, len * sizeof (PluginSortHelper));
1532     if (!plugins)
1533     {
1534 	ccsStringListFree (rv, TRUE);
1535 	return NULL;
1536     }
1537 
1538     for (i = 0, list = ap; i < len; i++, list = list->next)
1539     {
1540 	plugins[i].plugin = list->data;
1541 	plugins[i].after = NULL;
1542     }
1543 
1544     for (i = 0; i < len; i++)
1545     {
1546 	CCSStringList l = plugins[i].plugin->loadAfter;
1547 	while (l)
1548 	{
1549 	    p = findPluginInList (ap, l->data);
1550 
1551 	    if (p && !ccsPluginListFind (plugins[i].after, p))
1552 		plugins[i].after = ccsPluginListAppend (plugins[i].after, p);
1553 
1554 	    l = l->next;
1555 	}
1556 
1557 	l = plugins[i].plugin->requiresPlugin;
1558 	while (l)
1559 	{
1560 	    Bool found = FALSE;
1561 	    p = findPluginInList (ap, l->data);
1562 
1563 	    CCSStringList l2 = plugins[i].plugin->loadBefore;
1564 	    while (l2)
1565 	    {
1566 		if (strcmp (l2->data, l->data) == 0)
1567 		    found = TRUE;
1568 		l2 = l2->next;
1569 	    }
1570 
1571 	    if (p && !ccsPluginListFind (plugins[i].after, p) && !found)
1572 		plugins[i].after = ccsPluginListAppend (plugins[i].after, p);
1573 
1574 	    l = l->next;
1575 	}
1576 
1577 	l = plugins[i].plugin->loadBefore;
1578 	while (l)
1579 	{
1580 	    p = findPluginInList (ap, l->data);
1581 
1582 	    if (p)
1583 	    {
1584 		ph = NULL;
1585 
1586 		for (j = 0; j < len; j++)
1587 		    if (p == plugins[j].plugin)
1588 			ph = &plugins[j];
1589 
1590 		if (ph && !ccsPluginListFind (ph->after, plugins[i].plugin))
1591 		    ph->after = ccsPluginListAppend (ph->after,
1592 						     plugins[i].plugin);
1593 	    }
1594 
1595 	    l = l->next;
1596 	}
1597     }
1598 
1599     ccsPluginListFree (ap, FALSE);
1600 
1601     Bool error = FALSE;
1602     int removed = 0;
1603     Bool found;
1604 
1605     while (!error && removed < len)
1606     {
1607 	found = FALSE;
1608 
1609 	for (i = 0; i < len; i++)
1610 	{
1611 	    if (!plugins[i].plugin)
1612 		continue;
1613 	    if (plugins[i].after)
1614 		continue;
1615 
1616 	    /* This is a special case to ensure that bench is the last plugin */
1617 	    if (len - removed > 1 &&
1618 		strcmp (plugins[i].plugin->name, "bench") == 0)
1619 		continue;
1620 
1621 	    found = TRUE;
1622 	    removed++;
1623 	    p = plugins[i].plugin;
1624 	    plugins[i].plugin = NULL;
1625 
1626 	    for (j = 0; j < len; j++)
1627 		plugins[j].after =
1628 		    ccsPluginListRemove (plugins[j].after, p, FALSE);
1629 
1630 	    rv = ccsStringListAppend (rv, strdup (p->name));
1631 	}
1632 
1633 	if (!found)
1634 	    error = TRUE;
1635     }
1636 
1637     if (error)
1638     {
1639 	fprintf (stderr,
1640 		 "libccs: unable to generate sorted plugin list\n");
1641 
1642 	for (i = 0; i < len; i++)
1643 	{
1644 	    ccsPluginListFree (plugins[i].after, FALSE);
1645 	}
1646 
1647 	ccsStringListFree (rv, TRUE);
1648 
1649 	rv = NULL;
1650     }
1651 
1652     free (plugins);
1653 
1654     return rv;
1655 }
1656 
1657 char *
ccsGetBackend(CCSContext * context)1658 ccsGetBackend (CCSContext * context)
1659 {
1660     if (!context)
1661 	return NULL;
1662 
1663     CONTEXT_PRIV (context);
1664 
1665     if (!cPrivate->backend)
1666 	return NULL;
1667 
1668     return cPrivate->backend->vTable->name;
1669 }
1670 
1671 Bool
ccsGetIntegrationEnabled(CCSContext * context)1672 ccsGetIntegrationEnabled (CCSContext * context)
1673 {
1674     if (!context)
1675 	return FALSE;
1676 
1677     CONTEXT_PRIV (context);
1678 
1679     return cPrivate->deIntegration;
1680 }
1681 
1682 char *
ccsGetProfile(CCSContext * context)1683 ccsGetProfile (CCSContext * context)
1684 {
1685     if (!context)
1686 	return NULL;
1687 
1688     CONTEXT_PRIV (context);
1689 
1690     return cPrivate->profile;
1691 }
1692 
1693 Bool
ccsGetPluginListAutoSort(CCSContext * context)1694 ccsGetPluginListAutoSort (CCSContext * context)
1695 {
1696     if (!context)
1697 	return FALSE;
1698 
1699     CONTEXT_PRIV (context);
1700 
1701     return cPrivate->pluginListAutoSort;
1702 }
1703 
1704 void
ccsSetIntegrationEnabled(CCSContext * context,Bool value)1705 ccsSetIntegrationEnabled (CCSContext * context, Bool value)
1706 {
1707     CONTEXT_PRIV (context);
1708 
1709     /* no action required if nothing changed */
1710     if ((!cPrivate->deIntegration && !value) ||
1711 	 (cPrivate->deIntegration && value))
1712 	return;
1713 
1714     cPrivate->deIntegration = value;
1715 
1716     ccsDisableFileWatch (cPrivate->configWatchId);
1717     ccsWriteConfig (OptionIntegration, (value) ? "true" : "false");
1718     ccsEnableFileWatch (cPrivate->configWatchId);
1719 }
1720 
1721 static void
ccsWriteAutoSortedPluginList(CCSContext * context)1722 ccsWriteAutoSortedPluginList (CCSContext *context)
1723 {
1724     CCSStringList list;
1725     CCSPlugin     *p;
1726 
1727     list = ccsGetSortedPluginStringList (context);
1728     p    = ccsFindPlugin (context, "core");
1729     if (p)
1730     {
1731 	CCSSetting *s;
1732 
1733 	s = ccsFindSetting (p, "active_plugins", FALSE, 0);
1734 	if (s)
1735 	{
1736 	    CCSSettingValueList vl;
1737 
1738 	    vl = ccsGetValueListFromStringList (list, s);
1739 	    ccsSetList (s, vl);
1740 	    ccsSettingValueListFree (vl, TRUE);
1741 	    ccsWriteChangedSettings (context);
1742 	}
1743     }
1744     ccsStringListFree (list, TRUE);
1745 }
1746 
1747 void
ccsSetPluginListAutoSort(CCSContext * context,Bool value)1748 ccsSetPluginListAutoSort (CCSContext * context, Bool value)
1749 {
1750     CONTEXT_PRIV (context);
1751 
1752     /* no action required if nothing changed */
1753     if ((!cPrivate->pluginListAutoSort && !value) ||
1754 	 (cPrivate->pluginListAutoSort && value))
1755 	return;
1756 
1757     cPrivate->pluginListAutoSort = value;
1758 
1759     ccsDisableFileWatch (cPrivate->configWatchId);
1760     ccsWriteConfig (OptionAutoSort, (value) ? "true" : "false");
1761     ccsEnableFileWatch (cPrivate->configWatchId);
1762 
1763     if (value)
1764 	ccsWriteAutoSortedPluginList (context);
1765 }
1766 
1767 void
ccsSetProfile(CCSContext * context,char * name)1768 ccsSetProfile (CCSContext * context, char *name)
1769 {
1770     if (!name)
1771 	name = "";
1772 
1773     CONTEXT_PRIV (context);
1774 
1775     /* no action required if profile stays the same */
1776     if (cPrivate->profile && (strcmp (cPrivate->profile, name) == 0))
1777 	return;
1778 
1779     if (cPrivate->profile)
1780 	free (cPrivate->profile);
1781 
1782     cPrivate->profile = strdup (name);
1783 
1784     ccsDisableFileWatch (cPrivate->configWatchId);
1785     ccsWriteConfig (OptionProfile, cPrivate->profile);
1786     ccsEnableFileWatch (cPrivate->configWatchId);
1787 }
1788 
1789 void
ccsProcessEvents(CCSContext * context,unsigned int flags)1790 ccsProcessEvents (CCSContext * context, unsigned int flags)
1791 {
1792     if (!context)
1793 	return;
1794 
1795     CONTEXT_PRIV (context);
1796 
1797     ccsCheckFileWatches ();
1798 
1799     if (cPrivate->backend && cPrivate->backend->vTable->executeEvents)
1800 	(*cPrivate->backend->vTable->executeEvents) (flags);
1801 }
1802 
1803 void
ccsReadSettings(CCSContext * context)1804 ccsReadSettings (CCSContext * context)
1805 {
1806     if (!context)
1807 	return;
1808 
1809     CONTEXT_PRIV (context);
1810 
1811     if (!cPrivate->backend)
1812 	return;
1813 
1814     if (!cPrivate->backend->vTable->readSetting)
1815 	return;
1816 
1817     if (cPrivate->backend->vTable->readInit)
1818 	if (!(*cPrivate->backend->vTable->readInit) (context))
1819 	    return;
1820 
1821     CCSPluginList pl = context->plugins;
1822     while (pl)
1823     {
1824 	PLUGIN_PRIV (pl->data);
1825 	CCSSettingList sl = pPrivate->settings;
1826 
1827 	while (sl)
1828 	{
1829 	    (*cPrivate->backend->vTable->readSetting) (context, sl->data);
1830 	    sl = sl->next;
1831 	}
1832 
1833 	pl = pl->next;
1834     }
1835 
1836     if (cPrivate->backend->vTable->readDone)
1837 	(*cPrivate->backend->vTable->readDone) (context);
1838 }
1839 
1840 void
ccsReadPluginSettings(CCSPlugin * plugin)1841 ccsReadPluginSettings (CCSPlugin * plugin)
1842 {
1843     if (!plugin || !plugin->context)
1844 	return;
1845 
1846     CONTEXT_PRIV (plugin->context);
1847 
1848     if (!cPrivate->backend)
1849 	return;
1850 
1851     if (!cPrivate->backend->vTable->readSetting)
1852 	return;
1853 
1854     if (cPrivate->backend->vTable->readInit)
1855 	if (!(*cPrivate->backend->vTable->readInit) (plugin->context))
1856 	    return;
1857 
1858     PLUGIN_PRIV (plugin);
1859 
1860     CCSSettingList sl = pPrivate->settings;
1861     while (sl)
1862     {
1863 	(*cPrivate->backend->vTable->readSetting) (plugin->context, sl->data);
1864 	sl = sl->next;
1865     }
1866 
1867     if (cPrivate->backend->vTable->readDone)
1868 	(*cPrivate->backend->vTable->readDone) (plugin->context);
1869 }
1870 
1871 void
ccsWriteSettings(CCSContext * context)1872 ccsWriteSettings (CCSContext * context)
1873 {
1874     if (!context)
1875 	return;
1876 
1877     CONTEXT_PRIV (context);
1878 
1879     if (!cPrivate->backend)
1880 	return;
1881 
1882     if (!cPrivate->backend->vTable->writeSetting)
1883 	return;
1884 
1885     if (cPrivate->backend->vTable->writeInit)
1886 	if (!(*cPrivate->backend->vTable->writeInit) (context))
1887 	    return;
1888 
1889     CCSPluginList pl = context->plugins;
1890     while (pl)
1891     {
1892 	PLUGIN_PRIV (pl->data);
1893 	CCSSettingList sl = pPrivate->settings;
1894 
1895 	while (sl)
1896 	{
1897 	    (*cPrivate->backend->vTable->writeSetting) (context, sl->data);
1898 	    sl = sl->next;
1899 	}
1900 
1901 	pl = pl->next;
1902     }
1903 
1904     if (cPrivate->backend->vTable->writeDone)
1905 	(*cPrivate->backend->vTable->writeDone) (context);
1906 
1907     context->changedSettings =
1908 	ccsSettingListFree (context->changedSettings, FALSE);
1909 }
1910 
1911 void
ccsWriteChangedSettings(CCSContext * context)1912 ccsWriteChangedSettings (CCSContext * context)
1913 {
1914     if (!context)
1915 	return;
1916 
1917     CONTEXT_PRIV (context);
1918 
1919     if (!cPrivate->backend)
1920 	return;
1921 
1922     if (!cPrivate->backend->vTable->writeSetting)
1923 	return;
1924 
1925     if (cPrivate->backend->vTable->writeInit)
1926 	if (!(*cPrivate->backend->vTable->writeInit) (context))
1927 	    return;
1928 
1929     if (ccsSettingListLength (context->changedSettings))
1930     {
1931 	CCSSettingList l = context->changedSettings;
1932 
1933 	while (l)
1934 	{
1935 	    (*cPrivate->backend->vTable->writeSetting) (context, l->data);
1936 	    l = l->next;
1937 	}
1938     }
1939 
1940     if (cPrivate->backend->vTable->writeDone)
1941 	(*cPrivate->backend->vTable->writeDone) (context);
1942 
1943     context->changedSettings =
1944 	ccsSettingListFree (context->changedSettings, FALSE);
1945 }
1946 
1947 Bool
ccsIsEqualColor(CCSSettingColorValue c1,CCSSettingColorValue c2)1948 ccsIsEqualColor (CCSSettingColorValue c1, CCSSettingColorValue c2)
1949 {
1950     if (c1.color.red == c2.color.red     &&
1951 	c1.color.green == c2.color.green &&
1952 	c1.color.blue == c2.color.blue   &&
1953 	c1.color.alpha == c2.color.alpha)
1954     {
1955 	return TRUE;
1956     }
1957 
1958     return FALSE;
1959 }
1960 
1961 Bool
ccsIsEqualKey(CCSSettingKeyValue c1,CCSSettingKeyValue c2)1962 ccsIsEqualKey (CCSSettingKeyValue c1, CCSSettingKeyValue c2)
1963 {
1964     if (c1.keysym == c2.keysym && c1.keyModMask == c2.keyModMask)
1965 	return TRUE;
1966 
1967     return FALSE;
1968 }
1969 
1970 Bool
ccsIsEqualButton(CCSSettingButtonValue c1,CCSSettingButtonValue c2)1971 ccsIsEqualButton (CCSSettingButtonValue c1, CCSSettingButtonValue c2)
1972 {
1973     if (c1.button == c2.button               &&
1974 	c1.buttonModMask == c2.buttonModMask &&
1975 	c1.edgeMask == c2.edgeMask)
1976 	return TRUE;
1977 
1978     return FALSE;
1979 }
1980 
1981 Bool
ccsPluginSetActive(CCSPlugin * plugin,Bool value)1982 ccsPluginSetActive (CCSPlugin * plugin, Bool value)
1983 {
1984     if (!plugin)
1985 	return FALSE;
1986 
1987     PLUGIN_PRIV (plugin);
1988     CONTEXT_PRIV (plugin->context);
1989 
1990     pPrivate->active = value;
1991 
1992     if (cPrivate->pluginListAutoSort)
1993 	ccsWriteAutoSortedPluginList (plugin->context);
1994 
1995     return TRUE;
1996 }
1997 
1998 CCSPluginConflictList
ccsCanEnablePlugin(CCSContext * context,CCSPlugin * plugin)1999 ccsCanEnablePlugin (CCSContext * context, CCSPlugin * plugin)
2000 {
2001     CCSPluginConflictList list = NULL;
2002     CCSPluginList pl, pl2;
2003     CCSStringList sl;
2004 
2005     /* look if the plugin to be loaded requires a plugin not present */
2006     sl = plugin->requiresPlugin;
2007 
2008     while (sl)
2009     {
2010 	if (!ccsFindPlugin (context, sl->data))
2011 	{
2012 	    CCSPluginConflict *conflict = calloc (1,
2013 						  sizeof (CCSPluginConflict));
2014 	    if (conflict)
2015 	    {
2016 		conflict->value = strdup (sl->data);
2017 		conflict->type = ConflictPluginError;
2018 		conflict->plugins = NULL;
2019 		list = ccsPluginConflictListAppend (list, conflict);
2020 	    }
2021 	}
2022 	else if (!ccsPluginIsActive (context, sl->data))
2023 	{
2024 	    /* we've not seen a matching plugin */
2025 	    CCSPluginConflict *conflict = calloc (1,
2026 						  sizeof (CCSPluginConflict));
2027 	    if (conflict)
2028 	    {
2029 		conflict->value = strdup (sl->data);
2030 		conflict->type = ConflictRequiresPlugin;
2031 		conflict->plugins =
2032 		    ccsPluginListAppend (conflict->plugins,
2033 			    		 ccsFindPlugin (context, sl->data));
2034 		list = ccsPluginConflictListAppend (list, conflict);
2035 	    }
2036 	}
2037 
2038 	sl = sl->next;
2039     }
2040 
2041     /* look if the new plugin wants a non-present feature */
2042     sl = plugin->requiresFeature;
2043 
2044     while (sl)
2045     {
2046 	pl = context->plugins;
2047 	pl2 = NULL;
2048 
2049 	while (pl)
2050 	{
2051 	    CCSStringList featureList = pl->data->providesFeature;
2052 
2053 	    while (featureList)
2054 	    {
2055 		if (strcmp (sl->data, featureList->data) == 0)
2056 		{
2057 		    pl2 = ccsPluginListAppend (pl2, pl->data);
2058 		    break;
2059 		}
2060 		featureList = featureList->next;
2061 	    }
2062 
2063 	    pl = pl->next;
2064 	}
2065 
2066 	pl = pl2;
2067 
2068 	while (pl)
2069 	{
2070 	    if (ccsPluginIsActive (context, pl->data->name))
2071 	    {
2072 		ccsPluginListFree (pl2, FALSE);
2073 		break;
2074 	    }
2075 	    pl = pl->next;
2076 	}
2077 
2078 	if (!pl)
2079 	{
2080 	    /* no plugin provides that feature */
2081 	    CCSPluginConflict *conflict = calloc (1,
2082 						  sizeof (CCSPluginConflict));
2083 
2084 	    if (conflict)
2085 	    {
2086 		conflict->value = strdup (sl->data);
2087 		conflict->type = ConflictRequiresFeature;
2088 		conflict->plugins = pl2;
2089 
2090 		list = ccsPluginConflictListAppend (list, conflict);
2091 	    }
2092 	}
2093 
2094 	sl = sl->next;
2095     }
2096 
2097     /* look if another plugin provides the same feature */
2098     sl = plugin->providesFeature;
2099     while (sl)
2100     {
2101 	pl = context->plugins;
2102 	CCSPluginConflict *conflict = NULL;
2103 
2104 	while (pl)
2105 	{
2106 	    if (ccsPluginIsActive (context, pl->data->name))
2107 	    {
2108 		CCSStringList featureList = pl->data->providesFeature;
2109 
2110 		while (featureList)
2111 		{
2112 		    if (strcmp (sl->data, featureList->data) == 0)
2113 		    {
2114 			if (!conflict)
2115 			{
2116 			    conflict = calloc (1, sizeof (CCSPluginConflict));
2117 			    if (conflict)
2118 			    {
2119 				conflict->value = strdup (sl->data);
2120 				conflict->type = ConflictFeature;
2121 			    }
2122 			}
2123 			if (conflict)
2124 			    conflict->plugins =
2125 				ccsPluginListAppend (conflict->plugins,
2126 						     pl->data);
2127 		    }
2128 		    featureList = featureList->next;
2129 		}
2130 	    }
2131 	    pl = pl->next;
2132 	}
2133 
2134 	if (conflict)
2135 	    list = ccsPluginConflictListAppend (list, conflict);
2136 
2137 	sl = sl->next;
2138     }
2139 
2140     /* look if another plugin provides a conflicting feature*/
2141     sl = plugin->conflictFeature;
2142     while (sl)
2143     {
2144 	pl = context->plugins;
2145 	CCSPluginConflict *conflict = NULL;
2146 
2147 	while (pl)
2148 	{
2149 	    if (ccsPluginIsActive (context, pl->data->name))
2150 	    {
2151 		CCSStringList featureList = pl->data->providesFeature;
2152 		while (featureList)
2153 		{
2154 		    if (strcmp (sl->data, featureList->data) == 0)
2155 		    {
2156 			if (!conflict)
2157 			{
2158 			    conflict = calloc (1, sizeof (CCSPluginConflict));
2159 			    if (conflict)
2160 			    {
2161 				conflict->value = strdup (sl->data);
2162 				conflict->type = ConflictFeature;
2163 			    }
2164 			}
2165 			if (conflict)
2166 			    conflict->plugins =
2167 				ccsPluginListAppend (conflict->plugins,
2168 						     pl->data);
2169 		    }
2170 		    featureList = featureList->next;
2171 		}
2172 	    }
2173 	    pl = pl->next;
2174 	}
2175 
2176 	if (conflict)
2177 	    list = ccsPluginConflictListAppend (list, conflict);
2178 
2179 	sl = sl->next;
2180     }
2181 
2182     /* look if the plugin to be loaded conflict with a loaded plugin  */
2183     sl = plugin->conflictPlugin;
2184 
2185     while (sl)
2186     {
2187 	if (ccsPluginIsActive (context, sl->data))
2188 	{
2189 	    CCSPluginConflict *conflict = calloc (1,
2190 						  sizeof (CCSPluginConflict));
2191 	    if (conflict)
2192 	    {
2193 		conflict->value = strdup (sl->data);
2194 		conflict->type = ConflictPlugin;
2195 		conflict->plugins =
2196 		    ccsPluginListAppend (conflict->plugins,
2197 			    		 ccsFindPlugin (context, sl->data));
2198 		list = ccsPluginConflictListAppend (list, conflict);
2199 	    }
2200 	}
2201 
2202 	sl = sl->next;
2203     }
2204 
2205     return list;
2206 }
2207 
2208 CCSPluginConflictList
ccsCanDisablePlugin(CCSContext * context,CCSPlugin * plugin)2209 ccsCanDisablePlugin (CCSContext * context, CCSPlugin * plugin)
2210 {
2211     CCSPluginConflictList list = NULL;
2212     CCSPluginConflict *conflict = NULL;
2213     CCSPluginList pl;
2214     CCSStringList sl;
2215 
2216     /* look if the plugin to be unloaded is required by another plugin */
2217     pl = context->plugins;
2218 
2219     for (; pl; pl = pl->next)
2220     {
2221 	CCSStringList pluginList;
2222 
2223 	if (pl->data == plugin)
2224 	    continue;
2225 
2226 	if (!ccsPluginIsActive (context, pl->data->name))
2227 	    continue;
2228 
2229 	pluginList = pl->data->requiresPlugin;
2230 
2231 	while (pluginList)
2232 	{
2233 	    if (strcmp (plugin->name, pluginList->data) == 0)
2234 	    {
2235 		if (!conflict)
2236 		{
2237 		    conflict = calloc (1, sizeof (CCSPluginConflict));
2238 		    if (conflict)
2239 		    {
2240 			conflict->value = strdup (plugin->name);
2241 			conflict->type = ConflictPluginNeeded;
2242 		    }
2243 		}
2244 
2245 		if (conflict)
2246 		    conflict->plugins =
2247 			ccsPluginListAppend (conflict->plugins, pl->data);
2248 		break;
2249 	    }
2250 	    pluginList = pluginList->next;
2251 	}
2252     }
2253 
2254     if (conflict)
2255     {
2256 	list = ccsPluginConflictListAppend (list, conflict);
2257 	conflict = NULL;
2258     }
2259 
2260     /* look if a feature provided is required by another plugin */
2261     sl = plugin->providesFeature;
2262     while (sl)
2263     {
2264 	pl = context->plugins;
2265 	for (; pl; pl = pl->next)
2266 	{
2267 	    CCSStringList pluginList;
2268 
2269 	    if (pl->data == plugin)
2270 		continue;
2271 
2272 	    if (!ccsPluginIsActive (context, pl->data->name))
2273 		continue;
2274 
2275 	    pluginList = pl->data->requiresFeature;
2276 
2277 	    while (pluginList)
2278 	    {
2279 		if (strcmp (sl->data, pluginList->data) == 0)
2280 		{
2281 		    if (!conflict)
2282 		    {
2283 			conflict = calloc (1, sizeof (CCSPluginConflict));
2284 
2285 			if (conflict)
2286 			{
2287 			    conflict->value = strdup (sl->data);
2288 			    conflict->type = ConflictFeatureNeeded;
2289 			}
2290 		    }
2291 		    if (conflict)
2292 			conflict->plugins =
2293 			    ccsPluginListAppend (conflict->plugins, pl->data);
2294 		}
2295 		pluginList = pluginList->next;
2296 	    }
2297 
2298 	}
2299 	if (conflict)
2300 	    list = ccsPluginConflictListAppend (list, conflict);
2301 	conflict = NULL;
2302 	sl = sl->next;
2303     }
2304 
2305     return list;
2306 }
2307 
2308 CCSStringList
ccsGetExistingProfiles(CCSContext * context)2309 ccsGetExistingProfiles (CCSContext * context)
2310 {
2311     if (!context)
2312 	return NULL;
2313 
2314     CONTEXT_PRIV (context);
2315 
2316     if (!cPrivate->backend)
2317 	return NULL;
2318 
2319     if (cPrivate->backend->vTable->getExistingProfiles)
2320 	return (*cPrivate->backend->vTable->getExistingProfiles) (context);
2321 
2322     return NULL;
2323 }
2324 
2325 void
ccsDeleteProfile(CCSContext * context,char * name)2326 ccsDeleteProfile (CCSContext * context, char *name)
2327 {
2328     if (!context)
2329 	return;
2330 
2331     CONTEXT_PRIV (context);
2332 
2333     if (!cPrivate->backend)
2334 	return;
2335 
2336     /* never ever delete default profile */
2337     if (!name || !strlen (name))
2338 	return;
2339 
2340     /* if the current profile should be deleted,
2341        switch to default profile first */
2342     if (strcmp (cPrivate->profile, name) == 0)
2343 	ccsSetProfile (context, "");
2344 
2345     if (cPrivate->backend->vTable->deleteProfile)
2346 	(*cPrivate->backend->vTable->deleteProfile) (context, name);
2347 }
2348 
2349 static void
addBackendInfo(CCSBackendInfoList * bl,char * file)2350 addBackendInfo (CCSBackendInfoList * bl, char *file)
2351 {
2352     void *dlhand = NULL;
2353     char *err = NULL;
2354     Bool found = FALSE;
2355     CCSBackendInfo *info;
2356 
2357     dlerror ();
2358 
2359     dlhand = dlopen (file, RTLD_LAZY | RTLD_LOCAL);
2360     err = dlerror ();
2361     if (err || !dlhand)
2362 	return;
2363 
2364     BackendGetInfoProc getInfo = dlsym (dlhand, "getBackendInfo");
2365     if (!getInfo)
2366     {
2367 	dlclose (dlhand);
2368 	return;
2369     }
2370 
2371     CCSBackendVTable *vt = getInfo ();
2372     if (!vt)
2373     {
2374 	dlclose (dlhand);
2375 	return;
2376     }
2377 
2378     CCSBackendInfoList l = *bl;
2379     while (l)
2380     {
2381 	if (!strcmp (l->data->name, vt->name))
2382 	{
2383 	    found = TRUE;
2384 	    break;
2385 	}
2386 
2387 	l = l->next;
2388     }
2389 
2390     if (found)
2391     {
2392 	dlclose (dlhand);
2393 	return;
2394     }
2395 
2396     info = calloc (1, sizeof (CCSBackendInfo));
2397     if (!info)
2398     {
2399 	dlclose (dlhand);
2400 	return;
2401     }
2402 
2403     info->name = strdup (vt->name);
2404     info->shortDesc = (vt->shortDesc) ? strdup (vt->shortDesc) : strdup ("");
2405     info->longDesc = (vt->longDesc) ? strdup (vt->longDesc) : strdup ("");
2406     info->integrationSupport = vt->integrationSupport;
2407     info->profileSupport = vt->profileSupport;
2408 
2409     *bl = ccsBackendInfoListAppend (*bl, info);
2410     dlclose (dlhand);
2411 }
2412 
2413 static int
2414 
backendNameFilter(const struct dirent * name)2415 backendNameFilter (const struct dirent *name)
2416 {
2417     int length = strlen (name->d_name);
2418 
2419     if (length < 7)
2420 	return 0;
2421 
2422     if (strncmp (name->d_name, "lib", 3) ||
2423 	strncmp (name->d_name + length - 3, ".so", 3))
2424 	return 0;
2425 
2426     return 1;
2427 }
2428 
2429 static void
getBackendInfoFromDir(CCSBackendInfoList * bl,char * path)2430 getBackendInfoFromDir (CCSBackendInfoList * bl, char *path)
2431 {
2432 
2433     struct dirent **nameList;
2434     int nFile, i;
2435 
2436     if (!path)
2437 	return;
2438 
2439     nFile = scandir (path, &nameList, backendNameFilter, NULL);
2440     if (nFile <= 0)
2441 	return;
2442 
2443     for (i = 0; i < nFile; i++)
2444     {
2445 	char file[1024];
2446 	sprintf (file, "%s/%s", path, nameList[i]->d_name);
2447 	addBackendInfo (bl, file);
2448 	free (nameList[i]);
2449     }
2450 
2451     free (nameList);
2452 
2453 }
2454 
2455 CCSBackendInfoList
ccsGetExistingBackends()2456 ccsGetExistingBackends ()
2457 {
2458     CCSBackendInfoList rv = NULL;
2459     char *home = getenv ("HOME");
2460     char *backenddir;
2461 
2462     if (home && strlen (home))
2463     {
2464 	asprintf (&backenddir, "%s/.compizconfig/backends", home);
2465 	getBackendInfoFromDir (&rv, backenddir);
2466 	free (backenddir);
2467     }
2468 
2469     asprintf (&backenddir, "%s/compizconfig/backends", LIBDIR);
2470 
2471     getBackendInfoFromDir (&rv, backenddir);
2472     free (backenddir);
2473     return rv;
2474 }
2475 
2476 Bool
ccsExportToFile(CCSContext * context,const char * fileName,Bool skipDefaults)2477 ccsExportToFile (CCSContext *context,
2478 		 const char *fileName,
2479 		 Bool       skipDefaults)
2480 {
2481     IniDictionary *exportFile;
2482     CCSPluginList p;
2483     CCSSettingList s;
2484     CCSPlugin *plugin;
2485     CCSSetting *setting;
2486     char *keyName;
2487 
2488     exportFile = ccsIniNew ();
2489     if (!exportFile)
2490 	return FALSE;
2491 
2492     for (p = context->plugins; p; p = p->next)
2493     {
2494 	plugin = p->data;
2495 	PLUGIN_PRIV (plugin);
2496 
2497 	if (!pPrivate->loaded)
2498 	    ccsLoadPluginSettings (plugin);
2499 
2500 	for (s = pPrivate->settings; s; s = s->next)
2501 	{
2502 	    setting = s->data;
2503 
2504 	    if (skipDefaults && setting->isDefault)
2505 		continue;
2506 
2507 	    if (setting->isScreen)
2508 		asprintf (&keyName, "s%d_%s",
2509 			  setting->screenNum, setting->name);
2510 	    else
2511 		asprintf (&keyName, "as_%s", setting->name);
2512 
2513 	    switch (setting->type)
2514 	    {
2515 	    case TypeBool:
2516 		ccsIniSetBool (exportFile, plugin->name, keyName,
2517 			       setting->value->value.asBool);
2518 		break;
2519 	    case TypeInt:
2520 		ccsIniSetInt (exportFile, plugin->name, keyName,
2521 			      setting->value->value.asInt);
2522 		break;
2523 	    case TypeFloat:
2524 		ccsIniSetFloat (exportFile, plugin->name, keyName,
2525 				setting->value->value.asFloat);
2526 		break;
2527 	    case TypeString:
2528 		ccsIniSetString (exportFile, plugin->name, keyName,
2529 				 setting->value->value.asString);
2530 		break;
2531 	    case TypeKey:
2532 		ccsIniSetKey (exportFile, plugin->name, keyName,
2533 			      setting->value->value.asKey);
2534 		break;
2535 	    case TypeButton:
2536 		ccsIniSetButton (exportFile, plugin->name, keyName,
2537 				 setting->value->value.asButton);
2538 		break;
2539 	    case TypeEdge:
2540 		ccsIniSetEdge (exportFile, plugin->name, keyName,
2541 			       setting->value->value.asEdge);
2542 		break;
2543 	    case TypeBell:
2544 		ccsIniSetBell (exportFile, plugin->name, keyName,
2545 			       setting->value->value.asBell);
2546 		break;
2547 	    case TypeColor:
2548 		ccsIniSetColor (exportFile, plugin->name, keyName,
2549 				setting->value->value.asColor);
2550 		break;
2551 	    case TypeMatch:
2552 		ccsIniSetString (exportFile, plugin->name, keyName,
2553 				 setting->value->value.asMatch);
2554 		break;
2555 	    case TypeList:
2556 		ccsIniSetList (exportFile, plugin->name, keyName,
2557 			       setting->value->value.asList,
2558 			       setting->info.forList.listType);
2559 		break;
2560 	    default:
2561 		break;
2562 	    }
2563 	    free (keyName);
2564 	}
2565     }
2566 
2567     ccsIniSave (exportFile, fileName);
2568     ccsIniClose (exportFile);
2569 
2570     return TRUE;
2571 }
2572 
2573 Bool
ccsImportFromFile(CCSContext * context,const char * fileName,Bool overwriteNonDefault)2574 ccsImportFromFile (CCSContext *context,
2575 		   const char *fileName,
2576 		   Bool       overwriteNonDefault)
2577 {
2578     IniDictionary *importFile;
2579     CCSPluginList p;
2580     CCSSettingList s;
2581     CCSPlugin *plugin;
2582     CCSSetting *setting;
2583     char *keyName;
2584     FILE *fp;
2585 
2586     /* check if the file exists first */
2587     fp = fopen (fileName, "r");
2588     if (!fp)
2589 	return FALSE;
2590     fclose (fp);
2591 
2592     importFile = iniparser_new ((char *) fileName);
2593     if (!importFile)
2594 	return FALSE;
2595 
2596     for (p = context->plugins; p; p = p->next)
2597     {
2598 	plugin = p->data;
2599 	PLUGIN_PRIV (plugin);
2600 
2601 	if (!pPrivate->loaded)
2602 	    ccsLoadPluginSettings (plugin);
2603 
2604 	for (s = pPrivate->settings; s; s = s->next)
2605 	{
2606 	    setting = s->data;
2607 	    if (!setting->isDefault && !overwriteNonDefault)
2608 		continue;
2609 
2610 	    if (setting->isScreen)
2611 		asprintf (&keyName, "s%d_%s",
2612 			  setting->screenNum, setting->name);
2613 	    else
2614 		asprintf (&keyName, "as_%s", setting->name);
2615 
2616 	    switch (setting->type)
2617 	    {
2618 	    case TypeBool:
2619 		{
2620 		    Bool value;
2621 
2622 		    if (ccsIniGetBool (importFile, plugin->name,
2623 				       keyName, &value))
2624 			ccsSetBool (setting, value);
2625 		}
2626 		break;
2627 	    case TypeInt:
2628 		{
2629 		    int value;
2630 
2631 		    if (ccsIniGetInt (importFile, plugin->name,
2632 				      keyName, &value))
2633 			ccsSetInt (setting, value);
2634 		}
2635 		break;
2636 	    case TypeFloat:
2637 		{
2638 		    float value;
2639 
2640 		    if (ccsIniGetFloat (importFile, plugin->name,
2641 					keyName, &value))
2642 			ccsSetFloat (setting, value);
2643 		}
2644 		break;
2645 	    case TypeString:
2646 		{
2647 		    char *value;
2648 
2649 		    if (ccsIniGetString (importFile, plugin->name,
2650 					 keyName, &value))
2651 		    {
2652 		    	ccsSetString (setting, value);
2653 		    	free (value);
2654 		    }
2655 		}
2656 		break;
2657 	    case TypeKey:
2658 		{
2659 		    CCSSettingKeyValue value;
2660 
2661 		    if (ccsIniGetKey (importFile, plugin->name,
2662 				      keyName, &value))
2663 			ccsSetKey (setting, value);
2664 		}
2665 		break;
2666 	    case TypeButton:
2667 		{
2668 		    CCSSettingButtonValue value;
2669 
2670 		    if (ccsIniGetButton (importFile, plugin->name,
2671 					 keyName, &value))
2672 			ccsSetButton (setting, value);
2673 		}
2674 		break;
2675 	    case TypeEdge:
2676 		{
2677 		    unsigned int value;
2678 
2679 		    if (ccsIniGetEdge (importFile, plugin->name,
2680 				       keyName, &value))
2681 			ccsSetEdge (setting, value);
2682 		}
2683 		break;
2684 	    case TypeBell:
2685 		{
2686 		    Bool value;
2687 
2688 		    if (ccsIniGetBell (importFile, plugin->name,
2689 				       keyName, &value))
2690 			ccsSetBell (setting, value);
2691 		}
2692 		break;
2693 	    case TypeColor:
2694 		{
2695 		    CCSSettingColorValue value;
2696 
2697 		    if (ccsIniGetColor (importFile, plugin->name,
2698 					keyName, &value))
2699 			ccsSetColor (setting, value);
2700 		}
2701 		break;
2702 	    case TypeMatch:
2703 		{
2704 		    char *value;
2705 		    if (ccsIniGetString (importFile, plugin->name,
2706 					 keyName, &value))
2707 		    {
2708 		    	ccsSetMatch (setting, value);
2709 		    	free (value);
2710 		    }
2711 		}
2712 		break;
2713 	    case TypeList:
2714 		{
2715 		    CCSSettingValueList value;
2716 		    if (ccsIniGetList (importFile, plugin->name,
2717 				       keyName, &value, setting))
2718 		    {
2719 			ccsSetList (setting, value);
2720 			ccsSettingValueListFree (value, TRUE);
2721 		    }
2722 		}
2723 		break;
2724 	    default:
2725 		break;
2726 	    }
2727 
2728 	    free (keyName);
2729 	}
2730     }
2731 
2732     ccsIniClose (importFile);
2733 
2734     return TRUE;
2735 }
2736 
ccsGetPluginSettings(CCSPlugin * plugin)2737 CCSSettingList ccsGetPluginSettings (CCSPlugin *plugin)
2738 
2739 {
2740     PLUGIN_PRIV (plugin);
2741 
2742     if (!pPrivate->loaded)
2743 	ccsLoadPluginSettings (plugin);
2744 
2745     return pPrivate->settings;
2746 }
2747 
ccsGetPluginGroups(CCSPlugin * plugin)2748 CCSGroupList ccsGetPluginGroups (CCSPlugin *plugin)
2749 {
2750     PLUGIN_PRIV (plugin);
2751 
2752     if (!pPrivate->loaded)
2753 	ccsLoadPluginSettings (plugin);
2754 
2755     return pPrivate->groups;
2756 }
2757 
ccsSettingIsIntegrated(CCSSetting * setting)2758 Bool ccsSettingIsIntegrated (CCSSetting *setting)
2759 {
2760     if (!setting)
2761 	return FALSE;
2762 
2763     CONTEXT_PRIV (setting->parent->context);
2764 
2765     if (!cPrivate->backend)
2766 	return FALSE;
2767 
2768     if (cPrivate->backend->vTable->getSettingIsIntegrated)
2769 	return (*cPrivate->backend->vTable->getSettingIsIntegrated) (setting);
2770 
2771     return FALSE;
2772 }
2773 
ccsSettingIsReadOnly(CCSSetting * setting)2774 Bool ccsSettingIsReadOnly (CCSSetting *setting)
2775 {
2776     if (!setting)
2777 	return FALSE;
2778 
2779     CONTEXT_PRIV (setting->parent->context);
2780 
2781     if (!cPrivate->backend)
2782 	return FALSE;
2783 
2784     if (cPrivate->backend->vTable->getSettingIsReadOnly)
2785 	return (*cPrivate->backend->vTable->getSettingIsReadOnly) (setting);
2786 
2787     return FALSE;
2788 }
2789 
ccsGetPluginStrExtensions(CCSPlugin * plugin)2790 CCSStrExtensionList ccsGetPluginStrExtensions (CCSPlugin *plugin)
2791 {
2792     PLUGIN_PRIV (plugin);
2793 
2794     if (!pPrivate->loaded)
2795 	ccsLoadPluginSettings (plugin);
2796 
2797     return pPrivate->stringExtensions;
2798 }
2799 
2800