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, 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
];