[nautilus-actions] Define a new plugin for selection tracking



commit 2a64c1fce36b60ceb9a7c577bf6e278f2018b57d
Author: Pierre Wieser <pwieser trychlos org>
Date:   Thu Dec 10 20:13:27 2009 +0100

    Define a new plugin for selection tracking
    
    The plugin define a 'org.nautilus_actions.DBus' service, with /org/nautilus_actions/DBus/Tracker
    path object, which may be requested through GetSelectedPaths interface.

 ChangeLog                                     |   28 ++
 TODO                                          |    4 +
 configure.ac                                  |    1 +
 m4/na-log-domains.m4                          |    3 +
 nautilus-actions/Makefile.am                  |    1 +
 nautilus-actions/nact/nact-icommand-tab.c     |    1 +
 nautilus-actions/runtime/na-pivot.c           |   25 +--
 nautilus-actions/runtime/na-pivot.h           |    2 +-
 nautilus-actions/tracker/Makefile.am          |   61 +++++
 nautilus-actions/tracker/na-tracker-dbus.c    |  265 ++++++++++++++++++
 nautilus-actions/tracker/na-tracker-dbus.h    |   88 ++++++
 nautilus-actions/tracker/na-tracker-dbus.xml  |    9 +
 nautilus-actions/tracker/na-tracker-plugin.c  |  144 ++++++++++
 nautilus-actions/tracker/na-tracker.c         |  286 ++++++++++++++++++++
 nautilus-actions/tracker/na-tracker.h         |   83 ++++++
 nautilus-actions/utils/.gitignore             |    2 +
 nautilus-actions/utils/Makefile.am            |   21 ++
 nautilus-actions/utils/nautilus-actions-run.c |  357 +++++++++++++++++++++++++
 18 files changed, 1364 insertions(+), 17 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index c5cef4a..73a428e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2009-12-10 Pierre Wieser <pwieser trychlos org>
+
+	* nautilus-actions/runtime/na-pivot.c:
+	* nautilus-actions/runtime/na-pivot.h (get_item_from_tree):
+	No more require an UUID.
+
+	Be able to get the current Nautilus selection into an external
+	program via a DBus interface in the new Tracker plugin.
+
+	* configure.ac:
+	* nautilus-actions/Makefile.am:
+	Define new tracker subdirectory.
+
+	* m4/na-log-domains.m4:
+	Define new NA-tracker log domain.
+
+	* nautilus-actions/tracker/Makefile.am:
+	* nautilus-actions/tracker/na-tracker-dbus.c:
+	* nautilus-actions/tracker/na-tracker-dbus.h:
+	* nautilus-actions/tracker/na-tracker-dbus.xml:
+	* nautilus-actions/tracker/na-tracker-plugin.c:
+	* nautilus-actions/tracker/na-tracker.c:
+	* nautilus-actions/tracker/na-tracker.h: New files.
+
+	* nautilus-actions/utils/nautilus-actions-run.c: New file.
+
+	* nautilus-actions/utils/Makefile.am: Updated accordingly.
+
 2009-12-08 Pierre Wieser <pwieser trychlos org>
 
 	A try to implement a lockdown key in GConf mandatory settings.
diff --git a/TODO b/TODO
index d61de50..0de4d78 100644
--- a/TODO
+++ b/TODO
@@ -98,3 +98,7 @@
 - nact: new action assistant
 
 - desktop provider: fix default toolbar label
+
+- lockdown: cut should be disabled
+  inline edition should be disabled
+  all entry fields should be readonly
diff --git a/configure.ac b/configure.ac
index 011b109..8e06619 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,7 @@ AC_CONFIG_FILES([
 	nautilus-actions/private/Makefile
 	nautilus-actions/runtime/Makefile
 	nautilus-actions/test/Makefile
+	nautilus-actions/tracker/Makefile
 	nautilus-actions/utils/Makefile
 	po/Makefile.in
 ])
diff --git a/m4/na-log-domains.m4 b/m4/na-log-domains.m4
index 877235c..333d023 100644
--- a/m4/na-log-domains.m4
+++ b/m4/na-log-domains.m4
@@ -29,6 +29,9 @@ AC_DEFUN([NA_LOG_DOMAINS],[
 	AC_SUBST([NA_LOGDOMAIN_TEST],[NA-test])
 	AC_DEFINE_UNQUOTED([NA_LOGDOMAIN_TEST],["NA-test"],[Log domain of test programs])
 
+	AC_SUBST([NA_LOGDOMAIN_TRACKER],[NA-tracker])
+	AC_DEFINE_UNQUOTED([NA_LOGDOMAIN_TRACKER],["NA-tracker"],[Log domain of tracker plugin])
+
 	AC_SUBST([NA_LOGDOMAIN_UTILS],[NA-utils])
 	AC_DEFINE_UNQUOTED([NA_LOGDOMAIN_UTILS],["NA-utils"],[Log domain of utilities])
 ])
diff --git a/nautilus-actions/Makefile.am b/nautilus-actions/Makefile.am
index 9d84c1d..d576952 100644
--- a/nautilus-actions/Makefile.am
+++ b/nautilus-actions/Makefile.am
@@ -35,5 +35,6 @@ SUBDIRS = \
 	nact						\
 	plugin						\
 	test						\
+	tracker						\
 	utils						\
 	$(NULL)
diff --git a/nautilus-actions/nact/nact-icommand-tab.c b/nautilus-actions/nact/nact-icommand-tab.c
index dcb99b9..9afe39f 100644
--- a/nautilus-actions/nact/nact-icommand-tab.c
+++ b/nautilus-actions/nact/nact-icommand-tab.c
@@ -813,6 +813,7 @@ update_example_label( NactICommandTab *instance, NAObjectProfile *profile )
 
 	if( profile ){
 		parameters = parse_parameters( instance );
+		/*g_debug( "%s: parameters=%s", thisfn, parameters );*/
 
 		/* convert special xml chars (&, <, >,...) to avoid warnings
 		 * generated by Pango parser
diff --git a/nautilus-actions/runtime/na-pivot.c b/nautilus-actions/runtime/na-pivot.c
index e5709f6..16a3a5c 100644
--- a/nautilus-actions/runtime/na-pivot.c
+++ b/nautilus-actions/runtime/na-pivot.c
@@ -33,7 +33,6 @@
 #endif
 
 #include <string.h>
-#include <uuid/uuid.h>
 
 #include <api/na-object-api.h>
 #include <api/na-gconf-monitor.h>
@@ -104,7 +103,7 @@ static void          instance_init( GTypeInstance *instance, gpointer klass );
 static void          instance_dispose( GObject *object );
 static void          instance_finalize( GObject *object );
 
-static NAObjectItem *get_item_from_tree( const NAPivot *pivot, GList *tree, uuid_t uuid );
+static NAObjectItem *get_item_from_tree( const NAPivot *pivot, GList *tree, const gchar *id );
 
 /* NAIIOProvider management */
 static gboolean      on_item_changed_timeout( NAPivot *pivot );
@@ -548,7 +547,7 @@ na_pivot_add_item( NAPivot *pivot, const NAObjectItem *item )
 /**
  * na_pivot_get_action:
  * @pivot: this #NAPivot instance.
- * @uuid: the required globally unique identifier (uuid).
+ * @id: the required item identifier.
  *
  * Returns the specified action.
  *
@@ -558,22 +557,19 @@ na_pivot_add_item( NAPivot *pivot, const NAObjectItem *item )
  * g_free() nor g_object_unref() by the caller.
  */
 NAObjectItem *
-na_pivot_get_item( const NAPivot *pivot, const gchar *uuid )
+na_pivot_get_item( const NAPivot *pivot, const gchar *id )
 {
-	uuid_t uuid_bin;
 	NAObjectItem *object = NULL;
 
 	g_return_val_if_fail( NA_IS_PIVOT( pivot ), NULL );
 
 	if( !pivot->private->dispose_has_run ){
 
-		if( !uuid || !strlen( uuid )){
+		if( !id || !strlen( id )){
 			return( NULL );
 		}
 
-		uuid_parse( uuid, uuid_bin );
-
-		object = get_item_from_tree( pivot, pivot->private->tree, uuid_bin );
+		object = get_item_from_tree( pivot, pivot->private->tree, id );
 	}
 
 	return( object );
@@ -875,25 +871,22 @@ na_pivot_write_level_zero( const NAPivot *pivot, GList *items )
 }
 
 static NAObjectItem *
-get_item_from_tree( const NAPivot *pivot, GList *tree, uuid_t uuid )
+get_item_from_tree( const NAPivot *pivot, GList *tree, const gchar *id )
 {
-	uuid_t i_uuid_bin;
 	GList *subitems, *ia;
 	NAObjectItem *found = NULL;
 
 	for( ia = tree ; ia && !found ; ia = ia->next ){
 
-		gchar *i_uuid = na_object_get_id( NA_OBJECT( ia->data ));
-		uuid_parse( i_uuid, i_uuid_bin );
-		g_free( i_uuid );
+		gchar *i_id = na_object_get_id( NA_OBJECT( ia->data ));
 
-		if( !uuid_compare( uuid, i_uuid_bin )){
+		if( !g_ascii_strcasecmp( id, i_id )){
 			found = NA_OBJECT_ITEM( ia->data );
 		}
 
 		if( !found && NA_IS_OBJECT_ITEM( ia->data )){
 			subitems = na_object_get_items_list( ia->data );
-			found = get_item_from_tree( pivot, subitems, uuid );
+			found = get_item_from_tree( pivot, subitems, id );
 		}
 	}
 
diff --git a/nautilus-actions/runtime/na-pivot.h b/nautilus-actions/runtime/na-pivot.h
index 331bacc..98087c9 100644
--- a/nautilus-actions/runtime/na-pivot.h
+++ b/nautilus-actions/runtime/na-pivot.h
@@ -132,7 +132,7 @@ GList        *na_pivot_get_items( const NAPivot *pivot );
 void          na_pivot_load_items( NAPivot *pivot );
 
 void          na_pivot_add_item( NAPivot *pivot, const NAObjectItem *item );
-NAObjectItem *na_pivot_get_item( const NAPivot *pivot, const gchar *uuid );
+NAObjectItem *na_pivot_get_item( const NAPivot *pivot, const gchar *id );
 void          na_pivot_remove_item( NAPivot *pivot, NAObject *item );
 
 guint         na_pivot_delete_item( const NAPivot *pivot, const NAObjectItem *item, GSList **messages );
diff --git a/nautilus-actions/tracker/Makefile.am b/nautilus-actions/tracker/Makefile.am
new file mode 100644
index 0000000..1f6b63b
--- /dev/null
+++ b/nautilus-actions/tracker/Makefile.am
@@ -0,0 +1,61 @@
+# Nautilus Actions
+# A Nautilus extension which offers configurable context menu actions.
+#
+# Copyright (C) 2005 The GNOME Foundation
+# Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+# Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+#
+# This Program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This Program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this Library; see the file COPYING.  If not,
+# write to the Free Software Foundation, Inc., 59 Temple Place,
+# Suite 330, Boston, MA 02111-1307, USA.
+#
+# Authors:
+#   Frederic Ruaudel <grumz grumz net>
+#   Rodrigo Moya <rodrigo gnome-db org>
+#   Pierre Wieser <pwieser trychlos org>
+#   ... and many others (see AUTHORS)
+
+AM_CPPFLAGS += \
+	-I $(top_srcdir)											\
+	-I $(top_srcdir)/nautilus-actions							\
+	-DG_LOG_DOMAIN=\"${NA_LOGDOMAIN_TRACKER}\"					\
+	$(NAUTILUS_ACTIONS_CFLAGS)									\
+	$(NULL)
+
+nautilus_extensiondir = $(NAUTILUS_EXTENSIONS_DIR)
+
+nautilus_extension_LTLIBRARIES = libnautilus-actions-tracker.la
+
+BUILT_SOURCES = \
+	na-tracker-dbus-glue.h										\
+	$(NULL)
+
+na-tracker-dbus-glue.h: na-tracker-dbus.xml
+	dbus-binding-tool --mode=glib-server --prefix=na_tracker_dbus $< > $@
+
+libnautilus_actions_tracker_la_SOURCES = \
+	na-tracker.c												\
+	na-tracker.h												\
+	na-tracker-dbus.c											\
+	na-tracker-dbus.h											\
+	na-tracker-plugin.c											\
+	$(NULL)
+
+libnautilus_actions_tracker_la_LDFLAGS = -module -avoid-version
+
+libnautilus_actions_tracker_la_LIBADD = \
+	-L$(top_builddir)/nautilus-actions/private	-lna-private	\
+	-L$(top_builddir)/nautilus-actions/runtime	-lna-runtime	\
+	$(NAUTILUS_ACTIONS_LIBS)									\
+	$(NULL)
diff --git a/nautilus-actions/tracker/na-tracker-dbus.c b/nautilus-actions/tracker/na-tracker-dbus.c
new file mode 100644
index 0000000..636f180
--- /dev/null
+++ b/nautilus-actions/tracker/na-tracker-dbus.c
@@ -0,0 +1,265 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+/*
+ * pwi 2009-12-09 - French comments are from
+ * http://www.unixgarden.com/index.php/programmation/decouvertes-et-experimentation-avec-d-bus
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libnautilus-extension/nautilus-file-info.h>
+
+#include <dbus/dbus-glib.h>
+
+#include "na-tracker-dbus.h"
+#include "na-tracker-dbus-glue.h"
+
+/* private class data
+ */
+struct NATrackerDBusClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NATrackerDBusPrivate {
+	gboolean  dispose_has_run;
+	GList    *uris;
+};
+
+static GObjectClass *st_parent_class = NULL;
+
+static GType  register_type( void );
+static void   class_init( NATrackerDBusClass *klass );
+static void   instance_init( GTypeInstance *instance, gpointer klass );
+static void   instance_dispose( GObject *object );
+static void   instance_finalize( GObject *object );
+
+static GList *free_uris( GList *uris );
+
+GType
+na_tracker_dbus_get_type( void )
+{
+	static GType tracker_type = 0;
+
+	if( !tracker_type ){
+		tracker_type = register_type();
+	}
+
+	return( tracker_type );
+}
+
+static GType
+register_type( void )
+{
+	static const gchar *thisfn = "na_tracker_dbus_register_type";
+	GType type;
+
+	static GTypeInfo info = {
+		sizeof( NATrackerDBusClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NATrackerDBus ),
+		0,
+		( GInstanceInitFunc ) instance_init
+	};
+
+	g_debug( "%s", thisfn );
+
+	type = g_type_register_static( G_TYPE_OBJECT, "NATrackerDBus", &info, 0 );
+
+	return( type );
+}
+
+static void
+class_init( NATrackerDBusClass *klass )
+{
+	static const gchar *thisfn = "na_tracker_dbus_class_init";
+	GObjectClass *gobject_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	gobject_class = G_OBJECT_CLASS( klass );
+	gobject_class->dispose = instance_dispose;
+	gobject_class->finalize = instance_finalize;
+
+	klass->private = g_new0( NATrackerDBusClassPrivate, 1 );
+
+	/* Installation du mécanisme dâ??introspection,
+	 * permettant de faire lâ??appel de méthodes via un nom.
+	 * - Le second paramètre de cette fonction : &dbus_glib_dummy_object_object_info
+	 * est généré lors de lâ??appel à dbus-binding-tool
+	 * et sa définition peut être retrouvée dans le fichier
+	 * na-tracker-dbus-glue.h
+	 */
+	dbus_g_object_type_install_info( NA_TRACKER_DBUS_TYPE, &dbus_glib_na_tracker_dbus_object_info );
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_tracker_dbus_instance_init";
+	NATrackerDBus *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_return_if_fail( NA_IS_TRACKER_DBUS( instance ));
+
+	self = NA_TRACKER_DBUS( instance );
+
+	self->private = g_new0( NATrackerDBusPrivate, 1 );
+	self->private->dispose_has_run = FALSE;
+	self->private->uris = NULL;
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_tracker_dbus_instance_dispose";
+	NATrackerDBus *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_TRACKER_DBUS( object ));
+	self = NA_TRACKER_DBUS( object );
+
+	if( !self->private->dispose_has_run ){
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+
+		self->private->dispose_has_run = TRUE;
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	static const gchar *thisfn = "na_tracker_dbus_instance_finalize";
+	NATrackerDBus *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_TRACKER_DBUS( object ));
+	self = NA_TRACKER_DBUS( object );
+
+	self->private->uris = free_uris( self->private->uris );
+
+	g_free( self->private );
+
+	/* chain up to the parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/**
+ * na_tracker_dbus_set_uris:
+ * @tracker: this #NATrackerDBus instance.
+ * @files: the list of currently selected items.
+ *
+ * Maintains our own list of uris.
+ */
+void
+na_tracker_dbus_set_uris( NATrackerDBus *tracker, GList *files )
+{
+	GList *it;
+	gchar *uri;
+
+	if( !tracker->private->dispose_has_run ){
+
+		tracker->private->uris = free_uris( tracker->private->uris );
+
+		for( it = files ; it ; it = it->next ){
+			uri = nautilus_file_info_get_uri(( NautilusFileInfo * ) it->data );
+			tracker->private->uris = g_list_prepend( tracker->private->uris, uri );
+		}
+
+		tracker->private->uris = g_list_reverse( tracker->private->uris );
+	}
+}
+
+/**
+ * na_tracker_dbus_get_selected_paths:
+ * @tracker:
+ * @paths:
+ * @error:
+ *
+ * Exported as GetSelectedPaths method.
+ */
+gboolean
+na_tracker_dbus_get_selected_paths( NATrackerDBus *tracker, char ***paths, GError **error )
+{
+	static const gchar *thisfn = "na_tracker_dbus_get_selected_paths";
+	*error = NULL;
+	GList *it;
+	int count;
+	gchar **iter;
+
+	g_debug( "%s: object=%p, paths=%p, error=%p", thisfn, ( void * ) tracker, ( void * ) paths, ( void * ) error );
+
+	*error = NULL;
+	*paths = NULL;
+
+	if( !tracker->private->dispose_has_run ){
+
+		count = g_list_length( tracker->private->uris );
+		*paths = ( char ** ) g_new0( gchar *, 1+count );
+		iter = *paths;
+
+		for( it = tracker->private->uris ; it ; it = it->next ){
+			*iter = g_strdup(( gchar * ) it->data );
+			iter++;
+		}
+	}
+
+	return( TRUE );
+}
+
+static GList *
+free_uris( GList *uris )
+{
+	GList *it;
+
+	for( it = uris ; it ; it = it->next ){
+		g_free(( gchar * ) it->data );
+	}
+
+	g_list_free( uris );
+
+	return( NULL );
+}
diff --git a/nautilus-actions/tracker/na-tracker-dbus.h b/nautilus-actions/tracker/na-tracker-dbus.h
new file mode 100644
index 0000000..a2b7ca7
--- /dev/null
+++ b/nautilus-actions/tracker/na-tracker-dbus.h
@@ -0,0 +1,88 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __NA_TRACKER_DBUS_H__
+#define __NA_TRACKER_DBUS_H__
+
+/**
+ * SECTION: na_tracker_dbus
+ * @short_description: #NATrackerDBus class definition.
+ * @include: tracker/na-tracker.h
+ *
+ * There is only one NATrackerDBus object in the process.
+ *
+ * As a Nautilus extension, it is initialized when the module is loaded
+ * by the file manager at startup time.
+ *
+ * The NATrackerDBus object maintains the list of lastly selected items in
+ * Nautilus UI.
+ */
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NA_TRACKER_DBUS_TYPE				( na_tracker_dbus_get_type())
+#define NA_TRACKER_DBUS( object )			( G_TYPE_CHECK_INSTANCE_CAST(( object ), NA_TRACKER_DBUS_TYPE, NATrackerDBus ))
+#define NA_TRACKER_DBUS_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST(( klass ), NA_TRACKER_DBUS_TYPE, NATrackerDBusClass ))
+#define NA_IS_TRACKER_DBUS( object )		( G_TYPE_CHECK_INSTANCE_TYPE(( object ), NA_TRACKER_DBUS_TYPE ))
+#define NA_IS_TRACKER_DBUS_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_TRACKER_DBUS_TYPE ))
+#define NA_TRACKER_DBUS_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_TRACKER_DBUS_TYPE, NATrackerDBusClass ))
+
+typedef struct NATrackerDBusPrivate NATrackerDBusPrivate;
+
+typedef struct
+{
+	GObject               parent;
+	NATrackerDBusPrivate *private;
+}
+	NATrackerDBus;
+
+typedef struct NATrackerDBusClassPrivate NATrackerDBusClassPrivate;
+
+typedef struct
+{
+	GObjectClass               parent;
+	NATrackerDBusClassPrivate *private;
+}
+	NATrackerDBusClass;
+
+GType    na_tracker_dbus_get_type( void );
+
+void     na_tracker_dbus_set_uris( NATrackerDBus *tracker, GList *files );
+
+gboolean na_tracker_dbus_get_selected_paths( NATrackerDBus *tracker, char ***paths, GError **error );
+
+#define NA_TRACKER_DBUS_TRACKER_PATH		"/org/nautilus_actions/DBus/Tracker"
+#define NA_TRACKER_DBUS_TRACKER_INTERFACE	"org.nautilus_actions.DBus.Tracker.Status"
+
+G_END_DECLS
+
+#endif /* __NA_TRACKER_DBUS_H__ */
diff --git a/nautilus-actions/tracker/na-tracker-dbus.xml b/nautilus-actions/tracker/na-tracker-dbus.xml
new file mode 100644
index 0000000..b5d823c
--- /dev/null
+++ b/nautilus-actions/tracker/na-tracker-dbus.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<node name="/org/nautilus_actions/DBus/Tracker">
+  <interface name="org.nautilus_actions.DBus.Tracker.Status">
+    <method name="GetSelectedPaths">
+      <arg type="as" name="paths" direction="out" />
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="na_tracker_dbus_get_selected_paths" />
+    </method>
+  </interface>
+</node>
diff --git a/nautilus-actions/tracker/na-tracker-plugin.c b/nautilus-actions/tracker/na-tracker-plugin.c
new file mode 100644
index 0000000..dc6898c
--- /dev/null
+++ b/nautilus-actions/tracker/na-tracker-plugin.c
@@ -0,0 +1,144 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <syslog.h>
+
+#include <libnautilus-extension/nautilus-extension-types.h>
+
+#include "na-tracker.h"
+
+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_default_log_func = NULL;
+
+/*
+ * A nautilus extension must implement three functions :
+ *
+ * - nautilus_module_initialize
+ * - nautilus_module_list_types
+ * - nautilus_module_shutdown
+ *
+ * The first two functions are called at nautilus startup.
+ *
+ * The prototypes for these functions are defined in nautilus-extension-types.h
+ */
+
+void
+nautilus_module_initialize( GTypeModule *module )
+{
+	static const gchar *thisfn = "nautilus_module_initialize";
+
+	syslog( LOG_USER | LOG_INFO, "Nautilus-Actions Tracker %s initializing...", PACKAGE_VERSION );
+
+	set_log_handler();
+
+	g_debug( "%s: module=%p", thisfn, ( void * ) module );
+
+	g_type_module_set_name( module, PACKAGE_STRING );
+
+	na_tracker_register_type( module );
+}
+
+void
+nautilus_module_list_types( const GType **types, int *num_types )
+{
+	static const gchar *thisfn = "nautilus_module_list_types";
+	static GType type_list[1];
+
+	g_debug( "%s: types=%p, num_types=%p", thisfn, ( void * ) types, ( void * ) num_types );
+
+	type_list[0] = NA_TRACKER_TYPE;
+	*types = type_list;
+	*num_types = 1;
+}
+
+void
+nautilus_module_shutdown( void )
+{
+	static const gchar *thisfn = "nautilus_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...
+	 */
+	if( st_default_log_func ){
+		g_log_set_default_handler( st_default_log_func, NULL );
+		st_default_log_func = NULL;
+	}
+}
+
+/*
+ * 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
+set_log_handler( void )
+{
+	st_default_log_func = g_log_set_default_handler(( GLogFunc ) log_handler, NULL );
+}
+
+/*
+ * we used to install a log handler for each and every log domain used
+ * in Nautilus-Actions ; this led to a fastidious enumeration
+ * instead we install a default log handler which will receive all
+ * debug messages, i.e. not only from N-A, but also from other code
+ * in the Nautilus process
+ */
+static void
+log_handler( const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data )
+{
+	gchar *tmp;
+
+	tmp = g_strdup( "" );
+	if( log_domain && strlen( log_domain )){
+		g_free( tmp );
+		tmp = g_strdup_printf( "[%s] ", log_domain );
+	}
+
+#ifdef NA_MAINTAINER_MODE
+	/*( *st_default_log_func )( log_domain, log_level, message, user_data );*/
+	syslog( LOG_USER | LOG_DEBUG, "%s%s", tmp, message );
+#else
+	/* do nothing */
+#endif
+
+	g_free( tmp );
+}
diff --git a/nautilus-actions/tracker/na-tracker.c b/nautilus-actions/tracker/na-tracker.c
new file mode 100644
index 0000000..0861cf2
--- /dev/null
+++ b/nautilus-actions/tracker/na-tracker.c
@@ -0,0 +1,286 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <libnautilus-extension/nautilus-extension-types.h>
+#include <libnautilus-extension/nautilus-file-info.h>
+#include <libnautilus-extension/nautilus-menu-provider.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-bindings.h>
+
+#include "na-tracker.h"
+#include "na-tracker-dbus.h"
+
+/* private class data
+ */
+struct NATrackerClassPrivate {
+	void *empty;						/* so that gcc -pedantic is happy */
+};
+
+/* private instance data
+ */
+struct NATrackerPrivate {
+	gboolean       dispose_has_run;
+	NATrackerDBus *tracker;
+};
+
+static GObjectClass *st_parent_class = NULL;
+static GType         st_module_type = 0;
+
+static void           class_init( NATrackerClass *klass );
+static void           menu_provider_iface_init( NautilusMenuProviderIface *iface );
+static void           instance_init( GTypeInstance *instance, gpointer klass );
+static NATrackerDBus *initialize_dbus_connection( void );
+static void           instance_dispose( GObject *object );
+static void           instance_finalize( GObject *object );
+
+static GList         *get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files );
+
+GType
+na_tracker_get_type( void )
+{
+	g_assert( st_module_type );
+	return( st_module_type );
+}
+
+void
+na_tracker_register_type( GTypeModule *module )
+{
+	static const gchar *thisfn = "na_tracker_register_type";
+
+	static const GTypeInfo info = {
+		sizeof( NATrackerClass ),
+		( GBaseInitFunc ) NULL,
+		( GBaseFinalizeFunc ) NULL,
+		( GClassInitFunc ) class_init,
+		NULL,
+		NULL,
+		sizeof( NATracker ),
+		0,
+		( GInstanceInitFunc ) instance_init,
+	};
+
+	static const GInterfaceInfo menu_provider_iface_info = {
+		( GInterfaceInitFunc ) menu_provider_iface_init,
+		NULL,
+		NULL
+	};
+
+	g_debug( "%s: module=%p", thisfn, ( void * ) module );
+	g_assert( st_module_type == 0 );
+
+	st_module_type = g_type_module_register_type( module, G_TYPE_OBJECT, "NATracker", &info, 0 );
+
+	g_type_module_add_interface( module, st_module_type, NAUTILUS_TYPE_MENU_PROVIDER, &menu_provider_iface_info );
+}
+
+static void
+class_init( NATrackerClass *klass )
+{
+	static const gchar *thisfn = "na_tracker_class_init";
+	GObjectClass *gobject_class;
+
+	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
+
+	st_parent_class = g_type_class_peek_parent( klass );
+
+	gobject_class = G_OBJECT_CLASS( klass );
+	gobject_class->dispose = instance_dispose;
+	gobject_class->finalize = instance_finalize;
+
+	klass->private = g_new0( NATrackerClassPrivate, 1 );
+}
+
+static void
+menu_provider_iface_init( NautilusMenuProviderIface *iface )
+{
+	static const gchar *thisfn = "na_tracker_menu_provider_iface_init";
+
+	g_debug( "%s: iface=%p", thisfn, ( void * ) iface );
+
+	iface->get_file_items = get_file_items;
+	iface->get_background_items = NULL;
+	iface->get_toolbar_items = NULL;
+}
+
+static void
+instance_init( GTypeInstance *instance, gpointer klass )
+{
+	static const gchar *thisfn = "na_tracker_instance_init";
+	NATracker *self;
+
+	g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
+	g_return_if_fail( NA_IS_TRACKER( instance ));
+
+	self = NA_TRACKER( instance );
+
+	self->private = g_new0( NATrackerPrivate, 1 );
+	self->private->dispose_has_run = FALSE;
+	self->private->tracker = initialize_dbus_connection();
+}
+
+/*
+ * initialize the DBus connection at class init time
+ * & instantiate the object which will do effective tracking
+ */
+static NATrackerDBus *
+initialize_dbus_connection( void )
+{
+	static const gchar *thisfn = "na_tracker_initialize_dbus_connection";
+	NATrackerDBus *tracker;
+	DBusGConnection *connection;
+	GError *error;
+	DBusGProxy *proxy;
+	guint32 request_name_ret;
+
+	/* get a connection on session DBus
+	 */
+	tracker = NULL;
+	error = NULL;
+	connection = dbus_g_bus_get( DBUS_BUS_SESSION, &error );
+	if( !connection ){
+		g_warning( "%s: unable to get a connection on session DBus: %s", thisfn, error->message );
+		g_error_free( error );
+		return( NULL );
+	}
+	g_debug( "%s: connection is ok", thisfn );
+
+	/* get a proxy for this connection
+	 * this proxy let us request some standard DBus services
+	 */
+	proxy = dbus_g_proxy_new_for_name( connection, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS );
+	if( !proxy ){
+		g_warning( "%s: unable to get a proxy for the connection", thisfn );
+		dbus_g_connection_unref( connection );
+		return( NULL );
+	}
+	g_debug( "%s: proxy is ok", thisfn );
+
+	/* try to register our service name as a unique 'well known' name
+	 */
+	if( !org_freedesktop_DBus_request_name(
+			proxy, NAUTILUS_ACTIONS_DBUS_SERVICE, 0, &request_name_ret, &error )){
+
+		g_warning( "%s: unable to register %s as a 'well known' name on the bus: %s",
+				thisfn, NAUTILUS_ACTIONS_DBUS_SERVICE, error->message );
+		g_error_free( error );
+		dbus_g_connection_unref( connection );
+		return( NULL );
+	}
+	g_debug( "%s: well known name registration is ok", thisfn );
+
+	if( request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER ){
+		g_warning("%s: got result code %u from requesting name (not the primary owner of the name)", thisfn, request_name_ret );
+		dbus_g_connection_unref( connection );
+		return( NULL );
+	}
+	g_debug( "%s: primary owner check is ok", thisfn );
+
+	/* allocate the tracking object and register it
+	 * instantiation takes care of installing introspection infos
+	 */
+	tracker = g_object_new( NA_TRACKER_DBUS_TYPE, NULL );
+	dbus_g_connection_register_g_object( connection, NA_TRACKER_DBUS_TRACKER_PATH, G_OBJECT( tracker ));
+
+	g_debug( "%s: registering tracker path is ok", thisfn );
+	return( tracker );
+}
+
+static void
+instance_dispose( GObject *object )
+{
+	static const gchar *thisfn = "na_tracker_instance_dispose";
+	NATracker *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_TRACKER( object ));
+	self = NA_TRACKER( object );
+
+	if( !self->private->dispose_has_run ){
+
+		g_object_unref( self->private->tracker );
+		self->private->tracker = NULL;
+
+		/* chain up to the parent class */
+		if( G_OBJECT_CLASS( st_parent_class )->dispose ){
+			G_OBJECT_CLASS( st_parent_class )->dispose( object );
+		}
+
+		self->private->dispose_has_run = TRUE;
+	}
+}
+
+static void
+instance_finalize( GObject *object )
+{
+	static const gchar *thisfn = "na_tracker_instance_finalize";
+	NATracker *self;
+
+	g_debug( "%s: object=%p", thisfn, ( void * ) object );
+	g_return_if_fail( NA_IS_TRACKER( object ));
+	self = NA_TRACKER( object );
+
+	g_free( self->private );
+
+	/* chain up to the parent class */
+	if( G_OBJECT_CLASS( st_parent_class )->finalize ){
+		G_OBJECT_CLASS( st_parent_class )->finalize( object );
+	}
+}
+
+/*
+ * this function is called each time the selection changed
+ * menus items are available :
+ * a) in Edit menu while the selection stays unchanged
+ * b) in contextual menu while the selection stays unchanged
+ */
+static GList *
+get_file_items( NautilusMenuProvider *provider, GtkWidget *window, GList *files )
+{
+	static const gchar *thisfn = "na_tracker_get_file_items";
+	NATracker *self;
+
+	g_debug( "%s: provider=%p, window=%p, files=%p, count=%d",
+			thisfn, ( void * ) provider, ( void * ) window, ( void * ) files, g_list_length( files ));
+
+	g_return_val_if_fail( NA_IS_TRACKER( provider ), NULL );
+	self = NA_TRACKER( provider );
+
+	if( !self->private->dispose_has_run && self->private->tracker ){
+
+		na_tracker_dbus_set_uris( self->private->tracker, files );
+	}
+
+	return( NULL );
+}
diff --git a/nautilus-actions/tracker/na-tracker.h b/nautilus-actions/tracker/na-tracker.h
new file mode 100644
index 0000000..8aa009a
--- /dev/null
+++ b/nautilus-actions/tracker/na-tracker.h
@@ -0,0 +1,83 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifndef __NA_TRACKER_H__
+#define __NA_TRACKER_H__
+
+/**
+ * SECTION: na_tracker
+ * @short_description: #NATracker class definition.
+ * @include: tracker/na-tracker.h
+ *
+ * There is only one #NATracker object in the process. As any Nautilus
+ * extension, it is instantiated when the module is loaded by the file
+ * manager at startup time.
+ *
+ * The #NATracker object initiates the DBus connection, and allocates
+ * the object responsable of effective tracking.
+ */
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define NA_TRACKER_TYPE					( na_tracker_get_type())
+#define NA_TRACKER( object )			( G_TYPE_CHECK_INSTANCE_CAST(( object ), NA_TRACKER_TYPE, NATracker ))
+#define NA_TRACKER_CLASS( klass )		( G_TYPE_CHECK_CLASS_CAST(( klass ), NA_TRACKER_TYPE, NATrackerClass ))
+#define NA_IS_TRACKER( object )			( G_TYPE_CHECK_INSTANCE_TYPE(( object ), NA_TRACKER_TYPE ))
+#define NA_IS_TRACKER_CLASS( klass )	( G_TYPE_CHECK_CLASS_TYPE(( klass ), NA_TRACKER_TYPE ))
+#define NA_TRACKER_GET_CLASS( object )	( G_TYPE_INSTANCE_GET_CLASS(( object ), NA_TRACKER_TYPE, NATrackerClass ))
+
+typedef struct NATrackerPrivate NATrackerPrivate;
+
+typedef struct
+{
+	GObject           parent;
+	NATrackerPrivate *private;
+}
+	NATracker;
+
+typedef struct NATrackerClassPrivate NATrackerClassPrivate;
+
+typedef struct
+{
+	GObjectClass           parent;
+	NATrackerClassPrivate *private;
+}
+	NATrackerClass;
+
+GType na_tracker_get_type( void );
+void  na_tracker_register_type( GTypeModule *module );
+
+#define NAUTILUS_ACTIONS_DBUS_SERVICE	"org.nautilus-actions.DBus"
+
+G_END_DECLS
+
+#endif /* __NA_TRACKER_H__ */
diff --git a/nautilus-actions/utils/.gitignore b/nautilus-actions/utils/.gitignore
index 9789155..d94650a 100644
--- a/nautilus-actions/utils/.gitignore
+++ b/nautilus-actions/utils/.gitignore
@@ -1,4 +1,6 @@
 nautilus-actions-check-actions-change
 nautilus-actions-new-config
 nautilus-actions-new
+nautilus-actions-run
+nautilus-actions-run-bindings.h
 nautilus-actions-schemas
diff --git a/nautilus-actions/utils/Makefile.am b/nautilus-actions/utils/Makefile.am
index ced80bf..8fd940e 100644
--- a/nautilus-actions/utils/Makefile.am
+++ b/nautilus-actions/utils/Makefile.am
@@ -28,6 +28,7 @@
 
 bin_PROGRAMS = \
 	nautilus-actions-new										\
+	nautilus-actions-run										\
 	nautilus-actions-schemas									\
 	$(NULL)
 
@@ -52,6 +53,26 @@ nautilus_actions_new_LDADD = \
 	$(NAUTILUS_ACTIONS_LIBS)									\
 	$(NULL)
 
+BUILT_SOURCES = \
+	nautilus-actions-run-bindings.h								\
+	$(NULL)
+
+nautilus-actions-run-bindings.h: $(top_srcdir)/nautilus-actions/tracker/na-tracker-dbus.xml
+	dbus-binding-tool --mode=glib-client $< > $@
+
+nautilus_actions_run_SOURCES = \
+	nautilus-actions-run.c										\
+	console-utils.c												\
+	console-utils.h												\
+	$(NULL)
+
+nautilus_actions_run_LDADD = \
+	-L$(top_builddir)/nautilus-actions/api		-lna-api		\
+	-L$(top_builddir)/nautilus-actions/private	-lna-private	\
+	-L$(top_builddir)/nautilus-actions/runtime	-lna-runtime	\
+	$(NAUTILUS_ACTIONS_LIBS)									\
+	$(NULL)
+
 nautilus_actions_schemas_SOURCES = \
 	nautilus-actions-schemas.c									\
 	console-utils.c												\
diff --git a/nautilus-actions/utils/nautilus-actions-run.c b/nautilus-actions/utils/nautilus-actions-run.c
new file mode 100644
index 0000000..de7e1cd
--- /dev/null
+++ b/nautilus-actions/utils/nautilus-actions-run.c
@@ -0,0 +1,357 @@
+/*
+ * Nautilus Actions
+ * A Nautilus extension which offers configurable context menu actions.
+ *
+ * Copyright (C) 2005 The GNOME Foundation
+ * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
+ * Copyright (C) 2009 Pierre Wieser and others (see AUTHORS)
+ *
+ * This Program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ *   Frederic Ruaudel <grumz grumz net>
+ *   Rodrigo Moya <rodrigo gnome-db org>
+ *   Pierre Wieser <pwieser trychlos org>
+ *   ... and many others (see AUTHORS)
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <api/na-object-api.h>
+
+#include <runtime/na-pivot.h>
+#include <runtime/na-utils.h>
+
+#include <tracker/na-tracker.h>
+#include <tracker/na-tracker-dbus.h>
+
+#include "console-utils.h"
+#include "nautilus-actions-run-bindings.h"
+
+static gchar     *id               = "";
+static gchar     *parms            = "";
+static gchar    **targets_array    = NULL;
+static gboolean   current          = FALSE;
+static gboolean   version          = FALSE;
+
+static GOptionEntry entries[] = {
+
+	{ "id"                   , 'i', 0, G_OPTION_ARG_STRING      , &id,
+			N_( "The internal identifiant of the action to be launched" ), N_( "<STRING>" ) },
+	{ "parameters"           , 'p', 0, G_OPTION_ARG_STRING      , &parms,
+			N_( "The parameters to be applied to the action" ), N_( "<STRING>" ) },
+	{ "target"               , 't', 0, G_OPTION_ARG_STRING      , &targets_array,
+			N_( "A target of the action. More than one options may be specified. Incompatible with '--current' option" ), N_( "<STRING>" ) },
+	{ "current"              , 'c', 0, G_OPTION_ARG_NONE        , &current,
+			N_( "Whether the action should be executed on current Nautilus selection [default]. Incompatible with '--target' option" ), NULL },
+	{ NULL }
+};
+
+static GOptionEntry misc_entries[] = {
+
+	{ "version"              , 'v', 0, G_OPTION_ARG_NONE        , &version,
+			N_( "Output the version number" ), NULL },
+	{ NULL }
+};
+
+static GOptionContext *init_options( void );
+static NAObjectAction *get_action( const gchar *id );
+static GList          *get_current_selection( void );
+static GList          *targets_from_commandline( void );
+static void            dump_targets( GList *targets );
+static void            free_targets( GList *targets );
+static void            exit_with_usage( void );
+
+int
+main( int argc, char** argv )
+{
+	static const gchar *thisfn = "nautilus_actions_run_main";
+	int status = EXIT_SUCCESS;
+	GOptionContext *context;
+	GError *error = NULL;
+	gchar *help;
+	gint errors;
+	NAObjectAction *action;
+	GList *targets;
+
+	g_type_init();
+	console_init_log_handler();
+
+	context = init_options();
+
+	if( argc == 1 ){
+		g_set_prgname( argv[0] );
+		help = g_option_context_get_help( context, FALSE, NULL );
+		g_print( "\n%s", help );
+		g_free( help );
+		exit( status );
+	}
+
+	if( !g_option_context_parse( context, &argc, &argv, &error )){
+		g_printerr( _( "Syntax error: %s\n" ), error->message );
+		g_error_free (error);
+		exit_with_usage();
+	}
+
+	g_option_context_free( context );
+
+	if( version ){
+		na_utils_print_version();
+		exit( status );
+	}
+
+	errors = 0;
+
+	if( !id || !strlen( id )){
+		g_printerr( _( "Error: action id is mandatory.\n" ));
+		errors += 1;
+	}
+
+	if( current && targets_array ){
+		g_printerr( _( "Error: '--target' and '--current' options cannot both be specified.\n" ));
+		errors += 1;
+	}
+
+	if( !current && !targets_array ){
+		current = TRUE;
+	}
+
+	action = get_action( id );
+	if( !action ){
+		errors += 1;
+	}
+	g_debug( "%s: action %s have been found, and is enabled and valid", thisfn, id );
+
+	if( errors ){
+		exit_with_usage();
+	}
+
+	if( current ){
+		targets = get_current_selection();
+	} else {
+		targets = targets_from_commandline();
+	}
+
+	dump_targets( targets );
+	free_targets( targets );
+
+	exit( status );
+}
+
+/*
+ * init options context
+ */
+static GOptionContext *
+init_options( void )
+{
+	GOptionContext *context;
+	gchar* description;
+	GOptionGroup *misc_group;
+
+	context = g_option_context_new( _( "Execute an action on the specified target." ));
+
+#ifdef ENABLE_NLS
+	bindtextdomain( GETTEXT_PACKAGE, GNOMELOCALEDIR );
+# ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+	bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" );
+# endif
+	textdomain( GETTEXT_PACKAGE );
+	g_option_context_add_main_entries( context, entries, GETTEXT_PACKAGE );
+#else
+	g_option_context_add_main_entries( context, entries, NULL );
+#endif
+
+	description = g_strdup_printf( "%s.\n%s", PACKAGE_STRING,
+			_( "Bug reports are welcomed at http://bugzilla.gnome.org,";
+				" or you may prefer to mail to <maintainer nautilus-actions org>.\n" ));
+
+	g_option_context_set_description( context, description );
+
+	g_free( description );
+
+	misc_group = g_option_group_new(
+			"misc", _( "Miscellaneous options" ), _( "Miscellaneous options" ), NULL, NULL );
+	g_option_group_add_entries( misc_group, misc_entries );
+	g_option_context_add_group( context, misc_group );
+
+	return( context );
+}
+
+/*
+ * search for the action in the repository
+ */
+static NAObjectAction *
+get_action( const gchar *id )
+{
+	NAObjectAction *action;
+	NAPivot *pivot;
+
+	action = NULL;
+
+	pivot = na_pivot_new();
+	na_pivot_load_items( pivot );
+	action = ( NAObjectAction * ) na_pivot_get_item( pivot, id );
+
+	if( !action ){
+		g_printerr( _( "Error: action '%s' doesn't exist.\n" ), id );
+	}
+
+	if( action ){
+		if( !na_object_is_enabled( action )){
+			g_printerr( _( "Error: action '%s' is disabled.\n" ), id );
+			g_object_unref( action );
+			action = NULL;
+		}
+	}
+
+	if( action ){
+		if( !na_object_is_valid( action )){
+			g_printerr( _( "Error: action '%s' is not valid.\n" ), id );
+			g_object_unref( action );
+			action = NULL;
+		}
+	}
+
+	return( action );
+}
+
+static GList *
+get_current_selection( void )
+{
+	static const gchar *thisfn = "nautilus_actions_run_get_current_selection";
+	GList *selection;
+	DBusGConnection *connection;
+	DBusGProxy *proxy;
+	GError *error;
+	gchar **paths, **iter;
+
+	selection = NULL;
+	error = NULL;
+	proxy = NULL;
+	paths = NULL;
+
+	connection = dbus_g_bus_get( DBUS_BUS_SESSION, &error );
+
+	if( !connection ){
+		if( error ){
+			g_printerr( _( "Error: unable to get a connection to session DBus: %s" ), error->message );
+			g_error_free( error );
+		}
+		return( NULL );
+	}
+	g_debug( "%s: connection is ok", thisfn );
+
+	proxy = dbus_g_proxy_new_for_name( connection,
+			NAUTILUS_ACTIONS_DBUS_SERVICE, NA_TRACKER_DBUS_TRACKER_PATH, NA_TRACKER_DBUS_TRACKER_INTERFACE );
+
+	if( !proxy ){
+		g_printerr( _( "Error: unable to get a proxy on %s service" ), NAUTILUS_ACTIONS_DBUS_SERVICE );
+		dbus_g_connection_unref( connection );
+		return( NULL );
+	}
+	g_debug( "%s: proxy is ok", thisfn );
+
+	if( !dbus_g_proxy_call( proxy, "GetSelectedPaths", &error,
+			G_TYPE_INVALID,
+			G_TYPE_STRV, &paths, G_TYPE_INVALID )){
+
+		g_printerr( _( "Error on GetSelectedPaths call: %s" ), error->message );
+		g_error_free( error );
+		/* TODO: unref proxy */
+		dbus_g_connection_unref( connection );
+		return( NULL );
+	}
+	g_debug( "%s: function call is ok", thisfn );
+
+	iter = paths;
+	while( *iter ){
+		selection = g_list_prepend( selection, g_strdup( *iter ));
+		iter++;
+	}
+	g_strfreev( paths );
+	selection = g_list_reverse( selection );
+
+	/* TODO: unref proxy */
+	dbus_g_connection_unref( connection );
+
+	return( selection );
+}
+
+/*
+ * get targets from command-line
+ */
+static GList *
+targets_from_commandline( void )
+{
+	GList *targets;
+	gchar **iter;
+
+	targets = NULL;
+	iter = targets_array;
+	while( *iter ){
+		targets = g_list_prepend( targets, g_strdup( *iter ));
+		iter++;
+	}
+
+	targets = g_list_reverse( targets );
+
+	return( targets );
+}
+
+/*
+ *
+ */
+static void
+dump_targets( GList *targets )
+{
+	GList *it;
+
+	for( it = targets ; it ; it = it->next ){
+		g_print( "%s\n", ( gchar * ) it->data );
+	}
+}
+
+/*
+ *
+ */
+static void
+free_targets( GList *targets )
+{
+	GList *it;
+
+	for( it = targets ; it ; it = it->next ){
+		g_free(( gchar * ) it->data );
+	}
+
+	g_list_free( targets );
+}
+
+/*
+ * print a help message and exit with failure
+ */
+static void
+exit_with_usage( void )
+{
+	g_printerr( _( "Try %s --help for usage.\n" ), g_get_prgname());
+	exit( EXIT_FAILURE );
+}



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