1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/system/gnome/nsGSettingsService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,350 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/ArrayUtils.h" 1.10 + 1.11 +#include "nsGSettingsService.h" 1.12 +#include "nsStringAPI.h" 1.13 +#include "nsCOMPtr.h" 1.14 +#include "nsMemory.h" 1.15 +#include "prlink.h" 1.16 +#include "nsComponentManagerUtils.h" 1.17 +#include "nsIMutableArray.h" 1.18 +#include "nsISupportsPrimitives.h" 1.19 + 1.20 +#include <glib.h> 1.21 +#include <glib-object.h> 1.22 + 1.23 +using namespace mozilla; 1.24 + 1.25 +typedef struct _GSettings GSettings; 1.26 +typedef struct _GVariantType GVariantType; 1.27 +typedef struct _GVariant GVariant; 1.28 + 1.29 +#ifndef G_VARIANT_TYPE_INT32 1.30 +# define G_VARIANT_TYPE_INT32 ((const GVariantType *) "i") 1.31 +# define G_VARIANT_TYPE_BOOLEAN ((const GVariantType *) "b") 1.32 +# define G_VARIANT_TYPE_STRING ((const GVariantType *) "s") 1.33 +# define G_VARIANT_TYPE_OBJECT_PATH ((const GVariantType *) "o") 1.34 +# define G_VARIANT_TYPE_SIGNATURE ((const GVariantType *) "g") 1.35 +#endif 1.36 +#ifndef G_VARIANT_TYPE_STRING_ARRAY 1.37 +# define G_VARIANT_TYPE_STRING_ARRAY ((const GVariantType *) "as") 1.38 +#endif 1.39 + 1.40 +#define GSETTINGS_FUNCTIONS \ 1.41 + FUNC(g_settings_new, GSettings *, (const char* schema)) \ 1.42 + FUNC(g_settings_list_schemas, const char * const *, (void)) \ 1.43 + FUNC(g_settings_list_keys, char **, (GSettings* settings)) \ 1.44 + FUNC(g_settings_get_value, GVariant *, (GSettings* settings, const char* key)) \ 1.45 + FUNC(g_settings_set_value, gboolean, (GSettings* settings, const char* key, GVariant* value)) \ 1.46 + FUNC(g_settings_range_check, gboolean, (GSettings* settings, const char* key, GVariant* value)) \ 1.47 + FUNC(g_variant_get_int32, gint32, (GVariant* variant)) \ 1.48 + FUNC(g_variant_get_boolean, gboolean, (GVariant* variant)) \ 1.49 + FUNC(g_variant_get_string, const char *, (GVariant* value, gsize* length)) \ 1.50 + FUNC(g_variant_get_strv, const char **, (GVariant* value, gsize* length)) \ 1.51 + FUNC(g_variant_is_of_type, gboolean, (GVariant* value, const GVariantType* type)) \ 1.52 + FUNC(g_variant_new_int32, GVariant *, (gint32 value)) \ 1.53 + FUNC(g_variant_new_boolean, GVariant *, (gboolean value)) \ 1.54 + FUNC(g_variant_new_string, GVariant *, (const char* string)) \ 1.55 + FUNC(g_variant_unref, void, (GVariant* value)) 1.56 + 1.57 +#define FUNC(name, type, params) \ 1.58 + typedef type (*_##name##_fn) params; \ 1.59 + static _##name##_fn _##name; 1.60 + 1.61 +GSETTINGS_FUNCTIONS 1.62 + 1.63 +#undef FUNC 1.64 + 1.65 +#define g_settings_new _g_settings_new 1.66 +#define g_settings_list_schemas _g_settings_list_schemas 1.67 +#define g_settings_list_keys _g_settings_list_keys 1.68 +#define g_settings_get_value _g_settings_get_value 1.69 +#define g_settings_set_value _g_settings_set_value 1.70 +#define g_settings_range_check _g_settings_range_check 1.71 +#define g_variant_get_int32 _g_variant_get_int32 1.72 +#define g_variant_get_boolean _g_variant_get_boolean 1.73 +#define g_variant_get_string _g_variant_get_string 1.74 +#define g_variant_get_strv _g_variant_get_strv 1.75 +#define g_variant_is_of_type _g_variant_is_of_type 1.76 +#define g_variant_new_int32 _g_variant_new_int32 1.77 +#define g_variant_new_boolean _g_variant_new_boolean 1.78 +#define g_variant_new_string _g_variant_new_string 1.79 +#define g_variant_unref _g_variant_unref 1.80 + 1.81 +static PRLibrary *gioLib = nullptr; 1.82 + 1.83 +class nsGSettingsCollection MOZ_FINAL : public nsIGSettingsCollection 1.84 +{ 1.85 +public: 1.86 + NS_DECL_ISUPPORTS 1.87 + NS_DECL_NSIGSETTINGSCOLLECTION 1.88 + 1.89 + nsGSettingsCollection(GSettings* aSettings) : mSettings(aSettings), 1.90 + mKeys(nullptr) {} 1.91 + ~nsGSettingsCollection(); 1.92 + 1.93 +private: 1.94 + bool KeyExists(const nsACString& aKey); 1.95 + bool SetValue(const nsACString& aKey, 1.96 + GVariant *aValue); 1.97 + 1.98 + GSettings *mSettings; 1.99 + char **mKeys; 1.100 +}; 1.101 + 1.102 +nsGSettingsCollection::~nsGSettingsCollection() 1.103 +{ 1.104 + g_strfreev(mKeys); 1.105 + g_object_unref(mSettings); 1.106 +} 1.107 + 1.108 +bool 1.109 +nsGSettingsCollection::KeyExists(const nsACString& aKey) 1.110 +{ 1.111 + if (!mKeys) 1.112 + mKeys = g_settings_list_keys(mSettings); 1.113 + 1.114 + for (uint32_t i = 0; mKeys[i] != nullptr; i++) { 1.115 + if (aKey.Equals(mKeys[i])) 1.116 + return true; 1.117 + } 1.118 + 1.119 + return false; 1.120 +} 1.121 + 1.122 +bool 1.123 +nsGSettingsCollection::SetValue(const nsACString& aKey, 1.124 + GVariant *aValue) 1.125 +{ 1.126 + if (!KeyExists(aKey) || 1.127 + !g_settings_range_check(mSettings, 1.128 + PromiseFlatCString(aKey).get(), 1.129 + aValue)) { 1.130 + g_variant_unref(aValue); 1.131 + return false; 1.132 + } 1.133 + 1.134 + return g_settings_set_value(mSettings, 1.135 + PromiseFlatCString(aKey).get(), 1.136 + aValue); 1.137 +} 1.138 + 1.139 +NS_IMPL_ISUPPORTS(nsGSettingsCollection, nsIGSettingsCollection) 1.140 + 1.141 +NS_IMETHODIMP 1.142 +nsGSettingsCollection::SetString(const nsACString& aKey, 1.143 + const nsACString& aValue) 1.144 +{ 1.145 + GVariant *value = g_variant_new_string(PromiseFlatCString(aValue).get()); 1.146 + if (!value) 1.147 + return NS_ERROR_OUT_OF_MEMORY; 1.148 + 1.149 + bool res = SetValue(aKey, value); 1.150 + 1.151 + return res ? NS_OK : NS_ERROR_FAILURE; 1.152 +} 1.153 + 1.154 +NS_IMETHODIMP 1.155 +nsGSettingsCollection::SetBoolean(const nsACString& aKey, 1.156 + bool aValue) 1.157 +{ 1.158 + GVariant *value = g_variant_new_boolean(aValue); 1.159 + if (!value) 1.160 + return NS_ERROR_OUT_OF_MEMORY; 1.161 + 1.162 + bool res = SetValue(aKey, value); 1.163 + 1.164 + return res ? NS_OK : NS_ERROR_FAILURE; 1.165 +} 1.166 + 1.167 +NS_IMETHODIMP 1.168 +nsGSettingsCollection::SetInt(const nsACString& aKey, 1.169 + int32_t aValue) 1.170 +{ 1.171 + GVariant *value = g_variant_new_int32(aValue); 1.172 + if (!value) 1.173 + return NS_ERROR_OUT_OF_MEMORY; 1.174 + 1.175 + bool res = SetValue(aKey, value); 1.176 + 1.177 + return res ? NS_OK : NS_ERROR_FAILURE; 1.178 +} 1.179 + 1.180 +NS_IMETHODIMP 1.181 +nsGSettingsCollection::GetString(const nsACString& aKey, 1.182 + nsACString& aResult) 1.183 +{ 1.184 + if (!KeyExists(aKey)) 1.185 + return NS_ERROR_INVALID_ARG; 1.186 + 1.187 + GVariant *value = g_settings_get_value(mSettings, 1.188 + PromiseFlatCString(aKey).get()); 1.189 + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING) && 1.190 + !g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH) && 1.191 + !g_variant_is_of_type(value, G_VARIANT_TYPE_SIGNATURE)) { 1.192 + g_variant_unref(value); 1.193 + return NS_ERROR_FAILURE; 1.194 + } 1.195 + 1.196 + aResult.Assign(g_variant_get_string(value, nullptr)); 1.197 + g_variant_unref(value); 1.198 + 1.199 + return NS_OK; 1.200 +} 1.201 + 1.202 +NS_IMETHODIMP 1.203 +nsGSettingsCollection::GetBoolean(const nsACString& aKey, 1.204 + bool* aResult) 1.205 +{ 1.206 + NS_ENSURE_ARG_POINTER(aResult); 1.207 + 1.208 + if (!KeyExists(aKey)) 1.209 + return NS_ERROR_INVALID_ARG; 1.210 + 1.211 + GVariant *value = g_settings_get_value(mSettings, 1.212 + PromiseFlatCString(aKey).get()); 1.213 + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) { 1.214 + g_variant_unref(value); 1.215 + return NS_ERROR_FAILURE; 1.216 + } 1.217 + 1.218 + gboolean res = g_variant_get_boolean(value); 1.219 + *aResult = res ? true : false; 1.220 + g_variant_unref(value); 1.221 + 1.222 + return NS_OK; 1.223 +} 1.224 + 1.225 +NS_IMETHODIMP 1.226 +nsGSettingsCollection::GetInt(const nsACString& aKey, 1.227 + int32_t* aResult) 1.228 +{ 1.229 + NS_ENSURE_ARG_POINTER(aResult); 1.230 + 1.231 + if (!KeyExists(aKey)) 1.232 + return NS_ERROR_INVALID_ARG; 1.233 + 1.234 + GVariant *value = g_settings_get_value(mSettings, 1.235 + PromiseFlatCString(aKey).get()); 1.236 + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) { 1.237 + g_variant_unref(value); 1.238 + return NS_ERROR_FAILURE; 1.239 + } 1.240 + 1.241 + *aResult = g_variant_get_int32(value); 1.242 + g_variant_unref(value); 1.243 + 1.244 + return NS_OK; 1.245 +} 1.246 + 1.247 +// These types are local to nsGSettingsService::Init, but ISO C++98 doesn't 1.248 +// allow a template (ArrayLength) to be instantiated based on a local type. 1.249 +// Boo-urns! 1.250 +typedef void (*nsGSettingsFunc)(); 1.251 +struct nsGSettingsDynamicFunction { 1.252 + const char *functionName; 1.253 + nsGSettingsFunc *function; 1.254 +}; 1.255 + 1.256 +NS_IMETHODIMP 1.257 +nsGSettingsCollection::GetStringList(const nsACString& aKey, nsIArray** aResult) 1.258 +{ 1.259 + if (!KeyExists(aKey)) 1.260 + return NS_ERROR_INVALID_ARG; 1.261 + 1.262 + nsCOMPtr<nsIMutableArray> items(do_CreateInstance(NS_ARRAY_CONTRACTID)); 1.263 + if (!items) { 1.264 + return NS_ERROR_OUT_OF_MEMORY; 1.265 + } 1.266 + 1.267 + GVariant *value = g_settings_get_value(mSettings, 1.268 + PromiseFlatCString(aKey).get()); 1.269 + 1.270 + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) { 1.271 + g_variant_unref(value); 1.272 + return NS_ERROR_FAILURE; 1.273 + } 1.274 + 1.275 + const gchar ** gs_strings = g_variant_get_strv(value, nullptr); 1.276 + if (!gs_strings) { 1.277 + // empty array 1.278 + NS_ADDREF(*aResult = items); 1.279 + g_variant_unref(value); 1.280 + return NS_OK; 1.281 + } 1.282 + 1.283 + const gchar** p_gs_strings = gs_strings; 1.284 + while (*p_gs_strings != nullptr) 1.285 + { 1.286 + nsCOMPtr<nsISupportsCString> obj(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID)); 1.287 + if (obj) { 1.288 + obj->SetData(nsDependentCString(*p_gs_strings)); 1.289 + items->AppendElement(obj, false); 1.290 + } 1.291 + p_gs_strings++; 1.292 + } 1.293 + g_free(gs_strings); 1.294 + NS_ADDREF(*aResult = items); 1.295 + g_variant_unref(value); 1.296 + return NS_OK; 1.297 +} 1.298 + 1.299 +nsresult 1.300 +nsGSettingsService::Init() 1.301 +{ 1.302 +#define FUNC(name, type, params) { #name, (nsGSettingsFunc *)&_##name }, 1.303 + static const nsGSettingsDynamicFunction kGSettingsSymbols[] = { 1.304 + GSETTINGS_FUNCTIONS 1.305 + }; 1.306 +#undef FUNC 1.307 + 1.308 + if (!gioLib) { 1.309 + gioLib = PR_LoadLibrary("libgio-2.0.so.0"); 1.310 + if (!gioLib) 1.311 + return NS_ERROR_FAILURE; 1.312 + } 1.313 + 1.314 + for (uint32_t i = 0; i < ArrayLength(kGSettingsSymbols); i++) { 1.315 + *kGSettingsSymbols[i].function = 1.316 + PR_FindFunctionSymbol(gioLib, kGSettingsSymbols[i].functionName); 1.317 + if (!*kGSettingsSymbols[i].function) { 1.318 + return NS_ERROR_FAILURE; 1.319 + } 1.320 + } 1.321 + 1.322 + return NS_OK; 1.323 +} 1.324 + 1.325 +NS_IMPL_ISUPPORTS(nsGSettingsService, nsIGSettingsService) 1.326 + 1.327 +nsGSettingsService::~nsGSettingsService() 1.328 +{ 1.329 + if (gioLib) { 1.330 + PR_UnloadLibrary(gioLib); 1.331 + gioLib = nullptr; 1.332 + } 1.333 +} 1.334 + 1.335 +NS_IMETHODIMP 1.336 +nsGSettingsService::GetCollectionForSchema(const nsACString& schema, 1.337 + nsIGSettingsCollection** collection) 1.338 +{ 1.339 + NS_ENSURE_ARG_POINTER(collection); 1.340 + 1.341 + const char * const *schemas = g_settings_list_schemas(); 1.342 + 1.343 + for (uint32_t i = 0; schemas[i] != nullptr; i++) { 1.344 + if (schema.Equals(schemas[i])) { 1.345 + GSettings *settings = g_settings_new(PromiseFlatCString(schema).get()); 1.346 + nsGSettingsCollection *mozGSettings = new nsGSettingsCollection(settings); 1.347 + NS_ADDREF(*collection = mozGSettings); 1.348 + return NS_OK; 1.349 + } 1.350 + } 1.351 + 1.352 + return NS_ERROR_FAILURE; 1.353 +}