7
* Copyright (c) 2007 Danny Baumann <maniac@opencompositing.org>
9
* Parts of this code are taken from libberylsettings
10
* gconf backend, written by:
12
* Copyright (c) 2006 Robert Carr <racarr@opencompositing.org>
13
* Copyright (c) 2007 Dennis Kasprzyk <onestone@opencompositing.org>
15
* This program is free software; you can redistribute it and/or
16
* modify it under the terms of the GNU General Public License
17
* as published by the Free Software Foundation; either version 2
18
* of the License, or (at your option) any later version.
20
* This program is distributed in the hope that it will be useful,
21
* but WITHOUT ANY WARRANTY; without even the implied warranty of
22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
* GNU General Public License for more details.
27
#define CCS_LOG_DOMAIN "gconf"
38
#include <ccs-backend.h>
43
#include <gconf/gconf.h>
44
#include <gconf/gconf-client.h>
45
#include <gconf/gconf-value.h>
47
#include "ccs_gnome_integration.h"
48
#include "ccs_gnome_integration_gconf_integrated_setting_factory.h"
50
#define COMPIZ "/apps/compiz-1"
51
#define COMPIZCONFIG "/apps/compizconfig-1"
52
#define PROFILEPATH COMPIZCONFIG "/profiles"
53
#define DEFAULTPROF "Default"
54
#define CORE_NAME "core"
58
#define KEYNAME(sn) char keyName[BUFSIZE]; \
59
snprintf (keyName, BUFSIZE, "screen%i", sn);
61
#define PATHNAME char pathName[BUFSIZE]; \
62
if (!ccsPluginGetName (ccsSettingGetParent (setting)) || \
63
strcmp (ccsPluginGetName (ccsSettingGetParent (setting)), "core") == 0) \
64
snprintf (pathName, BUFSIZE, \
65
"%s/general/%s/options/%s", COMPIZ, \
66
keyName, ccsSettingGetName (setting)); \
68
snprintf(pathName, BUFSIZE, \
69
"%s/plugins/%s/%s/options/%s", COMPIZ, \
70
ccsPluginGetName (ccsSettingGetParent (setting)), keyName, ccsSettingGetName (setting));
72
static GConfClient *client = NULL;
73
static GConfEngine *conf = NULL;
74
static guint compizNotifyId;
75
static char *currentProfile = NULL;
76
static CCSGNOMEValueChangeData valueChangeData =
84
/* some forward declarations */
85
static Bool readInit (CCSBackend *backend, CCSContext * context);
86
static void readSetting (CCSBackend *backend, CCSContext * context, CCSSetting * setting);
87
static Bool readOption (CCSSetting * setting);
88
static Bool writeInit (CCSBackend *backend, CCSContext * context);
89
static void writeIntegratedOption (CCSContext *context, CCSSetting *setting, CCSIntegratedSetting *integrated);
92
isIntegratedOption (CCSSetting *setting,
93
CCSIntegratedSetting **integrated)
95
CCSPlugin *plugin = ccsSettingGetParent (setting);
96
const char *pluginName = ccsPluginGetName (plugin);
97
const char *settingName = ccsSettingGetName (setting);
98
CCSIntegratedSetting *tmp = ccsIntegrationGetIntegratedSetting (valueChangeData.integration, pluginName, settingName);
107
updateSetting (CCSBackend *backend, CCSContext *context, CCSPlugin *plugin, CCSSetting *setting)
109
CCSIntegratedSetting *integrated;
110
readInit (backend, context);
111
if (!readOption (setting))
112
ccsResetToDefault (setting, TRUE);
114
if (ccsGetIntegrationEnabled (context) &&
115
isIntegratedOption (setting, &integrated))
117
writeInit (backend, context);
118
writeIntegratedOption (context, setting, integrated);
123
valueChanged (GConfClient *client,
128
CCSContext *context = (CCSContext *)user_data;
129
char *keyName = (char*) gconf_entry_get_key (entry);
132
unsigned int screenNum;
136
keyName += strlen (COMPIZ) + 1;
138
token = strsep (&keyName, "/"); /* plugin */
142
if (strcmp (token, "general") == 0)
148
token = strsep (&keyName, "/");
154
plugin = ccsFindPlugin (context, pluginName);
158
token = strsep (&keyName, "/");
162
sscanf (token, "screen%d", &screenNum);
164
token = strsep (&keyName, "/"); /* 'options' */
168
token = strsep (&keyName, "/");
172
setting = ccsFindSetting (plugin, token);
176
/* Passing null here is not optimal, but we are not
177
* maintaining gconf actively here */
178
updateSetting (NULL, context, plugin, setting);
182
initClient (CCSBackend *backend, CCSContext *context)
184
client = gconf_client_get_for_engine (conf);
186
valueChangeData.context = context;
187
valueChangeData.storage = ccsIntegratedSettingsStorageDefaultImplNew (&ccsDefaultObjectAllocator);
188
valueChangeData.factory = ccsGConfIntegratedSettingFactoryNew (client, &valueChangeData, &ccsDefaultObjectAllocator);
190
valueChangeData.integration = ccsGNOMEIntegrationBackendNew (backend,
192
valueChangeData.factory,
193
valueChangeData.storage,
194
&ccsDefaultObjectAllocator);
196
compizNotifyId = gconf_client_notify_add (client, COMPIZ, valueChanged,
197
context, NULL, NULL);
198
gconf_client_add_dir (client, COMPIZ, GCONF_CLIENT_PRELOAD_NONE, NULL);
204
ccsIntegrationUnref (valueChangeData.integration);
208
gconf_client_notify_remove (client, compizNotifyId);
211
gconf_client_remove_dir (client, COMPIZ, NULL);
212
gconf_client_suggest_sync (client, NULL);
214
g_object_unref (client);
217
memset (&valueChangeData, 0, sizeof (CCSGNOMEValueChangeData));
221
copyGconfValues (GConfEngine *conf,
225
const gchar *schemaPath)
227
GSList *values, *tmp;
230
values = gconf_engine_all_entries (conf, from, &err);
235
GConfEntry *entry = tmp->data;
236
const char *key = gconf_entry_get_key (entry);
237
char *name, *newKey, *newSchema = NULL;
239
name = strrchr (key, '/');
247
if (asprintf (&newKey, "%s/%s", to, name + 1) == -1)
250
if (associate && schemaPath)
251
if (asprintf (&newSchema, "%s/%s", schemaPath, name + 1) == -1)
254
if (newKey && newSchema)
255
gconf_engine_associate_schema (conf, newKey, newSchema, NULL);
259
value = gconf_engine_get_without_default (conf, key, NULL);
262
gconf_engine_set (conf, newKey, value, NULL);
263
gconf_value_free (value);
275
gconf_engine_associate_schema (conf, key, NULL, NULL);
276
gconf_engine_unset (conf, key, NULL);
279
gconf_entry_unref (entry);
280
tmp = g_slist_next (tmp);
284
g_slist_free (values);
288
copyGconfRecursively (GConfEngine *conf,
292
const gchar *schemaPath)
300
gchar *path = tmp->data;
301
char *newKey, *newSchema = NULL, *name;
303
name = strrchr (path, '/');
306
if (!(to && asprintf (&newKey, "%s/%s", to, name + 1) != -1))
309
if (associate && schemaPath)
310
if (asprintf (&newSchema, "%s/%s", schemaPath, name + 1) == -1)
313
copyGconfValues (conf, path, newKey, associate, newSchema);
314
copyGconfRecursively (conf,
315
gconf_engine_all_dirs (conf, path, NULL),
316
newKey, associate, newSchema);
325
gconf_engine_remove_dir (conf, path, NULL);
329
tmp = g_slist_next (tmp);
333
g_slist_free (subdirs);
337
copyGconfTree (CCSBackend *backend,
342
const gchar *schemaPath)
346
/* we aren't allowed to have an open GConfClient object while
347
using GConfEngine, so shut it down and open it again afterwards */
350
subdirs = gconf_engine_all_dirs (conf, from, NULL);
351
gconf_engine_suggest_sync (conf, NULL);
353
copyGconfRecursively (conf, subdirs, to, associate, schemaPath);
355
gconf_engine_suggest_sync (conf, NULL);
357
initClient (backend, context);
361
readListValue (CCSSetting *setting,
362
GConfValue *gconfValue)
364
GConfValueType valueType;
365
unsigned int nItems, i = 0;
366
CCSSettingValueList list = NULL;
367
GSList *valueList = NULL;
369
switch (ccsSettingGetInfo (setting)->forList.listType)
374
valueType = GCONF_VALUE_STRING;
377
valueType = GCONF_VALUE_BOOL;
380
valueType = GCONF_VALUE_INT;
383
valueType = GCONF_VALUE_FLOAT;
386
valueType = GCONF_VALUE_INVALID;
390
if (valueType == GCONF_VALUE_INVALID)
393
if (valueType != gconf_value_get_list_type (gconfValue))
396
valueList = gconf_value_get_list (gconfValue);
399
ccsSetList (setting, NULL, TRUE);
403
nItems = g_slist_length (valueList);
405
switch (ccsSettingGetInfo (setting)->forList.listType)
409
Bool *array = malloc (nItems * sizeof (Bool));
413
for (; valueList; valueList = valueList->next, ++i)
415
gconf_value_get_bool (valueList->data) ? TRUE : FALSE;
416
list = ccsGetValueListFromBoolArray (array, nItems, setting);
422
int *array = malloc (nItems * sizeof (int));
426
for (; valueList; valueList = valueList->next, ++i)
427
array[i] = gconf_value_get_int (valueList->data);
428
list = ccsGetValueListFromIntArray (array, nItems, setting);
434
float *array = malloc (nItems * sizeof (float));
438
for (; valueList; valueList = valueList->next, ++i)
439
array[i] = gconf_value_get_float (valueList->data);
440
list = ccsGetValueListFromFloatArray (array, nItems, setting);
447
gchar **array = malloc ((nItems + 1) * sizeof (char*));
451
for (; valueList; valueList = valueList->next, ++i)
452
array[i] = strdup (gconf_value_get_string (valueList->data));
454
array[nItems] = NULL;
456
list = ccsGetValueListFromStringArray ((const char **) array, nItems, setting);
462
CCSSettingColorValue *array;
463
array = malloc (nItems * sizeof (CCSSettingColorValue));
467
for (; valueList; valueList = valueList->next, ++i)
469
memset (&array[i], 0, sizeof (CCSSettingColorValue));
470
ccsStringToColor (gconf_value_get_string (valueList->data),
473
list = ccsGetValueListFromColorArray (array, nItems, setting);
483
ccsSetList (setting, list, TRUE);
484
ccsSettingValueListFree (list, TRUE);
493
readIntegratedOption (CCSContext *context,
495
CCSIntegratedSetting *integrated)
497
return ccsIntegrationReadOptionIntoSetting (valueChangeData.integration, context, setting, integrated);
501
readOption (CCSSetting * setting)
503
GConfValue *gconfValue = NULL;
508
KEYNAME (ccsContextGetScreenNum (ccsPluginGetContext (ccsSettingGetParent (setting))));
511
/* first check if the key is set */
512
gconfValue = gconf_client_get_without_default (client, pathName, &err);
519
/* value is not set */
522
/* setting type sanity check */
523
switch (ccsSettingGetType (setting))
531
valid = (gconfValue->type == GCONF_VALUE_STRING);
534
valid = (gconfValue->type == GCONF_VALUE_INT);
538
valid = (gconfValue->type == GCONF_VALUE_BOOL);
541
valid = (gconfValue->type == GCONF_VALUE_FLOAT);
544
valid = (gconfValue->type == GCONF_VALUE_LIST);
551
ccsWarning ("There is an unsupported value at path %s. "
552
"Settings from this path won't be read. Try to remove "
553
"that value so that operation can continue properly.",
558
switch (ccsSettingGetType (setting))
563
value = gconf_value_get_string (gconfValue);
566
ccsSetString (setting, value, TRUE);
574
value = gconf_value_get_string (gconfValue);
577
ccsSetMatch (setting, value, TRUE);
585
value = gconf_value_get_int (gconfValue);
587
ccsSetInt (setting, value, TRUE);
594
value = gconf_value_get_bool (gconfValue);
596
ccsSetBool (setting, value ? TRUE : FALSE, TRUE);
603
value = gconf_value_get_float (gconfValue);
605
ccsSetFloat (setting, (float)value, TRUE);
612
CCSSettingColorValue color;
613
value = gconf_value_get_string (gconfValue);
615
if (value && ccsStringToColor (value, &color))
617
ccsSetColor (setting, color, TRUE);
625
CCSSettingKeyValue key;
626
value = gconf_value_get_string (gconfValue);
628
if (value && ccsStringToKeyBinding (value, &key))
630
ccsSetKey (setting, key, TRUE);
638
CCSSettingButtonValue button;
639
value = gconf_value_get_string (gconfValue);
641
if (value && ccsStringToButtonBinding (value, &button))
643
ccsSetButton (setting, button, TRUE);
651
value = gconf_value_get_string (gconfValue);
656
edges = ccsStringToEdges (value);
657
ccsSetEdge (setting, edges, TRUE);
665
value = gconf_value_get_bool (gconfValue);
667
ccsSetBell (setting, value ? TRUE : FALSE, TRUE);
672
ret = readListValue (setting, gconfValue);
675
ccsWarning ("Attempt to read unsupported setting type %d from path %s!",
676
ccsSettingGetType (setting), pathName);
681
gconf_value_free (gconfValue);
687
writeListValue (CCSSetting *setting,
690
GSList *valueList = NULL;
691
GConfValueType valueType;
692
Bool freeItems = FALSE;
693
CCSSettingValueList list;
696
if (!ccsGetList (setting, &list))
699
switch (ccsSettingGetInfo (setting)->forList.listType)
705
data = GINT_TO_POINTER (list->data->value.asBool);
706
valueList = g_slist_append (valueList, data);
709
valueType = GCONF_VALUE_BOOL;
716
data = GINT_TO_POINTER (list->data->value.asInt);
717
valueList = g_slist_append(valueList, data);
720
valueType = GCONF_VALUE_INT;
728
item = malloc (sizeof (gdouble));
731
*item = list->data->value.asFloat;
732
valueList = g_slist_append (valueList, item);
737
valueType = GCONF_VALUE_FLOAT;
744
valueList = g_slist_append(valueList,
745
list->data->value.asString);
748
valueType = GCONF_VALUE_STRING;
755
valueList = g_slist_append(valueList,
756
list->data->value.asMatch);
759
valueType = GCONF_VALUE_STRING;
767
item = ccsColorToString (&list->data->value.asColor);
768
valueList = g_slist_append (valueList, item);
772
valueType = GCONF_VALUE_STRING;
776
ccsWarning ("Attempt to write unsupported list type %d at path %s!",
777
ccsSettingGetInfo (setting)->forList.listType, pathName);
778
valueType = GCONF_VALUE_INVALID;
782
if (valueType != GCONF_VALUE_INVALID)
784
gconf_client_set_list (client, pathName, valueType, valueList, NULL);
788
GSList *tmpList = valueList;
789
for (; tmpList; tmpList = tmpList->next)
791
free (tmpList->data);
795
g_slist_free (valueList);
799
writeIntegratedOption (CCSContext *context,
801
CCSIntegratedSetting *integrated)
803
ccsIntegrationWriteSettingIntoOption (valueChangeData.integration, context, setting, integrated);
807
resetOptionToDefault (CCSSetting * setting)
809
KEYNAME (ccsContextGetScreenNum (ccsPluginGetContext (ccsSettingGetParent (setting))));
812
gconf_client_recursive_unset (client, pathName, 0, NULL);
813
gconf_client_suggest_sync (client, NULL);
817
writeOption (CCSSetting * setting)
819
KEYNAME (ccsContextGetScreenNum (ccsPluginGetContext (ccsSettingGetParent (setting))));
822
switch (ccsSettingGetType (setting))
827
if (ccsGetString (setting, &value))
828
gconf_client_set_string (client, pathName, value, NULL);
834
if (ccsGetMatch (setting, &value))
835
gconf_client_set_string (client, pathName, value, NULL);
840
if (ccsGetFloat (setting, &value))
841
gconf_client_set_float (client, pathName, value, NULL);
847
if (ccsGetInt (setting, &value))
848
gconf_client_set_int (client, pathName, value, NULL);
854
if (ccsGetBool (setting, &value))
855
gconf_client_set_bool (client, pathName, value, NULL);
860
CCSSettingColorValue value;
863
if (!ccsGetColor (setting, &value))
866
colString = ccsColorToString (&value);
870
gconf_client_set_string (client, pathName, colString, NULL);
876
CCSSettingKeyValue key;
879
if (!ccsGetKey (setting, &key))
882
keyString = ccsKeyBindingToString (&key);
886
gconf_client_set_string (client, pathName, keyString, NULL);
892
CCSSettingButtonValue button;
895
if (!ccsGetButton (setting, &button))
898
buttonString = ccsButtonBindingToString (&button);
902
gconf_client_set_string (client, pathName, buttonString, NULL);
911
if (!ccsGetEdge (setting, &edges))
914
edgeString = ccsEdgesToString (edges);
918
gconf_client_set_string (client, pathName, edgeString, NULL);
925
if (ccsGetBell (setting, &value))
926
gconf_client_set_bool (client, pathName, value, NULL);
930
writeListValue (setting, pathName);
933
ccsWarning ("Attempt to write unsupported setting type %d",
934
ccsSettingGetType (setting));
940
updateCurrentProfileName (char *profile)
945
schema = gconf_schema_new ();
949
value = gconf_value_new (GCONF_VALUE_STRING);
952
gconf_schema_free (schema);
956
gconf_schema_set_type (schema, GCONF_VALUE_STRING);
957
gconf_schema_set_locale (schema, "C");
958
gconf_schema_set_short_desc (schema, "Current profile");
959
gconf_schema_set_long_desc (schema, "Current profile of gconf backend");
960
gconf_schema_set_owner (schema, "compizconfig-1");
961
gconf_value_set_string (value, profile);
962
gconf_schema_set_default_value (schema, value);
964
gconf_client_set_schema (client, COMPIZCONFIG "/current_profile",
967
gconf_schema_free (schema);
968
gconf_value_free (value);
972
getCurrentProfileName (void)
974
GConfSchema *schema = NULL;
976
schema = gconf_client_get_schema (client,
977
COMPIZCONFIG "/current_profile", NULL);
984
value = gconf_schema_get_default_value (schema);
986
ret = strdup (gconf_value_get_string (value));
987
gconf_schema_free (schema);
996
checkProfile (CCSBackend *backend,
999
const char *profileCCS;
1002
lastProfile = currentProfile;
1004
profileCCS = ccsGetProfile (context);
1005
if (!profileCCS || !strlen (profileCCS))
1006
currentProfile = strdup (DEFAULTPROF);
1008
currentProfile = strdup (profileCCS);
1010
if (!lastProfile || strcmp (lastProfile, currentProfile) != 0)
1016
/* copy /apps/compiz-1 tree to profile path */
1017
if (asprintf (&pathName, "%s/%s", PROFILEPATH, lastProfile) == -1)
1022
copyGconfTree (backend,
1023
context, COMPIZ, pathName,
1024
TRUE, "/schemas" COMPIZ);
1029
/* reset /apps/compiz-1 tree */
1030
gconf_client_recursive_unset (client, COMPIZ, 0, NULL);
1032
/* copy new profile tree to /apps/compiz-1 */
1033
if (asprintf (&pathName, "%s/%s", PROFILEPATH, currentProfile) == -1)
1038
copyGconfTree (backend, context, pathName, COMPIZ, FALSE, NULL);
1040
/* delete the new profile tree in /apps/compizconfig-1
1041
to avoid user modification in the wrong tree */
1042
copyGconfTree (backend, context, pathName, NULL, TRUE, NULL);
1046
/* update current profile name */
1047
updateCurrentProfileName (currentProfile);
1057
processEvents (CCSBackend *backend, unsigned int flags)
1059
if (!(flags & ProcessEventsNoGlibMainLoopMask))
1061
while (g_main_context_pending(NULL))
1062
g_main_context_iteration(NULL, FALSE);
1067
initBackend (CCSBackend *backend, CCSContext * context)
1071
conf = gconf_engine_get_default ();
1072
initClient (backend, context);
1074
currentProfile = getCurrentProfileName ();
1080
finiBackend (CCSBackend *backend)
1082
gconf_client_clear_cache (client);
1087
free (currentProfile);
1088
currentProfile = NULL;
1091
gconf_engine_unref (conf);
1098
readInit (CCSBackend *backend, CCSContext * context)
1100
return checkProfile (backend, context);
1104
readSetting (CCSBackend *backend,
1105
CCSContext *context,
1106
CCSSetting *setting)
1109
CCSIntegratedSetting *integrated;
1111
if (ccsGetIntegrationEnabled (context) &&
1112
isIntegratedOption (setting, &integrated))
1114
status = readIntegratedOption (context, setting, integrated);
1117
status = readOption (setting);
1120
ccsResetToDefault (setting, TRUE);
1124
writeInit (CCSBackend *backend, CCSContext * context)
1126
return checkProfile (backend, context);
1130
writeSetting (CCSBackend *backend,
1131
CCSContext *context,
1132
CCSSetting *setting)
1134
CCSIntegratedSetting *integrated;
1136
if (ccsGetIntegrationEnabled (context) &&
1137
isIntegratedOption (setting, &integrated))
1139
writeIntegratedOption (context, setting, integrated);
1141
else if (ccsSettingGetIsDefault (setting))
1143
resetOptionToDefault (setting);
1146
writeOption (setting);
1151
getSettingIsIntegrated (CCSBackend *backend, CCSSetting * setting)
1153
if (!ccsGetIntegrationEnabled (ccsPluginGetContext (ccsSettingGetParent (setting))))
1156
if (!isIntegratedOption (setting, NULL))
1163
getSettingIsReadOnly (CCSBackend *backend, CCSSetting * setting)
1169
static CCSStringList
1170
getExistingProfiles (CCSBackend *backend, CCSContext *context)
1173
CCSStringList ret = NULL;
1176
gconf_client_suggest_sync (client, NULL);
1177
data = gconf_client_all_dirs (client, PROFILEPATH, NULL);
1179
for (tmp = data; tmp; tmp = g_slist_next (tmp))
1181
name = strrchr (tmp->data, '/');
1182
if (name && (strcmp (name + 1, DEFAULTPROF) != 0))
1184
CCSString *str = calloc (1, sizeof (CCSString));
1185
str->value = strdup (name + 1);
1186
ret = ccsStringListAppend (ret, str);
1192
g_slist_free (data);
1194
name = getCurrentProfileName ();
1195
if (name && strcmp (name, DEFAULTPROF) != 0)
1197
CCSString *str = calloc (1, sizeof (CCSString));
1199
ret = ccsStringListAppend (ret, str);
1208
deleteProfile (CCSBackend *backend,
1209
CCSContext *context,
1213
gboolean status = FALSE;
1215
checkProfile (backend, context);
1217
snprintf (path, BUFSIZE, "%s/%s", PROFILEPATH, profile);
1219
if (gconf_client_dir_exists (client, path, NULL))
1222
gconf_client_recursive_unset (client, path,
1223
GCONF_UNSET_INCLUDING_SCHEMA_NAMES,
1225
gconf_client_suggest_sync (client, NULL);
1231
const CCSBackendInfo gconfBackendInfo =
1234
"GConf Configuration Backend",
1235
"GConf Configuration Backend for libccs",
1241
static const CCSBackendInfo *
1242
getInfo (CCSBackend *backend)
1244
return &gconfBackendInfo;
1247
static CCSBackendInterface gconfVTable = {
1259
getSettingIsIntegrated,
1260
getSettingIsReadOnly,
1261
getExistingProfiles,
1265
CCSBackendInterface *
1266
getBackendInfo (void)
1268
return &gconfVTable;