2 * Copyright © 2011 William Hua
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.1 of the License, or (at your option) any later version.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 * Author: William Hua <william@attente.ca>
22 #include "gsettingsbackendinternal.h"
23 #include "gsimplepermission.h"
24 #include "giomodule.h"
26 #import <Foundation/Foundation.h>
28 GType g_nextstep_settings_backend_get_type (void);
30 #define G_NEXTSTEP_SETTINGS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), g_nextstep_settings_backend_get_type (), GNextstepSettingsBackend))
32 typedef struct _GNextstepSettingsBackend GNextstepSettingsBackend;
33 typedef GSettingsBackendClass GNextstepSettingsBackendClass;
35 struct _GNextstepSettingsBackend
37 GSettingsBackend parent_instance;
40 NSUserDefaults *user_defaults;
44 G_DEFINE_TYPE_WITH_CODE (GNextstepSettingsBackend,
45 g_nextstep_settings_backend,
46 G_TYPE_SETTINGS_BACKEND,
47 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
48 g_define_type_id, "nextstep", 90));
50 static void g_nextstep_settings_backend_finalize (GObject *backend);
52 static GVariant * g_nextstep_settings_backend_read (GSettingsBackend *backend,
54 const GVariantType *expected_type,
55 gboolean default_value);
57 static gboolean g_nextstep_settings_backend_get_writable (GSettingsBackend *backend,
60 static gboolean g_nextstep_settings_backend_write (GSettingsBackend *backend,
65 static gboolean g_nextstep_settings_backend_write_tree (GSettingsBackend *backend,
69 static void g_nextstep_settings_backend_reset (GSettingsBackend *backend,
73 static void g_nextstep_settings_backend_subscribe (GSettingsBackend *backend,
76 static void g_nextstep_settings_backend_unsubscribe (GSettingsBackend *backend,
79 static void g_nextstep_settings_backend_sync (GSettingsBackend *backend);
81 static GPermission * g_nextstep_settings_backend_get_permission (GSettingsBackend *backend,
84 static gboolean g_nextstep_settings_backend_write_pair (gpointer name,
88 static GVariant * g_nextstep_settings_backend_get_g_variant (id object,
89 const GVariantType *type);
91 static id g_nextstep_settings_backend_get_ns_object (GVariant *variant);
94 g_nextstep_settings_backend_class_init (GNextstepSettingsBackendClass *class)
96 G_OBJECT_CLASS (class)->finalize = g_nextstep_settings_backend_finalize;
97 class->read = g_nextstep_settings_backend_read;
98 class->get_writable = g_nextstep_settings_backend_get_writable;
99 class->write = g_nextstep_settings_backend_write;
100 class->write_tree = g_nextstep_settings_backend_write_tree;
101 class->reset = g_nextstep_settings_backend_reset;
102 class->subscribe = g_nextstep_settings_backend_subscribe;
103 class->unsubscribe = g_nextstep_settings_backend_unsubscribe;
104 class->sync = g_nextstep_settings_backend_sync;
105 class->get_permission = g_nextstep_settings_backend_get_permission;
109 g_nextstep_settings_backend_init (GNextstepSettingsBackend *self)
111 NSAutoreleasePool *pool;
113 pool = [[NSAutoreleasePool alloc] init];
115 self->user_defaults = [[NSUserDefaults standardUserDefaults] retain];
117 g_mutex_init (&self->mutex);
123 g_nextstep_settings_backend_finalize (GObject *self)
125 GNextstepSettingsBackend *backend = G_NEXTSTEP_SETTINGS_BACKEND (self);
126 NSAutoreleasePool *pool;
128 pool = [[NSAutoreleasePool alloc] init];
130 g_mutex_clear (&backend->mutex);
132 [backend->user_defaults release];
136 G_OBJECT_CLASS (g_nextstep_settings_backend_parent_class)->finalize (self);
140 g_nextstep_settings_backend_read (GSettingsBackend *backend,
142 const GVariantType *expected_type,
143 gboolean default_value)
145 GNextstepSettingsBackend *self = G_NEXTSTEP_SETTINGS_BACKEND (backend);
146 NSAutoreleasePool *pool;
154 pool = [[NSAutoreleasePool alloc] init];
155 name = [NSString stringWithUTF8String:key];
157 g_mutex_lock (&self->mutex);
158 value = [self->user_defaults objectForKey:name];
159 g_mutex_unlock (&self->mutex);
161 variant = g_nextstep_settings_backend_get_g_variant (value, expected_type);
169 g_nextstep_settings_backend_get_writable (GSettingsBackend *backend,
176 g_nextstep_settings_backend_write (GSettingsBackend *backend,
181 GNextstepSettingsBackend *self = G_NEXTSTEP_SETTINGS_BACKEND (backend);
182 NSAutoreleasePool *pool;
184 pool = [[NSAutoreleasePool alloc] init];
186 g_mutex_lock (&self->mutex);
187 g_nextstep_settings_backend_write_pair ((gpointer) key, value, self);
188 g_mutex_unlock (&self->mutex);
190 g_settings_backend_changed (backend, key, origin_tag);
198 g_nextstep_settings_backend_write_tree (GSettingsBackend *backend,
202 GNextstepSettingsBackend *self = G_NEXTSTEP_SETTINGS_BACKEND (backend);
203 NSAutoreleasePool *pool;
205 pool = [[NSAutoreleasePool alloc] init];
207 g_mutex_lock (&self->mutex);
208 g_tree_foreach (tree, g_nextstep_settings_backend_write_pair, self);
209 g_mutex_unlock (&self->mutex);
210 g_settings_backend_changed_tree (backend, tree, origin_tag);
218 g_nextstep_settings_backend_reset (GSettingsBackend *backend,
222 GNextstepSettingsBackend *self = G_NEXTSTEP_SETTINGS_BACKEND (backend);
223 NSAutoreleasePool *pool;
226 pool = [[NSAutoreleasePool alloc] init];
227 name = [NSString stringWithUTF8String:key];
229 g_mutex_lock (&self->mutex);
230 [self->user_defaults removeObjectForKey:name];
231 g_mutex_unlock (&self->mutex);
233 g_settings_backend_changed (backend, key, origin_tag);
239 g_nextstep_settings_backend_subscribe (GSettingsBackend *backend,
245 g_nextstep_settings_backend_unsubscribe (GSettingsBackend *backend,
251 g_nextstep_settings_backend_sync (GSettingsBackend *backend)
253 GNextstepSettingsBackend *self = G_NEXTSTEP_SETTINGS_BACKEND (backend);
254 NSAutoreleasePool *pool;
256 pool = [[NSAutoreleasePool alloc] init];
258 g_mutex_lock (&self->mutex);
259 [self->user_defaults synchronize];
260 g_mutex_unlock (&self->mutex);
266 g_nextstep_settings_backend_get_permission (GSettingsBackend *backend,
269 return g_simple_permission_new (TRUE);
273 g_nextstep_settings_backend_write_pair (gpointer name,
277 GNextstepSettingsBackend *backend = G_NEXTSTEP_SETTINGS_BACKEND (data);
281 key = [NSString stringWithUTF8String:name];
282 object = g_nextstep_settings_backend_get_ns_object (value);
284 [backend->user_defaults setObject:object forKey:key];
290 g_nextstep_settings_backend_get_g_variant (id object,
291 const GVariantType *type)
293 if ([object isKindOfClass:[NSData class]])
294 return g_variant_parse (type, [[[[NSString alloc] initWithData:object encoding:NSUTF8StringEncoding] autorelease] UTF8String], NULL, NULL, NULL);
295 else if ([object isKindOfClass:[NSNumber class]])
297 if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
298 return g_variant_new_boolean ([object boolValue]);
299 else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
300 return g_variant_new_byte ([object unsignedCharValue]);
301 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
302 return g_variant_new_int16 ([object shortValue]);
303 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
304 return g_variant_new_uint16 ([object unsignedShortValue]);
305 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
306 return g_variant_new_int32 ([object longValue]);
307 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
308 return g_variant_new_uint32 ([object unsignedLongValue]);
309 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
310 return g_variant_new_int64 ([object longLongValue]);
311 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
312 return g_variant_new_uint64 ([object unsignedLongLongValue]);
313 else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
314 return g_variant_new_handle ([object longValue]);
315 else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
316 return g_variant_new_double ([object doubleValue]);
318 else if ([object isKindOfClass:[NSString class]])
322 string = [object UTF8String];
324 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
325 return g_variant_new_string (string);
326 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
327 return g_variant_is_object_path (string) ?
328 g_variant_new_object_path (string) : NULL;
329 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
330 return g_variant_is_signature (string) ?
331 g_variant_new_signature (string) : NULL;
333 else if ([object isKindOfClass:[NSDictionary class]])
335 if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE ("a{s*}")))
337 const GVariantType *value_type;
338 GVariantBuilder builder;
341 value_type = g_variant_type_value (g_variant_type_element (type));
343 g_variant_builder_init (&builder, type);
345 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
348 NSEnumerator *enumerator = [object objectEnumerator];
349 while((key = [enumerator nextObject]))
357 name = g_variant_new_string ([key UTF8String]);
358 value = [object objectForKey:key];
359 variant = g_nextstep_settings_backend_get_g_variant (value, value_type);
363 g_variant_builder_clear (&builder);
368 entry = g_variant_new_dict_entry (name, variant);
369 g_variant_builder_add_value (&builder, entry);
372 return g_variant_builder_end (&builder);
375 else if ([object isKindOfClass:[NSArray class]])
377 if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_ARRAY))
379 const GVariantType *value_type;
380 GVariantBuilder builder;
383 value_type = g_variant_type_element (type);
384 g_variant_builder_init (&builder, type);
386 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
389 NSEnumerator *enumerator = [object objectEnumerator];
390 while((value = [enumerator nextObject]))
393 GVariant *variant = g_nextstep_settings_backend_get_g_variant (value, value_type);
397 g_variant_builder_clear (&builder);
402 g_variant_builder_add_value (&builder, variant);
405 return g_variant_builder_end (&builder);
413 g_nextstep_settings_backend_get_ns_object (GVariant *variant)
417 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
418 return [NSNumber numberWithBool:g_variant_get_boolean (variant)];
419 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
420 return [NSNumber numberWithUnsignedChar:g_variant_get_byte (variant)];
421 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16))
422 return [NSNumber numberWithShort:g_variant_get_int16 (variant)];
423 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16))
424 return [NSNumber numberWithUnsignedShort:g_variant_get_uint16 (variant)];
425 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32))
426 return [NSNumber numberWithLong:g_variant_get_int32 (variant)];
427 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32))
428 return [NSNumber numberWithUnsignedLong:g_variant_get_uint32 (variant)];
429 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64))
430 return [NSNumber numberWithLongLong:g_variant_get_int64 (variant)];
431 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64))
432 return [NSNumber numberWithUnsignedLongLong:g_variant_get_uint64 (variant)];
433 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
434 return [NSNumber numberWithLong:g_variant_get_handle (variant)];
435 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
436 return [NSNumber numberWithDouble:g_variant_get_double (variant)];
437 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING))
438 return [NSString stringWithUTF8String:g_variant_get_string (variant, NULL)];
439 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH))
440 return [NSString stringWithUTF8String:g_variant_get_string (variant, NULL)];
441 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
442 return [NSString stringWithUTF8String:g_variant_get_string (variant, NULL)];
443 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE ("a{s*}")))
445 NSMutableDictionary *dictionary;
450 dictionary = [NSMutableDictionary dictionaryWithCapacity:g_variant_iter_init (&iter, variant)];
452 while (g_variant_iter_loop (&iter, "{s*}", &name, &value))
457 key = [NSString stringWithUTF8String:g_variant_get_string (name, NULL)];
458 object = g_nextstep_settings_backend_get_ns_object (value);
460 [dictionary setObject:object forKey:key];
465 else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_ARRAY))
467 NSMutableArray *array;
471 array = [NSMutableArray arrayWithCapacity:g_variant_iter_init (&iter, variant)];
473 while ((value = g_variant_iter_next_value (&iter)) != NULL)
474 [array addObject:g_nextstep_settings_backend_get_ns_object (value)];
479 return [[NSString stringWithUTF8String:g_variant_print (variant, TRUE)] dataUsingEncoding:NSUTF8StringEncoding];