[nautilus-actions] Global review of the notification systems



commit d1ae2196a1b5c81ba5cbdbb0a662c6dcc7d0b71f
Author: Pierre Wieser <pwieser trychlos org>
Date:   Mon Jan 24 23:34:05 2011 +0100

    Global review of the notification systems
    
    + NAPivot always acts as a summarizing relay for items changes from i/o providers
    + NASettings always enables a pre-key callback preregistration system
    + NASettings now also have its own signal notification system, only distinguishing between
      runtime and user preferences.

 ChangeLog              |    7 ++
 src/core/na-pivot.c    |   25 +++--
 src/core/na-pivot.h    |   55 +++++------
 src/core/na-settings.c |  270 ++++++++++++++++++++++++++++++------------------
 src/core/na-settings.h |   29 +++++-
 5 files changed, 243 insertions(+), 143 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index fa00b09..cb28065 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2011-01-24 Pierre Wieser <pwieser trychlos org>
 
+	* src/core/na-pivot.c:
+	* src/core/na-pivot.h: Review the notification system.
+
+	* src/core/na-settings.c:
+	* src/core/na-settings.h:
+	Add a signal notification to the existing callback pregistration system.
+
 	* data/gconf-schemas/nautilus-actions-prefs.schemas.in:
 	* docs/des-ema/des-ema-0.15:
 	* docs/nact/C/nact-conditions.xml:
diff --git a/src/core/na-pivot.c b/src/core/na-pivot.c
index f246db8..93a2df7 100644
--- a/src/core/na-pivot.c
+++ b/src/core/na-pivot.c
@@ -117,7 +117,7 @@ static NAObjectItem *get_item_from_tree( const NAPivot *pivot, GList *tree, cons
 static void          free_consumers( GList *list );
 
 /* NAIIOProvider management */
-static void          on_item_changed_timeout( NAPivot *pivot );
+static void          on_items_changed_timeout( NAPivot *pivot );
 
 GType
 na_pivot_get_type( void )
@@ -186,7 +186,7 @@ class_init( NAPivotClass *klass )
 	/*
 	 * NAPivot::pivot-items-changed:
 	 *
-	 * This signal is sent by NAPivot ath the end of a burst of modifications
+	 * This signal is sent by NAPivot at the end of a burst of modifications
 	 * as signaled by i/o providers.
 	 *
 	 * The signal is registered without any default handler.
@@ -228,7 +228,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	/* initialize timeout parameters for 'item-changed' handler
 	 */
 	self->private->change_timeout.timeout = st_burst_timeout;
-	self->private->change_timeout.handler = ( NATimeoutFunc ) on_item_changed_timeout;
+	self->private->change_timeout.handler = ( NATimeoutFunc ) on_items_changed_timeout;
 	self->private->change_timeout.user_data = self;
 	self->private->change_timeout.source_id = 0;
 }
@@ -619,9 +619,13 @@ na_pivot_set_new_items( NAPivot *pivot, GList *items )
  *
  * This handler is trigerred by #NAIIOProvider providers when an action
  * is changed in their underlying storage subsystems.
+ *
+ * The NAIIOProvider is supposed to have itself already summarized
+ * a minima its own burst of notifications.
+ *
  * We don't care of updating our internal list with each and every
  * atomic modification; instead we wait for the end of notifications
- * serie, and then reload the whole list of actions
+ * serie, and then signal our consumers.
  */
 void
 na_pivot_on_item_changed_handler( NAIIOProvider *provider, NAPivot *pivot  )
@@ -645,16 +649,18 @@ na_pivot_on_item_changed_handler( NAIIOProvider *provider, NAPivot *pivot  )
  * this is up to NAPivot to send now its summarized signal
  */
 static void
-on_item_changed_timeout( NAPivot *pivot )
+on_items_changed_timeout( NAPivot *pivot )
 {
-	static const gchar *thisfn = "na_pivot_on_item_changed_timeout";
-	GList *ic;
+	static const gchar *thisfn = "na_pivot_on_items_changed_timeout";
 
 	g_return_if_fail( NA_IS_PIVOT( pivot ));
 
 	g_debug( "%s: emitting %s signal", thisfn, PIVOT_SIGNAL_ITEMS_CHANGED );
 	g_signal_emit_by_name(( gpointer ) pivot, PIVOT_SIGNAL_ITEMS_CHANGED );
 
+#if 0
+	GList *ic;
+
 	/* this has to be deprecated.. or not ?? */
 	g_debug( "%s: triggering NAIPivotConsumer interfaces", thisfn );
 	if( pivot->private->automatic_reload ){
@@ -663,6 +669,7 @@ on_item_changed_timeout( NAPivot *pivot )
 	for( ic = pivot->private->consumers ; ic ; ic = ic->next ){
 		na_ipivot_consumer_notify_of_items_changed( NA_IPIVOT_CONSUMER( ic->data ));
 	}
+#endif
 }
 
 /*
@@ -727,13 +734,13 @@ na_pivot_get_settings( const NAPivot *pivot )
  * na_pivot_set_automatic_reload:
  * @pivot: this #NAPivot instance.
  * @reload: whether this #NAPivot instance should automatically reload
- * its list of actions when I/O providers advertize it of a
+ * its list of actions when I/O providers advertise it of a
  * modification.
  *
  * Sets the automatic reload flag.
  *
  * Note that even if the #NAPivot instance is not authorized to
- * automatically reload its list of actions when it is advertized of
+ * automatically reload its list of actions when it is advertised of
  * a modification by one of the I/O providers, it always sends an
  * ad-hoc notification to its consumers.
  */
diff --git a/src/core/na-pivot.h b/src/core/na-pivot.h
index d81bbf4..fcc8ce8 100644
--- a/src/core/na-pivot.h
+++ b/src/core/na-pivot.h
@@ -42,41 +42,35 @@
  *
  * With this newly allocated #NAPivot object, the consuming program
  * is then able to ask for loading the items.
- * 		na_pivot_load_items( pivot, PIVOT_LOADABLE_SET );
+ * 		na_pivot_set_loadable( pivot, PIVOT_LOADABLE_SET );
+ * 		na_pivot_load_items( pivot );
  *
  * Notification system.
  *
- * Each I/O storage provider should monitor modifications/deletions of
- * actions, and advertize this #NAPivot, which itself will then
- * advertise any registered consumers.
+ * The NAPivot object acts as a sort of "summarizing relay" for notification
+ * messages sent by I/O storage providers:
  *
- * This notification system is so a double-stage one :
+ * - When an I/O storage subsystem detects a change on an item it manages,
+ *   action or menu, it is first supposed to do its best effort in order
+ *   to summarize its notifications messages;
  *
- * 1. When an I/O storage subsystem detects a change on an action, it
- *    should call the na_iio_provider_item_changed() function, which
- *    itself will emit the "io-provider-item-changed" signal.
+ * - At the end of this first stage of summarization, the I/O provider
+ *   should call the na_iio_provider_item_changed() function, which
+ *   itself will emit the "io-provider-item-changed" signal.
+ *   This is done so that an external I/O provider does not have to know
+ *   anything with the signal name, but has only to take care of calling
+ *   a function of the NAIIOProvider API.
  *
- *    All these signals are catched by na_pivot_on_item_changed_handler()
+ * - The emitted signal is catched by na_pivot_on_item_changed_handler(),
+ *   which was connected when the I/O provider plugin was associated with
+ *   the NAIOProvider object.
  *
- *    notify #NAPivot of this change. The user data associated with the
- *    message is the internal id of the #NAObjectItem-derived modified
- *    object.
+ * - The NAPivot object receives these notifications originating from all
+ *   loaded I/O providers, itself summarizes them, and only then notify its
+ *   consumers with only one message for a whole set of modifications.
  *
- *    When this signal is received, #NAPivot updates accordingly the
- *    list of actions it maintains.
- *
- *    It is up to the I/O storage provider to decide if it sends a
- *    message for each and every one detected modification, or if it
- *    sends only one message for a whole, maybe coherent, set of
- *    updates.
- *
- * 2. When #NAPivot has successfully updated its list of actions, it
- *    notifies its consumers so they update themselves.
- *
- *    Note that #NAPivot tries to factorize notification messages, and
- *    to notify its consumers only once even if it has itself received
- *    many elementary notifications from the underlying I/O storage
- *    subsystems.
+ * It is eventually up to the consumer to connect to this signal, and
+ * choose itself whether to reload items or not.
  */
 
 #include <api/na-iio-provider.h>
@@ -120,9 +114,10 @@ GType    na_pivot_get_type( void );
 
 /* signals
  *
- * NAPivot acts as a 'summarizing' proxy for signals emitted by the NAIIOProvider
- * providers when they detect a modification of their underlying items storage
- * subsystems.
+ * NAPivot acts as a 'summarizing' proxy for signals emitted by the
+ * NAIIOProvider providers when they detect a modification in their
+ * underlying items storage subsystems.
+ *
  * As several to many signals may be emitted when such a modification occurs,
  * NAPivot summarizes all these signals in an only one 'items-changed' event.
  */
diff --git a/src/core/na-settings.c b/src/core/na-settings.c
index be295f1..7000f25 100644
--- a/src/core/na-settings.c
+++ b/src/core/na-settings.c
@@ -62,23 +62,13 @@ typedef struct {
 }
 	KeyFile;
 
-/* The configuration content is handled as a GList of NAKeyValue structs.
- * This list is loaded at initialization time, and then compared each
- * time our file monitors signal us that a change has occured.
- */
-typedef struct {
-	gchar   *group;
-	gchar   *key;
-	gboolean mandatory;
-	NABoxed *boxed;
-}
-	KeyValue;
-
 /* Each consumer may register a callback function which will be triggered
  * when a key is modified.
- * The monitored key may be a real key of the file, but also be a composite
- * key (e.g. NA_IPREFS_IO_PROVIDERS_READ_STATUS monitors the 'readable'
- * key of all i/o providers).
+ *
+ * The monitored key usually is the real key read in the file;
+ * as a special case, composite keys are defined:
+ * - NA_IPREFS_IO_PROVIDERS_READ_STATUS monitors the 'readable' key for all i/o providers
+ *
  * Note that we actually monitor the _user_view_ of the configuration:
  * e.g. if a key has a mandatory value in global conf, then the same
  * key in user conf will just be ignored.
@@ -107,69 +97,91 @@ struct _NASettingsPrivate {
 typedef struct {
 	const gchar *key;
 	const gchar *group;
+	gboolean     runtime;	/* whether the key participates to the 'runtime-change' signal */
 	guint        type;
 	const gchar *default_value;
 }
 	KeyDef;
 
 static const KeyDef st_def_keys[] = {
-	{ NA_IPREFS_ADMIN_PREFERENCES_LOCKED,         GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_ADMIN_IO_PROVIDERS_LOCKED,        GROUP_RUNTIME, NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_ASSISTANT_ESC_CONFIRM,            GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_ASSISTANT_ESC_QUIT,               GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_CAPABILITY_ADD_CAPABILITY_WSP,    GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_COMMAND_CHOOSER_WSP,              GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_COMMAND_CHOOSER_URI,              GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///bin" },
-	{ NA_IPREFS_COMMAND_LEGEND_WSP,               GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_WORKING_DIR_WSP,                  GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_WORKING_DIR_URI,                  GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///" },
-	{ NA_IPREFS_SHOW_IF_RUNNING_WSP,              GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_SHOW_IF_RUNNING_URI,              GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///bin" },
-	{ NA_IPREFS_TRY_EXEC_WSP,                     GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_TRY_EXEC_URI,                     GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///bin" },
-	{ NA_IPREFS_EXPORT_ASK_USER_WSP,              GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_EXPORT_ASK_USER_LAST_FORMAT,      GROUP_NACT,    NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_EXPORT_FORMAT },
-	{ NA_IPREFS_EXPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_EXPORT_ASSISTANT_WSP,             GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_EXPORT_ASSISTANT_URI,             GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///tmp" },
-	{ NA_IPREFS_EXPORT_PREFERRED_FORMAT,          GROUP_NACT,    NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_EXPORT_FORMAT },
-	{ NA_IPREFS_FOLDER_CHOOSER_WSP,               GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_FOLDER_CHOOSER_URI,               GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///" },
-	{ NA_IPREFS_IMPORT_ASK_USER_WSP,              GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_IMPORT_ASK_USER_LAST_MODE,        GROUP_NACT,    NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_IMPORT_MODE },
-	{ NA_IPREFS_IMPORT_ASSISTANT_WSP,             GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_IMPORT_ASSISTANT_URI,             GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///tmp" },
-	{ NA_IPREFS_IMPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_IMPORT_PREFERRED_MODE,            GROUP_NACT,    NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_IMPORT_MODE },
-	{ NA_IPREFS_IO_PROVIDERS_WRITE_ORDER,         GROUP_NACT,    NA_BOXED_TYPE_STRING_LIST, "" },
-	{ NA_IPREFS_ICON_CHOOSER_URI,                 GROUP_NACT,    NA_BOXED_TYPE_STRING,      "file:///" },
-	{ NA_IPREFS_ICON_CHOOSER_PANED,               GROUP_NACT,    NA_BOXED_TYPE_UINT,        "200" },
-	{ NA_IPREFS_ICON_CHOOSER_WSP,                 GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_ITEMS_ADD_ABOUT_ITEM,             GROUP_RUNTIME, NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_ITEMS_CREATE_ROOT_MENU,           GROUP_RUNTIME, NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER,           GROUP_RUNTIME, NA_BOXED_TYPE_STRING_LIST, "" },
-	{ NA_IPREFS_ITEMS_LIST_ORDER_MODE,            GROUP_RUNTIME, NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_LIST_ORDER_MODE },
-	{ NA_IPREFS_MAIN_PANED,                       GROUP_NACT,    NA_BOXED_TYPE_UINT,        "200" },
-	{ NA_IPREFS_MAIN_SAVE_AUTO,                   GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_MAIN_SAVE_PERIOD,                 GROUP_NACT,    NA_BOXED_TYPE_UINT,        "5" },
-	{ NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY,        GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY,        GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY,        GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "true" },
-	{ NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY,       GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_MAIN_WINDOW_WSP,                  GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_PREFERENCES_WSP,                  GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_RELABEL_DUPLICATE_ACTION,         GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_RELABEL_DUPLICATE_MENU,           GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_RELABEL_DUPLICATE_PROFILE,        GROUP_NACT,    NA_BOXED_TYPE_BOOLEAN,     "false" },
-	{ NA_IPREFS_SCHEME_ADD_SCHEME_WSP,            GROUP_NACT,    NA_BOXED_TYPE_UINT_LIST,   "" },
-	{ NA_IPREFS_SCHEME_DEFAULT_LIST,              GROUP_NACT,    NA_BOXED_TYPE_STRING_LIST, "" },
-	{ NA_IPREFS_IO_PROVIDER_READABLE,             NA_IPREFS_IO_PROVIDER_GROUP, NA_BOXED_TYPE_BOOLEAN, "true" },
-	{ NA_IPREFS_IO_PROVIDER_WRITABLE,             NA_IPREFS_IO_PROVIDER_GROUP, NA_BOXED_TYPE_BOOLEAN, "true" },
+	{ NA_IPREFS_ADMIN_PREFERENCES_LOCKED,         GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_ADMIN_IO_PROVIDERS_LOCKED,        GROUP_RUNTIME, FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_ASSISTANT_ESC_CONFIRM,            GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_ASSISTANT_ESC_QUIT,               GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_CAPABILITY_ADD_CAPABILITY_WSP,    GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_COMMAND_CHOOSER_WSP,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_COMMAND_CHOOSER_URI,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///bin" },
+	{ NA_IPREFS_COMMAND_LEGEND_WSP,               GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_WORKING_DIR_WSP,                  GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_WORKING_DIR_URI,                  GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///" },
+	{ NA_IPREFS_SHOW_IF_RUNNING_WSP,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_SHOW_IF_RUNNING_URI,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///bin" },
+	{ NA_IPREFS_TRY_EXEC_WSP,                     GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_TRY_EXEC_URI,                     GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///bin" },
+	{ NA_IPREFS_EXPORT_ASK_USER_WSP,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_EXPORT_ASK_USER_LAST_FORMAT,      GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_EXPORT_FORMAT },
+	{ NA_IPREFS_EXPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_EXPORT_ASSISTANT_WSP,             GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_EXPORT_ASSISTANT_URI,             GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///tmp" },
+	{ NA_IPREFS_EXPORT_PREFERRED_FORMAT,          GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_EXPORT_FORMAT },
+	{ NA_IPREFS_FOLDER_CHOOSER_WSP,               GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_FOLDER_CHOOSER_URI,               GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///" },
+	{ NA_IPREFS_IMPORT_ASK_USER_WSP,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_IMPORT_ASK_USER_LAST_MODE,        GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_IMPORT_MODE },
+	{ NA_IPREFS_IMPORT_ASSISTANT_WSP,             GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_IMPORT_ASSISTANT_URI,             GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///tmp" },
+	{ NA_IPREFS_IMPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_IMPORT_PREFERRED_MODE,            GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_IMPORT_MODE },
+	{ NA_IPREFS_IO_PROVIDERS_WRITE_ORDER,         GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING_LIST, "" },
+	{ NA_IPREFS_ICON_CHOOSER_URI,                 GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING,      "file:///" },
+	{ NA_IPREFS_ICON_CHOOSER_PANED,               GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT,        "200" },
+	{ NA_IPREFS_ICON_CHOOSER_WSP,                 GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_ITEMS_ADD_ABOUT_ITEM,             GROUP_RUNTIME,  TRUE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_ITEMS_CREATE_ROOT_MENU,           GROUP_RUNTIME,  TRUE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER,           GROUP_RUNTIME,  TRUE, NA_BOXED_TYPE_STRING_LIST, "" },
+	{ NA_IPREFS_ITEMS_LIST_ORDER_MODE,            GROUP_RUNTIME,  TRUE, NA_BOXED_TYPE_STRING,      NA_IPREFS_DEFAULT_LIST_ORDER_MODE },
+	{ NA_IPREFS_MAIN_PANED,                       GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT,        "200" },
+	{ NA_IPREFS_MAIN_SAVE_AUTO,                   GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_MAIN_SAVE_PERIOD,                 GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT,        "5" },
+	{ NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY,        GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY,        GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY,        GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "true" },
+	{ NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY,       GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_MAIN_WINDOW_WSP,                  GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_PREFERENCES_WSP,                  GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_RELABEL_DUPLICATE_ACTION,         GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_RELABEL_DUPLICATE_MENU,           GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_RELABEL_DUPLICATE_PROFILE,        GROUP_NACT,    FALSE, NA_BOXED_TYPE_BOOLEAN,     "false" },
+	{ NA_IPREFS_SCHEME_ADD_SCHEME_WSP,            GROUP_NACT,    FALSE, NA_BOXED_TYPE_UINT_LIST,   "" },
+	{ NA_IPREFS_SCHEME_DEFAULT_LIST,              GROUP_NACT,    FALSE, NA_BOXED_TYPE_STRING_LIST, "" },
+	{ NA_IPREFS_IO_PROVIDER_READABLE,             NA_IPREFS_IO_PROVIDER_GROUP,  TRUE, NA_BOXED_TYPE_BOOLEAN, "true" },
+	{ NA_IPREFS_IO_PROVIDER_WRITABLE,             NA_IPREFS_IO_PROVIDER_GROUP, FALSE, NA_BOXED_TYPE_BOOLEAN, "true" },
 	{ 0 }
 };
 
-static GObjectClass *st_parent_class    = NULL;
-static gint          st_burst_timeout   = 100;		/* burst timeout in msec */
+/* The configuration content is handled as a GList of KeyValue structs.
+ * This list is loaded at initialization time, and then compared each
+ * time our file monitors signal us that a change has occured.
+ */
+typedef struct {
+	const KeyDef *def;
+	const gchar  *group;
+	gboolean      mandatory;
+	NABoxed      *boxed;
+}
+	KeyValue;
+
+/* signals
+ */
+enum {
+	RUNTIME_CHANGE,
+	UI_CHANGE,
+	LAST_SIGNAL
+};
+
+static GObjectClass *st_parent_class           = NULL;
+static gint          st_burst_timeout          = 100;		/* burst timeout in msec */
+static gint          st_signals[ LAST_SIGNAL ] = { 0 };
 
 static GType     register_type( void );
 static void      class_init( NASettingsClass *klass );
@@ -245,6 +257,46 @@ class_init( NASettingsClass *klass )
 	object_class->finalize = instance_finalize;
 
 	klass->private = g_new0( NASettingsClassPrivate, 1 );
+
+	/*
+	 * NASettings::settings-runtime-change:
+	 *
+	 * This signal is sent by NASettings at the end of a burst of
+	 * modifications which may affect the way the file manager displays
+	 * its context menus.
+	 *
+	 * The signal is registered without any default handler.
+	 */
+	st_signals[ RUNTIME_CHANGE ] = g_signal_new(
+				SETTINGS_SIGNAL_RUNTIME_CHANGE,
+				NA_SETTINGS_TYPE,
+				G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+				0,									/* class offset */
+				NULL,								/* accumulator */
+				NULL,								/* accumulator data */
+				g_cclosure_marshal_VOID__VOID,
+				G_TYPE_NONE,
+				0 );
+
+	/*
+	 * NASettings::settings-ui-change:
+	 *
+	 * This signal is sent by NASettings at the end of a burst of
+	 * modifications which only affect the behavior of the NACT
+	 * configuration tool.
+	 *
+	 * The signal is registered without any default handler.
+	 */
+	st_signals[ UI_CHANGE ] = g_signal_new(
+				SETTINGS_SIGNAL_UI_CHANGE,
+				NA_SETTINGS_TYPE,
+				G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+				0,									/* class offset */
+				NULL,								/* accumulator */
+				NULL,								/* accumulator data */
+				g_cclosure_marshal_VOID__VOID,
+				G_TYPE_NONE,
+				0 );
 }
 
 static void
@@ -882,7 +934,6 @@ content_diff( GList *old, GList *new )
 	GList *diffs, *io, *in;
 	KeyValue *kold, *knew, *kdiff;
 	gboolean found;
-	KeyDef *key_def;
 
 	diffs = NULL;
 
@@ -891,13 +942,13 @@ content_diff( GList *old, GList *new )
 		found = FALSE;
 		for( in = new ; in && !found ; in = in->next ){
 			knew = ( KeyValue * ) in->data;
-			if( !strcmp( kold->group, knew->group ) && !strcmp( kold->key, knew->key )){
+			if( !strcmp( kold->group, knew->group ) && ( gpointer ) kold->def == ( gpointer ) knew->def ){
 				found = TRUE;
 				if( na_boxed_compare( kold->boxed, knew->boxed ) != 0 ){
 					/* a key has been modified */
 					kdiff = g_new0( KeyValue, 1 );
 					kdiff->group = g_strdup( knew->group );
-					kdiff->key = g_strdup( knew->key );
+					kdiff->def = knew->def;
 					kdiff->mandatory = knew->mandatory;
 					kdiff->boxed = na_boxed_copy( knew->boxed );
 					diffs = g_list_prepend( diffs, kdiff );
@@ -905,16 +956,13 @@ content_diff( GList *old, GList *new )
 			}
 		}
 		if( !found ){
-			key_def = get_key_def( kold->key );
-			if( key_def ){
-				/* a key has disappeared */
-				kdiff = g_new0( KeyValue, 1 );
-				kdiff->group = g_strdup( kold->group );
-				kdiff->key = g_strdup( kold->key );
-				kdiff->mandatory = FALSE;
-				kdiff->boxed = na_boxed_new_from_string( key_def->type, key_def->default_value );
-				diffs = g_list_prepend( diffs, kdiff );
-			}
+			/* a key has disappeared */
+			kdiff = g_new0( KeyValue, 1 );
+			kdiff->group = g_strdup( kold->group );
+			kdiff->def = kold->def;
+			kdiff->mandatory = FALSE;
+			kdiff->boxed = na_boxed_new_from_string( kold->def->type, kold->def->default_value );
+			diffs = g_list_prepend( diffs, kdiff );
 		}
 	}
 
@@ -923,21 +971,18 @@ content_diff( GList *old, GList *new )
 		found = FALSE;
 		for( io = old ; io && !found ; io = io->next ){
 			kold = ( KeyValue * ) io->data;
-			if( !strcmp( kold->group, knew->group ) && !strcmp( kold->key, knew->key )){
+			if( !strcmp( kold->group, knew->group ) && ( gpointer ) kold->def == ( gpointer ) knew->def ){
 				found = TRUE;
 			}
 		}
 		if( !found ){
-			key_def = get_key_def( knew->key );
-			if( key_def ){
-				/* a key is new */
-				kdiff = g_new0( KeyValue, 1 );
-				kdiff->group = g_strdup( knew->group );
-				kdiff->key = g_strdup( knew->key );
-				kdiff->mandatory = knew->mandatory;
-				kdiff->boxed = na_boxed_copy( knew->boxed );
-				diffs = g_list_prepend( diffs, kdiff );
-			}
+			/* a key is new */
+			kdiff = g_new0( KeyValue, 1 );
+			kdiff->group = g_strdup( knew->group );
+			kdiff->def = knew->def;
+			kdiff->mandatory = knew->mandatory;
+			kdiff->boxed = na_boxed_copy( knew->boxed );
+			diffs = g_list_prepend( diffs, kdiff );
 		}
 	}
 
@@ -1085,23 +1130,31 @@ on_keyfile_changed_timeout( NASettings *settings )
 	GList *new_content;
 	GList *modifs;
 	GList *ic, *im;
-	gchar *value;
-	Consumer *consumer;
 	KeyValue *changed;
+	Consumer *consumer;
 	gchar *group_prefix, *key;
+	gboolean runtime_change, ui_change;
+#ifdef NA_MAINTAINER_MODE
+	gchar *value;
+#endif
 
 	/* last individual notification is older that the st_burst_timeout
 	 * we may so suppose that the burst is terminated
 	 */
 	new_content = content_load( settings );
 	modifs = content_diff( settings->private->content, new_content );
+#ifdef NA_MAINTAINER_MODE
 	g_debug( "%s: %d found update(s)", thisfn, g_list_length( modifs ));
 	for( im = modifs ; im ; im = im->next ){
 		changed = ( KeyValue * ) im->data;
 		value = na_boxed_get_string( changed->boxed );
-		g_debug( "%s: key=%s, value=%s", thisfn, changed->key, value );
+		g_debug( "%s: key=%s, value=%s", thisfn, changed->def->key, value );
 		g_free( value );
 	}
+#endif
+
+	runtime_change = FALSE;
+	ui_change = FALSE;
 
 	for( ic = settings->private->consumers ; ic ; ic = ic->next ){
 		consumer = ( Consumer * ) ic->data;
@@ -1116,14 +1169,28 @@ on_keyfile_changed_timeout( NASettings *settings )
 
 		for( im = modifs ; im ; im = im->next ){
 			changed = ( KeyValue * ) im->data;
-			if(( !group_prefix || g_str_has_prefix( changed->group, group_prefix )) && !strcmp( changed->key, key )){
-				( *( NASettingsKeyCallback ) consumer->callback )( changed->group, changed->key, na_boxed_get_pointer( changed->boxed ), changed->mandatory, consumer->user_data );
+			if(( !group_prefix || g_str_has_prefix( changed->group, group_prefix )) && !strcmp( changed->def->key, key )){
+				( *( NASettingsKeyCallback ) consumer->callback )( changed->group, changed->def->key, na_boxed_get_pointer( changed->boxed ), changed->mandatory, consumer->user_data );
+			}
+
+			if( changed->def->runtime ){
+				runtime_change = TRUE;
+			} else {
+				ui_change = FALSE;
 			}
 		}
 
 		g_free( group_prefix );
 	}
 
+	if( runtime_change ){
+		g_signal_emit_by_name(( gpointer ) settings, SETTINGS_SIGNAL_RUNTIME_CHANGE );
+	}
+
+	if( ui_change ){
+		g_signal_emit_by_name(( gpointer ) settings, SETTINGS_SIGNAL_UI_CHANGE );
+	}
+
 	g_list_foreach( settings->private->content, ( GFunc ) release_key_value, NULL );
 	g_list_free( settings->private->content );
 	settings->private->content = new_content;
@@ -1141,7 +1208,7 @@ peek_key_value_from_content( GList *content, const gchar *group, const gchar *ke
 	found = NULL;
 	for( ic = content ; ic && !found ; ic = ic->next ){
 		value = ( KeyValue * ) ic->data;
-		if( !strcmp( value->group, group ) && !strcmp( value->key, key )){
+		if( !strcmp( value->group, group ) && !strcmp( value->def->key, key )){
 			found = value;
 		}
 	}
@@ -1227,7 +1294,7 @@ read_key_value_from_key_file( GKeyFile *key_file, const gchar *group, const gcha
 			} else {
 				value = g_new0( KeyValue, 1 );
 				value->group = g_strdup( group );
-				value->key = g_strdup( key );
+				value->def = key_def;
 				switch( key_def->type ){
 					case NA_BOXED_TYPE_STRING:
 					case NA_BOXED_TYPE_UINT:
@@ -1288,8 +1355,7 @@ release_key_file( KeyFile *key_file )
 static void
 release_key_value( KeyValue *value )
 {
-	g_free( value->group );
-	g_free( value->key );
+	g_free(( gpointer ) value->group );
 	na_boxed_free( value->boxed );
 	g_free( value );
 }
diff --git a/src/core/na-settings.h b/src/core/na-settings.h
index 65bc05e..c825fe8 100644
--- a/src/core/na-settings.h
+++ b/src/core/na-settings.h
@@ -43,12 +43,23 @@
  * - a per-user configuration.
  *
  * The configuration is implemented as keyed files:
- * - global configuration is sysconfdir/nautilus-actions.conf
+ * - global configuration is sysconfdir/xdg/nautilus-actions.conf
  * - per-user configuration is HOME/.config/nautilus-actions.conf
  *
- * Each setting has so its own read-only attribute, whether it
+ * Each setting may so have its own read-only attribute, whether it
  * has been read from the global configuration or from the
  * per-user one.
+ *
+ * NASettings class implements two notification systems:
+ *
+ * a) a per-key system, which relies on a callback pre-registration;
+ *    see na_settings_register_key_callback() function;
+ * b) a per-usage system, which relies on the usage of the changed
+ *    key; see signal descriptions.
+ *
+ * The consumer of change notifications will choose the most accurate
+ * system for its needs, e.g. whether it requires to have an exact list
+ * of modified keys, or not.
  */
 
 #include <glib-object.h>
@@ -149,6 +160,20 @@ GType na_settings_get_type( void );
 #define NA_IPREFS_DEFAULT_IMPORT_MODE				"NoImport"
 #define NA_IPREFS_DEFAULT_LIST_ORDER_MODE			"AscendingOrder"
 
+/* signals
+ *
+ * NASettings monitors, and so is able to send messages about, two sort
+ * of changes:
+ * - runtime preferences change, which group all changes which may have
+ *   an effect on the display in file manager context menus;
+ * - user interface preferences change, which have only an effect on the
+ *   NACT configuration tool
+ *
+ * These two signals are a summarization of individual changes.
+ */
+#define SETTINGS_SIGNAL_RUNTIME_CHANGE				"settings-runtime-change"
+#define SETTINGS_SIGNAL_UI_CHANGE					"settings-ui-change"
+
 typedef void ( *NASettingsKeyCallback )( const gchar *group, const gchar *key, gconstpointer new_value, gboolean mandatory, void *user_data );
 
 NASettings *na_settings_new                     ( void );



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]