diff options
-rw-r--r-- | CMakeLists.txt | 23 | ||||
-rw-r--r-- | org.freedesktop.compizconfig.gschema.xml | 22 | ||||
-rw-r--r-- | src/gconf-integration.c (renamed from src/gconf.c) | 1268 | ||||
-rw-r--r-- | src/gsettings.c | 1251 | ||||
-rw-r--r-- | src/gsettings.h | 152 |
5 files changed, 1501 insertions, 1215 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index caee4b8..f372d38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,26 @@ -project (compizconfig-backend-gconf) +project (compizconfig-backend-gsettings) find_package (CompizConfig REQUIRED) include (LibCompizConfigCommon) +include (CompizGSettings) -compizconfig_backend (gconf PKGDEPS glib-2.0 gconf-2.0) +set (_deps glib-2.0>=2.20.0 + gio-2.0>=2.25.0) -compiz_print_configure_header ("CompizConfig GConf Storage Backend") +option (USE_GCONF "Enable legacy GNOME 2.x option integration with GConf" ON) + +if (USE_GCONF) + list (APPEND _deps gconf-2.0>=2.31.1) + + add_definitions (-DUSE_GCONF) +endif (USE_GCONF) + +compizconfig_backend (gsettings PKGDEPS ${_deps}) + +compiz_install_gsettings_schema (${CMAKE_SOURCE_DIR}/org.freedesktop.compizconfig.gschema.xml + ${CMAKE_INSTALL_PREFIX}/share/glib-2.0/schemas) + +compiz_print_configure_header ("CompizConfig GSettings Storage Backend") compiz_print_configure_footer () -compiz_package_generation ("CompizConfig GConf Storage Backend") +compiz_package_generation ("CompizConfig GSettings Storage Backend") diff --git a/org.freedesktop.compizconfig.gschema.xml b/org.freedesktop.compizconfig.gschema.xml new file mode 100644 index 0000000..ac3701f --- /dev/null +++ b/org.freedesktop.compizconfig.gschema.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<schemalist> + <schema id="org.freedesktop.compizconfig" path="/org/freedesktop/compizconfig/" gettext-domain="compiz"> + <key type="s" name="current-profile"> + <default>'Default'</default> + <summary>Current Profile</summary> + <description>Describes the current profile</description> + </key> + <key type="as" name="existing-profiles"> + <default>['Default']</default> + <summary>Existing Profiles</summary> + <description>Profiles available for the GSettings backend to use</description> + </key> + </schema> + <schema id="org.freedesktop.compizconfig.profile" gettext-domain="compiz"> + <key type="as" name="plugins-with-set-keys"> + <default>[]</default> + <summary>Plugins with set keys</summary> + <description>Plugins which have set keys</description> + </key> + </schema> +</schemalist> diff --git a/src/gconf.c b/src/gconf-integration.c index 342e3b1..067e28d 100644 --- a/src/gconf.c +++ b/src/gconf-integration.c @@ -1,8 +1,12 @@ /** * - * GConf libccs backend + * GSettings libccs backend * - * gconf.c + * gconf-integration.c + * + * Copyright (c) 2011 Canonical Ltd + * + * Based on the original compizconfig-backend-gconf * * Copyright (c) 2007 Danny Baumann <maniac@opencompositing.org> * @@ -22,95 +26,17 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * + * Authored By: + * Sam Spilsbury <sam.spilsbury@canonical.com> + * **/ -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <malloc.h> -#include <string.h> -#include <dirent.h> - -#include <ccs.h> -#include <ccs-backend.h> - -#include <X11/X.h> -#include <X11/Xlib.h> - -#include <gconf/gconf.h> -#include <gconf/gconf-client.h> -#include <gconf/gconf-value.h> - -#define CompAltMask (1 << 16) -#define CompMetaMask (1 << 17) -#define CompSuperMask (1 << 18) -#define CompHyperMask (1 << 19) -#define CompModeSwitchMask (1 << 20) -#define CompNumLockMask (1 << 21) -#define CompScrollLockMask (1 << 22) - -#define METACITY "/apps/metacity" -#define COMPIZ "/apps/compiz-1" -#define COMPIZCONFIG "/apps/compizconfig-1" -#define PROFILEPATH COMPIZCONFIG "/profiles" -#define DEFAULTPROF "Default" -#define CORE_NAME "core" - -#define BUFSIZE 512 - -#define KEYNAME(sn) char keyName[BUFSIZE]; \ - snprintf (keyName, BUFSIZE, "screen%i", sn); - -#define PATHNAME char pathName[BUFSIZE]; \ - if (!setting->parent->name || \ - strcmp (setting->parent->name, "core") == 0) \ - snprintf (pathName, BUFSIZE, \ - "%s/general/%s/options/%s", COMPIZ, \ - keyName, setting->name); \ - else \ - snprintf(pathName, BUFSIZE, \ - "%s/plugins/%s/%s/options/%s", COMPIZ, \ - setting->parent->name, keyName, setting->name); - -static const char* watchedGnomeDirectories[] = { - METACITY, - "/desktop/gnome/applications/terminal", - "/apps/panel/applets/window_list/prefs" -}; -#define NUM_WATCHED_DIRS 3 - -static GConfClient *client = NULL; -static GConfEngine *conf = NULL; -static guint compizNotifyId; -static guint gnomeNotifyIds[NUM_WATCHED_DIRS]; -static char *currentProfile = NULL; - -/* some forward declarations */ -static Bool readInit (CCSContext * context); -static void readSetting (CCSContext * context, CCSSetting * setting); -static Bool readOption (CCSSetting * setting); -static Bool writeInit (CCSContext * context); -static void writeIntegratedOption (CCSContext *context, CCSSetting *setting, - int index); - -typedef enum { - OptionInt, - OptionBool, - OptionKey, - OptionString, - OptionSpecial, -} SpecialOptionType; - -typedef struct _SpecialOption { - const char* settingName; - const char* pluginName; - Bool screen; - const char* gnomeName; - SpecialOptionType type; -} SpecialOption; - -const SpecialOption specialOptions[] = { +#include "gsettings.h" +#ifdef USE_GCONF +GConfClient *client = NULL; +guint gnomeGConfNotifyIds[NUM_WATCHED_DIRS]; + +const SpecialOptionGConf specialOptions[] = { {"run_key", "gnomecompat", FALSE, METACITY "/global_keybindings/panel_run_dialog", OptionKey}, {"main_menu_key", "gnomecompat", FALSE, @@ -376,7 +302,13 @@ const SpecialOption specialOptions[] = { METACITY "/general/num_workspaces", OptionInt},*/ }; -#define N_SOPTIONS (sizeof (specialOptions) / sizeof (struct _SpecialOption)) +static const char* watchedGConfGnomeDirectories[] = { + METACITY, + "/desktop/gnome/applications/terminal", + "/apps/panel/applets/window_list/prefs" +}; + +#define N_SOPTIONS (sizeof (specialOptions) / sizeof (struct _SpecialOptionGConf)) static CCSSetting * findDisplaySettingForPlugin (CCSContext *context, @@ -397,15 +329,15 @@ findDisplaySettingForPlugin (CCSContext *context, return s; } -static Bool -isIntegratedOption (CCSSetting *setting, - int *index) +Bool +isGConfIntegratedOption (CCSSetting *setting, + int *index) { unsigned int i; for (i = 0; i < N_SOPTIONS; i++) { - const SpecialOption *opt = &specialOptions[i]; + const SpecialOptionGConf *opt = &specialOptions[i]; if (strcmp (setting->name, opt->settingName) != 0) continue; @@ -432,80 +364,11 @@ isIntegratedOption (CCSSetting *setting, return FALSE; } -static void -valueChanged (GConfClient *client, - guint cnxn_id, - GConfEntry *entry, - gpointer user_data) -{ - CCSContext *context = (CCSContext *)user_data; - char *keyName = (char*) gconf_entry_get_key (entry); - char *pluginName; - char *token; - int index; - Bool isScreen; - unsigned int screenNum; - CCSPlugin *plugin; - CCSSetting *setting; - - keyName += strlen (COMPIZ) + 1; - - token = strsep (&keyName, "/"); /* plugin */ - if (!token) - return; - - if (strcmp (token, "general") == 0) - { - pluginName = "core"; - } - else - { - token = strsep (&keyName, "/"); - if (!token) - return; - pluginName = token; - } - - plugin = ccsFindPlugin (context, pluginName); - if (!plugin) - return; - - token = strsep (&keyName, "/"); - if (!token) - return; - - isScreen = TRUE; - sscanf (token, "screen%d", &screenNum); - - token = strsep (&keyName, "/"); /* 'options' */ - if (!token) - return; - - token = strsep (&keyName, "/"); - if (!token) - return; - - setting = ccsFindSetting (plugin, token); - if (!setting) - return; - - readInit (context); - if (!readOption (setting)) - ccsResetToDefault (setting); - - if (ccsGetIntegrationEnabled (context) && - isIntegratedOption (setting, &index)) - { - writeInit (context); - writeIntegratedOption (context, setting, index); - } -} - -static void -gnomeValueChanged (GConfClient *client, - guint cnxn_id, - GConfEntry *entry, - gpointer user_data) +void +gnomeGConfValueChanged (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data) { CCSContext *context = (CCSContext *)user_data; char *keyName = (char*) gconf_entry_get_key (entry); @@ -565,17 +428,13 @@ gnomeValueChanged (GConfClient *client, { CCSPlugin *plugin = NULL; CCSSetting *setting; - SpecialOption *opt = (SpecialOption *) &specialOptions[num]; + SpecialOptionGConf *opt = (SpecialOptionGConf *) &specialOptions[num]; plugin = ccsFindPlugin (context, (char*) opt->pluginName); if (plugin) { for (i = 0; i < 1; i++) { - unsigned int screen; - - screen = 0; - setting = ccsFindSetting (plugin, (char*) opt->settingName); if (setting) @@ -596,324 +455,44 @@ gnomeValueChanged (GConfClient *client, } } -static void -initClient (CCSContext *context) +void +initGConfClient (CCSContext *context) { int i; - client = gconf_client_get_for_engine (conf); - - compizNotifyId = gconf_client_notify_add (client, COMPIZ, valueChanged, - context, NULL, NULL); - gconf_client_add_dir (client, COMPIZ, GCONF_CLIENT_PRELOAD_NONE, NULL); + client = gconf_client_get_default (); for (i = 0; i < NUM_WATCHED_DIRS; i++) { - gnomeNotifyIds[i] = gconf_client_notify_add (client, - watchedGnomeDirectories[i], - gnomeValueChanged, context, + gnomeGConfNotifyIds[i] = gconf_client_notify_add (client, + watchedGConfGnomeDirectories[i], + gnomeGConfValueChanged, context, NULL, NULL); - gconf_client_add_dir (client, watchedGnomeDirectories[i], + gconf_client_add_dir (client, watchedGConfGnomeDirectories[i], GCONF_CLIENT_PRELOAD_NONE, NULL); } } -static void -finiClient (void) +void +finiGConfClient (void) { int i; - if (compizNotifyId) - { - gconf_client_notify_remove (client, compizNotifyId); - compizNotifyId = 0; - } - gconf_client_remove_dir (client, COMPIZ, NULL); - for (i = 0; i < NUM_WATCHED_DIRS; i++) { - if (gnomeNotifyIds[i]) + if (gnomeGConfNotifyIds[i]) { - gconf_client_notify_remove (client, gnomeNotifyIds[0]); - gnomeNotifyIds[i] = 0; + gconf_client_notify_remove (client, gnomeGConfNotifyIds[0]); + gnomeGConfNotifyIds[i] = 0; } - gconf_client_remove_dir (client, watchedGnomeDirectories[i], NULL); + gconf_client_remove_dir (client, watchedGConfGnomeDirectories[i], NULL); } - gconf_client_suggest_sync (client, NULL); g_object_unref (client); client = NULL; } -static void -copyGconfValues (GConfEngine *conf, - const gchar *from, - const gchar *to, - Bool associate, - const gchar *schemaPath) -{ - GSList *values, *tmp; - GError *err = NULL; - - values = gconf_engine_all_entries (conf, from, &err); - tmp = values; - - while (tmp) - { - GConfEntry *entry = tmp->data; - GConfValue *value; - const char *key = gconf_entry_get_key (entry); - char *name, *newKey, *newSchema = NULL; - - name = strrchr (key, '/'); - if (!name) - continue; - - if (to) - { - asprintf (&newKey, "%s/%s", to, name + 1); - - if (associate && schemaPath) - asprintf (&newSchema, "%s/%s", schemaPath, name + 1); - - if (newKey && newSchema) - gconf_engine_associate_schema (conf, newKey, newSchema, NULL); - - if (newKey) - { - value = gconf_engine_get_without_default (conf, key, NULL); - if (value) - { - gconf_engine_set (conf, newKey, value, NULL); - gconf_value_free (value); - } - } - - if (newSchema) - free (newSchema); - if (newKey) - free (newKey); - } - else - { - if (associate) - gconf_engine_associate_schema (conf, key, NULL, NULL); - gconf_engine_unset (conf, key, NULL); - } - - gconf_entry_unref (entry); - tmp = g_slist_next (tmp); - } - - if (values) - g_slist_free (values); -} - -static void -copyGconfRecursively (GConfEngine *conf, - GSList *subdirs, - const gchar *to, - Bool associate, - const gchar *schemaPath) -{ - GSList* tmp; - - tmp = subdirs; - - while (tmp) - { - gchar *path = tmp->data; - char *newKey, *newSchema = NULL, *name; - - name = strrchr (path, '/'); - if (name) - { - if (to) - asprintf (&newKey, "%s/%s", to, name + 1); - else - newKey = NULL; - - if (associate && schemaPath) - asprintf (&newSchema, "%s/%s", schemaPath, name + 1); - - copyGconfValues (conf, path, newKey, associate, newSchema); - copyGconfRecursively (conf, - gconf_engine_all_dirs (conf, path, NULL), - newKey, associate, newSchema); - - if (newSchema) - free (newSchema); - - if (newKey) - free (newKey); - - if (!to) - gconf_engine_remove_dir (conf, path, NULL); - } - - g_free (path); - tmp = g_slist_next (tmp); - } - - if (subdirs) - g_slist_free (subdirs); -} - -static void -copyGconfTree (CCSContext *context, - const gchar *from, - const gchar *to, - Bool associate, - const gchar *schemaPath) -{ - GSList* subdirs; - - /* we aren't allowed to have an open GConfClient object while - using GConfEngine, so shut it down and open it again afterwards */ - finiClient (); - - subdirs = gconf_engine_all_dirs (conf, from, NULL); - gconf_engine_suggest_sync (conf, NULL); - - copyGconfRecursively (conf, subdirs, to, associate, schemaPath); - - gconf_engine_suggest_sync (conf, NULL); - - initClient (context); -} - -static Bool -readListValue (CCSSetting *setting, - GConfValue *gconfValue) -{ - GConfValueType valueType; - unsigned int nItems, i = 0; - CCSSettingValueList list = NULL; - GSList *valueList = NULL; - - switch (setting->info.forList.listType) - { - case TypeString: - case TypeMatch: - case TypeColor: - valueType = GCONF_VALUE_STRING; - break; - case TypeBool: - valueType = GCONF_VALUE_BOOL; - break; - case TypeInt: - valueType = GCONF_VALUE_INT; - break; - case TypeFloat: - valueType = GCONF_VALUE_FLOAT; - break; - default: - valueType = GCONF_VALUE_INVALID; - break; - } - - if (valueType == GCONF_VALUE_INVALID) - return FALSE; - - if (valueType != gconf_value_get_list_type (gconfValue)) - return FALSE; - - valueList = gconf_value_get_list (gconfValue); - if (!valueList) - { - ccsSetList (setting, NULL); - return TRUE; - } - - nItems = g_slist_length (valueList); - - switch (setting->info.forList.listType) - { - case TypeBool: - { - Bool *array = malloc (nItems * sizeof (Bool)); - if (!array) - break; - - for (; valueList; valueList = valueList->next, i++) - array[i] = - gconf_value_get_bool (valueList->data) ? TRUE : FALSE; - list = ccsGetValueListFromBoolArray (array, nItems, setting); - free (array); - } - break; - case TypeInt: - { - int *array = malloc (nItems * sizeof (int)); - if (!array) - break; - - for (; valueList; valueList = valueList->next, i++) - array[i] = gconf_value_get_int (valueList->data); - list = ccsGetValueListFromIntArray (array, nItems, setting); - free (array); - } - break; - case TypeFloat: - { - float *array = malloc (nItems * sizeof (float)); - if (!array) - break; - - for (; valueList; valueList = valueList->next, i++) - array[i] = gconf_value_get_float (valueList->data); - list = ccsGetValueListFromFloatArray (array, nItems, setting); - free (array); - } - break; - case TypeString: - case TypeMatch: - { - char **array = malloc (nItems * sizeof (char*)); - if (!array) - break; - - for (; valueList; valueList = valueList->next, i++) - array[i] = strdup (gconf_value_get_string (valueList->data)); - list = ccsGetValueListFromStringArray (array, nItems, setting); - for (i = 0; i < nItems; i++) - if (array[i]) - free (array[i]); - free (array); - } - break; - case TypeColor: - { - CCSSettingColorValue *array; - array = malloc (nItems * sizeof (CCSSettingColorValue)); - if (!array) - break; - - for (; valueList; valueList = valueList->next, i++) - { - memset (&array[i], 0, sizeof (CCSSettingColorValue)); - ccsStringToColor (gconf_value_get_string (valueList->data), - &array[i]); - } - list = ccsGetValueListFromColorArray (array, nItems, setting); - free (array); - } - break; - default: - break; - } - - if (list) - { - ccsSetList (setting, list); - ccsSettingValueListFree (list, TRUE); - return TRUE; - } - - return FALSE; -} - static unsigned int getGnomeMouseButtonModifier(void) { @@ -957,15 +536,16 @@ getButtonBindingForSetting (CCSContext *context, return s->value->value.asButton.button; } - -static Bool -readIntegratedOption (CCSContext *context, - CCSSetting *setting, - int index) +Bool +readGConfIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index) { GConfValue *gconfValue; GError *err = NULL; Bool ret = FALSE; + + ret = readOption (setting); gconfValue = gconf_client_get (client, specialOptions[index].gnomeName, @@ -1124,304 +704,6 @@ readIntegratedOption (CCSContext *context, } static Bool -readOption (CCSSetting * setting) -{ - GConfValue *gconfValue = NULL; - GError *err = NULL; - Bool ret = FALSE; - Bool valid = TRUE; - - KEYNAME(setting->parent->context->screenNum); - PATHNAME; - - /* first check if the key is set */ - gconfValue = gconf_client_get_without_default (client, pathName, &err); - if (err) - { - g_error_free (err); - return FALSE; - } - if (!gconfValue) - /* value is not set */ - return FALSE; - - /* setting type sanity check */ - switch (setting->type) - { - case TypeString: - case TypeMatch: - case TypeColor: - case TypeKey: - case TypeButton: - case TypeEdge: - valid = (gconfValue->type == GCONF_VALUE_STRING); - break; - case TypeInt: - valid = (gconfValue->type == GCONF_VALUE_INT); - break; - case TypeBool: - case TypeBell: - valid = (gconfValue->type == GCONF_VALUE_BOOL); - break; - case TypeFloat: - valid = (gconfValue->type == GCONF_VALUE_FLOAT); - break; - case TypeList: - valid = (gconfValue->type == GCONF_VALUE_LIST); - break; - default: - break; - } - if (!valid) - { - printf ("GConf backend: There is an unsupported value at path %s. " - "Settings from this path won't be read. Try to remove " - "that value so that operation can continue properly.\n", - pathName); - return FALSE; - } - - switch (setting->type) - { - case TypeString: - { - const char *value; - value = gconf_value_get_string (gconfValue); - if (value) - { - ccsSetString (setting, value); - ret = TRUE; - } - } - break; - case TypeMatch: - { - const char * value; - value = gconf_value_get_string (gconfValue); - if (value) - { - ccsSetMatch (setting, value); - ret = TRUE; - } - } - break; - case TypeInt: - { - int value; - value = gconf_value_get_int (gconfValue); - - ccsSetInt (setting, value); - ret = TRUE; - } - break; - case TypeBool: - { - gboolean value; - value = gconf_value_get_bool (gconfValue); - - ccsSetBool (setting, value ? TRUE : FALSE); - ret = TRUE; - } - break; - case TypeFloat: - { - double value; - value = gconf_value_get_float (gconfValue); - - ccsSetFloat (setting, (float)value); - ret = TRUE; - } - break; - case TypeColor: - { - const char *value; - CCSSettingColorValue color; - value = gconf_value_get_string (gconfValue); - - if (value && ccsStringToColor (value, &color)) - { - ccsSetColor (setting, color); - ret = TRUE; - } - } - break; - case TypeKey: - { - const char *value; - CCSSettingKeyValue key; - value = gconf_value_get_string (gconfValue); - - if (value && ccsStringToKeyBinding (value, &key)) - { - ccsSetKey (setting, key); - ret = TRUE; - } - } - break; - case TypeButton: - { - const char *value; - CCSSettingButtonValue button; - value = gconf_value_get_string (gconfValue); - - if (value && ccsStringToButtonBinding (value, &button)) - { - ccsSetButton (setting, button); - ret = TRUE; - } - } - break; - case TypeEdge: - { - const char *value; - value = gconf_value_get_string (gconfValue); - - if (value) - { - unsigned int edges; - edges = ccsStringToEdges (value); - ccsSetEdge (setting, edges); - ret = TRUE; - } - } - break; - case TypeBell: - { - gboolean value; - value = gconf_value_get_bool (gconfValue); - - ccsSetBell (setting, value ? TRUE : FALSE); - ret = TRUE; - } - break; - case TypeList: - ret = readListValue (setting, gconfValue); - break; - default: - printf("GConf backend: attempt to read unsupported setting type %d from path %s!\n", - setting->type, pathName); - break; - } - - if (gconfValue) - gconf_value_free (gconfValue); - - return ret; -} - -static void -writeListValue (CCSSetting *setting, - char *pathName) -{ - GSList *valueList = NULL; - GConfValueType valueType; - Bool freeItems = FALSE; - CCSSettingValueList list; - gpointer data; - - if (!ccsGetList (setting, &list)) - return; - - switch (setting->info.forList.listType) - { - case TypeBool: - { - while (list) - { - data = GINT_TO_POINTER (list->data->value.asBool); - valueList = g_slist_append (valueList, data); - list = list->next; - } - valueType = GCONF_VALUE_BOOL; - } - break; - case TypeInt: - { - while (list) - { - data = GINT_TO_POINTER (list->data->value.asInt); - valueList = g_slist_append(valueList, data); - list = list->next; - } - valueType = GCONF_VALUE_INT; - } - break; - case TypeFloat: - { - gdouble *item; - while (list) - { - item = malloc (sizeof (gdouble)); - if (item) - { - *item = list->data->value.asFloat; - valueList = g_slist_append (valueList, item); - } - list = list->next; - } - freeItems = TRUE; - valueType = GCONF_VALUE_FLOAT; - } - break; - case TypeString: - { - while (list) - { - valueList = g_slist_append(valueList, - list->data->value.asString); - list = list->next; - } - valueType = GCONF_VALUE_STRING; - } - break; - case TypeMatch: - { - while (list) - { - valueList = g_slist_append(valueList, - list->data->value.asMatch); - list = list->next; - } - valueType = GCONF_VALUE_STRING; - } - break; - case TypeColor: - { - char *item; - while (list) - { - item = ccsColorToString (&list->data->value.asColor); - valueList = g_slist_append (valueList, item); - list = list->next; - } - freeItems = TRUE; - valueType = GCONF_VALUE_STRING; - } - break; - default: - printf("GConf backend: attempt to write unsupported list type %d at path %s!\n", - setting->info.forList.listType, pathName); - valueType = GCONF_VALUE_INVALID; - break; - } - - if (valueType != GCONF_VALUE_INVALID) - { - gconf_client_set_list (client, pathName, valueType, valueList, NULL); - - if (freeItems) - { - GSList *tmpList = valueList; - for (; tmpList; tmpList = tmpList->next) - if (tmpList->data) - free (tmpList->data); - } - } - if (valueList) - g_slist_free (valueList); -} - -static Bool setGnomeMouseButtonModifier (unsigned int modMask) { char *modifiers, *currentValue; @@ -1482,14 +764,14 @@ setButtonBindingForSetting (CCSContext *context, } } -static void -writeIntegratedOption (CCSContext *context, - CCSSetting *setting, - int index) +void +writeGConfIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index) { GError *err = NULL; const char *optionName = specialOptions[index].gnomeName; - + switch (specialOptions[index].type) { case OptionInt: @@ -1669,440 +951,4 @@ writeIntegratedOption (CCSContext *context, if (err) g_error_free (err); } - -static void -resetOptionToDefault (CCSSetting * setting) -{ - KEYNAME (setting->parent->context->screenNum); - PATHNAME; - - gconf_client_recursive_unset (client, pathName, 0, NULL); - gconf_client_suggest_sync (client, NULL); -} - -static void -writeOption (CCSSetting * setting) -{ - KEYNAME (setting->parent->context->screenNum); - PATHNAME; - - switch (setting->type) - { - case TypeString: - { - char *value; - if (ccsGetString (setting, &value)) - gconf_client_set_string (client, pathName, value, NULL); - } - break; - case TypeMatch: - { - char *value; - if (ccsGetMatch (setting, &value)) - gconf_client_set_string (client, pathName, value, NULL); - } - case TypeFloat: - { - float value; - if (ccsGetFloat (setting, &value)) - gconf_client_set_float (client, pathName, value, NULL); - } - break; - case TypeInt: - { - int value; - if (ccsGetInt (setting, &value)) - gconf_client_set_int (client, pathName, value, NULL); - } - break; - case TypeBool: - { - Bool value; - if (ccsGetBool (setting, &value)) - gconf_client_set_bool (client, pathName, value, NULL); - } - break; - case TypeColor: - { - CCSSettingColorValue value; - char *colString; - - if (!ccsGetColor (setting, &value)) - break; - - colString = ccsColorToString (&value); - if (!colString) - break; - - gconf_client_set_string (client, pathName, colString, NULL); - free (colString); - } - break; - case TypeKey: - { - CCSSettingKeyValue key; - char *keyString; - - if (!ccsGetKey (setting, &key)) - break; - - keyString = ccsKeyBindingToString (&key); - if (!keyString) - break; - - gconf_client_set_string (client, pathName, keyString, NULL); - free (keyString); - } - break; - case TypeButton: - { - CCSSettingButtonValue button; - char *buttonString; - - if (!ccsGetButton (setting, &button)) - break; - - buttonString = ccsButtonBindingToString (&button); - if (!buttonString) - break; - - gconf_client_set_string (client, pathName, buttonString, NULL); - free (buttonString); - } - break; - case TypeEdge: - { - unsigned int edges; - char *edgeString; - - if (!ccsGetEdge (setting, &edges)) - break; - - edgeString = ccsEdgesToString (edges); - if (!edgeString) - break; - - gconf_client_set_string (client, pathName, edgeString, NULL); - free (edgeString); - } - break; - case TypeBell: - { - Bool value; - if (ccsGetBell (setting, &value)) - gconf_client_set_bool (client, pathName, value, NULL); - } - break; - case TypeList: - writeListValue (setting, pathName); - break; - default: - printf("GConf backend: attempt to write unsupported setting type %d\n", - setting->type); - break; - } -} - -static void -updateCurrentProfileName (char *profile) -{ - GConfSchema *schema; - GConfValue *value; - - schema = gconf_schema_new (); - if (!schema) - return; - - value = gconf_value_new (GCONF_VALUE_STRING); - if (!value) - { - gconf_schema_free (schema); - return; - } - - gconf_schema_set_type (schema, GCONF_VALUE_STRING); - gconf_schema_set_locale (schema, "C"); - gconf_schema_set_short_desc (schema, "Current profile"); - gconf_schema_set_long_desc (schema, "Current profile of gconf backend"); - gconf_schema_set_owner (schema, "compizconfig-1"); - gconf_value_set_string (value, profile); - gconf_schema_set_default_value (schema, value); - - gconf_client_set_schema (client, COMPIZCONFIG "/current_profile", - schema, NULL); - - gconf_schema_free (schema); - gconf_value_free (value); -} - -static char* -getCurrentProfileName (void) -{ - GConfSchema *schema = NULL; - - schema = gconf_client_get_schema (client, - COMPIZCONFIG "/current_profile", NULL); - - if (schema) - { - GConfValue *value; - char *ret = NULL; - - value = gconf_schema_get_default_value (schema); - if (value) - ret = strdup (gconf_value_get_string (value)); - gconf_schema_free (schema); - - return ret; - } - - return strdup (DEFAULTPROF); -} - -static Bool -checkProfile (CCSContext *context) -{ - char *profile, *lastProfile; - - lastProfile = currentProfile; - - profile = ccsGetProfile (context); - if (!profile || !strlen (profile)) - currentProfile = strdup (DEFAULTPROF); - else - currentProfile = strdup (profile); - - if (!lastProfile || strcmp (lastProfile, currentProfile) != 0) - { - char *pathName; - - if (lastProfile) - { - /* copy /apps/compiz-1 tree to profile path */ - asprintf (&pathName, "%s/%s", PROFILEPATH, lastProfile); - if (pathName) - { - copyGconfTree (context, COMPIZ, pathName, - TRUE, "/schemas" COMPIZ); - free (pathName); - } - } - - /* reset /apps/compiz-1 tree */ - gconf_client_recursive_unset (client, COMPIZ, 0, NULL); - - /* copy new profile tree to /apps/compiz-1 */ - asprintf (&pathName, "%s/%s", PROFILEPATH, currentProfile); - if (pathName) - { - copyGconfTree (context, pathName, COMPIZ, FALSE, NULL); - - /* delete the new profile tree in /apps/compizconfig-1 - to avoid user modification in the wrong tree */ - copyGconfTree (context, pathName, NULL, TRUE, NULL); - free (pathName); - } - - /* update current profile name */ - updateCurrentProfileName (currentProfile); - } - - free (lastProfile); - - return TRUE; -} - -static void -processEvents (unsigned int flags) -{ - if (!(flags & ProcessEventsNoGlibMainLoopMask)) - { - while (g_main_context_pending(NULL)) - g_main_context_iteration(NULL, FALSE); - } -} - -static Bool -initBackend (CCSContext * context) -{ - g_type_init (); - - conf = gconf_engine_get_default (); - initClient (context); - - currentProfile = getCurrentProfileName (); - - return TRUE; -} - -static Bool -finiBackend (CCSContext * context) -{ - processEvents (0); - - gconf_client_clear_cache (client); - finiClient (); - - if (currentProfile) - { - free (currentProfile); - currentProfile = NULL; - } - - gconf_engine_unref (conf); - conf = NULL; - - processEvents (0); - return TRUE; -} - -static Bool -readInit (CCSContext * context) -{ - return checkProfile (context); -} - -static void -readSetting (CCSContext *context, - CCSSetting *setting) -{ - Bool status; - int index; - - if (ccsGetIntegrationEnabled (context) && - isIntegratedOption (setting, &index)) - { - status = readIntegratedOption (context, setting, index); - } - else - status = readOption (setting); - - if (!status) - ccsResetToDefault (setting); -} - -static Bool -writeInit (CCSContext * context) -{ - return checkProfile (context); -} - -static void -writeSetting (CCSContext *context, - CCSSetting *setting) -{ - int index; - - if (ccsGetIntegrationEnabled (context) && - isIntegratedOption (setting, &index)) - { - writeIntegratedOption (context, setting, index); - } - else if (setting->isDefault) - { - resetOptionToDefault (setting); - } - else - writeOption (setting); - -} - -static Bool -getSettingIsIntegrated (CCSSetting * setting) -{ - if (!ccsGetIntegrationEnabled (setting->parent->context)) - return FALSE; - - if (!isIntegratedOption (setting, NULL)) - return FALSE; - - return TRUE; -} - -static Bool -getSettingIsReadOnly (CCSSetting * setting) -{ - /* FIXME */ - return FALSE; -} - -static CCSStringList -getExistingProfiles (CCSContext *context) -{ - GSList *data, *tmp; - CCSStringList ret = NULL; - char *name; - - gconf_client_suggest_sync (client, NULL); - data = gconf_client_all_dirs (client, PROFILEPATH, NULL); - - for (tmp = data; tmp; tmp = g_slist_next (tmp)) - { - name = strrchr (tmp->data, '/'); - if (name && (strcmp (name + 1, DEFAULTPROF) != 0)) - ret = ccsStringListAppend (ret, strdup (name + 1)); - - g_free (tmp->data); - } - - g_slist_free (data); - - name = getCurrentProfileName (); - if (strcmp (name, DEFAULTPROF) != 0) - ret = ccsStringListAppend (ret, name); - else - free (name); - - return ret; -} - -static Bool -deleteProfile (CCSContext *context, - char *profile) -{ - char path[BUFSIZE]; - gboolean status = FALSE; - - checkProfile (context); - - snprintf (path, BUFSIZE, "%s/%s", PROFILEPATH, profile); - - if (gconf_client_dir_exists (client, path, NULL)) - { - status = - gconf_client_recursive_unset (client, path, - GCONF_UNSET_INCLUDING_SCHEMA_NAMES, - NULL); - gconf_client_suggest_sync (client, NULL); - } - - return status; -} - -static CCSBackendVTable gconfVTable = { - "gconf", - "GConf Configuration Backend", - "GConf Configuration Backend for libccs", - TRUE, - TRUE, - processEvents, - initBackend, - finiBackend, - readInit, - readSetting, - 0, - writeInit, - writeSetting, - 0, - getSettingIsIntegrated, - getSettingIsReadOnly, - getExistingProfiles, - deleteProfile -}; - -CCSBackendVTable * -getBackendInfo (void) -{ - return &gconfVTable; -} - +#endif diff --git a/src/gsettings.c b/src/gsettings.c new file mode 100644 index 0000000..0e91bb2 --- /dev/null +++ b/src/gsettings.c @@ -0,0 +1,1251 @@ +/** + * + * GSettings libccs backend + * + * gsettings.c + * + * Copyright (c) 2011 Canonical Ltd + * + * Based on the original compizconfig-backend-gconf + * + * Copyright (c) 2007 Danny Baumann <maniac@opencompositing.org> + * + * Parts of this code are taken from libberylsettings + * gconf backend, written by: + * + * Copyright (c) 2006 Robert Carr <racarr@opencompositing.org> + * Copyright (c) 2007 Dennis Kasprzyk <onestone@opencompositing.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Authored By: + * Sam Spilsbury <sam.spilsbury@canonical.com> + * + **/ + +#include "gsettings.h" + +static void +valueChanged (GSettings *settings, + gchar *keyname, + gpointer user_data); + +static void +gnomeValueChanged (GSettings *settings, + gchar *keyname, + gpointer user_data); + +static GList *settingsList = NULL; +static GSettings *compizconfigSettings = NULL; +static GSettings *currentProfileSettings = NULL; +static GList *watchedGnomeSettings = NULL; + +char *currentProfile = NULL; + +/* some forward declarations */ +static void writeIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index); + +typedef struct _SpecialOptionGSettings { + const char* settingName; + const char* pluginName; + const char* schemaName; + const char* keyName; + const char* type; +} SpecialOption; + +static gchar * +getSchemaNameForPlugin (const char *plugin) +{ + gchar *schemaName = NULL; + + schemaName = g_strconcat (COMPIZ_SCHEMA_ID, ".", plugin, NULL); + + return schemaName; +} + +static inline gchar * +translateKeyForGSettings (char *gsettingName) +{ + gchar *clean = NULL; + gchar **delimited = NULL; + guint i = 0; + + /* Replace underscores with dashes */ + delimited = g_strsplit (gsettingName, "_", 0); + + clean = g_strjoinv ("-", delimited); + + /* It can't be more than 32 chars, warn if that's the case */ + gchar *ret = g_strndup (clean, 31); + + if (strlen (clean) > 31) + printf ("GSettings Backend: Warning: key name %s is not valid in GSettings, it was changed to %s, this may cause problems!\n", clean, ret); + + /* Everything must be lowercase */ + for (; i < strlen (ret); i++) + ret[i] = g_ascii_tolower (ret[i]); + + g_free (clean); + g_strfreev (delimited); + + return ret; +} + +static inline gchar * +translateKeyForCCS (char *gsettingName) +{ + gchar *clean = NULL; + gchar **delimited = NULL; + + /* Replace dashes with underscores */ + delimited = g_strsplit (gsettingName, "-", 0); + + clean = g_strjoinv ("_", delimited); + + /* FIXME: Truncated and lowercased settings aren't going to work */ + + g_strfreev (delimited); + + return clean; +} + +static GSettings * +getSettingsObjectForPluginWithPath (const char *plugin, + const char *path, + CCSContext *context) +{ + GSettings *settingsObj = NULL; + GList *l = settingsList; + gchar *schemaName = getSchemaNameForPlugin (plugin); + GVariant *writtenPlugins; + char *plug; + GVariant *newWrittenPlugins; + GVariantBuilder *newWrittenPluginsBuilder; + GVariantIter *iter; + gboolean found = FALSE; + + while (l) + { + settingsObj = (GSettings *) l->data; + gchar *name = NULL; + + g_object_get (G_OBJECT (settingsObj), + "schema", + &name, NULL); + if (g_strcmp0 (name, schemaName) == 0) + { + g_free (name); + g_free (schemaName); + + return settingsObj; + } + + l = g_list_next (l); + } + + /* No existing settings object found for this schema, create one */ + + settingsObj = g_settings_new_with_path (schemaName, path); + + g_signal_connect (G_OBJECT (settingsObj), "changed", (GCallback) valueChanged, (gpointer) context); + + settingsList = g_list_append (settingsList, (void *) settingsObj); + + /* Also write the plugin name to the list of modified plugins so + * that when we delete the profile the keys for that profile are also + * unset FIXME: This could be a little more efficient, like we could + * store keys that have changed from their defaults ... though + * gsettings doesn't seem to give you a way to get all of the schemas */ + + writtenPlugins = g_settings_get_value (currentProfileSettings, "plugins-with-set-keys"); + + newWrittenPluginsBuilder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + + iter = g_variant_iter_new (writtenPlugins); + while (g_variant_iter_loop (iter, "s", &plug)) + { + g_variant_builder_add (newWrittenPluginsBuilder, "s", plug); + + if (!found) + found = (g_strcmp0 (plug, plugin) == 0); + } + + if (!found) + g_variant_builder_add (newWrittenPluginsBuilder, "s", plugin); + + newWrittenPlugins = g_variant_new ("as", newWrittenPluginsBuilder); + g_settings_set_value (currentProfileSettings, "plugins-with-set-keys", newWrittenPlugins); + + g_variant_iter_free (iter); + g_variant_unref (newWrittenPlugins); + g_variant_builder_unref (newWrittenPluginsBuilder); + + return settingsObj; +} + +static GSettings * +getSettingsObjectForCCSSetting (CCSSetting *setting) +{ + KEYNAME(setting->parent->context->screenNum); + PATHNAME (setting->parent->name, keyName); + + return getSettingsObjectForPluginWithPath (setting->parent->name, pathName, setting->parent->context); +} + +static Bool +isIntegratedOption (CCSSetting *setting, + int *index) +{ +#ifdef USE_GCONF + return isGConfIntegratedOption (setting, index); +#else + return FALSE; +#endif +} + +static void +gnomeValueChanged (GSettings *settings, + gchar *keyName, + gpointer user_data) +{ +} + +static void +valueChanged (GSettings *settings, + gchar *keyName, + gpointer user_data) +{ + CCSContext *context = (CCSContext *)user_data; + char *uncleanKeyName; + char *path; + char *token; + int index; + unsigned int screenNum; + CCSPlugin *plugin; + CCSSetting *setting; + + g_object_get (G_OBJECT (settings), "path", &path, NULL); + + path += strlen (COMPIZ) + 1; + + token = strsep (&path, "/"); /* Profile name */ + if (!token) + return; + + token = strsep (&path, "/"); /* plugins */ + if (!token) + return; + + token = strsep (&path, "/"); /* plugin */ + if (!token) + return; + + plugin = ccsFindPlugin (context, token); + if (!plugin) + return; + + token = strsep (&path, "/"); /* screen%i */ + if (!token) + return; + + sscanf (token, "screen%d", &screenNum); + + uncleanKeyName = translateKeyForCCS (keyName); + + setting = ccsFindSetting (plugin, uncleanKeyName); + if (!setting) + { + printf ("GSettings Backend: unable to find setting %s, for path %s\n", uncleanKeyName, path); + free (uncleanKeyName); + return; + } + + readInit (context); + if (!readOption (setting)) + { + ccsResetToDefault (setting); + } + + if (ccsGetIntegrationEnabled (context) && + isIntegratedOption (setting, &index)) + { + writeInit (context); + writeIntegratedOption (context, setting, index); + } + + free (uncleanKeyName); +} + +static Bool +readListValue (CCSSetting *setting) +{ + GSettings *settings = getSettingsObjectForCCSSetting (setting); + gchar *variantType; + unsigned int nItems, i = 0; + CCSSettingValueList list = NULL; + GVariant *value; + GVariantIter *iter; + + char *cleanSettingName = translateKeyForGSettings (setting->name); + + switch (setting->info.forList.listType) + { + case TypeString: + case TypeMatch: + case TypeColor: + variantType = g_strdup ("s"); + break; + case TypeBool: + variantType = g_strdup ("b"); + break; + case TypeInt: + variantType = g_strdup ("i"); + break; + case TypeFloat: + variantType = g_strdup ("d"); + break; + default: + variantType = NULL; + break; + } + + if (!variantType) + return FALSE; + + value = g_settings_get_value (settings, cleanSettingName); + if (!value) + { + ccsSetList (setting, NULL); + return TRUE; + } + + iter = g_variant_iter_new (value); + nItems = g_variant_iter_n_children (iter); + + switch (setting->info.forList.listType) + { + case TypeBool: + { + Bool *array = malloc (nItems * sizeof (Bool)); + Bool *arrayCounter = array; + + if (!array) + break; + + /* Reads each item from the variant into the position pointed + * at by arrayCounter */ + while (g_variant_iter_loop (iter, variantType, arrayCounter)) + arrayCounter++; + + list = ccsGetValueListFromBoolArray (array, nItems, setting); + free (array); + } + break; + case TypeInt: + { + int *array = malloc (nItems * sizeof (int)); + int *arrayCounter = array; + + if (!array) + break; + + /* Reads each item from the variant into the position pointed + * at by arrayCounter */ + while (g_variant_iter_loop (iter, variantType, arrayCounter)) + arrayCounter++; + + list = ccsGetValueListFromIntArray (array, nItems, setting); + free (array); + } + break; + case TypeFloat: + { + double *array = malloc (nItems * sizeof (double)); + double *arrayCounter = array; + + if (!array) + break; + + /* Reads each item from the variant into the position pointed + * at by arrayCounter */ + while (g_variant_iter_loop (iter, variantType, arrayCounter)) + arrayCounter++; + + list = ccsGetValueListFromFloatArray ((float *) array, nItems, setting); + free (array); + } + break; + case TypeString: + case TypeMatch: + { + char **array = calloc (1, (nItems + 1) * sizeof (char *)); + char **arrayCounter = array; + + if (!array) + { + break; + } + + /* Reads each item from the variant into the position pointed + * at by arrayCounter */ + while (g_variant_iter_loop (iter, variantType, arrayCounter)) + arrayCounter++; + + list = ccsGetValueListFromStringArray (array, nItems, setting); + for (i = 0; i < nItems; i++) + if (array[i]) + free (array[i]); + free (array); + } + break; + case TypeColor: + { + CCSSettingColorValue *array; + char *colorValue; + array = malloc (nItems * sizeof (CCSSettingColorValue)); + if (!array) + break; + + while (g_variant_iter_loop (iter, variantType, &colorValue)) + { + memset (&array[i], 0, sizeof (CCSSettingColorValue)); + ccsStringToColor (colorValue, + &array[i]); + } + list = ccsGetValueListFromColorArray (array, nItems, setting); + free (array); + } + break; + default: + break; + } + + free (cleanSettingName); + free (variantType); + + if (list) + { + ccsSetList (setting, list); + ccsSettingValueListFree (list, TRUE); + return TRUE; + } + + return FALSE; +} + +static Bool +readIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index) +{ +#ifdef USE_GCONF + return readGConfIntegratedOption (context, setting, index); +#else + return FALSE; +#endif +} + +Bool +readOption (CCSSetting * setting) +{ + GSettings *settings = getSettingsObjectForCCSSetting (setting); + GVariant *gsettingsValue = NULL; + Bool ret = FALSE; + Bool valid = TRUE; + + /* It is impossible for certain settings to have a schema, + * such as actions and read only settings, so in that case + * just return FALSE since compizconfig doesn't expect us + * to read them anyways */ + + if (setting->type == TypeAction || + ccsSettingIsReadOnly (setting)) + { + return FALSE; + } + + char *cleanSettingName = translateKeyForGSettings (setting->name); + KEYNAME(setting->parent->context->screenNum); + PATHNAME (setting->parent->name, keyName); + + /* first check if the key is set */ + gsettingsValue = g_settings_get_value (settings, cleanSettingName); + + switch (setting->type) + { + case TypeString: + case TypeMatch: + case TypeColor: + case TypeKey: + case TypeButton: + case TypeEdge: + valid = (g_variant_type_is_subtype_of (G_VARIANT_TYPE_STRING, g_variant_get_type (gsettingsValue))); + break; + case TypeInt: + valid = (g_variant_type_is_subtype_of (G_VARIANT_TYPE_INT32, g_variant_get_type (gsettingsValue))); + break; + case TypeBool: + case TypeBell: + valid = (g_variant_type_is_subtype_of (G_VARIANT_TYPE_BOOLEAN, g_variant_get_type (gsettingsValue))); + break; + case TypeFloat: + valid = (g_variant_type_is_subtype_of (G_VARIANT_TYPE_DOUBLE, g_variant_get_type (gsettingsValue))); + break; + case TypeList: + valid = (g_variant_type_is_array (g_variant_get_type (gsettingsValue))); + break; + default: + break; + } + + if (!valid) + { + printf ("GSettings backend: There is an unsupported value at path %s. " + "Settings from this path won't be read. Try to remove " + "that value so that operation can continue properly.\n", + pathName); + free (cleanSettingName); + g_variant_unref (gsettingsValue); + return FALSE; + } + + switch (setting->type) + { + case TypeString: + { + const char *value; + value = g_variant_get_string (gsettingsValue, NULL); + if (value) + { + ccsSetString (setting, value); + ret = TRUE; + } + } + break; + case TypeMatch: + { + const char * value; + value = g_variant_get_string (gsettingsValue, NULL); + if (value) + { + ccsSetMatch (setting, value); + ret = TRUE; + } + } + break; + case TypeInt: + { + int value; + value = g_variant_get_int32 (gsettingsValue); + + ccsSetInt (setting, value); + ret = TRUE; + } + break; + case TypeBool: + { + gboolean value; + value = g_variant_get_boolean (gsettingsValue); + + ccsSetBool (setting, value ? TRUE : FALSE); + ret = TRUE; + } + break; + case TypeFloat: + { + double value; + value = g_variant_get_double (gsettingsValue); + + ccsSetFloat (setting, (float)value); + ret = TRUE; + } + break; + case TypeColor: + { + const char *value; + CCSSettingColorValue color; + value = g_variant_get_string (gsettingsValue, NULL); + + if (value && ccsStringToColor (value, &color)) + { + ccsSetColor (setting, color); + ret = TRUE; + } + } + break; + case TypeKey: + { + const char *value; + CCSSettingKeyValue key; + value = g_variant_get_string (gsettingsValue, NULL); + + if (value && ccsStringToKeyBinding (value, &key)) + { + ccsSetKey (setting, key); + ret = TRUE; + } + } + break; + case TypeButton: + { + const char *value; + CCSSettingButtonValue button; + value = g_variant_get_string (gsettingsValue, NULL); + + if (value && ccsStringToButtonBinding (value, &button)) + { + ccsSetButton (setting, button); + ret = TRUE; + } + } + break; + case TypeEdge: + { + const char *value; + value = g_variant_get_string (gsettingsValue, NULL); + + if (value) + { + unsigned int edges; + edges = ccsStringToEdges (value); + ccsSetEdge (setting, edges); + ret = TRUE; + } + } + break; + case TypeBell: + { + gboolean value; + value = g_variant_get_boolean (gsettingsValue); + + ccsSetBell (setting, value ? TRUE : FALSE); + ret = TRUE; + } + break; + case TypeList: + ret = readListValue (setting); + break; + default: + printf("GSettings backend: attempt to read unsupported setting type %d!\n", + setting->type); + break; + } + + free (cleanSettingName); + g_variant_unref (gsettingsValue); + + return ret; +} + +static void +writeListValue (CCSSetting *setting, + char *pathName) +{ + GSettings *settings = getSettingsObjectForCCSSetting (setting); + GVariant *value; + gchar *variantType = NULL; + CCSSettingValueList list; + + char *cleanSettingName = translateKeyForGSettings (setting->name); + + if (!ccsGetList (setting, &list)) + return; + + switch (setting->info.forList.listType) + { + case TypeBool: + { + variantType = "ab"; + GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ab")); + while (list) + { + g_variant_builder_add (builder, "b", list->data->value.asBool); + list = list->next; + } + value = g_variant_new ("ab", builder); + g_variant_builder_unref (builder); + } + break; + case TypeInt: + { + variantType = "ai"; + GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ai")); + while (list) + { + g_variant_builder_add (builder, "i", list->data->value.asInt); + list = list->next; + } + value = g_variant_new ("ai", builder); + g_variant_builder_unref (builder); + } + break; + case TypeFloat: + { + variantType = "ad"; + GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ad")); + while (list) + { + g_variant_builder_add (builder, "d", (gdouble) list->data->value.asFloat); + list = list->next; + } + value = g_variant_new ("ad", builder); + g_variant_builder_unref (builder); + } + break; + case TypeString: + { + variantType = "as"; + GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + while (list) + { + g_variant_builder_add (builder, "s", list->data->value.asString); + list = list->next; + } + value = g_variant_new ("as", builder); + g_variant_builder_unref (builder); + } + break; + case TypeMatch: + { + variantType = "as"; + GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + while (list) + { + g_variant_builder_add (builder, "s", list->data->value.asMatch); + list = list->next; + } + value = g_variant_new ("as", builder); + g_variant_builder_unref (builder); + } + break; + case TypeColor: + { + variantType = "as"; + GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + char *item; + while (list) + { + item = ccsColorToString (&list->data->value.asColor); + g_variant_builder_add (builder, "s", item); + list = list->next; + } + value = g_variant_new ("as", builder); + g_variant_builder_unref (builder); + } + break; + default: + printf("GSettings backend: attempt to write unsupported list type %d!\n", + setting->info.forList.listType); + variantType = NULL; + break; + } + + if (variantType != NULL) + { + g_settings_set_value (settings, cleanSettingName, value); + g_variant_unref (value); + } + + free (cleanSettingName); +} + +static void +writeIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index) +{ +#ifdef USE_GCONF + writeGConfIntegratedOption (context, setting, index); +#endif + + return; +} + +static void +resetOptionToDefault (CCSSetting * setting) +{ + GSettings *settings = getSettingsObjectForCCSSetting (setting); + + char *cleanSettingName = translateKeyForGSettings (setting->name); + KEYNAME (setting->parent->context->screenNum); + PATHNAME (setting->parent->name, keyName); + + g_settings_reset (settings, cleanSettingName); + + free (cleanSettingName); +} + +void +writeOption (CCSSetting * setting) +{ + GSettings *settings = getSettingsObjectForCCSSetting (setting); + char *cleanSettingName = translateKeyForGSettings (setting->name); + KEYNAME (setting->parent->context->screenNum); + PATHNAME (setting->parent->name, keyName); + + switch (setting->type) + { + case TypeString: + { + char *value; + if (ccsGetString (setting, &value)) + { + g_settings_set (settings, cleanSettingName, "s", value, NULL); + } + } + break; + case TypeMatch: + { + char *value; + if (ccsGetMatch (setting, &value)) + { + g_settings_set (settings, cleanSettingName, "s", value, NULL); + } + } + case TypeFloat: + { + float value; + if (ccsGetFloat (setting, &value)) + { + g_settings_set (settings, cleanSettingName, "d", (double) value, NULL); + } + } + break; + case TypeInt: + { + int value; + if (ccsGetInt (setting, &value)) + { + g_settings_set (settings, cleanSettingName, "i", value, NULL); + } + } + break; + case TypeBool: + { + Bool value; + if (ccsGetBool (setting, &value)) + { + g_settings_set (settings, cleanSettingName, "b", value, NULL); + } + } + break; + case TypeColor: + { + CCSSettingColorValue value; + char *colString; + + if (!ccsGetColor (setting, &value)) + break; + + colString = ccsColorToString (&value); + if (!colString) + break; + + g_settings_set (settings, cleanSettingName, "s", value, NULL); + free (colString); + } + break; + case TypeKey: + { + CCSSettingKeyValue key; + char *keyString; + + if (!ccsGetKey (setting, &key)) + break; + + keyString = ccsKeyBindingToString (&key); + if (!keyString) + break; + + g_settings_set (settings, cleanSettingName, "s", keyString, NULL); + free (keyString); + } + break; + case TypeButton: + { + CCSSettingButtonValue button; + char *buttonString; + + if (!ccsGetButton (setting, &button)) + break; + + buttonString = ccsButtonBindingToString (&button); + if (!buttonString) + break; + + g_settings_set (settings, cleanSettingName, "s", buttonString, NULL); + free (buttonString); + } + break; + case TypeEdge: + { + unsigned int edges; + char *edgeString; + + if (!ccsGetEdge (setting, &edges)) + break; + + edgeString = ccsEdgesToString (edges); + if (!edgeString) + break; + + g_settings_set (settings, cleanSettingName, "s", edgeString, NULL); + free (edgeString); + } + break; + case TypeBell: + { + Bool value; + if (ccsGetBell (setting, &value)) + { + g_settings_set (settings, cleanSettingName, "s", value, NULL); + } + } + break; + case TypeList: + writeListValue (setting, pathName); + break; + default: + printf("GSettings backend: attempt to write unsupported setting type %d\n", + setting->type); + break; + } + + free (cleanSettingName); +} + +static void +updateCurrentProfileName (char *profile) +{ + GVariant *profiles; + char *prof; + char *profilePath = COMPIZ_PROFILEPATH; + char *currentProfilePath; + GVariant *newProfiles; + GVariantBuilder *newProfilesBuilder; + GVariantIter *iter; + gboolean found = FALSE; + + profiles = g_settings_get_value (compizconfigSettings, "existing-profiles"); + + newProfilesBuilder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + + iter = g_variant_iter_new (profiles); + while (g_variant_iter_loop (iter, "s", &prof)) + { + g_variant_builder_add (newProfilesBuilder, "s", prof); + + if (!found) + found = (g_strcmp0 (prof, profile) == 0); + } + + if (!found) + g_variant_builder_add (newProfilesBuilder, "s", profile); + + newProfiles = g_variant_new ("as", newProfilesBuilder); + g_settings_set_value (compizconfigSettings, "existing-profiles", newProfiles); + + g_variant_iter_free (iter); + g_variant_unref (newProfiles); + g_variant_builder_unref (newProfilesBuilder); + + /* Change the current profile and current profile settings */ + free (currentProfile); + + currentProfile = strdup (profile); + currentProfilePath = g_strconcat (profilePath, profile, "/", NULL); + currentProfileSettings = g_settings_new_with_path (PROFILE_SCHEMA_ID, profilePath); + + g_free (currentProfilePath); + + g_settings_set (compizconfigSettings, "current-profile", "s", profile, NULL); +} + +static gboolean +updateProfile (CCSContext *context) +{ + char *profile = strdup (ccsGetProfile (context)); + + if (!profile || !strlen (profile)) + profile = strdup (DEFAULTPROF); + + if (g_strcmp0 (profile, currentProfile)) + updateCurrentProfileName (profile); + + free (profile); + + return TRUE; +} + +static char* +getCurrentProfileName (void) +{ + GVariant *value; + char *ret = NULL; + + value = g_settings_get_value (compizconfigSettings, "current-profile"); + + if (value) + ret = strdup (g_variant_get_string (value, NULL)); + else + ret = strdup (DEFAULTPROF); + + return ret; +} + +static void +processEvents (unsigned int flags) +{ + if (!(flags & ProcessEventsNoGlibMainLoopMask)) + { + while (g_main_context_pending(NULL)) + g_main_context_iteration(NULL, FALSE); + } +} + +static Bool +initBackend (CCSContext * context) +{ + const char *profilePath = PROFILEPATH; + char *currentProfilePath; + + g_type_init (); + + compizconfigSettings = g_settings_new (COMPIZCONFIG_SCHEMA_ID); + +#ifdef USE_GCONF + initGConfClient (context); +#endif + + currentProfile = getCurrentProfileName (); + currentProfilePath = g_strconcat (profilePath, currentProfile, "/", NULL); + currentProfileSettings = g_settings_new_with_path (PROFILE_SCHEMA_ID, currentProfilePath); + + g_free (currentProfilePath); + + return TRUE; +} + +static Bool +finiBackend (CCSContext * context) +{ + GList *l = settingsList; + + processEvents (0); + +#ifdef USE_GCONF + gconf_client_clear_cache (client); + finiGConfClient (); +#endif + + if (currentProfile) + { + free (currentProfile); + currentProfile = NULL; + } + + while (l) + { + g_object_unref (G_OBJECT (l->data)); + l = g_list_next (l); + } + + g_object_unref (G_OBJECT (compizconfigSettings)); + + processEvents (0); + return TRUE; +} + +Bool +readInit (CCSContext * context) +{ + return updateProfile (context); +} + +void +readSetting (CCSContext *context, + CCSSetting *setting) +{ + Bool status; + int index; + + if (ccsGetIntegrationEnabled (context) && + isIntegratedOption (setting, &index)) + { + status = readIntegratedOption (context, setting, index); + } + else + status = readOption (setting); + + if (!status) + ccsResetToDefault (setting); +} + +Bool +writeInit (CCSContext * context) +{ + return updateProfile (context); +} + +void +writeSetting (CCSContext *context, + CCSSetting *setting) +{ + int index; + + if (ccsGetIntegrationEnabled (context) && + isIntegratedOption (setting, &index)) + { + writeIntegratedOption (context, setting, index); + } + else if (setting->isDefault) + { + resetOptionToDefault (setting); + } + else + writeOption (setting); + +} + +static Bool +getSettingIsIntegrated (CCSSetting * setting) +{ + if (!ccsGetIntegrationEnabled (setting->parent->context)) + return FALSE; + + if (!isIntegratedOption (setting, NULL)) + return FALSE; + + return TRUE; +} + +static Bool +getSettingIsReadOnly (CCSSetting * setting) +{ + /* FIXME */ + return FALSE; +} + +static CCSStringList +getExistingProfiles (CCSContext *context) +{ + GVariant *value; + char *profile; + GVariantIter iter; + CCSStringList ret = NULL; + + value = g_settings_get_value (compizconfigSettings, "existing-profiles"); + g_variant_iter_init (&iter, value); + while (g_variant_iter_loop (&iter, "s", &profile)) + ret = ccsStringListAppend (ret, strdup (profile)); + + g_variant_unref (value); + + return ret; +} + +static Bool +deleteProfile (CCSContext *context, + char *profile) +{ + GVariant *plugins; + GVariant *profiles; + GVariant *newProfiles; + GVariantBuilder *newProfilesBuilder; + char *plugin, *prof; + GVariantIter *iter; + char *profileSettingsPath = g_strconcat (PROFILEPATH, profile, "/", NULL); + GSettings *profileSettings = g_settings_new_with_path (PROFILE_SCHEMA_ID, profileSettingsPath); + + plugins = g_settings_get_value (currentProfileSettings, "plugins-with-set-keys"); + profiles = g_settings_get_value (compizconfigSettings, "existing-profiles"); + + iter = g_variant_iter_new (plugins); + while (g_variant_iter_loop (iter, "s", &plugin)) + { + GSettings *settings; + + KEYNAME (context->screenNum); + PATHNAME (plugin, keyName); + + settings = getSettingsObjectForPluginWithPath (plugin, pathName, context); + + /* The GSettings documentation says not to use this API + * because we should know our own schema ... though really + * we don't because we autogenerate schemas ... */ + if (settings) + { + char **keys = g_settings_list_keys (settings); + char **key_ptr; + + /* Unset all the keys */ + for (key_ptr = keys; *key_ptr; key_ptr++) + g_settings_reset (settings, *key_ptr); + + g_strfreev (keys); + } + } + + /* Remove the profile from existing-profiles */ + g_variant_iter_free (iter); + g_settings_reset (profileSettings, "plugins-with-set-values"); + + iter = g_variant_iter_new (profiles); + newProfilesBuilder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + + while (g_variant_iter_loop (iter, "s", &prof)) + { + if (g_strcmp0 (prof, profile)) + g_variant_builder_add (newProfilesBuilder, "s", prof); + } + + newProfiles = g_variant_new ("as", newProfilesBuilder); + g_settings_set_value (compizconfigSettings, "existing-profiles", newProfiles); + + g_variant_unref (newProfiles); + g_variant_builder_unref (newProfilesBuilder); + + free (profileSettingsPath); + + updateProfile (context); + + return TRUE; +} + +static CCSBackendVTable gsettingsVTable = { + "gsettings", + "GSettings Configuration Backend", + "GSettings Configuration Backend for libccs", + TRUE, + TRUE, + processEvents, + initBackend, + finiBackend, + readInit, + readSetting, + 0, + writeInit, + writeSetting, + 0, + getSettingIsIntegrated, + getSettingIsReadOnly, + getExistingProfiles, + deleteProfile +}; + +CCSBackendVTable * +getBackendInfo (void) +{ + return &gsettingsVTable; +} + diff --git a/src/gsettings.h b/src/gsettings.h new file mode 100644 index 0000000..ee0d51c --- /dev/null +++ b/src/gsettings.h @@ -0,0 +1,152 @@ +/** + * + * GSettings libccs backend + * + * gconf-integration.c + * + * Copyright (c) 2011 Canonical Ltd + * + * Based on the original compizconfig-backend-gconf + * + * Copyright (c) 2007 Danny Baumann <maniac@opencompositing.org> + * + * Parts of this code are taken from libberylsettings + * gconf backend, written by: + * + * Copyright (c) 2006 Robert Carr <racarr@opencompositing.org> + * Copyright (c) 2007 Dennis Kasprzyk <onestone@opencompositing.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Authored By: + * Sam Spilsbury <sam.spilsbury@canonical.com> + * + **/ + +#ifndef _COMPIZCONFIG_BACKEND_GSETTINGS_GSETTINGS_H +#define _COMPIZCONFIG_BACKEND_GSETTINGS_GSETTINGS_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <malloc.h> +#include <string.h> +#include <dirent.h> + +#include <ccs.h> +#include <ccs-backend.h> + +#include <gio/gio.h> + +#include <X11/X.h> +#include <X11/Xlib.h> + +#define CompAltMask (1 << 16) +#define CompMetaMask (1 << 17) +#define CompSuperMask (1 << 18) +#define CompHyperMask (1 << 19) +#define CompModeSwitchMask (1 << 20) +#define CompNumLockMask (1 << 21) +#define CompScrollLockMask (1 << 22) + +#define COMPIZ_SCHEMA_ID "org.freedesktop.compiz" +#define COMPIZCONFIG_SCHEMA_ID "org.freedesktop.compizconfig" +#define PROFILE_SCHEMA_ID "org.freedesktop.compizconfig.profile" +#define METACITY "/apps/metacity" +#define COMPIZ "/apps/compiz-1" +#define COMPIZ_PROFILEPATH COMPIZ "/profiles" +#define COMPIZCONFIG "/org/freedesktop/compizconfig" +#define PROFILEPATH COMPIZCONFIG "/profiles" +#define DEFAULTPROF "Default" +#define CORE_NAME "core" + +#define BUFSIZE 512 + +#define NUM_WATCHED_DIRS 3 + +#define KEYNAME(sn) char keyName[BUFSIZE]; \ + snprintf (keyName, BUFSIZE, "screen%i", sn); + +#define PATHNAME(p,k) char pathName[BUFSIZE]; \ + if (!p || \ + strcmp (p, "core") == 0) \ + snprintf (pathName, BUFSIZE, \ + "%s/%s/plugins/%s/%s/options/", COMPIZ, currentProfile, \ + p, k); \ + else \ + snprintf(pathName, BUFSIZE, \ + "%s/%s/plugins/%s/%s/options/", COMPIZ, currentProfile, \ + p, k); + +#define _GNU_SOURCE + +typedef enum { + OptionInt, + OptionBool, + OptionKey, + OptionString, + OptionSpecial, +} SpecialOptionType; + +char *currentProfile; + +Bool readInit (CCSContext * context); +void readSetting (CCSContext * context, CCSSetting * setting); +Bool readOption (CCSSetting * setting); +Bool writeInit (CCSContext * context); +void writeOption (CCSSetting *setting); + +#ifdef USE_GCONF + +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> +#include <gconf/gconf-value.h> + +GConfClient *client; +guint gnomeGConfNotifyIds[NUM_WATCHED_DIRS]; + +typedef struct _SpecialOptionGConf { + const char* settingName; + const char* pluginName; + Bool screen; + const char* gnomeName; + SpecialOptionType type; +} SpecialOptionGConf; + +Bool +isGConfIntegratedOption (CCSSetting *setting, + int *index); + +void +gnomeGConfValueChanged (GConfClient *client, + guint cnxn_id, + GConfEntry *entry, + gpointer user_data); + +void +initGConfClient (CCSContext *context); + +void +finiGConfClient (void); + +Bool +readGConfIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index); + +void +writeGConfIntegratedOption (CCSContext *context, + CCSSetting *setting, + int index); + +#endif + +#endif |