Create the configuration directory if it doesn't exist yet
[nautilus-actions.git] / src / core / na-settings.c
blobe9ce6cff53ca3992e3adaefa33d69e6a09df8a06
1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <gio/gio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
40 #include <api/na-boxed.h>
41 #include <api/na-data-types.h>
42 #include <api/na-core-utils.h>
43 #include <api/na-timeout.h>
45 #include "na-settings.h"
46 #include "na-marshal.h"
48 #define NA_SETTINGS_TYPE ( settings_get_type())
49 #define NA_SETTINGS( object ) ( G_TYPE_CHECK_INSTANCE_CAST( object, NA_SETTINGS_TYPE, NASettings ))
50 #define NA_SETTINGS_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( klass, NA_SETTINGS_TYPE, NASettingsClass ))
51 #define NA_IS_SETTINGS( object ) ( G_TYPE_CHECK_INSTANCE_TYPE( object, NA_SETTINGS_TYPE ))
52 #define NA_IS_SETTINGS_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_SETTINGS_TYPE ))
53 #define NA_SETTINGS_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_SETTINGS_TYPE, NASettingsClass ))
55 typedef struct _NASettingsPrivate NASettingsPrivate;
57 typedef struct {
58 /*< private >*/
59 GObject parent;
60 NASettingsPrivate *private;
62 NASettings;
64 typedef struct _NASettingsClassPrivate NASettingsClassPrivate;
66 typedef struct {
67 /*< private >*/
68 GObjectClass parent;
69 NASettingsClassPrivate *private;
71 NASettingsClass;
73 /* private class data
75 struct _NASettingsClassPrivate {
76 void *empty; /* so that gcc -pedantic is happy */
79 /* The characteristics of a configuration file.
80 * We manage two configuration files:
81 * - the global configuration file handles mandatory preferences;
82 * - the user configuration file handles.. well, user preferences.
84 typedef struct {
85 gchar *fname;
86 GKeyFile *key_file;
87 GFileMonitor *monitor;
88 gulong handler;
90 KeyFile;
92 /* Each consumer may register a callback function which will be triggered
93 * when a key is modified.
95 * The monitored key usually is the real key read in the file;
96 * as a special case, composite keys are defined:
97 * - NA_IPREFS_IO_PROVIDERS_READ_STATUS monitors the 'readable' key for all i/o providers
99 * Note that we actually monitor the _user_view_ of the configuration:
100 * e.g. if a key has a mandatory value in global conf, then the same
101 * key in user conf will just be ignored.
103 typedef struct {
104 gchar *monitored_key;
105 GCallback callback;
106 gpointer user_data;
108 Consumer;
110 /* private instance data
112 struct _NASettingsPrivate {
113 gboolean dispose_has_run;
114 KeyFile *mandatory;
115 KeyFile *user;
116 GList *content;
117 GList *consumers;
118 NATimeout timeout;
121 #define GROUP_NACT "nact"
122 #define GROUP_RUNTIME "runtime"
124 typedef struct {
125 const gchar *key;
126 const gchar *group;
127 guint type;
128 const gchar *default_value;
130 KeyDef;
132 static const KeyDef st_def_keys[] = {
133 { NA_IPREFS_ADMIN_PREFERENCES_LOCKED, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
134 { NA_IPREFS_ADMIN_IO_PROVIDERS_LOCKED, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "false" },
135 { NA_IPREFS_ASSISTANT_ESC_CONFIRM, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
136 { NA_IPREFS_ASSISTANT_ESC_QUIT, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
137 { NA_IPREFS_CAPABILITY_ADD_CAPABILITY_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
138 { NA_IPREFS_COMMAND_CHOOSER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
139 { NA_IPREFS_COMMAND_CHOOSER_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///bin" },
140 { NA_IPREFS_COMMAND_LEGEND_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
141 { NA_IPREFS_CONFIRM_LOGOUT_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
142 { NA_IPREFS_DESKTOP_ENVIRONMENT, GROUP_RUNTIME, NA_DATA_TYPE_STRING, "" },
143 { NA_IPREFS_WORKING_DIR_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
144 { NA_IPREFS_WORKING_DIR_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///" },
145 { NA_IPREFS_SHOW_IF_RUNNING_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
146 { NA_IPREFS_SHOW_IF_RUNNING_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///bin" },
147 { NA_IPREFS_TRY_EXEC_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
148 { NA_IPREFS_TRY_EXEC_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///bin" },
149 { NA_IPREFS_EXPORT_ASK_USER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
150 { NA_IPREFS_EXPORT_ASK_USER_LAST_FORMAT, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_EXPORT_FORMAT },
151 { NA_IPREFS_EXPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
152 { NA_IPREFS_EXPORT_ASSISTANT_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
153 { NA_IPREFS_EXPORT_ASSISTANT_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///tmp" },
154 { NA_IPREFS_EXPORT_PREFERRED_FORMAT, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_EXPORT_FORMAT },
155 { NA_IPREFS_FOLDER_CHOOSER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
156 { NA_IPREFS_FOLDER_CHOOSER_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///" },
157 { NA_IPREFS_IMPORT_ASK_USER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
158 { NA_IPREFS_IMPORT_ASK_USER_LAST_MODE, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_IMPORT_MODE },
159 { NA_IPREFS_IMPORT_ASSISTANT_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
160 { NA_IPREFS_IMPORT_ASSISTANT_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///tmp" },
161 { NA_IPREFS_IMPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
162 { NA_IPREFS_IMPORT_PREFERRED_MODE, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_IMPORT_MODE },
163 { NA_IPREFS_IO_PROVIDERS_WRITE_ORDER, GROUP_NACT, NA_DATA_TYPE_STRING_LIST, "" },
164 { NA_IPREFS_ICON_CHOOSER_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///" },
165 { NA_IPREFS_ICON_CHOOSER_PANED, GROUP_NACT, NA_DATA_TYPE_UINT, "200" },
166 { NA_IPREFS_ICON_CHOOSER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
167 { NA_IPREFS_ITEMS_ADD_ABOUT_ITEM, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "true" },
168 { NA_IPREFS_ITEMS_CREATE_ROOT_MENU, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "true" },
169 { NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER, GROUP_RUNTIME, NA_DATA_TYPE_STRING_LIST, "" },
170 { NA_IPREFS_ITEMS_LIST_ORDER_MODE, GROUP_RUNTIME, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_LIST_ORDER_MODE },
171 { NA_IPREFS_MAIN_PANED, GROUP_NACT, NA_DATA_TYPE_UINT, "200" },
172 { NA_IPREFS_MAIN_SAVE_AUTO, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
173 { NA_IPREFS_MAIN_SAVE_PERIOD, GROUP_NACT, NA_DATA_TYPE_UINT, "5" },
174 { NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
175 { NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
176 { NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
177 { NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
178 { NA_IPREFS_MAIN_WINDOW_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
179 { NA_IPREFS_PREFERENCES_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
180 { NA_IPREFS_PLUGIN_MENU_LOG, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "false" },
181 { NA_IPREFS_RELABEL_DUPLICATE_ACTION, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
182 { NA_IPREFS_RELABEL_DUPLICATE_MENU, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
183 { NA_IPREFS_RELABEL_DUPLICATE_PROFILE, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
184 { NA_IPREFS_SCHEME_ADD_SCHEME_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
185 { NA_IPREFS_SCHEME_DEFAULT_LIST, GROUP_NACT, NA_DATA_TYPE_STRING_LIST, "" },
186 { NA_IPREFS_TERMINAL_PATTERN, GROUP_RUNTIME, NA_DATA_TYPE_STRING, "" },
187 { NA_IPREFS_IO_PROVIDER_READABLE, NA_IPREFS_IO_PROVIDER_GROUP, NA_DATA_TYPE_BOOLEAN, "true" },
188 { NA_IPREFS_IO_PROVIDER_WRITABLE, NA_IPREFS_IO_PROVIDER_GROUP, NA_DATA_TYPE_BOOLEAN, "true" },
189 { 0 }
192 /* The configuration content is handled as a GList of KeyValue structs.
193 * This list is loaded at initialization time, and then compared each
194 * time our file monitors signal us that a change has occured.
196 typedef struct {
197 const KeyDef *def;
198 const gchar *group;
199 gboolean mandatory;
200 NABoxed *boxed;
202 KeyValue;
204 /* signals
206 enum {
207 KEY_CHANGED,
208 LAST_SIGNAL
211 static GObjectClass *st_parent_class = NULL;
212 static gint st_burst_timeout = 100; /* burst timeout in msec */
213 static gint st_signals[ LAST_SIGNAL ] = { 0 };
214 static NASettings *st_settings = NULL;
216 static GType settings_get_type( void );
217 static GType register_type( void );
218 static void class_init( NASettingsClass *klass );
219 static void instance_init( GTypeInstance *instance, gpointer klass );
220 static void instance_dispose( GObject *object );
221 static void instance_finalize( GObject *object );
223 static void settings_new( void );
225 static GList *content_diff( GList *old, GList *new );
226 static GList *content_load( void );
227 static GList *content_load_keys( GList *content, KeyFile *key_file, gboolean mandatory );
228 static KeyDef *get_key_def( const gchar *key );
229 static KeyFile *key_file_new( const gchar *dir );
230 static void on_keyfile_changed( GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type );
231 static void on_keyfile_changed_timeout( void );
232 static void on_key_changed_final_handler( NASettings *settings, gchar *group, gchar *key, NABoxed *new_value, gboolean mandatory );
233 static KeyValue *peek_key_value_from_content( GList *content, const gchar *group, const gchar *key );
234 static KeyValue *read_key_value( const gchar *group, const gchar *key, gboolean *found, gboolean *mandatory );
235 static KeyValue *read_key_value_from_key_file( GKeyFile *key_file, const gchar *group, const gchar *key, const KeyDef *key_def );
236 static void release_consumer( Consumer *consumer );
237 static void release_key_file( KeyFile *key_file );
238 static void release_key_value( KeyValue *value );
239 static gboolean set_key_value( const gchar *group, const gchar *key, const gchar *string );
240 static gboolean write_user_key_file( void );
242 static GType
243 settings_get_type( void )
245 static GType object_type = 0;
247 if( !object_type ){
248 object_type = register_type();
251 return( object_type );
254 static GType
255 register_type( void )
257 static const gchar *thisfn = "na_settings_register_type";
258 GType type;
260 static GTypeInfo info = {
261 sizeof( NASettingsClass ),
262 ( GBaseInitFunc ) NULL,
263 ( GBaseFinalizeFunc ) NULL,
264 ( GClassInitFunc ) class_init,
265 NULL,
266 NULL,
267 sizeof( NASettings ),
269 ( GInstanceInitFunc ) instance_init
272 g_debug( "%s", thisfn );
274 type = g_type_register_static( G_TYPE_OBJECT, "NASettings", &info, 0 );
276 return( type );
279 static void
280 class_init( NASettingsClass *klass )
282 static const gchar *thisfn = "na_settings_class_init";
283 GObjectClass *object_class;
285 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
287 st_parent_class = g_type_class_peek_parent( klass );
289 object_class = G_OBJECT_CLASS( klass );
290 object_class->dispose = instance_dispose;
291 object_class->finalize = instance_finalize;
293 klass->private = g_new0( NASettingsClassPrivate, 1 );
296 * NASettings::settings-key-changed:
298 * This signal is sent by NASettings when the value of a key is modified.
300 * Arguments are the group, the key, the new value as a NABoxed,
301 * and whether it is mandatory.
303 * Handler is of type:
304 * void ( *handler )( NASettings *settings,
305 * const gchar *group,
306 * const gchar *key,
307 * NABoxed *value,
308 * gboolean mandatory,
309 * gpointer user_data );
311 * The default class handler frees these datas.
313 st_signals[ KEY_CHANGED ] = g_signal_new_class_handler(
314 SETTINGS_SIGNAL_KEY_CHANGED,
315 NA_SETTINGS_TYPE,
316 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_ACTION,
317 G_CALLBACK( on_key_changed_final_handler ),
318 NULL, /* accumulator */
319 NULL, /* accumulator data */
320 na_cclosure_marshal_VOID__STRING_STRING_POINTER_BOOLEAN,
321 G_TYPE_NONE,
323 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN );
326 static void
327 instance_init( GTypeInstance *instance, gpointer klass )
329 static const gchar *thisfn = "na_settings_instance_init";
330 NASettings *self;
332 g_return_if_fail( NA_IS_SETTINGS( instance ));
334 g_debug( "%s: instance=%p (%s), klass=%p",
335 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
337 self = NA_SETTINGS( instance );
339 self->private = g_new0( NASettingsPrivate, 1 );
341 self->private->dispose_has_run = FALSE;
342 self->private->mandatory = NULL;
343 self->private->user = NULL;
344 self->private->content = NULL;
345 self->private->consumers = NULL;
347 self->private->timeout.timeout = st_burst_timeout;
348 self->private->timeout.handler = ( NATimeoutFunc ) on_keyfile_changed_timeout;
349 self->private->timeout.user_data = NULL;
350 self->private->timeout.source_id = 0;
353 static void
354 instance_dispose( GObject *object )
356 static const gchar *thisfn = "na_settings_instance_dispose";
357 NASettings *self;
359 g_return_if_fail( NA_IS_SETTINGS( object ));
361 self = NA_SETTINGS( object );
363 if( !self->private->dispose_has_run ){
365 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
367 self->private->dispose_has_run = TRUE;
369 release_key_file( self->private->mandatory );
370 release_key_file( self->private->user );
372 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
373 G_OBJECT_CLASS( st_parent_class )->dispose( object );
378 static void
379 instance_finalize( GObject *object )
381 static const gchar *thisfn = "na_settings_instance_finalize";
382 NASettings *self;
384 g_return_if_fail( NA_IS_SETTINGS( object ));
386 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
388 self = NA_SETTINGS( object );
390 g_list_foreach( self->private->content, ( GFunc ) release_key_value, NULL );
391 g_list_free( self->private->content );
393 g_list_foreach( self->private->consumers, ( GFunc ) release_consumer, NULL );
394 g_list_free( self->private->consumers );
396 g_free( self->private );
398 /* chain call to parent class */
399 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
400 G_OBJECT_CLASS( st_parent_class )->finalize( object );
405 * na_settings_new:
407 * Allocates a new #NASettings object which should be na_settings_free()
408 * by the caller.
410 static void
411 settings_new( void )
413 static const gchar *thisfn = "na_settings_new";
414 gchar *dir;
416 if( !st_settings ){
417 st_settings = g_object_new( NA_SETTINGS_TYPE, NULL );
419 dir = g_build_filename( SYSCONFDIR, "xdg", PACKAGE, NULL );
420 g_debug( "%s: reading mandatory configuration", thisfn );
421 st_settings->private->mandatory = key_file_new( dir );
422 g_free( dir );
424 dir = g_build_filename( g_get_home_dir(), ".config", PACKAGE, NULL );
425 g_mkdir_with_parents( dir, 750 );
426 g_debug( "%s: reading user configuration", thisfn );
427 st_settings->private->user = key_file_new( dir );
428 g_free( dir );
430 st_settings->private->content = content_load();
435 * na_settings_free:
437 void
438 na_settings_free( void )
440 if( st_settings ){
441 g_object_unref( st_settings );
442 st_settings = NULL;
447 * na_settings_register_key_callback:
448 * @key: the key to be monitored.
449 * @callback: the function to be called when the value of the key changes.
450 * @user_data: data to be passed to the @callback function.
452 * Registers a new consumer of the monitoring of the @key.
454 * Since: 3.1.0
456 void
457 na_settings_register_key_callback( const gchar *key, GCallback callback, gpointer user_data )
459 static const gchar *thisfn = "na_settings_register_key_callback";
461 g_debug( "%s: key=%s, callback=%p, user_data=%p",
462 thisfn, key, ( void * ) callback, ( void * ) user_data );
464 Consumer *consumer = g_new0( Consumer, 1 );
465 consumer->monitored_key = g_strdup( key );
466 consumer->callback = callback;
467 consumer->user_data = user_data;
469 settings_new();
470 st_settings->private->consumers = g_list_prepend( st_settings->private->consumers, consumer );
474 * na_settings_get_boolean:
475 * @key: the key whose value is to be returned.
476 * @found: if not %NULL, a pointer to a gboolean in which we will store
477 * whether the searched @key has been found (%TRUE), or if the returned
478 * value comes from default (%FALSE).
479 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
480 * whether the returned value has been read from mandatory preferences
481 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
482 * been found, @mandatory is set to %FALSE.
484 * This function should only be called for unambiguous keys; the resultat
485 * is otherwise undefined (and rather unpredictable).
487 * Returns: the value of the key, of its default value if not found.
489 * Since: 3.1.0
491 gboolean
492 na_settings_get_boolean( const gchar *key, gboolean *found, gboolean *mandatory )
494 return( na_settings_get_boolean_ex( NULL, key, found, mandatory ));
498 * na_settings_get_boolean_ex:
499 * @group: the group where the @key is to be searched for. May be %NULL.
500 * @key: the key whose value is to be returned.
501 * @found: if not %NULL, a pointer to a gboolean in which we will store
502 * whether the searched @key has been found (%TRUE), or if the returned
503 * value comes from default (%FALSE).
504 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
505 * whether the returned value has been read from mandatory preferences
506 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
507 * been found, @mandatory is set to %FALSE.
509 * Returns: the value of the key, of its default value if not found.
511 * Since: 3.1.0
513 gboolean
514 na_settings_get_boolean_ex( const gchar *group, const gchar *key, gboolean *found, gboolean *mandatory )
516 gboolean value;
517 KeyValue *key_value;
518 KeyDef *key_def;
520 value = FALSE;
521 key_value = read_key_value( group, key, found, mandatory );
523 if( key_value ){
524 value = na_boxed_get_boolean( key_value->boxed );
525 release_key_value( key_value );
527 } else {
528 key_def = get_key_def( key );
529 if( key_def ){
530 value = ( key_def->default_value ? ( strcasecmp( key_def->default_value, "true" ) == 0 || atoi( key_def->default_value ) != 0 ) : FALSE );
534 return( value );
538 * na_settings_get_string:
539 * @key: the key whose value is to be returned.
540 * @found: if not %NULL, a pointer to a gboolean in which we will store
541 * whether the searched @key has been found (%TRUE), or if the returned
542 * value comes from default (%FALSE).
543 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
544 * whether the returned value has been read from mandatory preferences
545 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
546 * been found, @mandatory is set to %FALSE.
548 * This function should only be called for unambiguous keys; the resultat
549 * is otherwise undefined (and rather unpredictable).
551 * Returns: the value of the key as a newly allocated string, which should
552 * be g_free() by the caller.
554 * Since: 3.1.0
556 gchar *
557 na_settings_get_string( const gchar *key, gboolean *found, gboolean *mandatory )
559 gchar *value;
560 KeyValue *key_value;
561 KeyDef *key_def;
563 value = NULL;
564 key_value = read_key_value( NULL, key, found, mandatory );
566 if( key_value ){
567 value = na_boxed_get_string( key_value->boxed );
568 release_key_value( key_value );
570 } else {
571 key_def = get_key_def( key );
572 if( key_def && key_def->default_value ){
573 value = g_strdup( key_def->default_value );
577 return( value );
581 * na_settings_get_string_list:
582 * @key: the key whose value is to be returned.
583 * @found: if not %NULL, a pointer to a gboolean in which we will store
584 * whether the searched @key has been found (%TRUE), or if the returned
585 * value comes from default (%FALSE).
586 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
587 * whether the returned value has been read from mandatory preferences
588 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
589 * been found, @mandatory is set to %FALSE.
591 * This function should only be called for unambiguous keys; the resultat
592 * is otherwise undefined (and rather unpredictable).
594 * Returns: the value of the key as a newly allocated list of strings.
595 * The returned list should be na_core_utils_slist_free() by the caller.
597 * Since: 3.1.0
599 GSList *
600 na_settings_get_string_list( const gchar *key, gboolean *found, gboolean *mandatory )
602 GSList *value;
603 KeyValue *key_value;
604 KeyDef *key_def;
606 value = NULL;
607 key_value = read_key_value( NULL, key, found, mandatory );
609 if( key_value ){
610 value = na_boxed_get_string_list( key_value->boxed );
611 release_key_value( key_value );
613 } else {
614 key_def = get_key_def( key );
615 if( key_def && key_def->default_value && strlen( key_def->default_value )){
616 value = g_slist_append( NULL, g_strdup( key_def->default_value ));
620 return( value );
624 * na_settings_get_uint:
625 * @key: the key whose value is to be returned.
626 * @found: if not %NULL, a pointer to a gboolean in which we will store
627 * whether the searched @key has been found (%TRUE), or if the returned
628 * value comes from default (%FALSE).
629 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
630 * whether the returned value has been read from mandatory preferences
631 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
632 * been found, @mandatory is set to %FALSE.
634 * This function should only be called for unambiguous keys; the resultat
635 * is otherwise undefined (and rather unpredictable).
637 * Returns: the value of the key.
639 * Since: 3.1.0
641 guint
642 na_settings_get_uint( const gchar *key, gboolean *found, gboolean *mandatory )
644 guint value;
645 KeyDef *key_def;
646 KeyValue *key_value;
648 value = 0;
649 key_value = read_key_value( NULL, key, found, mandatory );
651 if( key_value ){
652 value = na_boxed_get_uint( key_value->boxed );
653 release_key_value( key_value );
655 } else {
656 key_def = get_key_def( key );
657 if( key_def && key_def->default_value ){
658 value = atoi( key_def->default_value );
662 return( value );
666 * na_settings_get_uint_list:
667 * @key: the key whose value is to be returned.
668 * @found: if not %NULL, a pointer to a gboolean in which we will store
669 * whether the searched @key has been found (%TRUE), or if the returned
670 * value comes from default (%FALSE).
671 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
672 * whether the returned value has been read from mandatory preferences
673 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
674 * been found, @mandatory is set to %FALSE.
676 * This function should only be called for unambiguous keys; the resultat
677 * is otherwise undefined (and rather unpredictable).
679 * Returns: the value of the key as a newly allocated list of uints.
680 * The returned list should be g_list_free() by the caller.
682 * Since: 3.1.0
684 GList *
685 na_settings_get_uint_list( const gchar *key, gboolean *found, gboolean *mandatory )
687 GList *value;
688 KeyDef *key_def;
689 KeyValue *key_value;
691 value = NULL;
692 key_value = read_key_value( NULL, key, found, mandatory );
694 if( key_value ){
695 value = na_boxed_get_uint_list( key_value->boxed );
696 release_key_value( key_value );
698 } else {
699 key_def = get_key_def( key );
700 if( key_def && key_def->default_value ){
701 value = g_list_append( NULL, GUINT_TO_POINTER( atoi( key_def->default_value )));
705 return( value );
709 * na_settings_set_boolean:
710 * @key: the key whose value is to be returned.
711 * @value: the boolean to be written.
713 * This function writes @value as a user preference.
715 * This function should only be called for unambiguous keys; the resultat
716 * is otherwise undefined (and rather unpredictable).
718 * Returns: %TRUE is the writing has been successful, %FALSE else.
720 * Since: 3.1.0
722 gboolean
723 na_settings_set_boolean( const gchar *key, gboolean value )
725 gchar *string;
726 gboolean ok;
728 string = g_strdup_printf( "%s", value ? "true" : "false" );
729 ok = set_key_value( NULL, key, string );
730 g_free( string );
732 return( ok );
736 * na_settings_set_boolean_ex:
737 * @group: the group in the keyed file;
738 * @key: the key whose value is to be returned.
739 * @value: the boolean to be written.
741 * This function writes @value as a user preference.
743 * Returns: %TRUE is the writing has been successful, %FALSE else.
745 * Since: 3.1.0
747 gboolean
748 na_settings_set_boolean_ex( const gchar *group, const gchar *key, gboolean value )
750 gchar *string;
751 gboolean ok;
753 string = g_strdup_printf( "%s", value ? "true" : "false" );
754 ok = set_key_value( group, key, string );
755 g_free( string );
757 return( ok );
761 * na_settings_set_string:
762 * @key: the key whose value is to be returned.
763 * @value: the string to be written.
765 * This function writes @value as a user preference.
767 * This function should only be called for unambiguous keys; the resultat
768 * is otherwise undefined (and rather unpredictable).
770 * Returns: %TRUE is the writing has been successful, %FALSE else.
772 * Since: 3.1.0
774 gboolean
775 na_settings_set_string( const gchar *key, const gchar *value )
777 return( set_key_value( NULL, key, value ));
781 * na_settings_set_string_list:
782 * @key: the key whose value is to be returned.
783 * @value: the list of strings to be written.
785 * This function writes @value as a user preference.
787 * This function should only be called for unambiguous keys; the resultat
788 * is otherwise undefined (and rather unpredictable).
790 * Returns: %TRUE is the writing has been successful, %FALSE else.
792 * Since: 3.1.0
794 gboolean
795 na_settings_set_string_list( const gchar *key, const GSList *value )
797 GString *string;
798 const GSList *it;
799 gboolean ok;
801 string = g_string_new( "" );
802 for( it = value ; it ; it = it->next ){
803 g_string_append_printf( string, "%s;", ( const gchar * ) it->data );
805 ok = set_key_value( NULL, key, string->str );
806 g_string_free( string, TRUE );
808 return( ok );
812 * na_settings_set_uint:
813 * @key: the key whose value is to be returned.
814 * @value: the unsigned integer to be written.
816 * This function writes @value as a user preference.
818 * This function should only be called for unambiguous keys; the resultat
819 * is otherwise undefined (and rather unpredictable).
821 * Returns: %TRUE is the writing has been successful, %FALSE else.
823 * Since: 3.1.0
825 gboolean
826 na_settings_set_uint( const gchar *key, guint value )
828 gchar *string;
829 gboolean ok;
831 string = g_strdup_printf( "%u", value );
832 ok = set_key_value( NULL, key, string );
833 g_free( string );
835 return( ok );
839 * na_settings_set_uint_list:
840 * @key: the key whose value is to be returned.
841 * @value: the list of unsigned integers to be written.
843 * This function writes @value as a user preference.
845 * This function should only be called for unambiguous keys; the resultat
846 * is otherwise undefined (and rather unpredictable).
848 * Returns: %TRUE is the writing has been successful, %FALSE else.
850 * Since: 3.1.0
852 gboolean
853 na_settings_set_uint_list( const gchar *key, const GList *value )
855 GString *string;
856 const GList *it;
857 gboolean ok;
859 string = g_string_new( "" );
860 for( it = value ; it ; it = it->next ){
861 g_string_append_printf( string, "%u;", GPOINTER_TO_UINT( it->data ));
863 ok = set_key_value( NULL, key, string->str );
864 g_string_free( string, TRUE );
866 return( ok );
870 * na_settings_get_groups:
872 * Returns: the list of groups in the configuration; this list should be
873 * na_core_utils_slist_free() by the caller.
875 * This function participates to a rather bad hack to obtain the list of
876 * known i/o providers from preferences. We do not care of returning unique
877 * or sorted group names.
879 * Since: 3.1.0
881 GSList *
882 na_settings_get_groups( void )
884 GSList *groups;
885 gchar **array;
887 groups = NULL;
888 settings_new();
890 array = g_key_file_get_groups( st_settings->private->mandatory->key_file, NULL );
891 if( array ){
892 groups = na_core_utils_slist_from_array(( const gchar ** ) array );
893 g_strfreev( array );
896 array = g_key_file_get_groups( st_settings->private->user->key_file, NULL );
897 if( array ){
898 groups = g_slist_concat( groups, na_core_utils_slist_from_array(( const gchar ** ) array ));
899 g_strfreev( array );
902 return( groups );
906 * returns a list of modified KeyValue
907 * - order in the lists is not signifiant
908 * - the mandatory flag is not signifiant
909 * - a key is modified:
910 * > if it appears in new
911 * > if it disappears: the value is so reset to its default
912 * > if the value has been modified
914 * we return here a new list, with newly allocated KeyValue structs
915 * which hold the new value of each modified key
917 static GList *
918 content_diff( GList *old, GList *new )
920 GList *diffs, *io, *in;
921 KeyValue *kold, *knew, *kdiff;
922 gboolean found;
924 diffs = NULL;
926 for( io = old ; io ; io = io->next ){
927 kold = ( KeyValue * ) io->data;
928 found = FALSE;
929 for( in = new ; in && !found ; in = in->next ){
930 knew = ( KeyValue * ) in->data;
931 if( !strcmp( kold->group, knew->group ) && ( gpointer ) kold->def == ( gpointer ) knew->def ){
932 found = TRUE;
933 if( !na_boxed_are_equal( kold->boxed, knew->boxed )){
934 /* a key has been modified */
935 kdiff = g_new0( KeyValue, 1 );
936 kdiff->group = g_strdup( knew->group );
937 kdiff->def = knew->def;
938 kdiff->mandatory = knew->mandatory;
939 kdiff->boxed = na_boxed_copy( knew->boxed );
940 diffs = g_list_prepend( diffs, kdiff );
944 if( !found ){
945 /* a key has disappeared */
946 kdiff = g_new0( KeyValue, 1 );
947 kdiff->group = g_strdup( kold->group );
948 kdiff->def = kold->def;
949 kdiff->mandatory = FALSE;
950 kdiff->boxed = na_boxed_new_from_string( kold->def->type, kold->def->default_value );
951 diffs = g_list_prepend( diffs, kdiff );
955 for( in = new ; in ; in = in->next ){
956 knew = ( KeyValue * ) in->data;
957 found = FALSE;
958 for( io = old ; io && !found ; io = io->next ){
959 kold = ( KeyValue * ) io->data;
960 if( !strcmp( kold->group, knew->group ) && ( gpointer ) kold->def == ( gpointer ) knew->def ){
961 found = TRUE;
964 if( !found ){
965 /* a key is new */
966 kdiff = g_new0( KeyValue, 1 );
967 kdiff->group = g_strdup( knew->group );
968 kdiff->def = knew->def;
969 kdiff->mandatory = knew->mandatory;
970 kdiff->boxed = na_boxed_copy( knew->boxed );
971 diffs = g_list_prepend( diffs, kdiff );
975 return( diffs );
978 /* load the content of the two configuration files (actually of _the_ configuration)
979 * taking care of not overriding mandatory preferences with user ones
981 static GList *
982 content_load( void )
984 GList *content;
986 settings_new();
987 content = content_load_keys( NULL, st_settings->private->mandatory, TRUE );
988 content = content_load_keys( content, st_settings->private->user, FALSE );
990 return( content );
993 static GList *
994 content_load_keys( GList *content, KeyFile *key_file, gboolean mandatory )
996 static const gchar *thisfn = "na_settings_content_load_keys";
997 GError *error;
998 gchar **groups, **ig;
999 gchar **keys, **ik;
1000 KeyValue *key_value;
1001 KeyDef *key_def;
1003 error = NULL;
1004 if( !g_key_file_load_from_file( key_file->key_file, key_file->fname, G_KEY_FILE_KEEP_COMMENTS, &error )){
1005 if( error->code != G_FILE_ERROR_NOENT ){
1006 g_warning( "%s: %s (%d) %s", thisfn, key_file->fname, error->code, error->message );
1008 g_error_free( error );
1009 error = NULL;
1011 } else {
1012 groups = g_key_file_get_groups( key_file->key_file, NULL );
1013 ig = groups;
1014 while( *ig ){
1015 keys = g_key_file_get_keys( key_file->key_file, *ig, NULL, NULL );
1016 ik = keys;
1017 while( *ik ){
1018 key_def = get_key_def( *ik );
1019 if( key_def ){
1020 key_value = peek_key_value_from_content( content, *ig, *ik );
1021 if( !key_value ){
1022 key_value = read_key_value_from_key_file( key_file->key_file, *ig, *ik, key_def );
1023 if( key_value ){
1024 key_value->mandatory = mandatory;
1025 content = g_list_prepend( content, key_value );
1029 ik++;
1031 g_strfreev( keys );
1032 ig++;
1034 g_strfreev( groups );
1037 return( content );
1040 static KeyDef *
1041 get_key_def( const gchar *key )
1043 static const gchar *thisfn = "na_settings_get_key_def";
1044 KeyDef *found = NULL;
1045 KeyDef *idef;
1047 idef = ( KeyDef * ) st_def_keys;
1048 while( idef->key && !found ){
1049 if( !strcmp( idef->key, key )){
1050 found = idef;
1052 idef++;
1054 if( !found ){
1055 g_warning( "%s: no KeyDef found for key=%s", thisfn, key );
1058 return( found );
1062 * called from na_settings_new
1063 * allocate and load the key files for global and user preferences
1065 static KeyFile *
1066 key_file_new( const gchar *dir )
1068 static const gchar *thisfn = "na_settings_key_file_new";
1069 KeyFile *key_file;
1070 GError *error;
1071 GFile *file;
1073 key_file = g_new0( KeyFile, 1 );
1075 key_file->key_file = g_key_file_new();
1076 key_file->fname = g_strdup_printf( "%s/%s.conf", dir, PACKAGE );
1078 error = NULL;
1079 file = g_file_new_for_path( key_file->fname );
1080 key_file->monitor = g_file_monitor_file( file, 0, NULL, &error );
1081 if( error ){
1082 g_warning( "%s: %s: %s", thisfn, key_file->fname, error->message );
1083 g_error_free( error );
1084 error = NULL;
1085 } else {
1086 key_file->handler = g_signal_connect( key_file->monitor, "changed", ( GCallback ) on_keyfile_changed, NULL );
1088 g_object_unref( file );
1090 return( key_file );
1094 * one of the two monitored configuration files have changed on the disk
1095 * we do not try to identify which keys have actually change
1096 * instead we trigger each registered consumer for the 'global' event
1098 * consumers which register for the 'global_conf' event are recorded
1099 * with a NULL key
1101 static void
1102 on_keyfile_changed( GFileMonitor *monitor,
1103 GFile *file, GFile *other_file, GFileMonitorEvent event_type )
1105 settings_new();
1106 na_timeout_event( &st_settings->private->timeout );
1109 static void
1110 on_keyfile_changed_timeout( void )
1112 static const gchar *thisfn = "na_settings_on_keyfile_changed_timeout";
1113 GList *new_content;
1114 GList *modifs;
1115 GList *ic, *im;
1116 const KeyValue *changed;
1117 const Consumer *consumer;
1118 gchar *group_prefix, *key;
1119 #ifdef NA_MAINTAINER_MODE
1120 gchar *value;
1121 #endif
1123 /* last individual notification is older that the st_burst_timeout
1124 * we may so suppose that the burst is terminated
1126 new_content = content_load();
1127 modifs = content_diff( st_settings->private->content, new_content );
1129 #ifdef NA_MAINTAINER_MODE
1130 g_debug( "%s: %d found update(s)", thisfn, g_list_length( modifs ));
1131 for( im = modifs ; im ; im = im->next ){
1132 changed = ( const KeyValue * ) im->data;
1133 value = na_boxed_get_string( changed->boxed );
1134 g_debug( "%s: group=%s, key=%s, value=%s", thisfn, changed->group, changed->def->key, value );
1135 g_free( value );
1137 #endif
1139 /* for each modification found,
1140 * - check if a consumer has registered for this key, and triggers callback if apply
1141 * - send a notification message
1143 for( im = modifs ; im ; im = im->next ){
1144 changed = ( const KeyValue * ) im->data;
1146 for( ic = st_settings->private->consumers ; ic ; ic = ic->next ){
1147 consumer = ( const Consumer * ) ic->data;
1148 group_prefix = NULL;
1150 if( !strcmp( consumer->monitored_key, NA_IPREFS_IO_PROVIDERS_READ_STATUS )){
1151 group_prefix = g_strdup_printf( "%s ", NA_IPREFS_IO_PROVIDER_GROUP );
1152 key = NA_IPREFS_IO_PROVIDER_READABLE;
1153 } else {
1154 key = consumer->monitored_key;
1157 if(( !group_prefix || g_str_has_prefix( changed->group, group_prefix )) && !strcmp( changed->def->key, key )){
1158 ( *( NASettingsKeyCallback ) consumer->callback )(
1159 changed->group,
1160 changed->def->key,
1161 na_boxed_get_pointer( changed->boxed ),
1162 changed->mandatory,
1163 consumer->user_data );
1166 g_free( group_prefix );
1169 g_debug( "%s: sending signal for group=%s, key=%s", thisfn, changed->group, changed->def->key );
1170 g_signal_emit_by_name( st_settings,
1171 SETTINGS_SIGNAL_KEY_CHANGED,
1172 changed->group, changed->def->key, changed->boxed, changed->mandatory );
1175 g_debug( "%s: releasing content", thisfn );
1176 g_list_foreach( st_settings->private->content, ( GFunc ) release_key_value, NULL );
1177 g_list_free( st_settings->private->content );
1178 st_settings->private->content = new_content;
1180 g_debug( "%s: releasing modifs", thisfn );
1181 g_list_foreach( modifs, ( GFunc ) release_key_value, NULL );
1182 g_list_free( modifs );
1185 static void
1186 on_key_changed_final_handler( NASettings *settings, gchar *group, gchar *key, NABoxed *new_value, gboolean mandatory )
1188 g_debug( "na_settings_on_key_changed_final_handler: group=%s, key=%s", group, key );
1189 na_boxed_dump( new_value );
1192 static KeyValue *
1193 peek_key_value_from_content( GList *content, const gchar *group, const gchar *key )
1195 KeyValue *value, *found;
1196 GList *ic;
1198 found = NULL;
1199 for( ic = content ; ic && !found ; ic = ic->next ){
1200 value = ( KeyValue * ) ic->data;
1201 if( !strcmp( value->group, group ) && !strcmp( value->def->key, key )){
1202 found = value;
1206 return( found );
1209 /* group may be NULL
1211 static KeyValue *
1212 read_key_value( const gchar *group, const gchar *key, gboolean *found, gboolean *mandatory )
1214 KeyDef *key_def;
1215 gboolean has_entry;
1216 KeyValue *key_value;
1218 key_value = NULL;
1219 if( found ){
1220 *found = FALSE;
1222 if( mandatory ){
1223 *mandatory = FALSE;
1226 settings_new();
1227 key_def = get_key_def( key );
1229 if( key_def ){
1230 has_entry = FALSE;
1231 key_value = read_key_value_from_key_file( st_settings->private->mandatory->key_file, group ? group : key_def->group, key, key_def );
1232 if( key_value ){
1233 has_entry = TRUE;
1234 if( found ){
1235 *found = TRUE;
1237 if( mandatory ){
1238 *mandatory = TRUE;
1241 if( !has_entry ){
1242 key_value = read_key_value_from_key_file( st_settings->private->user->key_file, group ? group : key_def->group, key, key_def );
1243 if( key_value ){
1244 has_entry = TRUE;
1245 if( found ){
1246 *found = TRUE;
1252 return( key_value );
1255 static KeyValue *
1256 read_key_value_from_key_file( GKeyFile *key_file, const gchar *group, const gchar *key, const KeyDef *key_def )
1258 static const gchar *thisfn = "na_settings_read_key_value_from_key_file";
1259 KeyValue *value;
1260 gchar *str;
1261 GError *error;
1263 g_debug( "%s: group=%s, key=%s", thisfn, group, key );
1265 value = NULL;
1266 error = NULL;
1268 switch( key_def->type ){
1270 case NA_DATA_TYPE_STRING:
1271 case NA_DATA_TYPE_STRING_LIST:
1272 case NA_DATA_TYPE_UINT:
1273 case NA_DATA_TYPE_UINT_LIST:
1274 case NA_DATA_TYPE_BOOLEAN:
1275 str = g_key_file_get_string( key_file, group, key, &error );
1276 if( error ){
1277 if( error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND ){
1278 g_warning( "%s: %s", thisfn, error->message );
1280 g_error_free( error );
1282 /* key exists, but may be empty */
1283 } else {
1284 value = g_new0( KeyValue, 1 );
1285 value->group = g_strdup( group );
1286 value->def = key_def;
1287 switch( key_def->type ){
1288 case NA_DATA_TYPE_STRING:
1289 case NA_DATA_TYPE_UINT:
1290 case NA_DATA_TYPE_BOOLEAN:
1291 case NA_DATA_TYPE_STRING_LIST:
1292 case NA_DATA_TYPE_UINT_LIST:
1293 value->boxed = na_boxed_new_from_string( key_def->type, str );
1294 break;
1297 g_free( str );
1298 break;
1300 default:
1301 g_warning( "%s: unmanaged boxed type: %d", thisfn, key_def->type );
1302 break;
1305 return( value );
1309 * called from instance_finalize
1310 * release the list of registered consumers
1312 static void
1313 release_consumer( Consumer *consumer )
1315 g_free( consumer->monitored_key );
1316 g_free( consumer );
1320 * called from instance_dispose
1321 * release the opened and monitored GKeyFiles
1323 static void
1324 release_key_file( KeyFile *key_file )
1326 g_key_file_free( key_file->key_file );
1327 if( key_file->monitor ){
1328 if( key_file->handler ){
1329 g_signal_handler_disconnect( key_file->monitor, key_file->handler );
1331 g_file_monitor_cancel( key_file->monitor );
1332 g_object_unref( key_file->monitor );
1334 g_free( key_file->fname );
1335 g_free( key_file );
1339 * called from instance_finalize
1340 * release a KeyValue struct
1342 static void
1343 release_key_value( KeyValue *value )
1345 g_free(( gpointer ) value->group );
1346 g_object_unref( value->boxed );
1347 g_free( value );
1350 static gboolean
1351 set_key_value( const gchar *group, const gchar *key, const gchar *string )
1353 static const gchar *thisfn = "na_settings_set_key_value";
1354 KeyDef *key_def;
1355 const gchar *wgroup;
1356 gboolean ok;
1357 GError *error;
1359 ok = FALSE;
1360 settings_new();
1362 wgroup = group;
1363 if( !wgroup ){
1364 key_def = get_key_def( key );
1365 if( key_def ){
1366 wgroup = key_def->group;
1369 if( wgroup ){
1370 ok = TRUE;
1372 if( string ){
1373 g_key_file_set_string( st_settings->private->user->key_file, wgroup, key, string );
1375 } else {
1376 error = NULL;
1377 ok = g_key_file_remove_key( st_settings->private->user->key_file, wgroup, key, &error );
1378 if( error ){
1379 g_warning( "%s: g_key_file_remove_key: %s", thisfn, error->message );
1380 g_error_free( error );
1384 ok &= write_user_key_file();
1387 return( ok );
1390 static gboolean
1391 write_user_key_file( void )
1393 static const gchar *thisfn = "na_settings_write_user_key_file";
1394 gchar *data;
1395 GFile *file;
1396 GFileOutputStream *stream;
1397 GError *error;
1398 gsize length;
1400 error = NULL;
1401 settings_new();
1402 data = g_key_file_to_data( st_settings->private->user->key_file, &length, NULL );
1403 file = g_file_new_for_path( st_settings->private->user->fname );
1405 stream = g_file_replace( file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error );
1406 if( error ){
1407 g_warning( "%s: g_file_replace: %s", thisfn, error->message );
1408 g_error_free( error );
1409 if( stream ){
1410 g_object_unref( stream );
1412 g_object_unref( file );
1413 g_free( data );
1414 return( FALSE );
1417 g_output_stream_write( G_OUTPUT_STREAM( stream ), data, length, NULL, &error );
1418 if( error ){
1419 g_warning( "%s: g_output_stream_write: %s", thisfn, error->message );
1420 g_error_free( error );
1421 g_object_unref( stream );
1422 g_object_unref( file );
1423 g_free( data );
1424 return( FALSE );
1427 g_output_stream_close( G_OUTPUT_STREAM( stream ), NULL, &error );
1428 if( error ){
1429 g_warning( "%s: g_output_stream_close: %s", thisfn, error->message );
1430 g_error_free( error );
1431 g_object_unref( stream );
1432 g_object_unref( file );
1433 g_free( data );
1434 return( FALSE );
1437 g_object_unref( stream );
1438 g_object_unref( file );
1439 g_free( data );
1441 return( TRUE );