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 of the licence, 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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: William Hua <william@attente.ca>
24 #include "gsettingsbackendinternal.h"
25 #include "gsimplepermission.h"
26 #include "giomodule.h"
28 #import <Foundation/Foundation.h>
30 GType
g_nextstep_settings_backend_get_type (void);
32 #define G_NEXTSTEP_SETTINGS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), g_nextstep_settings_backend_get_type (), GNextstepSettingsBackend))
34 typedef struct _GNextstepSettingsBackend GNextstepSettingsBackend
;
35 typedef GSettingsBackendClass GNextstepSettingsBackendClass
;
37 struct _GNextstepSettingsBackend
39 GSettingsBackend parent_instance
;
42 NSUserDefaults
*user_defaults
;
46 G_DEFINE_TYPE_WITH_CODE (GNextstepSettingsBackend
,
47 g_nextstep_settings_backend
,
48 G_TYPE_SETTINGS_BACKEND
,
49 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME
,
50 g_define_type_id
, "nextstep", 90));
52 static void g_nextstep_settings_backend_finalize (GObject
*backend
);
54 static GVariant
* g_nextstep_settings_backend_read (GSettingsBackend
*backend
,
56 const GVariantType
*expected_type
,
57 gboolean default_value
);
59 static gboolean
g_nextstep_settings_backend_get_writable (GSettingsBackend
*backend
,
62 static gboolean
g_nextstep_settings_backend_write (GSettingsBackend
*backend
,
67 static gboolean
g_nextstep_settings_backend_write_tree (GSettingsBackend
*backend
,
71 static void g_nextstep_settings_backend_reset (GSettingsBackend
*backend
,
75 static void g_nextstep_settings_backend_subscribe (GSettingsBackend
*backend
,
78 static void g_nextstep_settings_backend_unsubscribe (GSettingsBackend
*backend
,
81 static void g_nextstep_settings_backend_sync (GSettingsBackend
*backend
);
83 static GPermission
* g_nextstep_settings_backend_get_permission (GSettingsBackend
*backend
,
86 static gboolean
g_nextstep_settings_backend_write_pair (gpointer name
,
90 static GVariant
* g_nextstep_settings_backend_get_g_variant (id object
,
91 const GVariantType
*type
);
93 static id
g_nextstep_settings_backend_get_ns_object (GVariant
*variant
);
96 g_nextstep_settings_backend_class_init (GNextstepSettingsBackendClass
*class)
98 G_OBJECT_CLASS (class)->finalize
= g_nextstep_settings_backend_finalize
;
99 class->read
= g_nextstep_settings_backend_read
;
100 class->get_writable
= g_nextstep_settings_backend_get_writable
;
101 class->write
= g_nextstep_settings_backend_write
;
102 class->write_tree
= g_nextstep_settings_backend_write_tree
;
103 class->reset
= g_nextstep_settings_backend_reset
;
104 class->subscribe
= g_nextstep_settings_backend_subscribe
;
105 class->unsubscribe
= g_nextstep_settings_backend_unsubscribe
;
106 class->sync
= g_nextstep_settings_backend_sync
;
107 class->get_permission
= g_nextstep_settings_backend_get_permission
;
111 g_nextstep_settings_backend_init (GNextstepSettingsBackend
*self
)
113 NSAutoreleasePool
*pool
;
115 pool
= [[NSAutoreleasePool alloc
] init
];
117 self
->user_defaults
= [[NSUserDefaults standardUserDefaults
] retain
];
119 g_mutex_init (&self
->mutex
);
125 g_nextstep_settings_backend_finalize (GObject
*self
)
127 GNextstepSettingsBackend
*backend
= G_NEXTSTEP_SETTINGS_BACKEND (self
);
128 NSAutoreleasePool
*pool
;
130 pool
= [[NSAutoreleasePool alloc
] init
];
132 g_mutex_clear (&backend
->mutex
);
134 [backend
->user_defaults release
];
138 G_OBJECT_CLASS (g_nextstep_settings_backend_parent_class
)->finalize (self
);
142 g_nextstep_settings_backend_read (GSettingsBackend
*backend
,
144 const GVariantType
*expected_type
,
145 gboolean default_value
)
147 GNextstepSettingsBackend
*self
= G_NEXTSTEP_SETTINGS_BACKEND (backend
);
148 NSAutoreleasePool
*pool
;
156 pool
= [[NSAutoreleasePool alloc
] init
];
157 name
= [NSString stringWithUTF8String
:key
];
159 g_mutex_lock (&self
->mutex
);
160 value
= [self
->user_defaults objectForKey
:name
];
161 g_mutex_unlock (&self
->mutex
);
163 variant
= g_nextstep_settings_backend_get_g_variant (value
, expected_type
);
171 g_nextstep_settings_backend_get_writable (GSettingsBackend
*backend
,
178 g_nextstep_settings_backend_write (GSettingsBackend
*backend
,
183 GNextstepSettingsBackend
*self
= G_NEXTSTEP_SETTINGS_BACKEND (backend
);
184 NSAutoreleasePool
*pool
;
186 pool
= [[NSAutoreleasePool alloc
] init
];
188 g_mutex_lock (&self
->mutex
);
189 g_nextstep_settings_backend_write_pair ((gpointer
) key
, value
, self
);
190 g_mutex_unlock (&self
->mutex
);
192 g_settings_backend_changed (backend
, key
, origin_tag
);
200 g_nextstep_settings_backend_write_tree (GSettingsBackend
*backend
,
204 GNextstepSettingsBackend
*self
= G_NEXTSTEP_SETTINGS_BACKEND (backend
);
205 NSAutoreleasePool
*pool
;
207 pool
= [[NSAutoreleasePool alloc
] init
];
209 g_mutex_lock (&self
->mutex
);
210 g_tree_foreach (tree
, g_nextstep_settings_backend_write_pair
, self
);
211 g_mutex_unlock (&self
->mutex
);
212 g_settings_backend_changed_tree (backend
, tree
, origin_tag
);
220 g_nextstep_settings_backend_reset (GSettingsBackend
*backend
,
224 GNextstepSettingsBackend
*self
= G_NEXTSTEP_SETTINGS_BACKEND (backend
);
225 NSAutoreleasePool
*pool
;
228 pool
= [[NSAutoreleasePool alloc
] init
];
229 name
= [NSString stringWithUTF8String
:key
];
231 g_mutex_lock (&self
->mutex
);
232 [self
->user_defaults removeObjectForKey
:name
];
233 g_mutex_unlock (&self
->mutex
);
235 g_settings_backend_changed (backend
, key
, origin_tag
);
241 g_nextstep_settings_backend_subscribe (GSettingsBackend
*backend
,
247 g_nextstep_settings_backend_unsubscribe (GSettingsBackend
*backend
,
253 g_nextstep_settings_backend_sync (GSettingsBackend
*backend
)
255 GNextstepSettingsBackend
*self
= G_NEXTSTEP_SETTINGS_BACKEND (backend
);
256 NSAutoreleasePool
*pool
;
258 pool
= [[NSAutoreleasePool alloc
] init
];
260 g_mutex_lock (&self
->mutex
);
261 [self
->user_defaults synchronize
];
262 g_mutex_unlock (&self
->mutex
);
268 g_nextstep_settings_backend_get_permission (GSettingsBackend
*backend
,
271 return g_simple_permission_new (TRUE
);
275 g_nextstep_settings_backend_write_pair (gpointer name
,
279 GNextstepSettingsBackend
*backend
= G_NEXTSTEP_SETTINGS_BACKEND (data
);
283 key
= [NSString stringWithUTF8String
:name
];
284 object
= g_nextstep_settings_backend_get_ns_object (value
);
286 [backend
->user_defaults setObject
:object forKey
:key
];
292 g_nextstep_settings_backend_get_g_variant (id object
,
293 const GVariantType
*type
)
295 if ([object isKindOfClass
:[NSData
class]])
296 return g_variant_parse (type
, [[[[NSString alloc
] initWithData
:object encoding
:NSUTF8StringEncoding
] autorelease
] UTF8String
], NULL
, NULL
, NULL
);
297 else if ([object isKindOfClass
:[NSNumber
class]])
299 if (g_variant_type_equal (type
, G_VARIANT_TYPE_BOOLEAN
))
300 return g_variant_new_boolean ([object boolValue
]);
301 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_BYTE
))
302 return g_variant_new_byte ([object unsignedCharValue
]);
303 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_INT16
))
304 return g_variant_new_int16 ([object shortValue
]);
305 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_UINT16
))
306 return g_variant_new_uint16 ([object unsignedShortValue
]);
307 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_INT32
))
308 return g_variant_new_int32 ([object longValue
]);
309 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_UINT32
))
310 return g_variant_new_uint32 ([object unsignedLongValue
]);
311 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_INT64
))
312 return g_variant_new_int64 ([object longLongValue
]);
313 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_UINT64
))
314 return g_variant_new_uint64 ([object unsignedLongLongValue
]);
315 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_HANDLE
))
316 return g_variant_new_handle ([object longValue
]);
317 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_DOUBLE
))
318 return g_variant_new_double ([object doubleValue
]);
320 else if ([object isKindOfClass
:[NSString
class]])
324 string
= [object UTF8String
];
326 if (g_variant_type_equal (type
, G_VARIANT_TYPE_STRING
))
327 return g_variant_new_string (string
);
328 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_OBJECT_PATH
))
329 return g_variant_is_object_path (string
) ?
330 g_variant_new_object_path (string
) : NULL
;
331 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_SIGNATURE
))
332 return g_variant_is_signature (string
) ?
333 g_variant_new_signature (string
) : NULL
;
335 else if ([object isKindOfClass
:[NSDictionary
class]])
337 if (g_variant_type_is_subtype_of (type
, G_VARIANT_TYPE ("a{s*}")))
339 const GVariantType
*value_type
;
340 GVariantBuilder builder
;
343 value_type
= g_variant_type_value (g_variant_type_element (type
));
345 g_variant_builder_init (&builder
, type
);
347 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
350 NSEnumerator
*enumerator
= [object objectEnumerator
];
351 while((key
= [enumerator nextObject
]))
359 name
= g_variant_new_string ([key UTF8String
]);
360 value
= [object objectForKey
:key
];
361 variant
= g_nextstep_settings_backend_get_g_variant (value
, value_type
);
365 g_variant_builder_clear (&builder
);
370 entry
= g_variant_new_dict_entry (name
, variant
);
371 g_variant_builder_add_value (&builder
, entry
);
374 return g_variant_builder_end (&builder
);
377 else if ([object isKindOfClass
:[NSArray
class]])
379 if (g_variant_type_is_subtype_of (type
, G_VARIANT_TYPE_ARRAY
))
381 const GVariantType
*value_type
;
382 GVariantBuilder builder
;
385 value_type
= g_variant_type_element (type
);
386 g_variant_builder_init (&builder
, type
);
388 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
391 NSEnumerator
*enumerator
= [object objectEnumerator
];
392 while((value
= [enumerator nextObject
]))
395 GVariant
*variant
= g_nextstep_settings_backend_get_g_variant (value
, value_type
);
399 g_variant_builder_clear (&builder
);
404 g_variant_builder_add_value (&builder
, variant
);
407 return g_variant_builder_end (&builder
);
415 g_nextstep_settings_backend_get_ns_object (GVariant
*variant
)
419 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_BOOLEAN
))
420 return [NSNumber numberWithBool
:g_variant_get_boolean (variant
)];
421 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_BYTE
))
422 return [NSNumber numberWithUnsignedChar
:g_variant_get_byte (variant
)];
423 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_INT16
))
424 return [NSNumber numberWithShort
:g_variant_get_int16 (variant
)];
425 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_UINT16
))
426 return [NSNumber numberWithUnsignedShort
:g_variant_get_uint16 (variant
)];
427 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_INT32
))
428 return [NSNumber numberWithLong
:g_variant_get_int32 (variant
)];
429 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_UINT32
))
430 return [NSNumber numberWithUnsignedLong
:g_variant_get_uint32 (variant
)];
431 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_INT64
))
432 return [NSNumber numberWithLongLong
:g_variant_get_int64 (variant
)];
433 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_UINT64
))
434 return [NSNumber numberWithUnsignedLongLong
:g_variant_get_uint64 (variant
)];
435 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_HANDLE
))
436 return [NSNumber numberWithLong
:g_variant_get_handle (variant
)];
437 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_DOUBLE
))
438 return [NSNumber numberWithDouble
:g_variant_get_double (variant
)];
439 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_STRING
))
440 return [NSString stringWithUTF8String
:g_variant_get_string (variant
, NULL
)];
441 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_OBJECT_PATH
))
442 return [NSString stringWithUTF8String
:g_variant_get_string (variant
, NULL
)];
443 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_SIGNATURE
))
444 return [NSString stringWithUTF8String
:g_variant_get_string (variant
, NULL
)];
445 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE ("a{s*}")))
447 NSMutableDictionary
*dictionary
;
452 dictionary
= [NSMutableDictionary dictionaryWithCapacity
:g_variant_iter_init (&iter
, variant
)];
454 while (g_variant_iter_loop (&iter
, "{s*}", &name
, &value
))
459 key
= [NSString stringWithUTF8String
:g_variant_get_string (name
, NULL
)];
460 object
= g_nextstep_settings_backend_get_ns_object (value
);
462 [dictionary setObject
:object forKey
:key
];
467 else if (g_variant_is_of_type (variant
, G_VARIANT_TYPE_ARRAY
))
469 NSMutableArray
*array
;
473 array
= [NSMutableArray arrayWithCapacity
:g_variant_iter_init (&iter
, variant
)];
475 while ((value
= g_variant_iter_next_value (&iter
)) != NULL
)
476 [array addObject
:g_nextstep_settings_backend_get_ns_object (value
)];
481 return [[NSString stringWithUTF8String
:g_variant_print (variant
, TRUE
)] dataUsingEncoding
:NSUTF8StringEncoding
];