|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "mozilla/ArrayUtils.h" |
|
7 #include "nsGConfService.h" |
|
8 #include "nsStringAPI.h" |
|
9 #include "nsCOMPtr.h" |
|
10 #include "nsComponentManagerUtils.h" |
|
11 #include "nsISupportsPrimitives.h" |
|
12 #include "nsIMutableArray.h" |
|
13 #include "prlink.h" |
|
14 |
|
15 #include <gconf/gconf-client.h> |
|
16 |
|
17 using namespace mozilla; |
|
18 |
|
19 #define GCONF_FUNCTIONS \ |
|
20 FUNC(gconf_client_get_default, GConfClient*, (void)) \ |
|
21 FUNC(gconf_client_get_bool, gboolean, (GConfClient*, const gchar*, GError**)) \ |
|
22 FUNC(gconf_client_get_string, gchar*, (GConfClient*, const gchar*, GError**)) \ |
|
23 FUNC(gconf_client_get_int, gint, (GConfClient*, const gchar*, GError**)) \ |
|
24 FUNC(gconf_client_get_float, gdouble, (GConfClient*, const gchar*, GError**)) \ |
|
25 FUNC(gconf_client_get_list, GSList*, (GConfClient*, const gchar*, GConfValueType, GError**)) \ |
|
26 FUNC(gconf_client_set_bool, gboolean, (GConfClient*, const gchar*, gboolean, GError**)) \ |
|
27 FUNC(gconf_client_set_string, gboolean, (GConfClient*, const gchar*, const gchar*, GError**)) \ |
|
28 FUNC(gconf_client_set_int, gboolean, (GConfClient*, const gchar*, gint, GError**)) \ |
|
29 FUNC(gconf_client_set_float, gboolean, (GConfClient*, const gchar*, gdouble, GError**)) \ |
|
30 FUNC(gconf_client_unset, gboolean, (GConfClient*, const gchar*, GError**)) |
|
31 |
|
32 #define FUNC(name, type, params) \ |
|
33 typedef type (*_##name##_fn) params; \ |
|
34 static _##name##_fn _##name; |
|
35 |
|
36 GCONF_FUNCTIONS |
|
37 |
|
38 #undef FUNC |
|
39 |
|
40 #define gconf_client_get_default _gconf_client_get_default |
|
41 #define gconf_client_get_bool _gconf_client_get_bool |
|
42 #define gconf_client_get_string _gconf_client_get_string |
|
43 #define gconf_client_get_int _gconf_client_get_int |
|
44 #define gconf_client_get_float _gconf_client_get_float |
|
45 #define gconf_client_get_list _gconf_client_get_list |
|
46 #define gconf_client_set_bool _gconf_client_set_bool |
|
47 #define gconf_client_set_string _gconf_client_set_string |
|
48 #define gconf_client_set_int _gconf_client_set_int |
|
49 #define gconf_client_set_float _gconf_client_set_float |
|
50 #define gconf_client_unset _gconf_client_unset |
|
51 |
|
52 static PRLibrary *gconfLib = nullptr; |
|
53 |
|
54 typedef void (*nsGConfFunc)(); |
|
55 struct nsGConfDynamicFunction { |
|
56 const char *functionName; |
|
57 nsGConfFunc *function; |
|
58 }; |
|
59 |
|
60 nsGConfService::~nsGConfService() |
|
61 { |
|
62 if (mClient) |
|
63 g_object_unref(mClient); |
|
64 |
|
65 // We don't unload gconf here because liborbit uses atexit(). In addition to |
|
66 // this, it's not a good idea to unload any gobject based library, as it |
|
67 // leaves types registered in glib's type system |
|
68 } |
|
69 |
|
70 nsresult |
|
71 nsGConfService::Init() |
|
72 { |
|
73 #define FUNC(name, type, params) { #name, (nsGConfFunc *)&_##name }, |
|
74 static const nsGConfDynamicFunction kGConfSymbols[] = { |
|
75 GCONF_FUNCTIONS |
|
76 }; |
|
77 #undef FUNC |
|
78 |
|
79 if (!gconfLib) { |
|
80 gconfLib = PR_LoadLibrary("libgconf-2.so.4"); |
|
81 if (!gconfLib) |
|
82 return NS_ERROR_FAILURE; |
|
83 } |
|
84 |
|
85 for (uint32_t i = 0; i < ArrayLength(kGConfSymbols); i++) { |
|
86 *kGConfSymbols[i].function = |
|
87 PR_FindFunctionSymbol(gconfLib, kGConfSymbols[i].functionName); |
|
88 if (!*kGConfSymbols[i].function) { |
|
89 return NS_ERROR_FAILURE; |
|
90 } |
|
91 } |
|
92 |
|
93 mClient = gconf_client_get_default(); |
|
94 return mClient ? NS_OK : NS_ERROR_FAILURE; |
|
95 } |
|
96 |
|
97 NS_IMPL_ISUPPORTS(nsGConfService, nsIGConfService) |
|
98 |
|
99 NS_IMETHODIMP |
|
100 nsGConfService::GetBool(const nsACString &aKey, bool *aResult) |
|
101 { |
|
102 GError* error = nullptr; |
|
103 *aResult = gconf_client_get_bool(mClient, PromiseFlatCString(aKey).get(), |
|
104 &error); |
|
105 |
|
106 if (error) { |
|
107 g_error_free(error); |
|
108 return NS_ERROR_FAILURE; |
|
109 } |
|
110 |
|
111 return NS_OK; |
|
112 } |
|
113 |
|
114 NS_IMETHODIMP |
|
115 nsGConfService::GetString(const nsACString &aKey, nsACString &aResult) |
|
116 { |
|
117 GError* error = nullptr; |
|
118 gchar *result = gconf_client_get_string(mClient, |
|
119 PromiseFlatCString(aKey).get(), |
|
120 &error); |
|
121 |
|
122 if (error) { |
|
123 g_error_free(error); |
|
124 return NS_ERROR_FAILURE; |
|
125 } |
|
126 |
|
127 // We do a string copy here so that the caller doesn't need to worry about |
|
128 // freeing the string with g_free(). |
|
129 |
|
130 aResult.Assign(result); |
|
131 g_free(result); |
|
132 |
|
133 return NS_OK; |
|
134 } |
|
135 |
|
136 NS_IMETHODIMP |
|
137 nsGConfService::GetInt(const nsACString &aKey, int32_t* aResult) |
|
138 { |
|
139 GError* error = nullptr; |
|
140 *aResult = gconf_client_get_int(mClient, PromiseFlatCString(aKey).get(), |
|
141 &error); |
|
142 |
|
143 if (error) { |
|
144 g_error_free(error); |
|
145 return NS_ERROR_FAILURE; |
|
146 } |
|
147 |
|
148 return NS_OK; |
|
149 } |
|
150 |
|
151 NS_IMETHODIMP |
|
152 nsGConfService::GetFloat(const nsACString &aKey, float* aResult) |
|
153 { |
|
154 GError* error = nullptr; |
|
155 *aResult = gconf_client_get_float(mClient, PromiseFlatCString(aKey).get(), |
|
156 &error); |
|
157 |
|
158 if (error) { |
|
159 g_error_free(error); |
|
160 return NS_ERROR_FAILURE; |
|
161 } |
|
162 |
|
163 return NS_OK; |
|
164 } |
|
165 |
|
166 NS_IMETHODIMP |
|
167 nsGConfService::GetStringList(const nsACString &aKey, nsIArray** aResult) |
|
168 { |
|
169 nsCOMPtr<nsIMutableArray> items(do_CreateInstance(NS_ARRAY_CONTRACTID)); |
|
170 if (!items) |
|
171 return NS_ERROR_OUT_OF_MEMORY; |
|
172 |
|
173 GError* error = nullptr; |
|
174 GSList* list = gconf_client_get_list(mClient, PromiseFlatCString(aKey).get(), |
|
175 GCONF_VALUE_STRING, &error); |
|
176 if (error) { |
|
177 g_error_free(error); |
|
178 return NS_ERROR_FAILURE; |
|
179 } |
|
180 |
|
181 for (GSList* l = list; l; l = l->next) { |
|
182 nsCOMPtr<nsISupportsString> obj(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID)); |
|
183 if (!obj) { |
|
184 g_slist_free(list); |
|
185 return NS_ERROR_OUT_OF_MEMORY; |
|
186 } |
|
187 obj->SetData(NS_ConvertUTF8toUTF16((const char*)l->data)); |
|
188 items->AppendElement(obj, false); |
|
189 g_free(l->data); |
|
190 } |
|
191 |
|
192 g_slist_free(list); |
|
193 NS_ADDREF(*aResult = items); |
|
194 return NS_OK; |
|
195 } |
|
196 |
|
197 NS_IMETHODIMP |
|
198 nsGConfService::SetBool(const nsACString &aKey, bool aValue) |
|
199 { |
|
200 bool res = gconf_client_set_bool(mClient, PromiseFlatCString(aKey).get(), |
|
201 aValue, nullptr); |
|
202 |
|
203 return res ? NS_OK : NS_ERROR_FAILURE; |
|
204 } |
|
205 |
|
206 NS_IMETHODIMP |
|
207 nsGConfService::SetString(const nsACString &aKey, const nsACString &aValue) |
|
208 { |
|
209 bool res = gconf_client_set_string(mClient, PromiseFlatCString(aKey).get(), |
|
210 PromiseFlatCString(aValue).get(), |
|
211 nullptr); |
|
212 |
|
213 return res ? NS_OK : NS_ERROR_FAILURE; |
|
214 } |
|
215 |
|
216 NS_IMETHODIMP |
|
217 nsGConfService::SetInt(const nsACString &aKey, int32_t aValue) |
|
218 { |
|
219 bool res = gconf_client_set_int(mClient, PromiseFlatCString(aKey).get(), |
|
220 aValue, nullptr); |
|
221 |
|
222 return res ? NS_OK : NS_ERROR_FAILURE; |
|
223 } |
|
224 |
|
225 NS_IMETHODIMP |
|
226 nsGConfService::SetFloat(const nsACString &aKey, float aValue) |
|
227 { |
|
228 bool res = gconf_client_set_float(mClient, PromiseFlatCString(aKey).get(), |
|
229 aValue, nullptr); |
|
230 |
|
231 return res ? NS_OK : NS_ERROR_FAILURE; |
|
232 } |
|
233 |
|
234 NS_IMETHODIMP |
|
235 nsGConfService::GetAppForProtocol(const nsACString &aScheme, bool *aEnabled, |
|
236 nsACString &aHandler) |
|
237 { |
|
238 nsAutoCString key("/desktop/gnome/url-handlers/"); |
|
239 key.Append(aScheme); |
|
240 key.Append("/command"); |
|
241 |
|
242 GError *err = nullptr; |
|
243 gchar *command = gconf_client_get_string(mClient, key.get(), &err); |
|
244 if (!err && command) { |
|
245 key.Replace(key.Length() - 7, 7, NS_LITERAL_CSTRING("enabled")); |
|
246 *aEnabled = gconf_client_get_bool(mClient, key.get(), &err); |
|
247 } else { |
|
248 *aEnabled = false; |
|
249 } |
|
250 |
|
251 aHandler.Assign(command); |
|
252 g_free(command); |
|
253 |
|
254 if (err) { |
|
255 g_error_free(err); |
|
256 return NS_ERROR_FAILURE; |
|
257 } |
|
258 |
|
259 return NS_OK; |
|
260 } |
|
261 |
|
262 NS_IMETHODIMP |
|
263 nsGConfService::HandlerRequiresTerminal(const nsACString &aScheme, |
|
264 bool *aResult) |
|
265 { |
|
266 nsAutoCString key("/desktop/gnome/url-handlers/"); |
|
267 key.Append(aScheme); |
|
268 key.Append("/requires_terminal"); |
|
269 |
|
270 GError *err = nullptr; |
|
271 *aResult = gconf_client_get_bool(mClient, key.get(), &err); |
|
272 if (err) { |
|
273 g_error_free(err); |
|
274 return NS_ERROR_FAILURE; |
|
275 } |
|
276 |
|
277 return NS_OK; |
|
278 } |
|
279 |
|
280 NS_IMETHODIMP |
|
281 nsGConfService::SetAppForProtocol(const nsACString &aScheme, |
|
282 const nsACString &aCommand) |
|
283 { |
|
284 nsAutoCString key("/desktop/gnome/url-handlers/"); |
|
285 key.Append(aScheme); |
|
286 key.Append("/command"); |
|
287 |
|
288 bool res = gconf_client_set_string(mClient, key.get(), |
|
289 PromiseFlatCString(aCommand).get(), |
|
290 nullptr); |
|
291 if (res) { |
|
292 key.Replace(key.Length() - 7, 7, NS_LITERAL_CSTRING("enabled")); |
|
293 res = gconf_client_set_bool(mClient, key.get(), true, nullptr); |
|
294 if (res) { |
|
295 key.Replace(key.Length() - 7, 7, NS_LITERAL_CSTRING("needs_terminal")); |
|
296 res = gconf_client_set_bool(mClient, key.get(), false, nullptr); |
|
297 if (res) { |
|
298 key.Replace(key.Length() - 14, 14, NS_LITERAL_CSTRING("command-id")); |
|
299 res = gconf_client_unset(mClient, key.get(), nullptr); |
|
300 } |
|
301 } |
|
302 } |
|
303 |
|
304 return res ? NS_OK : NS_ERROR_FAILURE; |
|
305 } |