GSettings: nextstep settings backend
[platform/upstream/glib.git] / gio / gnextstepsettingsbackend.c
1 /*
2  * Copyright © 2011 William Hua
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: William Hua <william@attente.ca>
20  */
21
22
23
24 #include "gsettingsbackendinternal.h"
25 #include "gsimplepermission.h"
26 #include "giomodule.h"
27
28
29
30 #import <Foundation/Foundation.h>
31
32
33
34 #define G_NEXTSTEP_SETTINGS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), g_nextstep_settings_backend_get_type (), GNextstepSettingsBackend))
35
36
37
38 typedef struct _GNextstepSettingsBackend GNextstepSettingsBackend;
39 typedef GSettingsBackendClass            GNextstepSettingsBackendClass;
40
41
42
43 struct _GNextstepSettingsBackend
44 {
45   GSettingsBackend  parent_instance;
46
47   /*< private >*/
48   NSUserDefaults   *user_defaults;
49 };
50
51
52
53 G_DEFINE_TYPE_WITH_CODE (GNextstepSettingsBackend,
54                          g_nextstep_settings_backend,
55                          G_TYPE_SETTINGS_BACKEND,
56                          g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
57                                                          g_define_type_id, "nextstep", 90));
58
59
60
61 static void          g_nextstep_settings_backend_finalize       (GObject            *backend);
62
63 static GVariant *    g_nextstep_settings_backend_read           (GSettingsBackend   *backend,
64                                                                  const gchar        *key,
65                                                                  const GVariantType *expected_type,
66                                                                  gboolean            default_value);
67
68 static gboolean      g_nextstep_settings_backend_get_writable   (GSettingsBackend   *backend,
69                                                                  const gchar        *key);
70
71 static gboolean      g_nextstep_settings_backend_write          (GSettingsBackend   *backend,
72                                                                  const gchar        *key,
73                                                                  GVariant           *value,
74                                                                  gpointer            origin_tag);
75
76 static gboolean      g_nextstep_settings_backend_write_tree     (GSettingsBackend   *backend,
77                                                                  GTree              *tree,
78                                                                  gpointer            origin_tag);
79
80 static void          g_nextstep_settings_backend_reset          (GSettingsBackend   *backend,
81                                                                  const gchar        *key,
82                                                                  gpointer            origin_tag);
83
84 static void          g_nextstep_settings_backend_subscribe      (GSettingsBackend   *backend,
85                                                                  const gchar        *name);
86
87 static void          g_nextstep_settings_backend_unsubscribe    (GSettingsBackend   *backend,
88                                                                  const gchar        *name);
89
90 static void          g_nextstep_settings_backend_sync           (GSettingsBackend   *backend);
91
92 static GPermission * g_nextstep_settings_backend_get_permission (GSettingsBackend   *backend,
93                                                                  const gchar        *path);
94
95 static gboolean      g_nextstep_settings_backend_write_pair     (gpointer            name,
96                                                                  gpointer            value,
97                                                                  gpointer            data);
98
99 static GVariant *    g_nextstep_settings_backend_get_g_variant  (id                  object,
100                                                                  const GVariantType *type);
101
102 static id            g_nextstep_settings_backend_get_ns_object  (GVariant           *variant);
103
104
105
106 static void
107 g_nextstep_settings_backend_class_init (GNextstepSettingsBackendClass *class)
108 {
109   G_OBJECT_CLASS (class)->finalize = g_nextstep_settings_backend_finalize;
110   class->read                      = g_nextstep_settings_backend_read;
111   class->get_writable              = g_nextstep_settings_backend_get_writable;
112   class->write                     = g_nextstep_settings_backend_write;
113   class->write_tree                = g_nextstep_settings_backend_write_tree;
114   class->reset                     = g_nextstep_settings_backend_reset;
115   class->subscribe                 = g_nextstep_settings_backend_subscribe;
116   class->unsubscribe               = g_nextstep_settings_backend_unsubscribe;
117   class->sync                      = g_nextstep_settings_backend_sync;
118   class->get_permission            = g_nextstep_settings_backend_get_permission;
119 }
120
121
122
123 static void
124 g_nextstep_settings_backend_init (GNextstepSettingsBackend *self)
125 {
126   NSAutoreleasePool *pool;
127
128   pool = [[NSAutoreleasePool alloc] init];
129
130   self->user_defaults = [[NSUserDefaults standardUserDefaults] retain];
131
132   [pool drain];
133 }
134
135
136
137 static void
138 g_nextstep_settings_backend_finalize (GObject *self)
139 {
140   NSAutoreleasePool *pool;
141
142   pool = [[NSAutoreleasePool alloc] init];
143
144   [G_NEXTSTEP_SETTINGS_BACKEND (self)->user_defaults release];
145
146   [pool drain];
147
148   G_OBJECT_CLASS (g_nextstep_settings_backend_parent_class)->finalize (self);
149 }
150
151
152
153 static GVariant *
154 g_nextstep_settings_backend_read (GSettingsBackend   *backend,
155                                   const gchar        *key,
156                                   const GVariantType *expected_type,
157                                   gboolean            default_value)
158 {
159   NSAutoreleasePool *pool;
160   NSString          *name;
161   id                 value;
162   GVariant          *variant;
163
164   if (default_value)
165     return NULL;
166
167   pool    = [[NSAutoreleasePool alloc] init];
168   name    = [NSString stringWithUTF8String:key];
169   value   = [G_NEXTSTEP_SETTINGS_BACKEND (backend)->user_defaults objectForKey:name];
170   variant = g_nextstep_settings_backend_get_g_variant (value, expected_type);
171
172   [pool drain];
173
174   return variant;
175 }
176
177
178
179 static gboolean
180 g_nextstep_settings_backend_get_writable (GSettingsBackend *backend,
181                                           const gchar      *key)
182 {
183   return TRUE;
184 }
185
186
187
188 static gboolean
189 g_nextstep_settings_backend_write (GSettingsBackend *backend,
190                                    const gchar      *key,
191                                    GVariant         *value,
192                                    gpointer          origin_tag)
193 {
194   NSAutoreleasePool *pool;
195
196   pool = [[NSAutoreleasePool alloc] init];
197
198   g_nextstep_settings_backend_write_pair ((gpointer) key, value, backend);
199   g_settings_backend_changed (backend, key, origin_tag);
200
201   [pool drain];
202
203   return TRUE;
204 }
205
206
207
208 static gboolean
209 g_nextstep_settings_backend_write_tree (GSettingsBackend *backend,
210                                         GTree            *tree,
211                                         gpointer          origin_tag)
212 {
213   NSAutoreleasePool *pool;
214
215   pool = [[NSAutoreleasePool alloc] init];
216
217   g_tree_foreach (tree, g_nextstep_settings_backend_write_pair, backend);
218   g_settings_backend_changed_tree (backend, tree, origin_tag);
219
220   [pool drain];
221
222   return TRUE;
223 }
224
225
226
227 static void
228 g_nextstep_settings_backend_reset (GSettingsBackend *backend,
229                                    const gchar      *key,
230                                    gpointer          origin_tag)
231 {
232   NSAutoreleasePool *pool;
233   NSUserDefaults    *user_defaults;
234   NSString          *name;
235   id                 value;
236   id                 default_value;
237
238   pool          = [[NSAutoreleasePool alloc] init];
239   user_defaults = G_NEXTSTEP_SETTINGS_BACKEND (backend)->user_defaults;
240   name          = [NSString stringWithUTF8String:key];
241   value         = [user_defaults objectForKey:name];
242
243   [user_defaults removeObjectForKey:name];
244
245   default_value = [user_defaults objectForKey:name];
246
247   if (default_value != value && ![default_value isEqual:value])
248     g_settings_backend_changed (backend, key, origin_tag);
249
250   [pool drain];
251 }
252
253
254
255 static void
256 g_nextstep_settings_backend_subscribe (GSettingsBackend *backend,
257                                        const gchar      *name)
258 {
259 }
260
261
262
263 static void
264 g_nextstep_settings_backend_unsubscribe (GSettingsBackend *backend,
265                                          const gchar      *name)
266 {
267 }
268
269
270
271 static void
272 g_nextstep_settings_backend_sync (GSettingsBackend *backend)
273 {
274   NSAutoreleasePool *pool;
275
276   pool = [[NSAutoreleasePool alloc] init];
277
278   [G_NEXTSTEP_SETTINGS_BACKEND (backend)->user_defaults synchronize];
279
280   [pool drain];
281 }
282
283
284
285 static GPermission *
286 g_nextstep_settings_backend_get_permission (GSettingsBackend *backend,
287                                             const gchar      *path)
288 {
289   return g_simple_permission_new (TRUE);
290 }
291
292
293
294 static gboolean
295 g_nextstep_settings_backend_write_pair (gpointer name,
296                                         gpointer value,
297                                         gpointer data)
298 {
299   GNextstepSettingsBackend *backend;
300   NSString                 *key;
301   id                        object;
302
303   backend = G_NEXTSTEP_SETTINGS_BACKEND (data);
304   key     = [NSString stringWithUTF8String:name];
305   object  = g_nextstep_settings_backend_get_ns_object (value);
306
307   [backend->user_defaults setObject:object forKey:key];
308
309   return FALSE;
310 }
311
312
313
314 static GVariant *
315 g_nextstep_settings_backend_get_g_variant (id                  object,
316                                            const GVariantType *type)
317 {
318   if ([object isKindOfClass:[NSData class]])
319     return g_variant_parse (type, [[[[NSString alloc] initWithData:object encoding:NSUTF8StringEncoding] autorelease] UTF8String], NULL, NULL, NULL);
320   else if ([object isKindOfClass:[NSNumber class]])
321     {
322       if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
323         return g_variant_new_boolean ([object boolValue]);
324       else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
325         return g_variant_new_byte ([object unsignedCharValue]);
326       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
327         return g_variant_new_int16 ([object shortValue]);
328       else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
329         return g_variant_new_uint16 ([object unsignedShortValue]);
330       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
331         return g_variant_new_int32 ([object longValue]);
332       else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
333         return g_variant_new_uint32 ([object unsignedLongValue]);
334       else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
335         return g_variant_new_int64 ([object longLongValue]);
336       else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
337         return g_variant_new_uint64 ([object unsignedLongLongValue]);
338       else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
339         return g_variant_new_handle ([object longValue]);
340       else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
341         return g_variant_new_double ([object doubleValue]);
342     }
343   else if ([object isKindOfClass:[NSString class]])
344     {
345       const char *string;
346
347       string = [object UTF8String];
348
349       if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
350         return g_variant_new_string (string);
351       else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
352         return g_variant_is_object_path  (string) ?
353                g_variant_new_object_path (string) : NULL;
354       else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
355         return g_variant_is_signature  (string) ?
356                g_variant_new_signature (string) : NULL;
357     }
358   else if ([object isKindOfClass:[NSDictionary class]])
359     {
360       if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE ("a{s*}")))
361         {
362           const GVariantType *value_type;
363           GVariantBuilder     builder;
364           NSString           *key;
365
366           value_type = g_variant_type_value (g_variant_type_element (type));
367
368           g_variant_builder_init (&builder, type);
369
370           for (key in object)
371             {
372               GVariant *name;
373               id        value;
374               GVariant *variant;
375               GVariant *entry;
376
377               name    = g_variant_new_string ([key UTF8String]);
378               value   = [object objectForKey:key];
379               variant = g_nextstep_settings_backend_get_g_variant (value, value_type);
380
381               if (variant == NULL)
382                 {
383                   g_variant_builder_clear (&builder);
384
385                   return NULL;
386                 }
387
388               entry = g_variant_new_dict_entry (name, variant);
389               g_variant_builder_add_value (&builder, entry);
390             }
391
392           return g_variant_builder_end (&builder);
393         }
394     }
395   else if ([object isKindOfClass:[NSArray class]])
396     {
397       if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_ARRAY))
398         {
399           const GVariantType *value_type;
400           GVariantBuilder     builder;
401           id                  value;
402
403           value_type = g_variant_type_element (type);
404           g_variant_builder_init (&builder, type);
405
406           for (value in object)
407             {
408               GVariant *variant = g_nextstep_settings_backend_get_g_variant (value, value_type);
409
410               if (variant == NULL)
411                 {
412                   g_variant_builder_clear (&builder);
413
414                   return NULL;
415                 }
416
417               g_variant_builder_add_value (&builder, variant);
418             }
419
420           return g_variant_builder_end (&builder);
421         }
422     }
423
424   return NULL;
425 }
426
427
428
429 static id
430 g_nextstep_settings_backend_get_ns_object (GVariant *variant)
431 {
432   if (variant == NULL)
433     return nil;
434   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
435     return [NSNumber numberWithBool:g_variant_get_boolean (variant)];
436   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
437     return [NSNumber numberWithUnsignedChar:g_variant_get_byte (variant)];
438   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16))
439     return [NSNumber numberWithShort:g_variant_get_int16 (variant)];
440   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16))
441     return [NSNumber numberWithUnsignedShort:g_variant_get_uint16 (variant)];
442   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32))
443     return [NSNumber numberWithLong:g_variant_get_int32 (variant)];
444   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
445     return [NSNumber numberWithUnsignedLong:g_variant_get_uint32 (variant)];
446   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64))
447     return [NSNumber numberWithLongLong:g_variant_get_int64 (variant)];
448   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64))
449     return [NSNumber numberWithUnsignedLongLong:g_variant_get_uint64 (variant)];
450   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
451     return [NSNumber numberWithLong:g_variant_get_handle (variant)];
452   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
453     return [NSNumber numberWithDouble:g_variant_get_double (variant)];
454   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING))
455     return [NSString stringWithUTF8String:g_variant_get_string (variant, NULL)];
456   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH))
457     return [NSString stringWithUTF8String:g_variant_get_string (variant, NULL)];
458   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
459     return [NSString stringWithUTF8String:g_variant_get_string (variant, NULL)];
460   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("a{s*}")))
461     {
462       NSMutableDictionary *dictionary;
463       GVariantIter         iter;
464       GVariant            *name;
465       GVariant            *value;
466
467       dictionary = [NSMutableDictionary dictionaryWithCapacity:g_variant_iter_init (&iter, variant)];
468
469       while (g_variant_iter_loop (&iter, "{s*}", &name, &value))
470         {
471           NSString *key;
472           id        object;
473
474           key    = [NSString stringWithUTF8String:g_variant_get_string (name, NULL)];
475           object = g_nextstep_settings_backend_get_ns_object (value);
476
477           [dictionary setObject:object forKey:key];
478         }
479
480       return dictionary;
481     }
482   else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_ARRAY))
483     {
484       NSMutableArray *array;
485       GVariantIter    iter;
486       GVariant       *value;
487
488       array = [NSMutableArray arrayWithCapacity:g_variant_iter_init (&iter, variant)];
489
490       while ((value = g_variant_iter_next_value (&iter)) != NULL)
491         [array addObject:g_nextstep_settings_backend_get_ns_object (value)];
492
493       return array;
494     }
495   else
496     return [[NSString stringWithUTF8String:g_variant_print (variant, TRUE)] dataUsingEncoding:NSUTF8StringEncoding];
497 }