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-core-utils.h>
42 #include <api/na-timeout.h>
44 #include "na-settings.h"
48 struct _NASettingsClassPrivate
{
49 void *empty
; /* so that gcc -pedantic is happy */
52 /* The characteristics of a configuration file.
53 * We manage two configuration files:
54 * - the global configuration file handles mandatory preferences;
55 * - the user configuration file handles.. well, user preferences.
60 GFileMonitor
*monitor
;
65 /* The configuration content is handled as a GList of NAKeyValue structs.
66 * This list is loaded at initialization time, and then compared each
67 * time our file monitors signal us that a change has occured.
77 /* Each consumer may register a callback function which will be triggered
78 * when a key is modified.
79 * The monitored key may be a real key of the file, but also be a composite
80 * key (e.g. NA_IPREFS_IO_PROVIDERS_READ_STATUS monitors the 'readable'
81 * key of all i/o providers).
82 * Note that we actually monitor the _user_view_ of the configuration:
83 * e.g. if a key has a mandatory value in global conf, then the same
84 * key in user conf will just be ignored.
93 /* private instance data
95 struct _NASettingsPrivate
{
96 gboolean dispose_has_run
;
104 #define GROUP_NACT "nact"
105 #define GROUP_RUNTIME "runtime"
111 const gchar
*default_value
;
115 static const KeyDef st_def_keys
[] = {
116 { NA_IPREFS_ADMIN_PREFERENCES_LOCKED
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
117 { NA_IPREFS_ADMIN_IO_PROVIDERS_LOCKED
, GROUP_RUNTIME
, NA_BOXED_TYPE_BOOLEAN
, "false" },
118 { NA_IPREFS_ASSISTANT_ESC_CONFIRM
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "true" },
119 { NA_IPREFS_ASSISTANT_ESC_QUIT
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "true" },
120 { NA_IPREFS_CAPABILITY_ADD_CAPABILITY_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
121 { NA_IPREFS_COMMAND_CHOOSER_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
122 { NA_IPREFS_COMMAND_CHOOSER_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///bin" },
123 { NA_IPREFS_COMMAND_LEGEND_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
124 { NA_IPREFS_WORKING_DIR_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
125 { NA_IPREFS_WORKING_DIR_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///" },
126 { NA_IPREFS_SHOW_IF_RUNNING_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
127 { NA_IPREFS_SHOW_IF_RUNNING_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///bin" },
128 { NA_IPREFS_TRY_EXEC_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
129 { NA_IPREFS_TRY_EXEC_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///bin" },
130 { NA_IPREFS_EXPORT_ASK_USER_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
131 { NA_IPREFS_EXPORT_ASK_USER_LAST_FORMAT
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, NA_IPREFS_DEFAULT_EXPORT_FORMAT
},
132 { NA_IPREFS_EXPORT_ASK_USER_KEEP_LAST_CHOICE
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
133 { NA_IPREFS_EXPORT_ASSISTANT_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
134 { NA_IPREFS_EXPORT_ASSISTANT_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///tmp" },
135 { NA_IPREFS_EXPORT_PREFERRED_FORMAT
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, NA_IPREFS_DEFAULT_EXPORT_FORMAT
},
136 { NA_IPREFS_FOLDER_CHOOSER_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
137 { NA_IPREFS_FOLDER_CHOOSER_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///" },
138 { NA_IPREFS_IMPORT_ASK_USER_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
139 { NA_IPREFS_IMPORT_ASK_USER_LAST_MODE
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, NA_IPREFS_DEFAULT_IMPORT_MODE
},
140 { NA_IPREFS_IMPORT_ASSISTANT_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
141 { NA_IPREFS_IMPORT_ASSISTANT_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///tmp" },
142 { NA_IPREFS_IMPORT_ASK_USER_KEEP_LAST_CHOICE
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
143 { NA_IPREFS_IMPORT_PREFERRED_MODE
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, NA_IPREFS_DEFAULT_IMPORT_MODE
},
144 { NA_IPREFS_IO_PROVIDERS_WRITE_ORDER
, GROUP_NACT
, NA_BOXED_TYPE_STRING_LIST
, "" },
145 { NA_IPREFS_ICON_CHOOSER_URI
, GROUP_NACT
, NA_BOXED_TYPE_STRING
, "file:///" },
146 { NA_IPREFS_ICON_CHOOSER_PANED
, GROUP_NACT
, NA_BOXED_TYPE_UINT
, "200" },
147 { NA_IPREFS_ICON_CHOOSER_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
148 { NA_IPREFS_ITEMS_ADD_ABOUT_ITEM
, GROUP_RUNTIME
, NA_BOXED_TYPE_BOOLEAN
, "true" },
149 { NA_IPREFS_ITEMS_CREATE_ROOT_MENU
, GROUP_RUNTIME
, NA_BOXED_TYPE_BOOLEAN
, "true" },
150 { NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER
, GROUP_RUNTIME
, NA_BOXED_TYPE_STRING_LIST
, "" },
151 { NA_IPREFS_ITEMS_LIST_ORDER_MODE
, GROUP_RUNTIME
, NA_BOXED_TYPE_STRING
, NA_IPREFS_DEFAULT_LIST_ORDER_MODE
},
152 { NA_IPREFS_MAIN_PANED
, GROUP_NACT
, NA_BOXED_TYPE_UINT
, "200" },
153 { NA_IPREFS_MAIN_SAVE_AUTO
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
154 { NA_IPREFS_MAIN_SAVE_PERIOD
, GROUP_NACT
, NA_BOXED_TYPE_UINT
, "5" },
155 { NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "true" },
156 { NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "true" },
157 { NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "true" },
158 { NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
159 { NA_IPREFS_MAIN_WINDOW_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
160 { NA_IPREFS_PREFERENCES_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
161 { NA_IPREFS_RELABEL_DUPLICATE_ACTION
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
162 { NA_IPREFS_RELABEL_DUPLICATE_MENU
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
163 { NA_IPREFS_RELABEL_DUPLICATE_PROFILE
, GROUP_NACT
, NA_BOXED_TYPE_BOOLEAN
, "false" },
164 { NA_IPREFS_SCHEME_ADD_SCHEME_WSP
, GROUP_NACT
, NA_BOXED_TYPE_UINT_LIST
, "" },
165 { NA_IPREFS_SCHEME_DEFAULT_LIST
, GROUP_NACT
, NA_BOXED_TYPE_STRING_LIST
, "" },
166 { NA_IPREFS_IO_PROVIDER_READABLE
, NA_IPREFS_IO_PROVIDER_GROUP
, NA_BOXED_TYPE_BOOLEAN
, "true" },
167 { NA_IPREFS_IO_PROVIDER_WRITABLE
, NA_IPREFS_IO_PROVIDER_GROUP
, NA_BOXED_TYPE_BOOLEAN
, "true" },
171 static GObjectClass
*st_parent_class
= NULL
;
172 static gint st_burst_timeout
= 100; /* burst timeout in msec */
174 static GType
register_type( void );
175 static void class_init( NASettingsClass
*klass
);
176 static void instance_init( GTypeInstance
*instance
, gpointer klass
);
177 static void instance_dispose( GObject
*object
);
178 static void instance_finalize( GObject
*object
);
180 static GList
*content_diff( GList
*old
, GList
*new );
181 static GList
*content_load( NASettings
*settings
);
182 static GList
*content_load_keys( NASettings
*settings
, GList
*content
, KeyFile
*key_file
, gboolean mandatory
);
183 static KeyDef
*get_key_def( const gchar
*key
);
184 static KeyFile
*key_file_new( NASettings
*settings
, const gchar
*dir
);
185 static void on_keyfile_changed( GFileMonitor
*monitor
, GFile
*file
, GFile
*other_file
, GFileMonitorEvent event_type
, NASettings
*settings
);
186 static void on_keyfile_changed_timeout( NASettings
*settings
);
187 static KeyValue
*peek_key_value_from_content( GList
*content
, const gchar
*group
, const gchar
*key
);
188 static KeyValue
*read_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
);
189 static KeyValue
*read_key_value_from_key_file( GKeyFile
*key_file
, const gchar
*group
, const gchar
*key
, const KeyDef
*key_def
);
190 static void release_consumer( Consumer
*consumer
);
191 static void release_key_file( KeyFile
*key_file
);
192 static void release_key_value( KeyValue
*value
);
193 static gboolean
set_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, const gchar
*string
);
194 static gboolean
write_user_key_file( NASettings
*settings
);
197 na_settings_get_type( void )
199 static GType object_type
= 0;
202 object_type
= register_type();
205 return( object_type
);
209 register_type( void )
211 static const gchar
*thisfn
= "na_settings_register_type";
214 static GTypeInfo info
= {
215 sizeof( NASettingsClass
),
216 ( GBaseInitFunc
) NULL
,
217 ( GBaseFinalizeFunc
) NULL
,
218 ( GClassInitFunc
) class_init
,
221 sizeof( NASettings
),
223 ( GInstanceInitFunc
) instance_init
226 g_debug( "%s", thisfn
);
228 type
= g_type_register_static( G_TYPE_OBJECT
, "NASettings", &info
, 0 );
234 class_init( NASettingsClass
*klass
)
236 static const gchar
*thisfn
= "na_settings_class_init";
237 GObjectClass
*object_class
;
239 g_debug( "%s: klass=%p", thisfn
, ( void * ) klass
);
241 st_parent_class
= g_type_class_peek_parent( klass
);
243 object_class
= G_OBJECT_CLASS( klass
);
244 object_class
->dispose
= instance_dispose
;
245 object_class
->finalize
= instance_finalize
;
247 klass
->private = g_new0( NASettingsClassPrivate
, 1 );
251 instance_init( GTypeInstance
*instance
, gpointer klass
)
253 static const gchar
*thisfn
= "na_settings_instance_init";
256 g_return_if_fail( NA_IS_SETTINGS( instance
));
258 g_debug( "%s: instance=%p (%s), klass=%p",
259 thisfn
, ( void * ) instance
, G_OBJECT_TYPE_NAME( instance
), ( void * ) klass
);
261 self
= NA_SETTINGS( instance
);
263 self
->private = g_new0( NASettingsPrivate
, 1 );
265 self
->private->dispose_has_run
= FALSE
;
266 self
->private->mandatory
= NULL
;
267 self
->private->user
= NULL
;
268 self
->private->content
= NULL
;
269 self
->private->consumers
= NULL
;
271 self
->private->timeout
.timeout
= st_burst_timeout
;
272 self
->private->timeout
.handler
= ( NATimeoutFunc
) on_keyfile_changed_timeout
;
273 self
->private->timeout
.user_data
= self
;
274 self
->private->timeout
.source_id
= 0;
278 instance_dispose( GObject
*object
)
280 static const gchar
*thisfn
= "na_settings_instance_dispose";
283 g_return_if_fail( NA_IS_SETTINGS( object
));
285 self
= NA_SETTINGS( object
);
287 if( !self
->private->dispose_has_run
){
289 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
291 self
->private->dispose_has_run
= TRUE
;
293 release_key_file( self
->private->mandatory
);
294 release_key_file( self
->private->user
);
296 if( G_OBJECT_CLASS( st_parent_class
)->dispose
){
297 G_OBJECT_CLASS( st_parent_class
)->dispose( object
);
303 instance_finalize( GObject
*object
)
305 static const gchar
*thisfn
= "na_settings_instance_finalize";
308 g_return_if_fail( NA_IS_SETTINGS( object
));
310 g_debug( "%s: object=%p (%s)", thisfn
, ( void * ) object
, G_OBJECT_TYPE_NAME( object
));
312 self
= NA_SETTINGS( object
);
314 g_list_foreach( self
->private->content
, ( GFunc
) release_key_value
, NULL
);
315 g_list_free( self
->private->content
);
317 g_list_foreach( self
->private->consumers
, ( GFunc
) release_consumer
, NULL
);
318 g_list_free( self
->private->consumers
);
320 g_free( self
->private );
322 /* chain call to parent class */
323 if( G_OBJECT_CLASS( st_parent_class
)->finalize
){
324 G_OBJECT_CLASS( st_parent_class
)->finalize( object
);
331 * Returns: a new #NASettings object which should be g_object_unref()
335 na_settings_new( void )
337 static const gchar
*thisfn
= "na_settings_new";
338 NASettings
*settings
;
341 settings
= g_object_new( NA_SETTINGS_TYPE
, NULL
);
343 dir
= g_build_filename( SYSCONFDIR
, "xdg", NULL
);
344 g_debug( "%s: reading mandatory configuration", thisfn
);
345 settings
->private->mandatory
= key_file_new( settings
, dir
);
348 dir
= g_build_filename( g_get_home_dir(), ".config", NULL
);
349 g_debug( "%s: reading user configuration", thisfn
);
350 settings
->private->user
= key_file_new( settings
, dir
);
353 settings
->private->content
= content_load( settings
);
359 * na_settings_register_key_callback:
360 * @settings: this #NASettings instance.
361 * @key: the key to be monitored.
362 * @callback: the function to be called when the value of the key changes.
363 * @user_data: data to be passed to the @callback function.
365 * Registers a new consumer of the monitoring of the @key.
370 na_settings_register_key_callback( NASettings
*settings
, const gchar
*key
, GCallback callback
, gpointer user_data
)
372 static const gchar
*thisfn
= "na_settings_register_key_callback";
374 g_return_if_fail( NA_IS_SETTINGS( settings
));
376 if( !settings
->private->dispose_has_run
){
377 g_debug( "%s: settings=%p, key=%s, callback=%p, user_data=%p",
378 thisfn
, ( void * ) settings
, key
, ( void * ) callback
, ( void * ) user_data
);
380 Consumer
*consumer
= g_new0( Consumer
, 1 );
382 consumer
->monitored_key
= g_strdup( key
);
383 consumer
->callback
= callback
;
384 consumer
->user_data
= user_data
;
385 settings
->private->consumers
= g_list_prepend( settings
->private->consumers
, consumer
);
391 * na_settings_register_global_callback:
392 * @settings: this #NASettings instance.
393 * @callback: the function to be called when the value of the key changes.
394 * @user_data: data to be passed to the @callback function.
396 * Registers a new consumer of the monitoring of the configuration files.
401 na_settings_register_global_callback( NASettings
*settings
, GCallback callback
, gpointer user_data
)
403 g_return_if_fail( NA_IS_SETTINGS( settings
));
405 if( !settings
->private->dispose_has_run
){
407 Consumer
*consumer
= g_new0( Consumer
, 1 );
409 consumer
->key
= NULL
;
410 consumer
->callback
= callback
;
411 consumer
->user_data
= user_data
;
412 settings
->private->consumers
= g_list_prepend( settings
->private->consumers
, consumer
);
419 * na_settings_get_boolean:
420 * @settings: this #NASettings instance.
421 * @key: the key whose value is to be returned.
422 * @found: if not %NULL, a pointer to a gboolean in which we will store
423 * whether the searched @key has been found (%TRUE), or if the returned
424 * value comes from default (%FALSE).
425 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
426 * whether the returned value has been read from mandatory preferences
427 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
428 * been found, @mandatory is set to %FALSE.
430 * This function should only be called for unambiguous keys; the resultat
431 * is otherwise undefined (and rather unpredictable).
433 * Returns: the value of the key, of its default value if not found.
438 na_settings_get_boolean( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
440 return( na_settings_get_boolean_ex( settings
, NULL
, key
, found
, mandatory
));
444 * na_settings_get_boolean_ex:
445 * @settings: this #NASettings instance.
446 * @group: the group where the @key is to be searched for. May be %NULL.
447 * @key: the key whose value is to be returned.
448 * @found: if not %NULL, a pointer to a gboolean in which we will store
449 * whether the searched @key has been found (%TRUE), or if the returned
450 * value comes from default (%FALSE).
451 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
452 * whether the returned value has been read from mandatory preferences
453 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
454 * been found, @mandatory is set to %FALSE.
456 * Returns: the value of the key, of its default value if not found.
461 na_settings_get_boolean_ex( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
468 key_value
= read_key_value( settings
, group
, key
, found
, mandatory
);
471 value
= na_boxed_get_boolean( key_value
->boxed
);
472 release_key_value( key_value
);
475 key_def
= get_key_def( key
);
477 value
= ( key_def
->default_value
? ( strcasecmp( key_def
->default_value
, "true" ) == 0 || atoi( key_def
->default_value
) != 0 ) : FALSE
);
485 * na_settings_get_string:
486 * @settings: this #NASettings instance.
487 * @key: the key whose value is to be returned.
488 * @found: if not %NULL, a pointer to a gboolean in which we will store
489 * whether the searched @key has been found (%TRUE), or if the returned
490 * value comes from default (%FALSE).
491 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
492 * whether the returned value has been read from mandatory preferences
493 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
494 * been found, @mandatory is set to %FALSE.
496 * This function should only be called for unambiguous keys; the resultat
497 * is otherwise undefined (and rather unpredictable).
499 * Returns: the value of the key as a newly allocated string, which should
500 * be g_free() by the caller.
505 na_settings_get_string( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
512 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
515 value
= na_boxed_get_string( key_value
->boxed
);
516 release_key_value( key_value
);
519 key_def
= get_key_def( key
);
520 if( key_def
&& key_def
->default_value
){
521 value
= g_strdup( key_def
->default_value
);
529 * na_settings_get_string_list:
530 * @settings: this #NASettings instance.
531 * @key: the key whose value is to be returned.
532 * @found: if not %NULL, a pointer to a gboolean in which we will store
533 * whether the searched @key has been found (%TRUE), or if the returned
534 * value comes from default (%FALSE).
535 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
536 * whether the returned value has been read from mandatory preferences
537 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
538 * been found, @mandatory is set to %FALSE.
540 * This function should only be called for unambiguous keys; the resultat
541 * is otherwise undefined (and rather unpredictable).
543 * Returns: the value of the key as a newly allocated list of strings.
544 * The returned list should be na_core_utils_slist_free() by the caller.
549 na_settings_get_string_list( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
556 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
559 value
= na_boxed_get_string_list( key_value
->boxed
);
560 release_key_value( key_value
);
563 key_def
= get_key_def( key
);
564 if( key_def
&& key_def
->default_value
&& strlen( key_def
->default_value
)){
565 value
= g_slist_append( NULL
, g_strdup( key_def
->default_value
));
573 * na_settings_get_uint:
574 * @settings: this #NASettings instance.
575 * @key: the key whose value is to be returned.
576 * @found: if not %NULL, a pointer to a gboolean in which we will store
577 * whether the searched @key has been found (%TRUE), or if the returned
578 * value comes from default (%FALSE).
579 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
580 * whether the returned value has been read from mandatory preferences
581 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
582 * been found, @mandatory is set to %FALSE.
584 * This function should only be called for unambiguous keys; the resultat
585 * is otherwise undefined (and rather unpredictable).
587 * Returns: the value of the key.
592 na_settings_get_uint( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
599 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
602 value
= na_boxed_get_uint( key_value
->boxed
);
603 release_key_value( key_value
);
606 key_def
= get_key_def( key
);
607 if( key_def
&& key_def
->default_value
){
608 value
= atoi( key_def
->default_value
);
616 * na_settings_get_uint_list:
617 * @settings: this #NASettings instance.
618 * @key: the key whose value is to be returned.
619 * @found: if not %NULL, a pointer to a gboolean in which we will store
620 * whether the searched @key has been found (%TRUE), or if the returned
621 * value comes from default (%FALSE).
622 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
623 * whether the returned value has been read from mandatory preferences
624 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
625 * been found, @mandatory is set to %FALSE.
627 * This function should only be called for unambiguous keys; the resultat
628 * is otherwise undefined (and rather unpredictable).
630 * Returns: the value of the key as a newly allocated list of uints.
631 * The returned list should be g_list_free() by the caller.
636 na_settings_get_uint_list( NASettings
*settings
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
643 key_value
= read_key_value( settings
, NULL
, key
, found
, mandatory
);
646 value
= na_boxed_get_uint_list( key_value
->boxed
);
647 release_key_value( key_value
);
650 key_def
= get_key_def( key
);
651 if( key_def
&& key_def
->default_value
){
652 value
= g_list_append( NULL
, GUINT_TO_POINTER( atoi( key_def
->default_value
)));
660 * na_settings_set_boolean:
661 * @settings: this #NASettings instance.
662 * @key: the key whose value is to be returned.
663 * @value: the boolean to be written.
665 * This function writes @value as a user preference.
667 * This function should only be called for unambiguous keys; the resultat
668 * is otherwise undefined (and rather unpredictable).
670 * Returns: %TRUE is the writing has been successfull, %FALSE else.
675 na_settings_set_boolean( NASettings
*settings
, const gchar
*key
, gboolean value
)
680 string
= g_strdup_printf( "%s", value
? "true" : "false" );
681 ok
= set_key_value( settings
, NULL
, key
, string
);
688 * na_settings_set_boolean_ex:
689 * @settings: this #NASettings instance.
690 * @group: the group in the keyed file;
691 * @key: the key whose value is to be returned.
692 * @value: the boolean to be written.
694 * This function writes @value as a user preference.
696 * Returns: %TRUE is the writing has been successfull, %FALSE else.
701 na_settings_set_boolean_ex( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean value
)
706 string
= g_strdup_printf( "%s", value
? "true" : "false" );
707 ok
= set_key_value( settings
, group
, key
, string
);
714 * na_settings_set_string:
715 * @settings: this #NASettings instance.
716 * @key: the key whose value is to be returned.
717 * @value: the string to be written.
719 * This function writes @value as a user preference.
721 * This function should only be called for unambiguous keys; the resultat
722 * is otherwise undefined (and rather unpredictable).
724 * Returns: %TRUE is the writing has been successfull, %FALSE else.
729 na_settings_set_string( NASettings
*settings
, const gchar
*key
, const gchar
*value
)
731 return( set_key_value( settings
, NULL
, key
, value
));
735 * na_settings_set_string_list:
736 * @settings: this #NASettings instance.
737 * @key: the key whose value is to be returned.
738 * @value: the list of strings to be written.
740 * This function writes @value as a user preference.
742 * This function should only be called for unambiguous keys; the resultat
743 * is otherwise undefined (and rather unpredictable).
745 * Returns: %TRUE is the writing has been successfull, %FALSE else.
750 na_settings_set_string_list( NASettings
*settings
, const gchar
*key
, const GSList
*value
)
756 string
= g_string_new( "" );
757 for( it
= value
; it
; it
= it
->next
){
758 g_string_append_printf( string
, "%s;", ( const gchar
* ) it
->data
);
760 ok
= set_key_value( settings
, NULL
, key
, string
->str
);
761 g_string_free( string
, TRUE
);
767 * na_settings_set_uint:
768 * @settings: this #NASettings instance.
769 * @key: the key whose value is to be returned.
770 * @value: the unsigned integer to be written.
772 * This function writes @value as a user preference.
774 * This function should only be called for unambiguous keys; the resultat
775 * is otherwise undefined (and rather unpredictable).
777 * Returns: %TRUE is the writing has been successfull, %FALSE else.
782 na_settings_set_uint( NASettings
*settings
, const gchar
*key
, guint value
)
787 string
= g_strdup_printf( "%u", value
);
788 ok
= set_key_value( settings
, NULL
, key
, string
);
795 * na_settings_set_uint_list:
796 * @settings: this #NASettings instance.
797 * @key: the key whose value is to be returned.
798 * @value: the list of unsigned integers to be written.
800 * This function writes @value as a user preference.
802 * This function should only be called for unambiguous keys; the resultat
803 * is otherwise undefined (and rather unpredictable).
805 * Returns: %TRUE is the writing has been successfull, %FALSE else.
810 na_settings_set_uint_list( NASettings
*settings
, const gchar
*key
, const GList
*value
)
816 string
= g_string_new( "" );
817 for( it
= value
; it
; it
= it
->next
){
818 g_string_append_printf( string
, "%u;", GPOINTER_TO_UINT( it
->data
));
820 ok
= set_key_value( settings
, NULL
, key
, string
->str
);
821 g_string_free( string
, TRUE
);
827 * na_settings_get_groups:
828 * @settings: this #NASettings instance.
830 * Returns: the list of groups in the configuration; this list should be
831 * na_core_utils_slist_free() by the caller.
833 * This function participates to a rather bad hack to obtain the list of
834 * known i/o providers from preferences. We do not care of returning unique
835 * or sorted group names.
840 na_settings_get_groups( NASettings
*settings
)
847 g_return_val_if_fail( NA_IS_SETTINGS( settings
), NULL
);
849 if( !settings
->private->dispose_has_run
){
851 array
= g_key_file_get_groups( settings
->private->mandatory
->key_file
, NULL
);
853 groups
= na_core_utils_slist_from_array(( const gchar
** ) array
);
857 array
= g_key_file_get_groups( settings
->private->user
->key_file
, NULL
);
859 groups
= g_slist_concat( groups
, na_core_utils_slist_from_array(( const gchar
** ) array
));
868 * returns a list of modified KeyValue
869 * - order in the lists is not signifiant
870 * - the mandatory flag is not signifiant
871 * - a key is modified:
872 * > if it appears in new
873 * > if it disappears: the value is so reset to its default
874 * > if the value has been modified
876 * we return here a new list, with newly allocated KeyValue structs
877 * which hold the new value of each modified key
880 content_diff( GList
*old
, GList
*new )
882 GList
*diffs
, *io
, *in
;
883 KeyValue
*kold
, *knew
, *kdiff
;
889 for( io
= old
; io
; io
= io
->next
){
890 kold
= ( KeyValue
* ) io
->data
;
892 for( in
= new ; in
&& !found
; in
= in
->next
){
893 knew
= ( KeyValue
* ) in
->data
;
894 if( !strcmp( kold
->group
, knew
->group
) && !strcmp( kold
->key
, knew
->key
)){
896 if( na_boxed_compare( kold
->boxed
, knew
->boxed
) != 0 ){
897 /* a key has been modified */
898 kdiff
= g_new0( KeyValue
, 1 );
899 kdiff
->group
= g_strdup( knew
->group
);
900 kdiff
->key
= g_strdup( knew
->key
);
901 kdiff
->mandatory
= knew
->mandatory
;
902 kdiff
->boxed
= na_boxed_copy( knew
->boxed
);
903 diffs
= g_list_prepend( diffs
, kdiff
);
908 key_def
= get_key_def( kold
->key
);
910 /* a key has disappeared */
911 kdiff
= g_new0( KeyValue
, 1 );
912 kdiff
->group
= g_strdup( kold
->group
);
913 kdiff
->key
= g_strdup( kold
->key
);
914 kdiff
->mandatory
= FALSE
;
915 kdiff
->boxed
= na_boxed_new_from_string( key_def
->type
, key_def
->default_value
);
916 diffs
= g_list_prepend( diffs
, kdiff
);
921 for( in
= new ; in
; in
= in
->next
){
922 knew
= ( KeyValue
* ) in
->data
;
924 for( io
= old
; io
&& !found
; io
= io
->next
){
925 kold
= ( KeyValue
* ) io
->data
;
926 if( !strcmp( kold
->group
, knew
->group
) && !strcmp( kold
->key
, knew
->key
)){
931 key_def
= get_key_def( knew
->key
);
934 kdiff
= g_new0( KeyValue
, 1 );
935 kdiff
->group
= g_strdup( knew
->group
);
936 kdiff
->key
= g_strdup( knew
->key
);
937 kdiff
->mandatory
= knew
->mandatory
;
938 kdiff
->boxed
= na_boxed_copy( knew
->boxed
);
939 diffs
= g_list_prepend( diffs
, kdiff
);
947 /* load the content of the two configuration files (actually of _the_ configuration)
948 * taking care of not overriding mandatory preferences with user ones
951 content_load( NASettings
*settings
)
955 content
= content_load_keys( settings
, NULL
, settings
->private->mandatory
, TRUE
);
956 content
= content_load_keys( settings
, content
, settings
->private->user
, FALSE
);
962 content_load_keys( NASettings
*settings
, GList
*content
, KeyFile
*key_file
, gboolean mandatory
)
964 static const gchar
*thisfn
= "na_settings_content_load_keys";
966 gchar
**groups
, **ig
;
972 if( !g_key_file_load_from_file( key_file
->key_file
, key_file
->fname
, G_KEY_FILE_KEEP_COMMENTS
, &error
)){
973 if( error
->code
!= G_FILE_ERROR_NOENT
){
974 g_warning( "%s: %s (%d) %s", thisfn
, key_file
->fname
, error
->code
, error
->message
);
976 g_error_free( error
);
980 groups
= g_key_file_get_groups( key_file
->key_file
, NULL
);
983 keys
= g_key_file_get_keys( key_file
->key_file
, *ig
, NULL
, NULL
);
986 key_def
= get_key_def( *ik
);
988 key_value
= peek_key_value_from_content( content
, *ig
, *ik
);
990 key_value
= read_key_value_from_key_file( key_file
->key_file
, *ig
, *ik
, key_def
);
992 key_value
->mandatory
= mandatory
;
993 content
= g_list_prepend( content
, key_value
);
1002 g_strfreev( groups
);
1009 get_key_def( const gchar
*key
)
1011 static const gchar
*thisfn
= "na_settings_get_key_def";
1012 KeyDef
*found
= NULL
;
1015 idef
= ( KeyDef
* ) st_def_keys
;
1016 while( idef
->key
&& !found
){
1017 if( !strcmp( idef
->key
, key
)){
1023 g_warning( "%s: no KeyDef found for key=%s", thisfn
, key
);
1030 * called from na_settings_new
1031 * allocate and load the key files for global and user preferences
1034 key_file_new( NASettings
*settings
, const gchar
*dir
)
1036 static const gchar
*thisfn
= "na_settings_key_file_new";
1041 key_file
= g_new0( KeyFile
, 1 );
1043 key_file
->key_file
= g_key_file_new();
1044 key_file
->fname
= g_strdup_printf( "%s/%s.conf", dir
, PACKAGE
);
1047 file
= g_file_new_for_path( key_file
->fname
);
1048 key_file
->monitor
= g_file_monitor_file( file
, 0, NULL
, &error
);
1050 g_warning( "%s: %s: %s", thisfn
, key_file
->fname
, error
->message
);
1051 g_error_free( error
);
1054 key_file
->handler
= g_signal_connect( key_file
->monitor
, "changed", ( GCallback
) on_keyfile_changed
, settings
);
1056 g_object_unref( file
);
1062 * one of the two monitored configuration files have changed on the disk
1063 * we do not try to identify which keys have actually change
1064 * instead we trigger each registered consumer for the 'global' event
1066 * consumers which register for the 'global_conf' event are recorded
1070 on_keyfile_changed( GFileMonitor
*monitor
,
1071 GFile
*file
, GFile
*other_file
, GFileMonitorEvent event_type
, NASettings
*settings
)
1073 g_return_if_fail( NA_IS_SETTINGS( settings
));
1075 if( !settings
->private->dispose_has_run
){
1077 na_timeout_event( &settings
->private->timeout
);
1082 on_keyfile_changed_timeout( NASettings
*settings
)
1084 static const gchar
*thisfn
= "na_settings_on_keyfile_changed_timeout";
1091 gchar
*group_prefix
, *key
;
1093 /* last individual notification is older that the st_burst_timeout
1094 * we may so suppose that the burst is terminated
1096 new_content
= content_load( settings
);
1097 modifs
= content_diff( settings
->private->content
, new_content
);
1098 g_debug( "%s: %d found update(s)", thisfn
, g_list_length( modifs
));
1099 for( im
= modifs
; im
; im
= im
->next
){
1100 changed
= ( KeyValue
* ) im
->data
;
1101 value
= na_boxed_get_string( changed
->boxed
);
1102 g_debug( "%s: key=%s, value=%s", thisfn
, changed
->key
, value
);
1106 for( ic
= settings
->private->consumers
; ic
; ic
= ic
->next
){
1107 consumer
= ( Consumer
* ) ic
->data
;
1109 group_prefix
= NULL
;
1110 if( !strcmp( consumer
->monitored_key
, NA_IPREFS_IO_PROVIDERS_READ_STATUS
)){
1111 group_prefix
= g_strdup_printf( "%s ", NA_IPREFS_IO_PROVIDER_GROUP
);
1112 key
= NA_IPREFS_IO_PROVIDER_READABLE
;
1114 key
= consumer
->monitored_key
;
1117 for( im
= modifs
; im
; im
= im
->next
){
1118 changed
= ( KeyValue
* ) im
->data
;
1119 if(( !group_prefix
|| g_str_has_prefix( changed
->group
, group_prefix
)) && !strcmp( changed
->key
, key
)){
1120 ( *( NASettingsKeyCallback
) consumer
->callback
)( changed
->group
, changed
->key
, na_boxed_get_pointer( changed
->boxed
), changed
->mandatory
, consumer
->user_data
);
1124 g_free( group_prefix
);
1127 g_list_foreach( settings
->private->content
, ( GFunc
) release_key_value
, NULL
);
1128 g_list_free( settings
->private->content
);
1129 settings
->private->content
= new_content
;
1131 g_list_foreach( modifs
, ( GFunc
) release_key_value
, NULL
);
1132 g_list_free( modifs
);
1136 peek_key_value_from_content( GList
*content
, const gchar
*group
, const gchar
*key
)
1138 KeyValue
*value
, *found
;
1142 for( ic
= content
; ic
&& !found
; ic
= ic
->next
){
1143 value
= ( KeyValue
* ) ic
->data
;
1144 if( !strcmp( value
->group
, group
) && !strcmp( value
->key
, key
)){
1152 /* group may be NULL
1155 read_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, gboolean
*found
, gboolean
*mandatory
)
1159 KeyValue
*key_value
;
1161 g_return_val_if_fail( NA_IS_SETTINGS( settings
), NULL
);
1171 if( !settings
->private->dispose_has_run
){
1173 key_def
= get_key_def( key
);
1176 key_value
= read_key_value_from_key_file( settings
->private->mandatory
->key_file
, group
? group
: key_def
->group
, key
, key_def
);
1187 key_value
= read_key_value_from_key_file( settings
->private->user
->key_file
, group
? group
: key_def
->group
, key
, key_def
);
1198 return( key_value
);
1202 read_key_value_from_key_file( GKeyFile
*key_file
, const gchar
*group
, const gchar
*key
, const KeyDef
*key_def
)
1204 static const gchar
*thisfn
= "na_settings_read_key_value_from_key_file";
1212 switch( key_def
->type
){
1214 case NA_BOXED_TYPE_STRING
:
1215 case NA_BOXED_TYPE_STRING_LIST
:
1216 case NA_BOXED_TYPE_UINT
:
1217 case NA_BOXED_TYPE_UINT_LIST
:
1218 case NA_BOXED_TYPE_BOOLEAN
:
1219 str
= g_key_file_get_string( key_file
, group
, key
, &error
);
1221 if( error
->code
!= G_KEY_FILE_ERROR_KEY_NOT_FOUND
&& error
->code
!= G_KEY_FILE_ERROR_GROUP_NOT_FOUND
){
1222 g_warning( "%s: %s", thisfn
, error
->message
);
1224 g_error_free( error
);
1226 /* key exists, but may be empty */
1228 value
= g_new0( KeyValue
, 1 );
1229 value
->group
= g_strdup( group
);
1230 value
->key
= g_strdup( key
);
1231 switch( key_def
->type
){
1232 case NA_BOXED_TYPE_STRING
:
1233 case NA_BOXED_TYPE_UINT
:
1234 case NA_BOXED_TYPE_BOOLEAN
:
1235 value
->boxed
= na_boxed_new_from_string( key_def
->type
, str
);
1237 case NA_BOXED_TYPE_STRING_LIST
:
1238 case NA_BOXED_TYPE_UINT_LIST
:
1239 value
->boxed
= na_boxed_new_from_string_with_sep( key_def
->type
, str
, ";" );
1247 g_warning( "%s: unmanaged boxed type: %d", thisfn
, key_def
->type
);
1255 * called from instance_finalize
1256 * release the list of registered consumers
1259 release_consumer( Consumer
*consumer
)
1261 g_free( consumer
->monitored_key
);
1266 * called from instance_dispose
1267 * release the opened and monitored GKeyFiles
1270 release_key_file( KeyFile
*key_file
)
1272 g_key_file_free( key_file
->key_file
);
1273 if( key_file
->monitor
){
1274 if( key_file
->handler
){
1275 g_signal_handler_disconnect( key_file
->monitor
, key_file
->handler
);
1277 g_file_monitor_cancel( key_file
->monitor
);
1278 g_object_unref( key_file
->monitor
);
1280 g_free( key_file
->fname
);
1285 * called from instance_finalize
1286 * release a KeyValue struct
1289 release_key_value( KeyValue
*value
)
1291 g_free( value
->group
);
1292 g_free( value
->key
);
1293 na_boxed_free( value
->boxed
);
1298 set_key_value( NASettings
*settings
, const gchar
*group
, const gchar
*key
, const gchar
*string
)
1301 const gchar
*wgroup
;
1304 g_return_val_if_fail( NA_IS_SETTINGS( settings
), FALSE
);
1308 if( !settings
->private->dispose_has_run
){
1312 key_def
= get_key_def( key
);
1314 wgroup
= key_def
->group
;
1318 g_key_file_set_string( settings
->private->user
->key_file
, wgroup
, key
, string
);
1319 ok
= write_user_key_file( settings
);
1327 write_user_key_file( NASettings
*settings
)
1329 static const gchar
*thisfn
= "na_settings_write_user_key_file";
1332 GFileOutputStream
*stream
;
1337 data
= g_key_file_to_data( settings
->private->user
->key_file
, &length
, NULL
);
1338 file
= g_file_new_for_path( settings
->private->user
->fname
);
1340 stream
= g_file_replace( file
, NULL
, FALSE
, G_FILE_CREATE_NONE
, NULL
, &error
);
1342 g_warning( "%s: g_file_replace: %s", thisfn
, error
->message
);
1343 g_error_free( error
);
1345 g_object_unref( stream
);
1347 g_object_unref( file
);
1352 g_output_stream_write( G_OUTPUT_STREAM( stream
), data
, length
, NULL
, &error
);
1354 g_warning( "%s: g_output_stream_write: %s", thisfn
, error
->message
);
1355 g_error_free( error
);
1356 g_object_unref( stream
);
1357 g_object_unref( file
);
1362 g_output_stream_close( G_OUTPUT_STREAM( stream
), NULL
, &error
);
1364 g_warning( "%s: g_output_stream_close: %s", thisfn
, error
->message
);
1365 g_error_free( error
);
1366 g_object_unref( stream
);
1367 g_object_unref( file
);
1372 g_object_unref( stream
);
1373 g_object_unref( file
);