[nautilus-actions: 20/30] Restore notification in NACT



commit 1be56f1365c132750a7fb7a8f5ea110bee47f6a5
Author: Pierre Wieser <pwieser trychlos org>
Date:   Fri Nov 20 23:41:00 2009 +0100

    Restore notification in NACT

 ChangeLog                                          |   24 +++
 TODO                                               |    6 +-
 nautilus-actions/api/na-iio-provider.c             |   10 +-
 nautilus-actions/api/na-iio-provider.h             |    7 +-
 .../io-provider-gconf/nagp-gconf-provider.c        |  207 +++++++++++---------
 nautilus-actions/io-provider-gconf/nagp-module.c   |   63 +------
 nautilus-actions/nact/nact-main.c                  |   19 ++-
 nautilus-actions/runtime/na-io-provider.c          |   25 +++
 nautilus-actions/runtime/na-io-provider.h          |    6 +-
 nautilus-actions/runtime/na-module.c               |    2 +-
 nautilus-actions/runtime/na-pivot.c                |  176 ++++++-----------
 nautilus-actions/runtime/na-pivot.h                |   31 +--
 12 files changed, 271 insertions(+), 305 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 675950b..ff4c8c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,30 @@
 	Update compilation order as io-provider-gconf plugin depends on
 	runtime.
 
+	* nautilus-actions/api/na-iio-provider.c:
+	* nautilus-actions/api/na-iio-provider.h (na_iio_provider_config_changed):
+	Advertise interface with id of modified item.
+
+	* nautilus-actions/io-provider-gconf/nagp-gconf-provider.c:
+	Add a timeout to only trigger NAIIOProvider when all modifications
+	on an item have been made.
+
+	* nautilus-actions/io-provider-gconf/nagp-module.c (na_api_module_init):
+	Remove log handler management, no more syslog at initialization.
+
+	* nautilus-actions/nact/nact-main.c:
+	Simplify log management.
+
+	* nautilus-actions/runtime/na-io-provider.c:
+	* nautilus-actions/runtime/na-io-provider.h
+	(na_io_provider_register_callbacks): New function.
+
+	* nautilus-actions/runtime/na-module.c (plugin_check):
+	Fix error message.
+
+	* nautilus-actions/runtime/na-pivot.c:
+	Move static variables to the instance.
+
 	* nautilus-actions/nact/nact-iaction-tab.c
 	(on_tab_updatable_selection_changed):
 	Fix label display when the widget is disabled.
diff --git a/TODO b/TODO
index ae416ea..18eda9d 100644
--- a/TODO
+++ b/TODO
@@ -86,8 +86,10 @@
 
 - na_pivot_new: shouldn't take an argument (use add_consumer)
 
-- gconf monitor doesn't work when creating with nautilus-actions-new
-
 - in 64bits arch, pkglibdir=/lib ??
 
 - NACT: unable to really delete an action imported with schemas
+
+- na_pivot_get_item: should return NAObjectItem
+
+- review log handlers (cf. nact for a ref)
diff --git a/nautilus-actions/api/na-iio-provider.c b/nautilus-actions/api/na-iio-provider.c
index d566ba8..4c4d2a6 100644
--- a/nautilus-actions/api/na-iio-provider.c
+++ b/nautilus-actions/api/na-iio-provider.c
@@ -142,12 +142,20 @@ do_is_writable( const NAIIOProvider *instance, const NAObjectItem *item )
 /**
  * na_iio_provider_config_changed:
  * @instance: the calling NAIIOProvider.
+ * @id: the id of the modified #NAObjectItem-derived object.
  *
  * Advertises Nautilus-Actions that this #NAIIOProvider @instance has
  * detected a modification in one of its configurations (menu or action).
+ *
+ * This function should be triggered for each and every #NAObjectItem-
+ * derived modified objects, but only once for each one.
  */
 void
-na_iio_provider_config_changed( const NAIIOProvider *instance )
+na_iio_provider_config_changed( const NAIIOProvider *instance, const gchar *id )
 {
+	static const gchar *thisfn = "na_iio_provider_config_changed";
+
+	g_debug( "%s: instance=%p, id=%s", thisfn, ( void * ) instance, id );
 
+	g_signal_emit_by_name(( gpointer ) instance, "notify-consumer-of-action-change", id );
 }
diff --git a/nautilus-actions/api/na-iio-provider.h b/nautilus-actions/api/na-iio-provider.h
index 0970a4e..6131f6b 100644
--- a/nautilus-actions/api/na-iio-provider.h
+++ b/nautilus-actions/api/na-iio-provider.h
@@ -140,10 +140,11 @@ typedef struct {
 
 GType na_iio_provider_get_type       ( void );
 
-/* This function is to be called by the I/O provider when it detects a
- * modification of one of its objects in its underlying storage subsystem.
+/* This function is to be called by the I/O provider when it detects
+ * that the specified object has been modified in its underlying storage
+ * subsystem.
  */
-void  na_iio_provider_config_changed ( const NAIIOProvider *instance );
+void  na_iio_provider_config_changed ( const NAIIOProvider *instance, const gchar *id );
 
 /* return code of write/delete operations
  */
diff --git a/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c b/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
index 547195b..535c2e9 100644
--- a/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
+++ b/nautilus-actions/io-provider-gconf/nagp-gconf-provider.c
@@ -57,10 +57,15 @@ struct NagpGConfProviderPrivate {
 	gboolean     dispose_has_run;
 	GConfClient *gconf;
 	GList       *monitors;
+	GTimeVal     last_event;
+	guint        event_source_id;
+	gchar       *last_triggered_id;
 };
 
 static GType         st_module_type = 0;
 static GObjectClass *st_parent_class = NULL;
+static gint          st_timeout_msec = 100;
+static gint          st_timeout_usec = 100000;
 
 static void           class_init( NagpGConfProviderClass *klass );
 static void           iio_provider_iface_init( NAIIOProviderInterface *iface );
@@ -70,9 +75,11 @@ static void           instance_finalize( GObject *object );
 
 static GList         *install_monitors( NagpGConfProvider *provider );
 static void           config_path_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, NagpGConfProvider *provider );
-#if 0
-static NAPivotNotify *entry_to_notify( const GConfEntry *entry );
-#endif
+static void           config_path_changed_reset_timeout( NagpGConfProvider *provider );
+static void           config_path_changed_set_timeout( NagpGConfProvider *provider, const gchar *uuid );
+static gboolean       config_path_changed_trigger_interface( NagpGConfProvider *provider );
+static gulong         time_val_diff( const GTimeVal *recent, const GTimeVal *old );
+static gchar         *entry2uuid( GConfEntry *entry );
 
 static GList         *iio_provider_read_items( const NAIIOProvider *provider, GSList **messages );
 static NAObjectItem  *read_item( NagpGConfProvider *provider, const gchar *path );
@@ -278,17 +285,21 @@ install_monitors( NagpGConfProvider *provider )
  * xml file in gconf, or gconf is directly edited), we'd have to rely
  * only on the standard monitor (GConf watch) mechanism
  *
- * this is what we do below, thus triggering the NAIIOProvider interface
- * for each and every modification in the GConf underlying system ; this
- * is the prerogative of NAIIOProvider to decide what to do with them
+ * this is what we do below, in three phases:
+ * - first, GConf underlying subsystem advertises us, through the watch
+ *   mechanism, of each and every modification ; this leads us to be
+ *   triggered for each new/modified/deleted _entry_
+ * - as we would trigger the NAIIOProvider interface only once for each
+ *   modified _object_, we install a timer in order to wait for all
+ *   entries have been modified, or another object is concerned
+ * - as soon as one of the two previous conditions is met, we trigger
+ *   the NAIIOProvider interface with the corresponding object id
  */
 static void
 config_path_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, NagpGConfProvider *provider )
 {
 	/*static const gchar *thisfn = "nagp_gconf_provider_config_path_changed_cb";*/
-#if 0
-	NAPivotNotify *npn;
-#endif
+	gchar *uuid;
 
 	/*g_debug( "%s: client=%p, cnxnid=%u, entry=%p, provider=%p",
 			thisfn, ( void * ) client, cnxn_id, ( void * ) entry, ( void * ) provider );*/
@@ -298,105 +309,117 @@ config_path_changed_cb( GConfClient *client, guint cnxn_id, GConfEntry *entry, N
 
 	if( !provider->private->dispose_has_run ){
 
-#if 0
-		npn = entry_to_notify( entry );
-		g_signal_emit_by_name( provider->private->pivot, NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED, npn );
-#endif
-		na_iio_provider_config_changed( NA_IIO_PROVIDER( provider ));
+		uuid = entry2uuid( entry );
+		/*g_debug( "%s: uuid=%s", thisfn, uuid );*/
+
+		if( provider->private->event_source_id ){
+			if( g_ascii_strcasecmp( uuid, provider->private->last_triggered_id )){
+
+				/* there already has a timeout, but on another object
+				 * so trigger the interface for the previous object
+				 * and set the timeout for the new object
+				 */
+				config_path_changed_trigger_interface( provider );
+				config_path_changed_set_timeout( provider, uuid );
+			}
+
+			/* there already has a timeout for this same object
+			 * do nothing
+			 */
+
+		} else {
+			/* there was not yet any timeout: set it
+			 */
+			config_path_changed_set_timeout( provider, uuid );
+		}
+
+		g_free( uuid );
 	}
 }
 
+static void
+config_path_changed_reset_timeout( NagpGConfProvider *provider )
+{
+	g_free( provider->private->last_triggered_id );
+	provider->private->last_triggered_id = NULL;
+	/*provider->private->last_event = ( GTimeVal ) 0;*/
+	provider->private->event_source_id = 0;
+}
+
+static void
+config_path_changed_set_timeout( NagpGConfProvider *provider, const gchar *uuid )
+{
+	config_path_changed_reset_timeout( provider );
+	provider->private->last_triggered_id = g_strdup( uuid );
+	g_get_current_time( &provider->private->last_event );
+	provider->private->event_source_id =
+		g_timeout_add(
+				st_timeout_msec,
+				( GSourceFunc ) config_path_changed_trigger_interface,
+				provider );
+}
+
 /*
- * convert a GConfEntry to a structure suitable to notify NAIIOProvider
- * interface
- *
- * when created or modified, the entry can be of the forms :
- *  key=path/uuid/parm
- *  key=path/uuid/profile/parm with a not null value
- *
- * but when removing an entry, it will be of the form :
- *  key=path/uuid
- *  key=path/uuid/parm
- *  key=path/uuid/profile
- *  key=path/uuid/profile/parm with a null value
- *
- * I don't see any way to choose between key/parm and key/profile (*)
- * as the entry no more exists in GConf and thus cannot be tested
- * -> we will set this as key/parm, letting the interface try to
- *    interpret it
- *
- * (*) other than assuming that a profile name begins with 'profile-'
- * (see action-profile.h)
+ * this timer is set when we receive the first event of a serie
+ * we continue to loop until last event is at least one half of a
+ * second old
+ * there is no race condition here as we are not multithreaded
+ * or .. is there ?
  */
-#if 0
-static NAPivotNotify *
-entry_to_notify( const GConfEntry *entry )
+static gboolean
+config_path_changed_trigger_interface( NagpGConfProvider *provider )
+{
+	/*static const gchar *thisfn = "nagp_gconf_provider_config_path_changed_trigger_interface";*/
+	GTimeVal now;
+	gulong diff;
+
+	/*g_debug( "%s: provider=%p", thisfn, ( void * ) provider );*/
+
+	g_get_current_time( &now );
+	diff = time_val_diff( &now, &provider->private->last_event );
+	if( diff < st_timeout_usec ){
+		return( TRUE );
+	}
+
+	na_iio_provider_config_changed( NA_IIO_PROVIDER( provider ), provider->private->last_triggered_id );
+
+	config_path_changed_reset_timeout( provider );
+	return( FALSE );
+}
+
+/*
+ * returns the difference in microseconds.
+ */
+static gulong
+time_val_diff( const GTimeVal *recent, const GTimeVal *old )
+{
+	gulong microsec = 1000000 * ( recent->tv_sec - old->tv_sec );
+	microsec += recent->tv_usec  - old->tv_usec;
+	return( microsec );
+}
+
+/*
+ * gets the uuid from an entry
+ */
+static gchar *
+entry2uuid( GConfEntry *entry )
 {
-	/*static const gchar *thisfn = "nagp_gconf_entry_to_notify";*/
-	GSList *listvalues, *iv, *strings;
-	NAPivotNotify *npn;
-	gchar **split;
 	const gchar *path;
 	const gchar *subpath;
-	const GConfValue *value;
-
-	g_assert( entry );
-	path = gconf_entry_get_key( entry );
-	g_assert( path );
+	gchar **split;
+	gchar *uuid;
 
-	npn = g_new0( NAPivotNotify, 1 );
+	g_return_val_if_fail( entry, NULL );
 
+	path = gconf_entry_get_key( entry );
 	subpath = path + strlen( NA_GCONF_CONFIG_PATH ) + 1;
 	split = g_strsplit( subpath, "/", -1 );
 	/*g_debug( "%s: [0]=%s, [1]=%s", thisfn, split[0], split[1] );*/
-	npn->uuid = g_strdup( split[0] );
-
-	if( g_strv_length( split ) == 2 ){
-		npn->parm = g_strdup( split[1] );
-
-	} else if( g_strv_length( split ) == 3 ){
-		npn->profile = g_strdup( split[1] );
-		npn->parm = g_strdup( split[2] );
-	}
-
+	uuid = g_strdup( split[0] );
 	g_strfreev( split );
 
-	value = gconf_entry_get_value( entry );
-
-	if( value ){
-		switch( value->type ){
-
-			case GCONF_VALUE_STRING:
-				npn->type = NA_PIVOT_STR;
-				npn->data = ( gpointer ) g_strdup( gconf_value_get_string( value ));
-				break;
-
-			case GCONF_VALUE_BOOL:
-				npn->type = NA_PIVOT_BOOL;
-				npn->data = GINT_TO_POINTER( gconf_value_get_bool( value ));
-				break;
-
-			case GCONF_VALUE_LIST:
-				listvalues = gconf_value_get_list( value );
-				strings = NULL;
-				for( iv = listvalues ; iv != NULL ; iv = iv->next ){
-					strings = g_slist_prepend( strings,
-							( gpointer ) gconf_value_get_string(( GConfValue * ) iv->data ));
-				}
-
-				npn->type = NA_PIVOT_STRLIST;
-				npn->data = ( gpointer ) na_utils_duplicate_string_list( strings );
-				/*na_utils_free_string_list( strings );*/
-				break;
-
-			default:
-				g_assert_not_reached();
-				break;
-		}
-	}
-	return( npn );
+	return( uuid );
 }
-#endif
 
 /**
  * iio_provider_read_items:
diff --git a/nautilus-actions/io-provider-gconf/nagp-module.c b/nautilus-actions/io-provider-gconf/nagp-module.c
index 2430fa5..aa82bce 100644
--- a/nautilus-actions/io-provider-gconf/nagp-module.c
+++ b/nautilus-actions/io-provider-gconf/nagp-module.c
@@ -38,13 +38,6 @@
 
 #include "nagp-gconf-provider.h"
 
-static guint st_log_handler_api = 0;
-static guint st_log_handler_plugin = 0;
-
-static void setup_log_handler( const gchar *log_domain, guint *handler_id );
-static void remove_log_handler( guint *handler_id );
-static void nagp_log_handler( const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data );
-
 /*
  * A Nautilus-Actions extension must implement four functions :
  *
@@ -55,7 +48,8 @@ static void nagp_log_handler( const gchar *log_domain, GLogLevelFlags log_level,
  *
  * The first two functions are called at Nautilus-Actions startup.
  *
- * The prototypes for these functions are defined in nautilus-actions/na-api.h
+ * The prototypes for these functions are defined in
+ * nautilus-actions/api/na-api.h
  */
 
 gboolean
@@ -64,14 +58,7 @@ na_api_module_init( GTypeModule *module )
 	static const gchar *thisfn = "nagp_module_na_api_module_initialize";
 	static const gchar *name = "NagpGConfIOProvider";
 
-	syslog( LOG_USER | LOG_INFO, "%s initializing...", name );
-
-	openlog( G_LOG_DOMAIN, LOG_PID, LOG_USER );
-
-	setup_log_handler( NA_LOGDOMAIN_API, &st_log_handler_api );
-	setup_log_handler( NA_LOGDOMAIN_IO_PROVIDER_GCONF, &st_log_handler_plugin );
-
-	g_debug( "%s: module=%p", thisfn, ( void * ) module );
+	g_debug( "%s: module=%p, %s initializing...", thisfn, ( void * ) module, name );
 
 	g_type_module_set_name( module, name );
 
@@ -103,7 +90,7 @@ na_api_module_get_name( GType type )
 	g_debug( "%s: type=%ld", thisfn, ( gulong ) type );
 
 	if( type == NAGP_GCONF_PROVIDER_TYPE ){
-		return( "Nautilus Actions GConf Provider" );
+		return( "Nautilus-Actions GConf IO Provider" );
 	}
 
 	return( NULL );
@@ -115,46 +102,4 @@ na_api_module_shutdown( void )
 	static const gchar *thisfn = "nagp_module_na_api_module_shutdown";
 
 	g_debug( "%s", thisfn );
-
-	/* remove the log handler
-	 * almost useless as the process is nonetheless terminating at this time
-	 * but this is the art of coding...
-	 */
-	remove_log_handler( &st_log_handler_api );
-	remove_log_handler( &st_log_handler_plugin );
-}
-
-static void
-setup_log_handler( const gchar *log_domain, guint *handler_id )
-{
-	*handler_id = g_log_set_handler( log_domain, G_LOG_LEVEL_DEBUG, nagp_log_handler, NULL );
-}
-
-static void
-remove_log_handler( guint *handler_id )
-{
-	if( *handler_id ){
-		g_log_remove_handler( G_LOG_DOMAIN, *handler_id );
-		*handler_id = 0;
-	}
-}
-
-/*
- * a log handler that we install when in development mode in order to be
- * able to log plugin runtime
- * TODO: the debug flag should be dynamic, so that an advanced user could
- * setup a given key and obtain a full log to send to Bugzilla..
- * For now, is always install when compiled in maintainer mode, never else
- */
-static void
-nagp_log_handler( const gchar *log_domain,
-					GLogLevelFlags log_level,
-					const gchar *message,
-					gpointer user_data )
-{
-#ifdef NA_MAINTAINER_MODE
-	syslog( LOG_USER | LOG_DEBUG, "%s", message );
-#else
-	/* do nothing */
-#endif
 }
diff --git a/nautilus-actions/nact/nact-main.c b/nautilus-actions/nact/nact-main.c
index 77f29b7..b70d103 100644
--- a/nautilus-actions/nact/nact-main.c
+++ b/nautilus-actions/nact/nact-main.c
@@ -34,7 +34,10 @@
 
 #include "nact-application.h"
 
-static void na_log_handler( const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data );
+static void set_log_handler( void );
+static void log_handler( const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data );
+
+static GLogFunc st_log_func = NULL;
 
 int
 main( int argc, char *argv[] )
@@ -42,9 +45,7 @@ main( int argc, char *argv[] )
 	NactApplication *app;
 	int ret;
 
-	g_log_set_handler( NA_LOGDOMAIN_NACT, G_LOG_LEVEL_DEBUG, na_log_handler, NULL );
-	g_log_set_handler( NA_LOGDOMAIN_PRIVATE, G_LOG_LEVEL_DEBUG, na_log_handler, NULL );
-	g_log_set_handler( NA_LOGDOMAIN_RUNTIME, G_LOG_LEVEL_DEBUG, na_log_handler, NULL );
+	set_log_handler();
 
 	app = nact_application_new_with_args( argc, argv );
 
@@ -56,10 +57,16 @@ main( int argc, char *argv[] )
 }
 
 static void
-na_log_handler( const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data )
+set_log_handler( void )
+{
+	st_log_func = g_log_set_default_handler(( GLogFunc ) log_handler, NULL );
+}
+
+static void
+log_handler( const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data )
 {
 #ifdef NA_MAINTAINER_MODE
-	g_log_default_handler( log_domain, log_level, message, user_data );
+	( *st_log_func )( log_domain, log_level, message, user_data );
 #else
 	/* do nothing */
 #endif
diff --git a/nautilus-actions/runtime/na-io-provider.c b/nautilus-actions/runtime/na-io-provider.c
index 824741b..1faa093 100644
--- a/nautilus-actions/runtime/na-io-provider.c
+++ b/nautilus-actions/runtime/na-io-provider.c
@@ -50,6 +50,31 @@ static guint    try_write_item( const NAIIOProvider *instance, NAObjectItem *ite
 static GList   *sort_tree( const NAPivot *pivot, GList *tree, GCompareFunc fn );
 
 /**
+ * na_io_provider_register_callbacks:
+ * @pivot: the current #NAPivot instance.
+ *
+ * Registers an handler for the item-changed signal for each loaded
+ * NAIIOProvider plugin.
+ */
+void
+na_io_provider_register_callbacks( const NAPivot *pivot )
+{
+	GList *providers, *ip;
+
+	providers = na_pivot_get_providers( pivot, NA_IIO_PROVIDER_TYPE );
+
+	for( ip = providers ; ip ; ip = ip->next ){
+		g_signal_connect(
+				( gpointer ) ip->data,
+				NA_PIVOT_SIGNAL_ACTION_CHANGED,
+				( GCallback ) na_pivot_item_changed_handler,
+				( gpointer ) pivot );
+	}
+
+	na_pivot_free_providers( providers );
+}
+
+/**
  * na_io_provider_read_items:
  * @pivot: the #NAPivot object which owns the list of registered I/O
  * storage providers.
diff --git a/nautilus-actions/runtime/na-io-provider.h b/nautilus-actions/runtime/na-io-provider.h
index f3d5bae..196504c 100644
--- a/nautilus-actions/runtime/na-io-provider.h
+++ b/nautilus-actions/runtime/na-io-provider.h
@@ -44,14 +44,12 @@
 
 G_BEGIN_DECLS
 
+void   na_io_provider_register_callbacks( const NAPivot *pivot );
+
 GList *na_io_provider_read_items ( const NAPivot *pivot, GSList **messages );
 guint  na_io_provider_write_item ( const NAPivot *pivot, NAObjectItem *item, GSList **messages );
 guint  na_io_provider_delete_item( const NAPivot *pivot, const NAObjectItem *item, GSList **messages );
 
-/* notification message to NAPivot
- */
-#define NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED			"notify-consumer-of-action-change"
-
 G_END_DECLS
 
 #endif /* __NA_RUNTIME_IO_PROVIDER_H__ */
diff --git a/nautilus-actions/runtime/na-module.c b/nautilus-actions/runtime/na-module.c
index c62dc64..fa18621 100644
--- a/nautilus-actions/runtime/na-module.c
+++ b/nautilus-actions/runtime/na-module.c
@@ -324,7 +324,7 @@ plugin_check( NAModule *module, const gchar *symbol, gpointer *pfn )
 	ok = g_module_symbol( module->private->library, symbol, pfn );
 
 	if( !ok ){
-		g_debug("%s: %s: %s: symbol", thisfn, module->private->path, symbol );
+		g_debug("%s: %s: %s: symbol not found", thisfn, module->private->path, symbol );
 	}
 
 	return( ok );
diff --git a/nautilus-actions/runtime/na-pivot.c b/nautilus-actions/runtime/na-pivot.c
index e8db861..58e5462 100644
--- a/nautilus-actions/runtime/na-pivot.c
+++ b/nautilus-actions/runtime/na-pivot.c
@@ -74,6 +74,9 @@ struct NAPivotPrivate {
 	 * defaults to FALSE
 	 */
 	gboolean automatic_reload;
+	GTimeVal last_event;
+	guint    event_source_id;
+	gulong   action_changed_handler;
 
 	/* list of monitoring objects on runtime preferences
 	 */
@@ -87,8 +90,6 @@ enum {
 
 static GObjectClass *st_parent_class = NULL;
 static gint          st_signals[ LAST_SIGNAL ] = { 0 };
-static GTimeVal      st_last_event;
-static guint         st_event_source_id = 0;
 static gint          st_timeout_msec = 100;
 static gint          st_timeout_usec = 100000;
 
@@ -101,14 +102,13 @@ static void      instance_finalize( GObject *object );
 
 static NAObject *get_item_from_tree( const NAPivot *pivot, GList *tree, uuid_t uuid );
 
-/* NAIPivotConsumer management */
-static void      free_consumers( GList *list );
-
 /* NAIIOProvider management */
-static void      action_changed_handler( NAPivot *pivot, gpointer user_data );
-static gboolean  on_actions_changed_timeout( gpointer user_data );
+static gboolean  on_item_changed_timeout( NAPivot *pivot );
 static gulong    time_val_diff( const GTimeVal *recent, const GTimeVal *old );
 
+/* NAIPivotConsumer management */
+static void      free_consumers( GList *list );
+
 /* NAGConf runtime preferences management */
 static void      monitor_runtime_preferences( NAPivot *pivot );
 
@@ -179,14 +179,14 @@ class_init( NAPivotClass *klass )
 	klass->private = g_new0( NAPivotClassPrivate, 1 );
 
 	/* register the signal and its default handler
-	 * this signal should be sent by the IIOProvider when an action
+	 * this signal should be sent by the IOProvider when an object
 	 * has changed in the underlying storage subsystem
 	 */
-	st_signals[ ACTION_CHANGED ] = g_signal_new_class_handler(
-				NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED,
-				G_TYPE_FROM_CLASS( klass ),
-				G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
-				( GCallback ) action_changed_handler,
+	st_signals[ ACTION_CHANGED ] = g_signal_new(
+				NA_PIVOT_SIGNAL_ACTION_CHANGED,
+				NA_IIO_PROVIDER_TYPE,
+				G_SIGNAL_RUN_LAST,
+				0,
 				NULL,
 				NULL,
 				g_cclosure_marshal_VOID__POINTER,
@@ -220,6 +220,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	self->private->consumers = NULL;
 	self->private->tree = NULL;
 	self->private->automatic_reload = FALSE;
+	self->private->event_source_id = 0;
 }
 
 static void
@@ -251,6 +252,10 @@ instance_dispose( GObject *object )
 		/* release the GConf monitoring */
 		na_gconf_monitor_release_monitors( self->private->monitors );
 
+		if( g_signal_handler_is_connected( self, self->private->action_changed_handler )){
+			g_signal_handler_disconnect( self, self->private->action_changed_handler );
+		}
+
 		/* chain up to the parent class */
 		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
 			G_OBJECT_CLASS( st_parent_class )->dispose( object );
@@ -300,6 +305,7 @@ na_pivot_new( const NAIPivotConsumer *target )
 	pivot = g_object_new( NA_PIVOT_TYPE, NULL );
 
 	pivot->private->modules = na_module_load_modules();
+	na_io_provider_register_callbacks( pivot );
 	/*g_debug( "%s: modules=%p, count=%d",
 			thisfn, ( void * ) pivot->private->modules, g_list_length( pivot->private->modules ));*/
 
@@ -366,6 +372,36 @@ na_pivot_dump( const NAPivot *pivot )
 	}
 }
 
+/*
+ * this handler is trigerred by IIOProviders when an action is changed
+ * in the underlying storage subsystems
+ * 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
+ */
+void
+na_pivot_item_changed_handler( NAIIOProvider *provider, const gchar *id, NAPivot *pivot  )
+{
+	static const gchar *thisfn = "na_pivot_item_changed_handler";
+
+	g_debug( "%s: provider=%p, id=%s, pivot=%p", thisfn, ( void * ) provider, id, ( void * ) pivot );
+
+	g_return_if_fail( NA_IS_IIO_PROVIDER( provider ));
+	g_return_if_fail( NA_IS_PIVOT( pivot ));
+
+	if( !pivot->private->dispose_has_run ){
+
+		/* set a timeout to notify clients at the end of the serie */
+		g_get_current_time( &pivot->private->last_event );
+
+		if( !pivot->private->event_source_id ){
+			pivot->private->event_source_id =
+				g_timeout_add( st_timeout_msec, ( GSourceFunc ) on_item_changed_timeout, pivot );
+		}
+	}
+}
+
 /**
  * na_pivot_get_providers:
  * @pivot: this #NAPivot instance.
@@ -485,6 +521,7 @@ na_pivot_reload_items( NAPivot *pivot )
 	static const gchar *thisfn = "na_pivot_reload_items";
 	GSList *messages, *im;
 
+	g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
 	g_return_if_fail( NA_IS_PIVOT( pivot ));
 
 	if( !pivot->private->dispose_has_run ){
@@ -811,66 +848,6 @@ get_item_from_tree( const NAPivot *pivot, GList *tree, uuid_t uuid )
 	return( found );
 }
 
-static void
-free_consumers( GList *consumers )
-{
-	/*g_list_foreach( consumers, ( GFunc ) g_object_unref, NULL );*/
-	g_list_free( consumers );
-}
-
-/*
- * Note that each implementation of NAIIOProvider interface must have
- * this same type of constructor, which accepts as parameter a pointer
- * to this NAPivot object.
- * This is required because NAIIOProviders will send all their
- * notification messages to this NAPivot, letting this later redirect
- * them to appropriate NAIPivotConsumers.
- */
-/*
-static void
-register_io_providers( NAPivot *pivot )
-{
-	static const gchar *thisfn = "na_pivot_register_io_providers";
-	GList *list = NULL;
-
-	g_debug( "%s: pivot=%p", thisfn, ( void * ) pivot );
-	g_return_if_fail( NA_IS_PIVOT( pivot ));
-	g_return_if_fail( !pivot->private->dispose_has_run );
-
-	list = g_list_prepend( list, na_gconf_provider_new( pivot ));
-
-	pivot->private->providers = list;
-}*/
-
-/*
- * this handler is trigerred by IIOProviders when an action is changed
- * in the underlying storage subsystems
- * 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
- */
-static void
-action_changed_handler( NAPivot *self, gpointer user_data  )
-{
-	/*static const gchar *thisfn = "na_pivot_action_changed_handler";
-	g_debug( "%s: self=%p, data=%p", thisfn, self, user_data );*/
-
-	g_return_if_fail( NA_IS_PIVOT( self ));
-	g_return_if_fail( !self->private->dispose_has_run );
-	g_return_if_fail( user_data );
-
-	if( self->private->dispose_has_run ){
-		return;
-	}
-
-	/* set a timeout to notify clients at the end of the serie */
-	g_get_current_time( &st_last_event );
-	if( !st_event_source_id ){
-		st_event_source_id = g_timeout_add( st_timeout_msec, ( GSourceFunc ) on_actions_changed_timeout, self );
-	}
-}
-
 /*
  * this timer is set when we receive the first event of a serie
  * we continue to loop until last event is at least one half of a
@@ -880,20 +857,18 @@ action_changed_handler( NAPivot *self, gpointer user_data  )
  * or .. is there ?
  */
 static gboolean
-on_actions_changed_timeout( gpointer user_data )
+on_item_changed_timeout( NAPivot *pivot )
 {
-	/*static const gchar *thisfn = "na_pivot_on_actions_changed_timeout";
-	g_debug( "%s: pivot=%p", thisfn, user_data );*/
+	static const gchar *thisfn = "na_pivot_on_item_changed_timeout";
 	GTimeVal now;
-	NAPivot *pivot;
 	gulong diff;
 	GList *ic;
 
-	g_return_val_if_fail( NA_IS_PIVOT( user_data ), FALSE );
-	pivot = NA_PIVOT( user_data );
+	g_debug( "%s: pivot=%p", thisfn, pivot );
+	g_return_val_if_fail( NA_IS_PIVOT( pivot ), FALSE );
 
 	g_get_current_time( &now );
-	diff = time_val_diff( &now, &st_last_event );
+	diff = time_val_diff( &now, &pivot->private->last_event );
 	if( diff < st_timeout_usec ){
 		return( TRUE );
 	}
@@ -907,7 +882,7 @@ on_actions_changed_timeout( gpointer user_data )
 		na_ipivot_consumer_notify_actions_changed( NA_IPIVOT_CONSUMER( ic->data ));
 	}
 
-	st_event_source_id = 0;
+	pivot->private->event_source_id = 0;
 	return( FALSE );
 }
 
@@ -922,42 +897,11 @@ time_val_diff( const GTimeVal *recent, const GTimeVal *old )
 	return( microsec );
 }
 
-/**
- * na_pivot_free_notify:
- * @npn: a #NAPivotNotify structure.
- *
- * Frees a #NAPivotNotify structure and its content.
- */
-void
-na_pivot_free_notify( NAPivotNotify *npn )
+static void
+free_consumers( GList *consumers )
 {
-	if( npn ){
-		if( npn->type ){
-			switch( npn->type ){
-
-				case NA_PIVOT_STR:
-					g_free(( gchar * ) npn->data );
-					break;
-
-				case NA_PIVOT_BOOL:
-					break;
-
-				case NA_PIVOT_STRLIST:
-					na_utils_free_string_list(( GSList * ) npn->data );
-					break;
-
-				default:
-					g_debug( "na_pivot_free_notify: uuid=%s, profile=%s, parm=%s, type=%d",
-							npn->uuid, npn->profile, npn->parm, npn->type );
-					g_assert_not_reached();
-					break;
-			}
-		}
-		g_free( npn->uuid );
-		g_free( npn->profile );
-		g_free( npn->parm );
-		g_free( npn );
-	}
+	/*g_list_foreach( consumers, ( GFunc ) g_object_unref, NULL );*/
+	g_list_free( consumers );
 }
 
 static void
diff --git a/nautilus-actions/runtime/na-pivot.h b/nautilus-actions/runtime/na-pivot.h
index b5e299d..c78e7b7 100644
--- a/nautilus-actions/runtime/na-pivot.h
+++ b/nautilus-actions/runtime/na-pivot.h
@@ -52,7 +52,8 @@
  * 1. When an I/O storage subsystem detects a change on an action, it
  *    should emit the "notify-consumer-of-action-change" signal to
  *    notify #NAPivot of this change. The user data associated with the
- *    message should be a #gpointer to a #NAPivotNotify structure.
+ *    message is the internal id of the #NAObjectItem-derived modified
+ *    object.
  *
  *    When this signal is received, #NAPivot updates accordingly the
  *    list of actions it maintains.
@@ -62,8 +63,7 @@
  *    sends only one message for a whole, maybe coherent, set of
  *    updates.
  *
- *    This first stage message is defined in na-iio-provider.h,
- *    as NA_IIO_PROVIDER_SIGNAL_ACTION_CHANGED.
+ *    This first stage message is defined below as NA_PIVOT_SIGNAL_ACTION_CHANGED.
  *
  * 2. When #NAPivot has successfully updated its list of actions, it
  *    notifies its consumers in order they update themselves.
@@ -71,9 +71,11 @@
  *    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
- *    subsystem.
+ *    subsystems.
  */
 
+#include <api/na-iio-provider.h>
+
 #include <private/na-object-class.h>
 #include <private/na-object-id-class.h>
 #include <private/na-object-item-class.h>
@@ -111,6 +113,8 @@ NAPivot  *na_pivot_new( const NAIPivotConsumer *notified );
 void      na_pivot_check_status( const NAPivot *pivot );
 void      na_pivot_dump( const NAPivot *pivot );
 
+void      na_pivot_item_changed_handler( NAIIOProvider *provider, const gchar *id, NAPivot *pivot );
+
 GList    *na_pivot_get_providers( const NAPivot *pivot, GType type );
 GObject  *na_pivot_get_provider( const NAPivot *pivot, GType type );
 void      na_pivot_release_provider( const GObject *provider );
@@ -136,24 +140,9 @@ gint      na_pivot_sort_alpha_desc( const NAObjectId *a, const NAObjectId *b );
 
 void      na_pivot_write_level_zero( const NAPivot *pivot, GList *items );
 
-/* data passed from the storage subsystem when an action is changed
+/* notification message from NAIIOProvider to NAPivot
  */
-enum {
-	NA_PIVOT_STR = 1,
-	NA_PIVOT_BOOL,
-	NA_PIVOT_STRLIST
-};
-
-typedef struct {
-	gchar   *uuid;
-	gchar   *profile;
-	gchar   *parm;
-	guint    type;
-	gpointer data;
-}
-	NAPivotNotify;
-
-void       na_pivot_free_notify( NAPivotNotify *data );
+#define NA_PIVOT_SIGNAL_ACTION_CHANGED	"notify-consumer-of-action-change"
 
 G_END_DECLS
 



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