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