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.
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)
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"
50 struct _NASettingsClassPrivate
{
51 void *empty
; /* so that gcc -pedantic is happy */
54 /* The characteristics of a configuration file.
55 * We manage two configuration files:
56 * - the global configuration file handles mandatory preferences;
57 * - the user configuration file handles.. well, user preferences.
62 GFileMonitor
*monitor
;
67 /* Each consumer may register a callback function which will be triggered
68 * when a key is modified.
70 * The monitored key usually is the real key read in the file;
71 * as a special case, composite keys are defined:
72 * - NA_IPREFS_IO_PROVIDERS_READ_STATUS monitors the 'readable' key for all i/o providers
74 * Note that we actually monitor the _user_view_ of the configuration:
75 * e.g. if a key has a mandatory value in global conf, then the same
76 * key in user conf will just be ignored.
85 /* private instance data
87 struct _NASettingsPrivate
{
88 gboolean dispose_has_run
;
96 #define GROUP_NACT "nact"
97 #define GROUP_RUNTIME "runtime"
103 const gchar
*default_value
;
107 static const KeyDef st_def_keys
[] = {
108 { NA_IPREFS_ADMIN_PREFERENCES_LOCKED
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
109 { NA_IPREFS_ADMIN_IO_PROVIDERS_LOCKED
, GROUP_RUNTIME
, NA_DATA_TYPE_BOOLEAN
, "false" },
110 { NA_IPREFS_ASSISTANT_ESC_CONFIRM
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "true" },
111 { NA_IPREFS_ASSISTANT_ESC_QUIT
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "true" },
112 { NA_IPREFS_CAPABILITY_ADD_CAPABILITY_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
113 { NA_IPREFS_COMMAND_CHOOSER_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
114 { NA_IPREFS_COMMAND_CHOOSER_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///bin" },
115 { NA_IPREFS_COMMAND_LEGEND_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
116 { NA_IPREFS_CONFIRM_LOGOUT_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
117 { NA_IPREFS_WORKING_DIR_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
118 { NA_IPREFS_WORKING_DIR_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///" },
119 { NA_IPREFS_SHOW_IF_RUNNING_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
120 { NA_IPREFS_SHOW_IF_RUNNING_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///bin" },
121 { NA_IPREFS_TRY_EXEC_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
122 { NA_IPREFS_TRY_EXEC_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///bin" },
123 { NA_IPREFS_EXPORT_ASK_USER_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
124 { NA_IPREFS_EXPORT_ASK_USER_LAST_FORMAT
, GROUP_NACT
, NA_DATA_TYPE_STRING
, NA_IPREFS_DEFAULT_EXPORT_FORMAT
},
125 { NA_IPREFS_EXPORT_ASK_USER_KEEP_LAST_CHOICE
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
126 { NA_IPREFS_EXPORT_ASSISTANT_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
127 { NA_IPREFS_EXPORT_ASSISTANT_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///tmp" },
128 { NA_IPREFS_EXPORT_PREFERRED_FORMAT
, GROUP_NACT
, NA_DATA_TYPE_STRING
, NA_IPREFS_DEFAULT_EXPORT_FORMAT
},
129 { NA_IPREFS_FOLDER_CHOOSER_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
130 { NA_IPREFS_FOLDER_CHOOSER_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///" },
131 { NA_IPREFS_IMPORT_ASK_USER_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
132 { NA_IPREFS_IMPORT_ASK_USER_LAST_MODE
, GROUP_NACT
, NA_DATA_TYPE_STRING
, NA_IPREFS_DEFAULT_IMPORT_MODE
},
133 { NA_IPREFS_IMPORT_ASSISTANT_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
134 { NA_IPREFS_IMPORT_ASSISTANT_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///tmp" },
135 { NA_IPREFS_IMPORT_ASK_USER_KEEP_LAST_CHOICE
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
136 { NA_IPREFS_IMPORT_PREFERRED_MODE
, GROUP_NACT
, NA_DATA_TYPE_STRING
, NA_IPREFS_DEFAULT_IMPORT_MODE
},
137 { NA_IPREFS_IO_PROVIDERS_WRITE_ORDER
, GROUP_NACT
, NA_DATA_TYPE_STRING_LIST
, "" },
138 { NA_IPREFS_ICON_CHOOSER_URI
, GROUP_NACT
, NA_DATA_TYPE_STRING
, "file:///" },
139 { NA_IPREFS_ICON_CHOOSER_PANED
, GROUP_NACT
, NA_DATA_TYPE_UINT
, "200" },
140 { NA_IPREFS_ICON_CHOOSER_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
141 { NA_IPREFS_ITEMS_ADD_ABOUT_ITEM
, GROUP_RUNTIME
, NA_DATA_TYPE_BOOLEAN
, "true" },
142 { NA_IPREFS_ITEMS_CREATE_ROOT_MENU
, GROUP_RUNTIME
, NA_DATA_TYPE_BOOLEAN
, "true" },
143 { NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER
, GROUP_RUNTIME
, NA_DATA_TYPE_STRING_LIST
, "" },
144 { NA_IPREFS_ITEMS_LIST_ORDER_MODE
, GROUP_RUNTIME
, NA_DATA_TYPE_STRING
, NA_IPREFS_DEFAULT_LIST_ORDER_MODE
},
145 { NA_IPREFS_MAIN_PANED
, GROUP_NACT
, NA_DATA_TYPE_UINT
, "200" },
146 { NA_IPREFS_MAIN_SAVE_AUTO
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
147 { NA_IPREFS_MAIN_SAVE_PERIOD
, GROUP_NACT
, NA_DATA_TYPE_UINT
, "5" },
148 { NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "true" },
149 { NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "true" },
150 { NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "true" },
151 { NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
152 { NA_IPREFS_MAIN_WINDOW_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
153 { NA_IPREFS_PREFERENCES_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
154 { NA_IPREFS_RELABEL_DUPLICATE_ACTION
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
155 { NA_IPREFS_RELABEL_DUPLICATE_MENU
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
156 { NA_IPREFS_RELABEL_DUPLICATE_PROFILE
, GROUP_NACT
, NA_DATA_TYPE_BOOLEAN
, "false" },
157 { NA_IPREFS_SCHEME_ADD_SCHEME_WSP
, GROUP_NACT
, NA_DATA_TYPE_UINT_LIST
, "" },
158 { NA_IPREFS_SCHEME_DEFAULT_LIST
, GROUP_NACT
, NA_DATA_TYPE_STRING_LIST
, "" },
159 { NA_IPREFS_IO_PROVIDER_READABLE
, NA_IPREFS_IO_PROVIDER_GROUP
, NA_DATA_TYPE_BOOLEAN
, "true" },
160 { NA_IPREFS_IO_PROVIDER_WRITABLE
, NA_IPREFS_IO_PROVIDER_GROUP
, NA_DATA_TYPE_BOOLEAN
, "true" },
164 /* The configuration content is handled as a GList of KeyValue structs.
165 * This list is loaded at initialization time, and then compared each
166 * time our file monitors signal us that a change has occured.
183 static GObjectClass
*st_parent_class
= NULL
;
184 static gint st_burst_timeout
= 100; /* burst timeout in msec */
185 static gint st_signals
[ LAST_SIGNAL
] = { 0 };
187 static GType
register_type( void );
188 static void class_init( NASettingsClass
*klass
);
189 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
190 static void instance_dispose( GObject
*object
);
191 static void instance_finalize( GObject
*object
);
193 static GList
*content_diff( GList
*old
, GList
*new );
194 static GList
*content_load( NASettings
*settings
);
195 static GList
*content_load_keys( NASettings
*settings
, GList
*content
, KeyFile
*key_file
, gboolean mandatory
);
196 static KeyDef
*get_key_def( const gchar
*key
);
197 static KeyFile
*key_file_new( NASettings
*settings
, const gchar
*dir
);
198 static void on_keyfile_changed( GFileMonitor
*monitor
, GFile
*file
, GFile
*other_file
, GFileMonitorEvent event_type
, NASettings
*settings
);
199 static void on_keyfile_changed_timeout( NASettings
*settings
);
200 static void on_key_changed_final_handler( NASettings
*settings
, gchar
*group
, gchar
*key
, NABoxed
*new_value
, gboolean mandatory
);
201 static KeyValue
*peek_key_value_from_content( GList
*content
, const gchar
*group
, const gchar
*key
);
202 static KeyValue
*read_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
);
203 static KeyValue
*read_key_value_from_key_file( GKeyFile
*key_file
, const gchar
*group
, const gchar
*key
, const KeyDef
*key_def
);
204 static void release_consumer( Consumer
*consumer
);
205 static void release_key_file( KeyFile
*key_file
);
206 static void release_key_value( KeyValue
*value
);
207 static gboolean
set_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, const gchar
*string
);
208 static gboolean
write_user_key_file( NASettings
*settings
);
211 na_settings_get_type( void )
213 static GType object_type
= 0;
216 object_type
= register_type();
219 return( object_type
);
223 register_type( void )
225 static const gchar
*thisfn
= "na_settings_register_type";
228 static GTypeInfo info
= {
229 sizeof( NASettingsClass
),
230 ( GBaseInitFunc
) NULL
,
231 ( GBaseFinalizeFunc
) NULL
,
232 ( GClassInitFunc
) class_init
,
235 sizeof( NASettings
),
237 ( GInstanceInitFunc
) instance_init
240 g_debug( "%s", thisfn
);
242 type
= g_type_register_static( G_TYPE_OBJECT
, "NASettings", &info
, 0 );
248 class_init( NASettingsClass
*klass
)
250 static const gchar
*thisfn
= "na_settings_class_init";
251 GObjectClass
*object_class
;
253 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
255 st_parent_class
= g_type_class_peek_parent( klass
);
257 object_class
= G_OBJECT_CLASS( klass
);
258 object_class
->dispose
= instance_dispose
;
259 object_class
->finalize
= instance_finalize
;
261 klass
->private = g_new0( NASettingsClassPrivate
, 1 );
264 * NASettings::settings-key-changed:
266 * This signal is sent by NASettings when the value of a key is modified.
268 * Arguments are the group, the key, the new value as a NABoxed,
269 * and whether it is mandatory.
271 * Handler is of type:
272 * void ( *handler )( NASettings *settings,
273 * const gchar *group,
276 * gboolean mandatory,
277 * gpointer user_data );
279 * The default class handler frees these datas.
281 st_signals
[ KEY_CHANGED
] = g_signal_new_class_handler(
282 SETTINGS_SIGNAL_KEY_CHANGED
,
284 G_SIGNAL_RUN_CLEANUP
| G_SIGNAL_ACTION
,
285 G_CALLBACK( on_key_changed_final_handler
),
286 NULL
, /* accumulator */
287 NULL
, /* accumulator data */
288 na_cclosure_marshal_VOID__STRING_STRING_POINTER_BOOLEAN
,
291 G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_POINTER
, G_TYPE_BOOLEAN
);
295 instance_init( GTypeInstance
*instance
, gpointer klass
)
297 static const gchar
*thisfn
= "na_settings_instance_init";
300 g_return_if_fail( NA_IS_SETTINGS( instance
));
302 g_debug( "%s: instance=%p (%s), klass=%p",
303 thisfn
, ( void * ) instance
, G_OBJECT_TYPE_NAME( instance
), ( void * ) klass
);
305 self
= NA_SETTINGS( instance
);
307 self
->private = g_new0( NASettingsPrivate
, 1 );
309 self
->private->dispose_has_run
= FALSE
;
310 self
->private->mandatory
= NULL
;
311 self
->private->user
= NULL
;
312 self
->private->content
= NULL
;
313 self
->private->consumers
= NULL
;
315 self
->private->timeout
.timeout
= st_burst_timeout
;
316 self
->private->timeout
.handler
= ( NATimeoutFunc
) on_keyfile_changed_timeout
;
317 self
->private->timeout
.user_data
= self
;
318 self
->private->timeout
.source_id
= 0;
322 instance_dispose( GObject
*object
)
324 static const gchar
*thisfn
= "na_settings_instance_dispose";
327 g_return_if_fail( NA_IS_SETTINGS( object
));
329 self
= NA_SETTINGS( object
);
331 if( !self
->private->dispose_has_run
){
333 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
335 self
->private->dispose_has_run
= TRUE
;
337 release_key_file( self
->private->mandatory
);
338 release_key_file( self
->private->user
);
340 if( G_OBJECT_CLASS( st_parent_class
)->dispose
){
341 G_OBJECT_CLASS( st_parent_class
)->dispose( object
);
347 instance_finalize( GObject
*object
)
349 static const gchar
*thisfn
= "na_settings_instance_finalize";
352 g_return_if_fail( NA_IS_SETTINGS( object
));
354 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
356 self
= NA_SETTINGS( object
);
358 g_list_foreach( self
->private->content
, ( GFunc
) release_key_value
, NULL
);
359 g_list_free( self
->private->content
);
361 g_list_foreach( self
->private->consumers
, ( GFunc
) release_consumer
, NULL
);
362 g_list_free( self
->private->consumers
);
364 g_free( self
->private );
366 /* chain call to parent class */
367 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
368 G_OBJECT_CLASS( st_parent_class
)->finalize( object
);
375 * Returns: a new #NASettings object which should be g_object_unref()
379 na_settings_new( void )
381 static const gchar
*thisfn
= "na_settings_new";
382 NASettings
*settings
;
385 settings
= g_object_new( NA_SETTINGS_TYPE
, NULL
);
387 dir
= g_build_filename( SYSCONFDIR
, "xdg", PACKAGE
, NULL
);
388 g_debug( "%s: reading mandatory configuration", thisfn
);
389 settings
->private->mandatory
= key_file_new( settings
, dir
);
392 dir
= g_build_filename( g_get_home_dir(), ".config", PACKAGE
, NULL
);
393 g_debug( "%s: reading user configuration", thisfn
);
394 settings
->private->user
= key_file_new( settings
, dir
);
397 settings
->private->content
= content_load( settings
);
403 * na_settings_register_key_callback:
404 * @settings: this #NASettings instance.
405 * @key: the key to be monitored.
406 * @callback: the function to be called when the value of the key changes.
407 * @user_data: data to be passed to the @callback function.
409 * Registers a new consumer of the monitoring of the @key.
414 na_settings_register_key_callback( NASettings
*settings
, const gchar
*key
, GCallback callback
, gpointer user_data
)
416 static const gchar
*thisfn
= "na_settings_register_key_callback";
418 g_return_if_fail( NA_IS_SETTINGS( settings
));
420 if( !settings
->private->dispose_has_run
){
421 g_debug( "%s: settings=%p, key=%s, callback=%p, user_data=%p",
422 thisfn
, ( void * ) settings
, key
, ( void * ) callback
, ( void * ) user_data
);
424 Consumer
*consumer
= g_new0( Consumer
, 1 );
426 consumer
->monitored_key
= g_strdup( key
);
427 consumer
->callback
= callback
;
428 consumer
->user_data
= user_data
;
429 settings
->private->consumers
= g_list_prepend( settings
->private->consumers
, consumer
);
434 * na_settings_get_boolean:
435 * @settings: this #NASettings instance.
436 * @key: the key whose value is to be returned.
437 * @found: if not %NULL, a pointer to a gboolean in which we will store
438 * whether the searched @key has been found (%TRUE), or if the returned
439 * value comes from default (%FALSE).
440 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
441 * whether the returned value has been read from mandatory preferences
442 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
443 * been found, @mandatory is set to %FALSE.
445 * This function should only be called for unambiguous keys; the resultat
446 * is otherwise undefined (and rather unpredictable).
448 * Returns: the value of the key, of its default value if not found.
453 na_settings_get_boolean( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
455 return( na_settings_get_boolean_ex( settings
, NULL
, key
, found
, mandatory
));
459 * na_settings_get_boolean_ex:
460 * @settings: this #NASettings instance.
461 * @group: the group where the @key is to be searched for. May be %NULL.
462 * @key: the key whose value is to be returned.
463 * @found: if not %NULL, a pointer to a gboolean in which we will store
464 * whether the searched @key has been found (%TRUE), or if the returned
465 * value comes from default (%FALSE).
466 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
467 * whether the returned value has been read from mandatory preferences
468 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
469 * been found, @mandatory is set to %FALSE.
471 * Returns: the value of the key, of its default value if not found.
476 na_settings_get_boolean_ex( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
483 key_value
= read_key_value( settings
, group
, key
, found
, mandatory
);
486 value
= na_boxed_get_boolean( key_value
->boxed
);
487 release_key_value( key_value
);
490 key_def
= get_key_def( key
);
492 value
= ( key_def
->default_value
? ( strcasecmp( key_def
->default_value
, "true" ) == 0 || atoi( key_def
->default_value
) != 0 ) : FALSE
);
500 * na_settings_get_string:
501 * @settings: this #NASettings instance.
502 * @key: the key whose value is to be returned.
503 * @found: if not %NULL, a pointer to a gboolean in which we will store
504 * whether the searched @key has been found (%TRUE), or if the returned
505 * value comes from default (%FALSE).
506 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
507 * whether the returned value has been read from mandatory preferences
508 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
509 * been found, @mandatory is set to %FALSE.
511 * This function should only be called for unambiguous keys; the resultat
512 * is otherwise undefined (and rather unpredictable).
514 * Returns: the value of the key as a newly allocated string, which should
515 * be g_free() by the caller.
520 na_settings_get_string( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
527 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
530 value
= na_boxed_get_string( key_value
->boxed
);
531 release_key_value( key_value
);
534 key_def
= get_key_def( key
);
535 if( key_def
&& key_def
->default_value
){
536 value
= g_strdup( key_def
->default_value
);
544 * na_settings_get_string_list:
545 * @settings: this #NASettings instance.
546 * @key: the key whose value is to be returned.
547 * @found: if not %NULL, a pointer to a gboolean in which we will store
548 * whether the searched @key has been found (%TRUE), or if the returned
549 * value comes from default (%FALSE).
550 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
551 * whether the returned value has been read from mandatory preferences
552 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
553 * been found, @mandatory is set to %FALSE.
555 * This function should only be called for unambiguous keys; the resultat
556 * is otherwise undefined (and rather unpredictable).
558 * Returns: the value of the key as a newly allocated list of strings.
559 * The returned list should be na_core_utils_slist_free() by the caller.
564 na_settings_get_string_list( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
571 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
574 value
= na_boxed_get_string_list( key_value
->boxed
);
575 release_key_value( key_value
);
578 key_def
= get_key_def( key
);
579 if( key_def
&& key_def
->default_value
&& strlen( key_def
->default_value
)){
580 value
= g_slist_append( NULL
, g_strdup( key_def
->default_value
));
588 * na_settings_get_uint:
589 * @settings: this #NASettings instance.
590 * @key: the key whose value is to be returned.
591 * @found: if not %NULL, a pointer to a gboolean in which we will store
592 * whether the searched @key has been found (%TRUE), or if the returned
593 * value comes from default (%FALSE).
594 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
595 * whether the returned value has been read from mandatory preferences
596 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
597 * been found, @mandatory is set to %FALSE.
599 * This function should only be called for unambiguous keys; the resultat
600 * is otherwise undefined (and rather unpredictable).
602 * Returns: the value of the key.
607 na_settings_get_uint( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
614 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
617 value
= na_boxed_get_uint( key_value
->boxed
);
618 release_key_value( key_value
);
621 key_def
= get_key_def( key
);
622 if( key_def
&& key_def
->default_value
){
623 value
= atoi( key_def
->default_value
);
631 * na_settings_get_uint_list:
632 * @settings: this #NASettings instance.
633 * @key: the key whose value is to be returned.
634 * @found: if not %NULL, a pointer to a gboolean in which we will store
635 * whether the searched @key has been found (%TRUE), or if the returned
636 * value comes from default (%FALSE).
637 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
638 * whether the returned value has been read from mandatory preferences
639 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
640 * been found, @mandatory is set to %FALSE.
642 * This function should only be called for unambiguous keys; the resultat
643 * is otherwise undefined (and rather unpredictable).
645 * Returns: the value of the key as a newly allocated list of uints.
646 * The returned list should be g_list_free() by the caller.
651 na_settings_get_uint_list( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
658 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
661 value
= na_boxed_get_uint_list( key_value
->boxed
);
662 release_key_value( key_value
);
665 key_def
= get_key_def( key
);
666 if( key_def
&& key_def
->default_value
){
667 value
= g_list_append( NULL
, GUINT_TO_POINTER( atoi( key_def
->default_value
)));
675 * na_settings_set_boolean:
676 * @settings: this #NASettings instance.
677 * @key: the key whose value is to be returned.
678 * @value: the boolean to be written.
680 * This function writes @value as a user preference.
682 * This function should only be called for unambiguous keys; the resultat
683 * is otherwise undefined (and rather unpredictable).
685 * Returns: %TRUE is the writing has been successful, %FALSE else.
690 na_settings_set_boolean( NASettings
*settings
, const gchar
*key
, gboolean value
)
695 string
= g_strdup_printf( "%s", value
? "true" : "false" );
696 ok
= set_key_value( settings
, NULL
, key
, string
);
703 * na_settings_set_boolean_ex:
704 * @settings: this #NASettings instance.
705 * @group: the group in the keyed file;
706 * @key: the key whose value is to be returned.
707 * @value: the boolean to be written.
709 * This function writes @value as a user preference.
711 * Returns: %TRUE is the writing has been successful, %FALSE else.
716 na_settings_set_boolean_ex( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean value
)
721 string
= g_strdup_printf( "%s", value
? "true" : "false" );
722 ok
= set_key_value( settings
, group
, key
, string
);
729 * na_settings_set_string:
730 * @settings: this #NASettings instance.
731 * @key: the key whose value is to be returned.
732 * @value: the string to be written.
734 * This function writes @value as a user preference.
736 * This function should only be called for unambiguous keys; the resultat
737 * is otherwise undefined (and rather unpredictable).
739 * Returns: %TRUE is the writing has been successful, %FALSE else.
744 na_settings_set_string( NASettings
*settings
, const gchar
*key
, const gchar
*value
)
746 return( set_key_value( settings
, NULL
, key
, value
));
750 * na_settings_set_string_list:
751 * @settings: this #NASettings instance.
752 * @key: the key whose value is to be returned.
753 * @value: the list of strings to be written.
755 * This function writes @value as a user preference.
757 * This function should only be called for unambiguous keys; the resultat
758 * is otherwise undefined (and rather unpredictable).
760 * Returns: %TRUE is the writing has been successful, %FALSE else.
765 na_settings_set_string_list( NASettings
*settings
, const gchar
*key
, const GSList
*value
)
771 string
= g_string_new( "" );
772 for( it
= value
; it
; it
= it
->next
){
773 g_string_append_printf( string
, "%s;", ( const gchar
* ) it
->data
);
775 ok
= set_key_value( settings
, NULL
, key
, string
->str
);
776 g_string_free( string
, TRUE
);
782 * na_settings_set_uint:
783 * @settings: this #NASettings instance.
784 * @key: the key whose value is to be returned.
785 * @value: the unsigned integer to be written.
787 * This function writes @value as a user preference.
789 * This function should only be called for unambiguous keys; the resultat
790 * is otherwise undefined (and rather unpredictable).
792 * Returns: %TRUE is the writing has been successful, %FALSE else.
797 na_settings_set_uint( NASettings
*settings
, const gchar
*key
, guint value
)
802 string
= g_strdup_printf( "%u", value
);
803 ok
= set_key_value( settings
, NULL
, key
, string
);
810 * na_settings_set_uint_list:
811 * @settings: this #NASettings instance.
812 * @key: the key whose value is to be returned.
813 * @value: the list of unsigned integers to be written.
815 * This function writes @value as a user preference.
817 * This function should only be called for unambiguous keys; the resultat
818 * is otherwise undefined (and rather unpredictable).
820 * Returns: %TRUE is the writing has been successful, %FALSE else.
825 na_settings_set_uint_list( NASettings
*settings
, const gchar
*key
, const GList
*value
)
831 string
= g_string_new( "" );
832 for( it
= value
; it
; it
= it
->next
){
833 g_string_append_printf( string
, "%u;", GPOINTER_TO_UINT( it
->data
));
835 ok
= set_key_value( settings
, NULL
, key
, string
->str
);
836 g_string_free( string
, TRUE
);
842 * na_settings_get_groups:
843 * @settings: this #NASettings instance.
845 * Returns: the list of groups in the configuration; this list should be
846 * na_core_utils_slist_free() by the caller.
848 * This function participates to a rather bad hack to obtain the list of
849 * known i/o providers from preferences. We do not care of returning unique
850 * or sorted group names.
855 na_settings_get_groups( NASettings
*settings
)
862 g_return_val_if_fail( NA_IS_SETTINGS( settings
), NULL
);
864 if( !settings
->private->dispose_has_run
){
866 array
= g_key_file_get_groups( settings
->private->mandatory
->key_file
, NULL
);
868 groups
= na_core_utils_slist_from_array(( const gchar
** ) array
);
872 array
= g_key_file_get_groups( settings
->private->user
->key_file
, NULL
);
874 groups
= g_slist_concat( groups
, na_core_utils_slist_from_array(( const gchar
** ) array
));
883 * returns a list of modified KeyValue
884 * - order in the lists is not signifiant
885 * - the mandatory flag is not signifiant
886 * - a key is modified:
887 * > if it appears in new
888 * > if it disappears: the value is so reset to its default
889 * > if the value has been modified
891 * we return here a new list, with newly allocated KeyValue structs
892 * which hold the new value of each modified key
895 content_diff( GList
*old
, GList
*new )
897 GList
*diffs
, *io
, *in
;
898 KeyValue
*kold
, *knew
, *kdiff
;
903 for( io
= old
; io
; io
= io
->next
){
904 kold
= ( KeyValue
* ) io
->data
;
906 for( in
= new ; in
&& !found
; in
= in
->next
){
907 knew
= ( KeyValue
* ) in
->data
;
908 if( !strcmp( kold
->group
, knew
->group
) && ( gpointer
) kold
->def
== ( gpointer
) knew
->def
){
910 if( !na_boxed_are_equal( kold
->boxed
, knew
->boxed
)){
911 /* a key has been modified */
912 kdiff
= g_new0( KeyValue
, 1 );
913 kdiff
->group
= g_strdup( knew
->group
);
914 kdiff
->def
= knew
->def
;
915 kdiff
->mandatory
= knew
->mandatory
;
916 kdiff
->boxed
= na_boxed_copy( knew
->boxed
);
917 diffs
= g_list_prepend( diffs
, kdiff
);
922 /* a key has disappeared */
923 kdiff
= g_new0( KeyValue
, 1 );
924 kdiff
->group
= g_strdup( kold
->group
);
925 kdiff
->def
= kold
->def
;
926 kdiff
->mandatory
= FALSE
;
927 kdiff
->boxed
= na_boxed_new_from_string( kold
->def
->type
, kold
->def
->default_value
);
928 diffs
= g_list_prepend( diffs
, kdiff
);
932 for( in
= new ; in
; in
= in
->next
){
933 knew
= ( KeyValue
* ) in
->data
;
935 for( io
= old
; io
&& !found
; io
= io
->next
){
936 kold
= ( KeyValue
* ) io
->data
;
937 if( !strcmp( kold
->group
, knew
->group
) && ( gpointer
) kold
->def
== ( gpointer
) knew
->def
){
943 kdiff
= g_new0( KeyValue
, 1 );
944 kdiff
->group
= g_strdup( knew
->group
);
945 kdiff
->def
= knew
->def
;
946 kdiff
->mandatory
= knew
->mandatory
;
947 kdiff
->boxed
= na_boxed_copy( knew
->boxed
);
948 diffs
= g_list_prepend( diffs
, kdiff
);
955 /* load the content of the two configuration files (actually of _the_ configuration)
956 * taking care of not overriding mandatory preferences with user ones
959 content_load( NASettings
*settings
)
963 content
= content_load_keys( settings
, NULL
, settings
->private->mandatory
, TRUE
);
964 content
= content_load_keys( settings
, content
, settings
->private->user
, FALSE
);
970 content_load_keys( NASettings
*settings
, GList
*content
, KeyFile
*key_file
, gboolean mandatory
)
972 static const gchar
*thisfn
= "na_settings_content_load_keys";
974 gchar
**groups
, **ig
;
980 if( !g_key_file_load_from_file( key_file
->key_file
, key_file
->fname
, G_KEY_FILE_KEEP_COMMENTS
, &error
)){
981 if( error
->code
!= G_FILE_ERROR_NOENT
){
982 g_warning( "%s: %s (%d) %s", thisfn
, key_file
->fname
, error
->code
, error
->message
);
984 g_error_free( error
);
988 groups
= g_key_file_get_groups( key_file
->key_file
, NULL
);
991 keys
= g_key_file_get_keys( key_file
->key_file
, *ig
, NULL
, NULL
);
994 key_def
= get_key_def( *ik
);
996 key_value
= peek_key_value_from_content( content
, *ig
, *ik
);
998 key_value
= read_key_value_from_key_file( key_file
->key_file
, *ig
, *ik
, key_def
);
1000 key_value
->mandatory
= mandatory
;
1001 content
= g_list_prepend( content
, key_value
);
1010 g_strfreev( groups
);
1017 get_key_def( const gchar
*key
)
1019 static const gchar
*thisfn
= "na_settings_get_key_def";
1020 KeyDef
*found
= NULL
;
1023 idef
= ( KeyDef
* ) st_def_keys
;
1024 while( idef
->key
&& !found
){
1025 if( !strcmp( idef
->key
, key
)){
1031 g_warning( "%s: no KeyDef found for key=%s", thisfn
, key
);
1038 * called from na_settings_new
1039 * allocate and load the key files for global and user preferences
1042 key_file_new( NASettings
*settings
, const gchar
*dir
)
1044 static const gchar
*thisfn
= "na_settings_key_file_new";
1049 key_file
= g_new0( KeyFile
, 1 );
1051 key_file
->key_file
= g_key_file_new();
1052 key_file
->fname
= g_strdup_printf( "%s/%s.conf", dir
, PACKAGE
);
1055 file
= g_file_new_for_path( key_file
->fname
);
1056 key_file
->monitor
= g_file_monitor_file( file
, 0, NULL
, &error
);
1058 g_warning( "%s: %s: %s", thisfn
, key_file
->fname
, error
->message
);
1059 g_error_free( error
);
1062 key_file
->handler
= g_signal_connect( key_file
->monitor
, "changed", ( GCallback
) on_keyfile_changed
, settings
);
1064 g_object_unref( file
);
1070 * one of the two monitored configuration files have changed on the disk
1071 * we do not try to identify which keys have actually change
1072 * instead we trigger each registered consumer for the 'global' event
1074 * consumers which register for the 'global_conf' event are recorded
1078 on_keyfile_changed( GFileMonitor
*monitor
,
1079 GFile
*file
, GFile
*other_file
, GFileMonitorEvent event_type
, NASettings
*settings
)
1081 g_return_if_fail( NA_IS_SETTINGS( settings
));
1083 if( !settings
->private->dispose_has_run
){
1085 na_timeout_event( &settings
->private->timeout
);
1090 on_keyfile_changed_timeout( NASettings
*settings
)
1092 static const gchar
*thisfn
= "na_settings_on_keyfile_changed_timeout";
1096 const KeyValue
*changed
;
1097 const Consumer
*consumer
;
1098 gchar
*group_prefix
, *key
;
1099 #ifdef NA_MAINTAINER_MODE
1103 /* last individual notification is older that the st_burst_timeout
1104 * we may so suppose that the burst is terminated
1106 new_content
= content_load( settings
);
1107 modifs
= content_diff( settings
->private->content
, new_content
);
1109 #ifdef NA_MAINTAINER_MODE
1110 g_debug( "%s: %d found update(s)", thisfn
, g_list_length( modifs
));
1111 for( im
= modifs
; im
; im
= im
->next
){
1112 changed
= ( const KeyValue
* ) im
->data
;
1113 value
= na_boxed_get_string( changed
->boxed
);
1114 g_debug( "%s: group=%s, key=%s, value=%s", thisfn
, changed
->group
, changed
->def
->key
, value
);
1119 /* for each modification found,
1120 * - check if a consumer has registered for this key, and triggers callback if apply
1121 * - send a notification message
1123 for( im
= modifs
; im
; im
= im
->next
){
1124 changed
= ( const KeyValue
* ) im
->data
;
1126 for( ic
= settings
->private->consumers
; ic
; ic
= ic
->next
){
1127 consumer
= ( const Consumer
* ) ic
->data
;
1128 group_prefix
= NULL
;
1130 if( !strcmp( consumer
->monitored_key
, NA_IPREFS_IO_PROVIDERS_READ_STATUS
)){
1131 group_prefix
= g_strdup_printf( "%s ", NA_IPREFS_IO_PROVIDER_GROUP
);
1132 key
= NA_IPREFS_IO_PROVIDER_READABLE
;
1134 key
= consumer
->monitored_key
;
1137 if(( !group_prefix
|| g_str_has_prefix( changed
->group
, group_prefix
)) && !strcmp( changed
->def
->key
, key
)){
1138 ( *( NASettingsKeyCallback
) consumer
->callback
)(
1141 na_boxed_get_pointer( changed
->boxed
),
1143 consumer
->user_data
);
1146 g_free( group_prefix
);
1149 g_debug( "%s: sending signal for group=%s, key=%s", thisfn
, changed
->group
, changed
->def
->key
);
1150 g_signal_emit_by_name( settings
,
1151 SETTINGS_SIGNAL_KEY_CHANGED
,
1152 changed
->group
, changed
->def
->key
, changed
->boxed
, changed
->mandatory
);
1155 g_debug( "%s: releasing content", thisfn
);
1156 g_list_foreach( settings
->private->content
, ( GFunc
) release_key_value
, NULL
);
1157 g_list_free( settings
->private->content
);
1158 settings
->private->content
= new_content
;
1160 g_debug( "%s: releasing modifs", thisfn
);
1161 g_list_foreach( modifs
, ( GFunc
) release_key_value
, NULL
);
1162 g_list_free( modifs
);
1166 on_key_changed_final_handler( NASettings
*settings
, gchar
*group
, gchar
*key
, NABoxed
*new_value
, gboolean mandatory
)
1168 g_debug( "na_settings_on_key_changed_final_handler: group=%s, key=%s", group
, key
);
1169 na_boxed_dump( new_value
);
1173 peek_key_value_from_content( GList
*content
, const gchar
*group
, const gchar
*key
)
1175 KeyValue
*value
, *found
;
1179 for( ic
= content
; ic
&& !found
; ic
= ic
->next
){
1180 value
= ( KeyValue
* ) ic
->data
;
1181 if( !strcmp( value
->group
, group
) && !strcmp( value
->def
->key
, key
)){
1189 /* group may be NULL
1192 read_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
1196 KeyValue
*key_value
;
1198 g_return_val_if_fail( NA_IS_SETTINGS( settings
), NULL
);
1208 if( !settings
->private->dispose_has_run
){
1210 key_def
= get_key_def( key
);
1213 key_value
= read_key_value_from_key_file( settings
->private->mandatory
->key_file
, group
? group
: key_def
->group
, key
, key_def
);
1224 key_value
= read_key_value_from_key_file( settings
->private->user
->key_file
, group
? group
: key_def
->group
, key
, key_def
);
1235 return( key_value
);
1239 read_key_value_from_key_file( GKeyFile
*key_file
, const gchar
*group
, const gchar
*key
, const KeyDef
*key_def
)
1241 static const gchar
*thisfn
= "na_settings_read_key_value_from_key_file";
1246 g_debug( "%s: group=%s, key=%s", thisfn
, group
, key
);
1251 switch( key_def
->type
){
1253 case NA_DATA_TYPE_STRING
:
1254 case NA_DATA_TYPE_STRING_LIST
:
1255 case NA_DATA_TYPE_UINT
:
1256 case NA_DATA_TYPE_UINT_LIST
:
1257 case NA_DATA_TYPE_BOOLEAN
:
1258 str
= g_key_file_get_string( key_file
, group
, key
, &error
);
1260 if( error
->code
!= G_KEY_FILE_ERROR_KEY_NOT_FOUND
&& error
->code
!= G_KEY_FILE_ERROR_GROUP_NOT_FOUND
){
1261 g_warning( "%s: %s", thisfn
, error
->message
);
1263 g_error_free( error
);
1265 /* key exists, but may be empty */
1267 value
= g_new0( KeyValue
, 1 );
1268 value
->group
= g_strdup( group
);
1269 value
->def
= key_def
;
1270 switch( key_def
->type
){
1271 case NA_DATA_TYPE_STRING
:
1272 case NA_DATA_TYPE_UINT
:
1273 case NA_DATA_TYPE_BOOLEAN
:
1274 case NA_DATA_TYPE_STRING_LIST
:
1275 case NA_DATA_TYPE_UINT_LIST
:
1276 value
->boxed
= na_boxed_new_from_string( key_def
->type
, str
);
1284 g_warning( "%s: unmanaged boxed type: %d", thisfn
, key_def
->type
);
1292 * called from instance_finalize
1293 * release the list of registered consumers
1296 release_consumer( Consumer
*consumer
)
1298 g_free( consumer
->monitored_key
);
1303 * called from instance_dispose
1304 * release the opened and monitored GKeyFiles
1307 release_key_file( KeyFile
*key_file
)
1309 g_key_file_free( key_file
->key_file
);
1310 if( key_file
->monitor
){
1311 if( key_file
->handler
){
1312 g_signal_handler_disconnect( key_file
->monitor
, key_file
->handler
);
1314 g_file_monitor_cancel( key_file
->monitor
);
1315 g_object_unref( key_file
->monitor
);
1317 g_free( key_file
->fname
);
1322 * called from instance_finalize
1323 * release a KeyValue struct
1326 release_key_value( KeyValue
*value
)
1328 g_free(( gpointer
) value
->group
);
1329 g_object_unref( value
->boxed
);
1334 set_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, const gchar
*string
)
1337 const gchar
*wgroup
;
1340 g_return_val_if_fail( NA_IS_SETTINGS( settings
), FALSE
);
1344 if( !settings
->private->dispose_has_run
){
1348 key_def
= get_key_def( key
);
1350 wgroup
= key_def
->group
;
1354 g_key_file_set_string( settings
->private->user
->key_file
, wgroup
, key
, string
);
1355 ok
= write_user_key_file( settings
);
1363 write_user_key_file( NASettings
*settings
)
1365 static const gchar
*thisfn
= "na_settings_write_user_key_file";
1368 GFileOutputStream
*stream
;
1373 data
= g_key_file_to_data( settings
->private->user
->key_file
, &length
, NULL
);
1374 file
= g_file_new_for_path( settings
->private->user
->fname
);
1376 stream
= g_file_replace( file
, NULL
, FALSE
, G_FILE_CREATE_NONE
, NULL
, &error
);
1378 g_warning( "%s: g_file_replace: %s", thisfn
, error
->message
);
1379 g_error_free( error
);
1381 g_object_unref( stream
);
1383 g_object_unref( file
);
1388 g_output_stream_write( G_OUTPUT_STREAM( stream
), data
, length
, NULL
, &error
);
1390 g_warning( "%s: g_output_stream_write: %s", thisfn
, error
->message
);
1391 g_error_free( error
);
1392 g_object_unref( stream
);
1393 g_object_unref( file
);
1398 g_output_stream_close( G_OUTPUT_STREAM( stream
), NULL
, &error
);
1400 g_warning( "%s: g_output_stream_close: %s", thisfn
, error
->message
);
1401 g_error_free( error
);
1402 g_object_unref( stream
);
1403 g_object_unref( file
);
1408 g_object_unref( stream
);
1409 g_object_unref( file
);