[nautilus-sendto] Rework widget additions



commit f5ea4b3e6067d2ed904d79084c1c1c1f0cdcf0be
Author: Bastien Nocera <hadess hadess net>
Date:   Fri Aug 27 16:32:47 2010 +0100

    Rework widget additions
    
    Widget additions are now made by the plugins themselves, so
    that plugins can handle multiple pages by themselves.
    
    This means:
    - plugin files don't need to be translated anymore
    - a get_object() API kludge was added to work-around
      a libpeas bug where it does not allow direct access
      to the plugin object
    - plugins now emit "add-widget" for each page they'd like to add
    - plugins emit "can-send" when the status of whether you
      can send changes
    
    Add proof of concept libsocialweb plugin.

 .gitignore                                         |    6 +-
 configure.in                                       |   21 +-
 po/POTFILES.in                                     |    2 +
 src/Makefile.am                                    |    2 -
 src/nautilus-sendto-command.c                      |  252 +++++++++-----
 src/plugins/Makefile.am                            |   13 +-
 src/plugins/evolution/Makefile.am                  |    4 +-
 src/plugins/evolution/evolution.c                  |   48 ++--
 ...volution.nst-plugin.in => evolution.nst-plugin} |    2 +-
 src/plugins/nautilus-sendto-plugin.c               |   45 ++--
 src/plugins/nautilus-sendto-plugin.h               |   25 +-
 src/plugins/nst-plugin-marshal.list                |    2 +
 src/plugins/removable-devices/Makefile.am          |    3 -
 src/plugins/removable-devices/removable-devices.c  |   24 +-
 ....nst-plugin.in => removable-devices.nst-plugin} |    2 +-
 src/plugins/socialweb/Makefile.am                  |   22 ++
 src/plugins/socialweb/socialweb.c                  |  356 ++++++++++++++++++++
 .../socialweb.nst-plugin}                          |    6 +-
 18 files changed, 658 insertions(+), 177 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 63abc1d..0122d16 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,8 +39,10 @@ po/POTFILES
 po/stamp-it
 src/test-mimetype
 src/nautilus-sendto
-src/nst-enum-types.c
-src/nst-enum-types.h
+src/plugins/nst-enum-types.c
+src/plugins/nst-enum-types.h
+src/plugins/nst-plugin-marshal.c
+src/plugins/nst-plugin-marshal.h
 src/plugins/NautilusSendto-1.0.gir
 src/plugins/NautilusSendto-1.0.typelib
 src/plugins/bluetooth/bluetooth-marshal.c
diff --git a/configure.in b/configure.in
index 3dfb130..7a63ffd 100644
--- a/configure.in
+++ b/configure.in
@@ -81,7 +81,7 @@ AC_MSG_NOTICE([installing nautilus plugin in ${ac_with_nautilusdir}])
 AC_SUBST([NAUTILUS_EXTENSION_DIR],[${ac_with_nautilusdir}])
 
 # The full list of plugins
-allowed_plugins="evolution gajim nautilus-burn pidgin removable-devices upnp"
+allowed_plugins="evolution gajim nautilus-burn pidgin removable-devices socialweb upnp"
 
 plugin_error_or_ignore()
 {
@@ -180,6 +180,14 @@ for plugin in ${used_plugins}; do
 				add_plugin="0"
 			fi
 		;;
+		socialweb)
+			PKG_CHECK_MODULES(SOCIALWEB, libsocialweb-client,
+					  enable_libsocialweb=yes, enable_libsocialweb=no)
+			if test "${enable_libsocialweb}" != "yes"; then
+				plugin_error_or_ignore "you need libsocialweb-client to build the libsocialweb plugin"
+				add_plugin="0"
+			fi
+		;;
 		upnp)
 			PKG_CHECK_MODULES(UPNP, gupnp-1.0 >= $GUPNP_REQUIRED libpeas-1.0,
 					  enable_upnp=yes, enable_upnp=no)
@@ -210,16 +218,6 @@ AC_MSG_RESULT([$PLUGINS])
 AC_SUBST([ALL_PLUGINS])
 AC_SUBST([PLUGINS])
 
-dnl For the pidgin plugin
-AM_CONDITIONAL(HAVE_PIDGIN, test "x$enable_pidgin" = "xyes")
-
-dnl For the GIO based plugins
-enable_nst_common=no
-if test "x$enable_burn" = "xyes" -o "x$enable_removable" = "xyes"; then
-	enable_nst_common=yes
-fi
-AM_CONDITIONAL(HAVE_GIO, test "x$enable_nst_common" = "xyes")
-
 GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
 AC_SUBST(GLIB_GENMARSHAL)
 
@@ -243,6 +241,7 @@ src/plugins/gajim/Makefile
 src/plugins/nautilus-burn/Makefile
 src/plugins/pidgin/Makefile
 src/plugins/removable-devices/Makefile
+src/plugins/socialweb/Makefile
 src/plugins/upnp/Makefile
 docs/Makefile
 docs/nautilus-sendto/Makefile
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 00b1e83..d2c19da 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@ src/nautilus-sendto-mimetype.c
 data/org.gnome.Nautilus.Sendto.gschema.xml.in
 [type: gettext/glade]data/nautilus-sendto.ui
 src/plugins/nst-common.c
+src/plugins/nautilus-sendto-packer.c
 data/pack-entry.ui
 src/plugins/evolution/evolution.c
 src/plugins/evolution/e-contact-entry.c
@@ -14,4 +15,5 @@ src/plugins/gajim/gajim.c
 src/plugins/nautilus-burn/nautilus-burn.c
 src/plugins/pidgin/pidgin.c
 src/plugins/removable-devices/removable-devices.c
+src/plugins/socialweb/socialweb.c
 src/plugins/upnp/upnp.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 4609776..ea0c637 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,8 +18,6 @@ INCLUDES =					\
 
 noinst_LTLIBRARIES = libnstplugin.la
 libnstplugin_la_SOURCES =			\
-	nst-enum-types.c			\
-	nst-enum-types.h			\
 	nautilus-sendto-mimetype.c		\
 	nautilus-sendto-mimetype.h
 libnstplugin_la_LIBADD = $(NAUTILUS_SENDTO_LIBS)
diff --git a/src/nautilus-sendto-command.c b/src/nautilus-sendto-command.c
index adc44e0..479fcfe 100644
--- a/src/nautilus-sendto-command.c
+++ b/src/nautilus-sendto-command.c
@@ -41,6 +41,7 @@ enum {
 	COLUMN_ID,
 	COLUMN_PAGE_NUM,
 	COLUMN_DESCRIPTION,
+	COLUMN_CAN_SEND,
 	NUM_COLUMNS,
 };
 
@@ -60,9 +61,7 @@ guint option = 0;
 
 static GSettings *settings = NULL;
 
-typedef struct _NS_ui NS_ui;
-
-struct _NS_ui {
+typedef struct {
 	GtkWidget *dialog;
 	GtkWidget *scrolled_window;
 	GtkWidget *options_treeview;
@@ -72,7 +71,9 @@ struct _NS_ui {
 	GtkWidget *buttons;
 	GtkWidget *cancel_button;
 	GtkWidget *send_button;
-};
+
+	char *last_used;
+} NautilusSendto;
 
 static const GOptionEntry entries[] = {
 	{ "run-from-build-dir", 'b', 0, G_OPTION_ARG_NONE, &run_from_build_dir, N_("Run from build directory"), NULL },
@@ -87,13 +88,13 @@ destroy_dialog (GtkWidget *widget, gpointer data )
 }
 
 static void
-make_sensitive_for_send (NS_ui *ui,
+make_sensitive_for_send (NautilusSendto *nst,
 			 gboolean sensitive)
 {
 	/* The plugins are responsible for making themselves
 	 * unsensitive during send */
-	gtk_widget_set_sensitive (ui->scrolled_window, sensitive);
-	gtk_widget_set_sensitive (ui->buttons, sensitive);
+	gtk_widget_set_sensitive (nst->scrolled_window, sensitive);
+	gtk_widget_set_sensitive (nst->buttons, sensitive);
 }
 
 static void
@@ -101,7 +102,7 @@ send_callback (GObject      *object,
 	       GAsyncResult *res,
 	       gpointer      user_data)
 {
-	NS_ui *ui = (NS_ui *) user_data;
+	NautilusSendto *nst = (NautilusSendto *) user_data;
 	NautilusSendtoSendStatus status;
 
 	status = nautilus_sendto_plugin_send_files_finish (NAUTILUS_SENDTO_PLUGIN (object),
@@ -121,7 +122,7 @@ send_callback (GObject      *object,
 }
 
 static void
-send_button_cb (GtkWidget *widget, NS_ui *ui)
+send_button_cb (GtkWidget *widget, NautilusSendto *nst)
 {
 	GtkTreeModel *model;
 	GtkTreeSelection *treeselection;
@@ -130,11 +131,11 @@ send_button_cb (GtkWidget *widget, NS_ui *ui)
 	PeasPluginInfo *info;
 	PeasExtension *ext;
 
-	treeselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->options_treeview));
+	treeselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (nst->options_treeview));
 	if (gtk_tree_selection_get_selected (treeselection, &model, &iter) == FALSE)
 		return;
 
-	make_sensitive_for_send (ui, FALSE);
+	make_sensitive_for_send (nst, FALSE);
 
 	gtk_tree_model_get (model, &iter,
 			    COLUMN_ID, &id,
@@ -147,10 +148,10 @@ send_button_cb (GtkWidget *widget, NS_ui *ui)
 	info = peas_engine_get_plugin_info (engine, id);
 	ext = peas_extension_set_get_extension (exten_set, info);
 
-	if (peas_extension_call (ext, "send_files", file_list, send_callback, ui) == FALSE) {
+	if (peas_extension_call (ext, "send_files", file_list, send_callback, nst) == FALSE) {
 		/* FIXME report the error in the UI */
 		g_warning ("Failed to send files");
-		make_sensitive_for_send (ui, TRUE);
+		make_sensitive_for_send (nst, TRUE);
 		g_free (id);
 		return;
 	}
@@ -159,24 +160,61 @@ send_button_cb (GtkWidget *widget, NS_ui *ui)
 }
 
 static void
+can_send_cb (NautilusSendtoPlugin *plugin,
+	     const char           *id,
+	     gboolean              can_send,
+	     NautilusSendto                *nst)
+{
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gboolean cont;
+
+	g_return_if_fail (id != NULL);
+
+	model = gtk_tree_view_get_model (GTK_TREE_VIEW (nst->options_treeview));
+
+	cont = gtk_tree_model_get_iter_first (model, &iter);
+	while (cont) {
+		char *selected_id;
+
+		gtk_tree_model_get (model, &iter,
+				    COLUMN_ID, &selected_id,
+				    -1);
+		if (selected_id != NULL &&
+		    g_str_equal (id, selected_id) != FALSE) {
+			g_free (selected_id);
+			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+					    COLUMN_CAN_SEND, can_send,
+					    -1);
+			return;
+		}
+		g_free (selected_id);
+		cont = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	g_warning ("Page ID '%s' not found in loaded pages", id);
+}
+
+static void
 option_changed (GtkTreeSelection *treeselection,
-		NS_ui *ui)
+		NautilusSendto *nst)
 {
 	GtkTreeModel *model;
 	GtkTreeIter iter;
 	int page_num;
+	gboolean can_send;
 
 	if (gtk_tree_selection_get_selected (treeselection, &model, &iter) == FALSE)
 		return;
 
 	gtk_tree_model_get (model, &iter,
 			    COLUMN_PAGE_NUM, &page_num,
+			    COLUMN_CAN_SEND, &can_send,
 			    -1);
 
-	gtk_notebook_set_current_page (GTK_NOTEBOOK (ui->contacts_notebook),
+	gtk_notebook_set_current_page (GTK_NOTEBOOK (nst->contacts_notebook),
 				       page_num);
-
-	/* FIXME: Get a widget in the plugin to grab focus? */
+	gtk_widget_set_sensitive (nst->send_button, can_send);
 }
 
 static gboolean
@@ -194,29 +232,80 @@ separator_func (GtkTreeModel *model,
 }
 
 static void
-set_model_for_options_treeview (NS_ui *ui)
+add_widget_cb (NautilusSendtoPlugin *plugin,
+	       const char           *name,
+	       const char           *icon_name,
+	       const char           *id,
+	       GtkWidget            *widget,
+	       NautilusSendto                *nst)
 {
 	GdkPixbuf *pixbuf;
+	GtkWidget *label;
+	GtkTreeIter iter;
+	GtkListStore *model;
+	int page_num;
+
+	g_return_if_fail (name != NULL);
+	g_return_if_fail (id != NULL);
+	g_return_if_fail (widget != NULL);
+
+	model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (nst->options_treeview)));
+
+	if (icon_name != NULL) {
+		GtkIconTheme *it;
+
+		it = gtk_icon_theme_get_default ();
+		pixbuf = gtk_icon_theme_load_icon (it, icon_name, 16,
+						   GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
+	} else {
+		pixbuf = NULL;
+	}
+	label = gtk_label_new (id);
+	page_num = gtk_notebook_append_page (GTK_NOTEBOOK (nst->contacts_notebook),
+					     widget, label);
+
+	/* XXX: do this properly */
+	if (strstr (id, "evolution")) {
+		gtk_list_store_insert_after (model, &iter, NULL);
+	} else {
+		gtk_list_store_append (model, &iter);
+	}
+	gtk_list_store_set (model, &iter,
+			    COLUMN_IS_SEPARATOR, FALSE,
+			    COLUMN_ICON, pixbuf,
+			    COLUMN_ID, id,
+			    COLUMN_PAGE_NUM, page_num,
+			    COLUMN_DESCRIPTION, name,
+			    -1);
+
+	gtk_widget_show (widget);
+
+	if (nst->last_used != NULL &&
+	    g_str_equal (nst->last_used, id)) {
+		GtkTreeSelection *selection;
+
+		selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (nst->options_treeview));
+		gtk_tree_selection_select_iter (selection, &iter);
+	}
+}
+
+static void
+set_model_for_options_treeview (NautilusSendto *nst)
+{
 	GtkTreeIter iter;
 	GtkListStore *model;
-	GtkIconTheme *it;
 	GtkCellRenderer *renderer;
-	char *last_used = NULL;
 	int i = 0;
 	GtkTreeViewColumn *column;
 	GtkTreeSelection *selection;
-	GtkTreePath *path;
 	char **list;
 
 	/* Disable this call if you want to debug */
-	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (ui->contacts_notebook), FALSE);
-
-	it = gtk_icon_theme_get_default ();
+	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (nst->contacts_notebook), FALSE);
 
-	model = gtk_list_store_new (NUM_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
-
-	last_used = g_settings_get_string (settings,
-					   NAUTILUS_SENDTO_LAST_MEDIUM);
+	model = gtk_list_store_new (NUM_COLUMNS, G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_BOOLEAN);
+	gtk_tree_view_set_model (GTK_TREE_VIEW (nst->options_treeview),
+				 GTK_TREE_MODEL (model));
 
 	/* Insert the expander */
 	gtk_list_store_insert_after (model, &iter, NULL);
@@ -224,65 +313,42 @@ set_model_for_options_treeview (NS_ui *ui)
 			    COLUMN_IS_SEPARATOR, TRUE,
 			    -1);
 
-	/* Populate the tree model */
+	/* Load the plugins */
 	list = peas_engine_get_loaded_plugins (engine);
 	for (i = 0; list[i] != NULL; i++) {
-		GtkWidget *label, *w;
 		PeasPluginInfo *info;
 		PeasExtension *ext;
 		const char *id;
-		int page_num;
 		gboolean supported;
+		GObject *object;
 
 		info = peas_engine_get_plugin_info (engine, list[i]);
 		id = peas_plugin_info_get_module_name (info);
 
 		ext = peas_extension_set_get_extension (exten_set, info);
 
-		/* Check if the plugin supports the mime-types of the files we have */
-		if (peas_extension_call (ext, "supports_mime_types", mime_types, &supported) == FALSE ||
-		    supported == FALSE) {
-			g_message ("'%s' does not support mime-types", id);
-			continue;
-		}
-
-		if (peas_extension_call (ext, "get_widget", file_list, &w) == FALSE || w == NULL) {
-			g_warning ("Failed to get widget for %s", id);
+		if (peas_extension_call (ext, "get_object", &object) == FALSE ||
+		    object == NULL) {
+			g_warning ("Could not get object for plugin '%s'", id);
 			continue;
 		}
 
-		pixbuf = gtk_icon_theme_load_icon (it, peas_plugin_info_get_icon_name (info), 16,
-						   GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
-		label = gtk_label_new (id);
-		page_num = gtk_notebook_append_page (GTK_NOTEBOOK (ui->contacts_notebook), w, label);
+		g_signal_connect (object, "add-widget",
+				  G_CALLBACK (add_widget_cb), nst);
+		g_signal_connect (object, "can-send",
+				  G_CALLBACK (can_send_cb), nst);
 
-		/* XXX: do this properly */
-		if (strstr (id, "evolution")) {
-			gtk_list_store_insert_after (model, &iter, NULL);
-		} else {
-			gtk_list_store_append (model, &iter);
+		/* Check if the plugin supports the mime-types of the files we have */
+		if (peas_extension_call (ext, "supports_mime_types", file_list, mime_types, &supported) == FALSE ||
+		    supported == FALSE) {
+			g_message ("'%s' does not support mime-types", id);
 		}
-		gtk_list_store_set (model, &iter,
-				    COLUMN_IS_SEPARATOR, FALSE,
-				    COLUMN_ICON, pixbuf,
-				    COLUMN_ID, id,
-				    COLUMN_PAGE_NUM, page_num,
-				    COLUMN_DESCRIPTION, peas_plugin_info_get_name (info),
-				    -1);
-
-		gtk_widget_show (w);
-
-		if (last_used != NULL && !strcmp(last_used, id))
-			option = i;
 	}
-	g_free(last_used);
 	g_strfreev (list);
 
-	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ui->options_treeview));
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (nst->options_treeview));
 	gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
 
-	gtk_tree_view_set_model (GTK_TREE_VIEW (ui->options_treeview),
-				 GTK_TREE_MODEL (model));
 	column = gtk_tree_view_column_new ();
 
 	/* Pixbuf */
@@ -307,18 +373,13 @@ set_model_for_options_treeview (NS_ui *ui)
 					NULL);
 
 	/* Separator */
-	gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (ui->options_treeview),
+	gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (nst->options_treeview),
 					      separator_func,
 					      NULL, NULL);
 
-	gtk_tree_view_append_column (GTK_TREE_VIEW (ui->options_treeview), column);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (nst->options_treeview), column);
 	g_signal_connect (G_OBJECT (selection), "changed",
-			  G_CALLBACK (option_changed), ui);
-
-	/* Select the previously selected option */
-	path = gtk_tree_path_new_from_indices (option, -1);
-	gtk_tree_selection_select_path (selection, path);
-	gtk_tree_path_free (path);
+			  G_CALLBACK (option_changed), nst);
 }
 
 static void
@@ -340,7 +401,7 @@ nautilus_sendto_create_ui (void)
 {
 	GtkBuilder *app;
 	GError* error = NULL;
-	NS_ui *ui;
+	NautilusSendto *nst;
 	GtkSettings *gtk_settings;
 	GtkWidget *button_image;
 	const char *ui_file;
@@ -359,17 +420,20 @@ nautilus_sendto_create_ui (void)
 		g_error_free (error);
 	}
 
-	ui = g_new0 (NS_ui, 1);
+	nst = g_new0 (NautilusSendto, 1);
 
-	ui->options_treeview = GTK_WIDGET (gtk_builder_get_object (app, "options_treeview"));
-	ui->contacts_notebook = GTK_WIDGET (gtk_builder_get_object (app, "contacts_notebook"));
-	ui->scrolled_window = GTK_WIDGET (gtk_builder_get_object (app, "scrolledwindow1"));
-	ui->hbox_contacts_ws = GTK_WIDGET (gtk_builder_get_object (app, "hbox_contacts_widgets"));
-	ui->send_to_label = GTK_WIDGET (gtk_builder_get_object (app, "send_to_label"));
-	ui->dialog = GTK_WIDGET (gtk_builder_get_object (app, "nautilus_sendto_dialog"));
-	ui->buttons = GTK_WIDGET (gtk_builder_get_object (app, "dialog-action_area2"));
-	ui->cancel_button = GTK_WIDGET (gtk_builder_get_object (app, "cancel_button"));
-	ui->send_button = GTK_WIDGET (gtk_builder_get_object (app, "send_button"));
+	nst->options_treeview = GTK_WIDGET (gtk_builder_get_object (app, "options_treeview"));
+	nst->contacts_notebook = GTK_WIDGET (gtk_builder_get_object (app, "contacts_notebook"));
+	nst->scrolled_window = GTK_WIDGET (gtk_builder_get_object (app, "scrolledwindow1"));
+	nst->hbox_contacts_ws = GTK_WIDGET (gtk_builder_get_object (app, "hbox_contacts_widgets"));
+	nst->send_to_label = GTK_WIDGET (gtk_builder_get_object (app, "send_to_label"));
+	nst->dialog = GTK_WIDGET (gtk_builder_get_object (app, "nautilus_sendto_dialog"));
+	nst->buttons = GTK_WIDGET (gtk_builder_get_object (app, "dialog-action_area2"));
+	nst->cancel_button = GTK_WIDGET (gtk_builder_get_object (app, "cancel_button"));
+	nst->send_button = GTK_WIDGET (gtk_builder_get_object (app, "send_button"));
+
+	nst->last_used = g_settings_get_string (settings,
+					       NAUTILUS_SENDTO_LAST_MEDIUM);
 
 	gtk_settings = gtk_settings_get_default ();
 	button_image = GTK_WIDGET (gtk_builder_get_object (app, "image1"));
@@ -386,15 +450,15 @@ nautilus_sendto_create_ui (void)
 			     title);
 	g_free (title);
 
-	set_model_for_options_treeview (ui);
-	g_signal_connect (G_OBJECT (ui->dialog), "destroy",
+	set_model_for_options_treeview (nst);
+	g_signal_connect (G_OBJECT (nst->dialog), "destroy",
                           G_CALLBACK (destroy_dialog), NULL);
-	g_signal_connect (G_OBJECT (ui->cancel_button), "clicked",
+	g_signal_connect (G_OBJECT (nst->cancel_button), "clicked",
 			  G_CALLBACK (destroy_dialog), NULL);
-	g_signal_connect (G_OBJECT (ui->send_button), "clicked",
-			  G_CALLBACK (send_button_cb), ui);
+	g_signal_connect (G_OBJECT (nst->send_button), "clicked",
+			  G_CALLBACK (send_button_cb), nst);
 
-	gtk_widget_show (ui->dialog);
+	gtk_widget_show (nst->dialog);
 }
 
 static void
@@ -602,6 +666,7 @@ int main (int argc, char **argv)
 {
 	GOptionContext *context;
 	GError *error = NULL;
+	NautilusSendto *nst;
 
 	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -617,6 +682,8 @@ int main (int argc, char **argv)
 		return 1;
 	}
 
+	/* FIXME create the nst object here */
+
 	settings = g_settings_new ("org.gnome.Nautilus.Sendto");
 	nautilus_sendto_init ();
 	if (nautilus_sendto_plugin_init () == FALSE)
@@ -624,6 +691,11 @@ int main (int argc, char **argv)
 	nautilus_sendto_create_ui ();
 
 	gtk_main ();
+
+	/* FIXME: shut down the plugins */
+	//gtk_widget_destroy (nst->dialog);
+	//g_free (nst->last_used);
+
 	g_object_unref(settings);
 	g_strfreev (mime_types);
 
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 4b7fea5..c0fb255 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -1,10 +1,18 @@
-SUBDIRS = . removable-devices evolution
+SUBDIRS = . removable-devices evolution socialweb
 #SUBDIRS = . $(PLUGINS)
 DIST_SUBDIRS = $(ALL_PLUGINS)
 
 nautilus_sendto_includedir = $(includedir)/nautilus-sendto/
 nautilus_sendto_include_HEADERS = nautilus-sendto-plugin.h nst-common.h nautilus-sendto-packer.h
 
+MARSHALFILES = nst-plugin-marshal.c nst-plugin-marshal.h
+BUILT_SOURCES = $(MARSHALFILES)
+
+nst-plugin-marshal.c: nst-plugin-marshal.h
+	$(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=nst_plugin_marshal $(srcdir)/nst-plugin-marshal.list --header --body > nst-plugin-marshal.c )
+nst-plugin-marshal.h: nst-plugin-marshal.list
+	$(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=nst_plugin_marshal $(srcdir)/nst-plugin-marshal.list --header > nst-plugin-marshal.h )
+
 lib_LTLIBRARIES = libnautilussendto-1.0.la
 libnautilussendto_1_0_la_SOURCES =				\
 	nautilus-sendto-plugin.c				\
@@ -12,7 +20,8 @@ libnautilussendto_1_0_la_SOURCES =				\
 	nautilus-sendto-packer.c				\
 	nst-enum-types.h					\
 	nst-enum-types.c					\
-	$(nautilus_sendto_include_HEADERS)
+	$(nautilus_sendto_include_HEADERS)			\
+	$(MARSHALFILES)
 libnautilussendto_1_0_la_LIBADD = $(NAUTILUS_SENDTO_LIBS)
 libnautilussendto_1_0_la_CFLAGS = $(NAUTILUS_SENDTO_CFLAGS) -DUIDIR=\""$(uidir)"\"
 
diff --git a/src/plugins/evolution/Makefile.am b/src/plugins/evolution/Makefile.am
index e5ce04e..d5b55fb 100644
--- a/src/plugins/evolution/Makefile.am
+++ b/src/plugins/evolution/Makefile.am
@@ -1,7 +1,5 @@
 plugindir = $(libdir)/nautilus-sendto/plugins
 
-plugin_in_files = evolution.nst-plugin.in
-%.nst-plugin: %.nst-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
 plugin_DATA = evolution.nst-plugin
 
 INCLUDES =                                      \
@@ -34,6 +32,6 @@ libnstevolution_la_SOURCES = evolution.c $(CLA_FILES) $(MARSHALFILES)
 libnstevolution_la_LDFLAGS = -module -avoid-version
 libnstevolution_la_LIBADD = $(NST_EBOOK_LIBS) $(NAUTILUS_SENDTO_LIBS) $(builddir)/../libnautilussendto-1.0.la
 
-EXTRA_DIST = $(CLA_FILES) $(plugin_in_files)
+EXTRA_DIST = $(CLA_FILES)
 CLEANFILES = econtactentry-marshal.c econtactentry-marshal.h
 
diff --git a/src/plugins/evolution/evolution.c b/src/plugins/evolution/evolution.c
index 0b30567..d001935 100644
--- a/src/plugins/evolution/evolution.c
+++ b/src/plugins/evolution/evolution.c
@@ -143,26 +143,6 @@ evolution_plugin_init (EvolutionPlugin *p)
 	}
 }
 
-static gboolean
-evolution_plugin_supports_mime_types (NautilusSendtoPlugin *plugin,
-				      const char          **mime_types)
-{
-	EvolutionPlugin *p;
-	guint i;
-
-	p = EVOLUTION_PLUGIN (plugin);
-
-	if (p->mail_cmd == NULL)
-		return FALSE;
-
-	for (i = 0; mime_types[i] != NULL; i++) {
-		if (g_str_equal (mime_types[i], "inode/directory"))
-			p->has_dirs = TRUE;
-	}
-
-	return TRUE;
-}
-
 static void
 contacts_selected_cb (GtkWidget       *entry,
 		      EContact        *contact,
@@ -301,6 +281,34 @@ evolution_plugin_get_widget (NautilusSendtoPlugin *plugin,
 	return p->vbox;
 }
 
+static gboolean
+evolution_plugin_supports_mime_types (NautilusSendtoPlugin *plugin,
+				      GList                *file_list,
+				      const char          **mime_types)
+{
+	EvolutionPlugin *p;
+	guint i;
+
+	p = EVOLUTION_PLUGIN (plugin);
+
+	if (p->mail_cmd == NULL)
+		return FALSE;
+
+	for (i = 0; mime_types[i] != NULL; i++) {
+		if (g_str_equal (mime_types[i], "inode/directory"))
+			p->has_dirs = TRUE;
+	}
+
+	g_signal_emit_by_name (G_OBJECT (plugin),
+			       "add-widget",
+			       _("Mail"),
+			       "emblem-mail",
+			       "evolution",
+			       evolution_plugin_get_widget (plugin, file_list));
+
+	return TRUE;
+}
+
 static void
 get_evo_mailto (EvolutionPlugin *p,
 		GString         *mailto,
diff --git a/src/plugins/evolution/evolution.nst-plugin.in b/src/plugins/evolution/evolution.nst-plugin
similarity index 89%
copy from src/plugins/evolution/evolution.nst-plugin.in
copy to src/plugins/evolution/evolution.nst-plugin
index bcd313f..4082885 100644
--- a/src/plugins/evolution/evolution.nst-plugin.in
+++ b/src/plugins/evolution/evolution.nst-plugin
@@ -1,6 +1,6 @@
 [Nst Plugin]
 Module=nstevolution
 IAge=1
-_Name=Email
+Name=Email
 Authors=Bastien Nocera <hadess hadess net>
 Icon=emblem-mail
diff --git a/src/plugins/nautilus-sendto-plugin.c b/src/plugins/nautilus-sendto-plugin.c
index 6fc41e8..c2ee238 100644
--- a/src/plugins/nautilus-sendto-plugin.c
+++ b/src/plugins/nautilus-sendto-plugin.c
@@ -24,45 +24,45 @@
 #endif
 
 #include "nautilus-sendto-plugin.h"
+#include "nst-plugin-marshal.h"
 
 G_DEFINE_INTERFACE(NautilusSendtoPlugin, nautilus_sendto_plugin, G_TYPE_OBJECT)
 
 static void
 nautilus_sendto_plugin_default_init (NautilusSendtoPluginInterface *iface)
 {
+	g_signal_new ("add-widget",
+		      NAUTILUS_SENDTO_TYPE_PLUGIN,
+		      G_SIGNAL_RUN_LAST,
+		      G_STRUCT_OFFSET (NautilusSendtoPluginInterface, add_widget),
+		      NULL, NULL,
+		      nst_plugin_marshal_VOID__STRING_STRING_STRING_OBJECT,
+		      G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_OBJECT);
+	g_signal_new ("can-send",
+		      NAUTILUS_SENDTO_TYPE_PLUGIN,
+		      G_SIGNAL_RUN_LAST,
+		      G_STRUCT_OFFSET (NautilusSendtoPluginInterface, can_send),
+		      NULL, NULL,
+		      nst_plugin_marshal_VOID__STRING_BOOLEAN,
+		      G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
 }
 
 /**
- * nautilus_sendto_plugin_get_widget:
+ * nautilus_sendto_get_object:
  * @plugin: a #NautilusSendtoPlugin instance
- * @file_list: (element-type utf8): a #GList of strings representing the files to send.
- * The file list should not be cached, and can be used to create a good archive name,
- * if the plugin allows for compression, for example.
  *
- * Returns a #GtkWidget for the plugin in question.
- *
- * Return value: a #GtkWidget, or %NULL if the plugin does not implement
- * the required interface.
+ * Returns: (transfer none): a reference to the #NautilusSendtoPlugin instance.
  */
-GtkWidget *
-nautilus_sendto_plugin_get_widget (NautilusSendtoPlugin  *plugin,
-				   GList                 *file_list)
+GObject *
+nautilus_sendto_plugin_get_object (NautilusSendtoPlugin *plugin)
 {
-	NautilusSendtoPluginInterface *iface;
-
-	g_return_val_if_fail (NAUTILUS_SENDTO_IS_PLUGIN (plugin), FALSE);
-
-	iface = NAUTILUS_SENDTO_PLUGIN_GET_IFACE (plugin);
-
-	if (G_LIKELY (iface->get_widget != NULL))
-		return iface->get_widget (plugin, file_list);
-
-	return NULL;
+	return G_OBJECT (plugin);
 }
 
 /**
  * nautilus_sendto_plugin_supports_mime_types:
  * @plugin: a #NautilusSendtoPlugin instance
+ * @file_list: (element-type utf8): a #GList of strings representing the files to send
  * @mime_types: a list of mime-types for the file types to send.
  *
  * Returns a #gboolean.
@@ -71,6 +71,7 @@ nautilus_sendto_plugin_get_widget (NautilusSendtoPlugin  *plugin,
  */
 gboolean
 nautilus_sendto_plugin_supports_mime_types (NautilusSendtoPlugin  *plugin,
+					    GList                 *file_list,
 					    const char           **mime_types)
 {
 	NautilusSendtoPluginInterface *iface;
@@ -80,7 +81,7 @@ nautilus_sendto_plugin_supports_mime_types (NautilusSendtoPlugin  *plugin,
 	iface = NAUTILUS_SENDTO_PLUGIN_GET_IFACE (plugin);
 
 	if (G_LIKELY (iface->supports_mime_types != NULL))
-		return iface->supports_mime_types (plugin, mime_types);
+		return iface->supports_mime_types (plugin, file_list, mime_types);
 
 	return FALSE;
 }
diff --git a/src/plugins/nautilus-sendto-plugin.h b/src/plugins/nautilus-sendto-plugin.h
index 9f9c1e9..38c7211 100644
--- a/src/plugins/nautilus-sendto-plugin.h
+++ b/src/plugins/nautilus-sendto-plugin.h
@@ -33,7 +33,7 @@ G_BEGIN_DECLS
 #define NAUTILUS_SENDTO_IS_PLUGIN(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_SENDTO_TYPE_PLUGIN))
 #define NAUTILUS_SENDTO_PLUGIN_GET_IFACE(obj)    (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NAUTILUS_SENDTO_TYPE_PLUGIN, NautilusSendtoPluginInterface))
 
-typedef struct _NautilusSendtoPlugin           NautilusSendtoPlugin; /* dummy typedef */
+typedef struct _NautilusSendtoPlugin           NautilusSendtoPlugin;
 typedef struct _NautilusSendtoPluginInterface  NautilusSendtoPluginInterface;
 
 typedef enum {
@@ -47,19 +47,28 @@ struct _NautilusSendtoPluginInterface
 	GTypeInterface g_iface;
 
 	gboolean    (*supports_mime_types) (NautilusSendtoPlugin *plugin,
+					    GList                *file_list,
 					    const char          **mime_types);
 	void	    (*send_files)  (NautilusSendtoPlugin *plugin,
 				    GList                *file_list,
 				    GAsyncReadyCallback   callback,
 				    gpointer              user_data);
-	GtkWidget  *(*get_widget)  (NautilusSendtoPlugin *plugin,
-				    GList                *file_list);
+
+	/* signals */
+	void        (*add_widget)  (NautilusSendtoPlugin *plugin,
+				    const char           *name,
+				    const char           *icon_name,
+				    const char           *id,
+				    GtkWidget            *widget);
+	void        (*can_send)    (NautilusSendtoPlugin *plugin,
+				    const char           *id,
+				    gboolean              can_send);
 };
 
-GType       nautilus_sendto_plugin_get_type                (void);
-GtkWidget  *nautilus_sendto_plugin_get_widget (NautilusSendtoPlugin  *plugin,
-					       GList                 *file_list);
+GType       nautilus_sendto_plugin_get_type            (void);
+GObject    *nautilus_sendto_plugin_get_object          (NautilusSendtoPlugin *plugin);
 gboolean    nautilus_sendto_plugin_supports_mime_types (NautilusSendtoPlugin *plugin,
+							GList                *file_list,
 							const char          **mime_types);
 void        nautilus_sendto_plugin_send_files (NautilusSendtoPlugin *plugin,
 					       GList                *file_list,
@@ -72,9 +81,8 @@ NautilusSendtoSendStatus nautilus_sendto_plugin_send_files_finish (NautilusSendt
 #define NAUTILUS_PLUGIN_REGISTER(TYPE_NAME, TypeName, type_name)					\
 	GType type_name##_get_type (void) G_GNUC_CONST;							\
 	G_MODULE_EXPORT void  peas_register_types (PeasObjectModule *module);				\
-	static GtkWidget *type_name##_get_widget (NautilusSendtoPlugin *plugin, GList *file_list);	\
 	static void type_name##_send_files (NautilusSendtoPlugin *plugin, GList *file_list, GAsyncReadyCallback callback, gpointer user_data); \
-	static gboolean type_name##_supports_mime_types (NautilusSendtoPlugin *plugin, const char **mime_types); \
+	static gboolean type_name##_supports_mime_types (NautilusSendtoPlugin *plugin, GList *file_list, const char **mime_types); \
 	static void nautilus_sendto_plugin_iface_init (NautilusSendtoPluginInterface *iface);		\
 	static void type_name##_finalize (GObject *object);						\
 	G_DEFINE_DYNAMIC_TYPE_EXTENDED (TypeName,							\
@@ -86,7 +94,6 @@ NautilusSendtoSendStatus nautilus_sendto_plugin_send_files_finish (NautilusSendt
 	static void											\
 	nautilus_sendto_plugin_iface_init (NautilusSendtoPluginInterface *iface)			\
 	{												\
-		iface->get_widget = type_name##_get_widget;						\
 		iface->send_files = type_name##_send_files;						\
 		iface->supports_mime_types = type_name##_supports_mime_types;				\
 	}												\
diff --git a/src/plugins/nst-plugin-marshal.list b/src/plugins/nst-plugin-marshal.list
new file mode 100644
index 0000000..83f6a8c
--- /dev/null
+++ b/src/plugins/nst-plugin-marshal.list
@@ -0,0 +1,2 @@
+VOID:STRING,STRING,STRING,OBJECT
+VOID:STRING,BOOLEAN
diff --git a/src/plugins/removable-devices/Makefile.am b/src/plugins/removable-devices/Makefile.am
index 6dfcd17..61f4adc 100644
--- a/src/plugins/removable-devices/Makefile.am
+++ b/src/plugins/removable-devices/Makefile.am
@@ -1,7 +1,5 @@
 plugindir = $(libdir)/nautilus-sendto/plugins
 
-plugin_in_files = removable-devices.nst-plugin.in
-%.nst-plugin: %.nst-plugin.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
 plugin_DATA = removable-devices.nst-plugin
 
 INCLUDES =                                      \
@@ -21,4 +19,3 @@ libnstremovable_devices_la_SOURCES = removable-devices.c
 libnstremovable_devices_la_LDFLAGS = -module -avoid-version
 libnstremovable_devices_la_LIBADD = $(GIO_LIBS) $(NAUTILUS_SENDTO_LIBS) $(builddir)/../libnautilussendto-1.0.la
 
-EXTRA_DIST = $(plugin_in_files)
diff --git a/src/plugins/removable-devices/removable-devices.c b/src/plugins/removable-devices/removable-devices.c
index 0f0f13d..78c4ddb 100644
--- a/src/plugins/removable-devices/removable-devices.c
+++ b/src/plugins/removable-devices/removable-devices.c
@@ -201,14 +201,6 @@ removable_devices_plugin_send_files (NautilusSendtoPlugin *plugin,
 	g_object_unref (simple);
 }
 
-static gboolean
-removable_devices_plugin_supports_mime_types (NautilusSendtoPlugin *plugin,
-					      const char          **mime_types)
-{
-	/* All the mime-types are supported */
-	return TRUE;
-}
-
 static GtkWidget *
 removable_devices_plugin_get_widget (NautilusSendtoPlugin *plugin,
 				     GList                *file_list)
@@ -269,6 +261,22 @@ removable_devices_plugin_get_widget (NautilusSendtoPlugin *plugin,
 	return box;
 }
 
+static gboolean
+removable_devices_plugin_supports_mime_types (NautilusSendtoPlugin *plugin,
+					      GList                *file_list,
+					      const char          **mime_types)
+{
+	g_signal_emit_by_name (G_OBJECT (plugin),
+			       "add-widget",
+			       _("Removable disks and shares"),
+			       "folder-remote",
+			       "removable-devices",
+			       removable_devices_plugin_get_widget (plugin, file_list));
+
+	/* All the mime-types are supported */
+	return TRUE;
+}
+
 static void
 removable_devices_plugin_init (RemovableDevicesPlugin *p)
 {
diff --git a/src/plugins/removable-devices/removable-devices.nst-plugin.in b/src/plugins/removable-devices/removable-devices.nst-plugin
similarity index 82%
rename from src/plugins/removable-devices/removable-devices.nst-plugin.in
rename to src/plugins/removable-devices/removable-devices.nst-plugin
index 801b369..d29f2c1 100644
--- a/src/plugins/removable-devices/removable-devices.nst-plugin.in
+++ b/src/plugins/removable-devices/removable-devices.nst-plugin
@@ -1,6 +1,6 @@
 [Nst Plugin]
 Module=nstremovable_devices
 IAge=1
-_Name=Removable disks and shares
+Name=Removable disks and shares
 Authors=Maxim Ermilov <ermilov maxim gmail com>, Bastien Nocera <hadess hadess net>
 Icon=folder-remote
diff --git a/src/plugins/socialweb/Makefile.am b/src/plugins/socialweb/Makefile.am
new file mode 100644
index 0000000..30af2ad
--- /dev/null
+++ b/src/plugins/socialweb/Makefile.am
@@ -0,0 +1,22 @@
+plugindir = $(libdir)/nautilus-sendto/plugins
+
+plugin_DATA = socialweb.nst-plugin
+
+INCLUDES =                                      \
+        -DDATADIR=\"$(datadir)\"                \
+        -DICONDIR=\"$(icondir)\"                \
+	-DLOCALEDIR="\"$(datadir)/locale\""	\
+        -I$(top_srcdir)/src                     \
+        -I$(top_builddir)                       \
+        -I$(srcdir)/../				\
+        $(SOCIALWEB_CFLAGS)			\
+        $(NAUTILUS_SENDTO_CFLAGS)               \
+        $(DISABLE_DEPRECATED)			\
+	$(WARN_CFLAGS)
+
+plugin_LTLIBRARIES = libnstsocialweb.la
+
+libnstsocialweb_la_SOURCES = socialweb.c
+libnstsocialweb_la_LDFLAGS = -module -avoid-version
+libnstsocialweb_la_LIBADD = $(SOCIALWEB_LIBS) $(NAUTILUS_SENDTO_LIBS) $(builddir)/../libnautilussendto-1.0.la
+
diff --git a/src/plugins/socialweb/socialweb.c b/src/plugins/socialweb/socialweb.c
new file mode 100644
index 0000000..01d145c
--- /dev/null
+++ b/src/plugins/socialweb/socialweb.c
@@ -0,0 +1,356 @@
+/*
+ * 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 av.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301  USA.
+ *
+ * Authors:  Bastien Nocera <hadess hadess net>
+ */
+
+#include "config.h"
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include "nautilus-sendto-plugin.h"
+#include <libsocialweb-client/sw-client.h>
+
+#define SOCIALWEB_TYPE_PLUGIN         (socialweb_plugin_get_type ())
+#define SOCIALWEB_PLUGIN(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), SOCIALWEB_TYPE_PLUGIN, SocialwebPlugin))
+#define SOCIALWEB_PLUGIN_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), SOCIALWEB_TYPE_PLUGIN, SocialwebPlugin))
+#define SOCIALWEB_IS_PLUGIN(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), SOCIALWEB_TYPE_PLUGIN))
+#define SOCIALWEB_IS_PLUGIN_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), SOCIALWEB_TYPE_PLUGIN))
+#define SOCIALWEB_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SOCIALWEB_TYPE_PLUGIN, SocialwebPluginClass))
+
+typedef struct _SocialwebPlugin       SocialwebPlugin;
+typedef struct _SocialwebPluginClass  SocialwebPluginClass;
+
+struct _SocialwebPlugin {
+	PeasExtensionBase parent_instance;
+
+	SwClient *client;
+	GHashTable *pages;
+
+	/* See socialweb_plugin_supports_mime_types() */
+	gboolean has_non_photos;
+};
+
+struct _SocialwebPluginClass {
+	PeasExtensionBaseClass parent_class;
+};
+
+typedef struct {
+	GtkWidget *page;
+	GtkWidget *bar;
+	SwClientService *service;
+} SocialwebPage;
+
+NAUTILUS_PLUGIN_REGISTER(SOCIALWEB_TYPE_PLUGIN, SocialwebPlugin, socialweb_plugin)
+
+static void
+socialweb_plugin_send_files (NautilusSendtoPlugin *plugin,
+				     GList                *file_list,
+				     GAsyncReadyCallback   callback,
+				     gpointer              user_data)
+{
+	/* FIXME
+	 * hack for facebook, convert files to jpeg for upload */
+#if 0
+	SocialwebPlugin *p = SOCIALWEB_PLUGIN (plugin);
+	GtkListStore *store;
+	GtkTreeIter iter;
+	GMount *dest_mount;
+	GFile *mount_root;
+	GSimpleAsyncResult *simple;
+
+	if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (p->cb), &iter) == FALSE) {
+		/* FIXME: This should not happen */
+		g_assert_not_reached ();
+		return;
+	}
+
+	store = GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (p->cb)));
+	gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, MOUNT_COL, &dest_mount, -1);
+	mount_root = g_mount_get_root (dest_mount);
+
+	simple = g_simple_async_result_new (G_OBJECT (plugin),
+					    callback,
+					    user_data,
+					    nautilus_sendto_plugin_send_files);
+
+	copy_files_to (file_list, mount_root);
+
+	g_object_unref (mount_root);
+
+	/* FIXME: Report errors properly */
+	g_simple_async_result_set_op_res_gpointer (simple,
+						   GINT_TO_POINTER (NST_SEND_STATUS_SUCCESS_DONE),
+						   NULL);
+	g_simple_async_result_complete_in_idle (simple);
+	g_object_unref (simple);
+#endif
+}
+
+static SocialwebPage *
+create_widget (SwClientService *service)
+{
+	SocialwebPage *page;
+
+	page = g_new0 (SocialwebPage, 1);
+	page->page = gtk_vbox_new (FALSE, 8);
+	page->service = g_object_ref (service);
+
+	return page;
+}
+
+static void
+infobar_response_cb (GtkInfoBar *info_bar,
+		     gint        response_id,
+		     SocialwebPlugin *plugin)
+{
+	const char *id;
+
+	id = g_object_get_data (G_OBJECT (info_bar), "id");
+	/* FIXME: implement */
+	g_warning ("Spawn configuration tool for '%s'", id);
+}
+
+static gboolean
+update_infobar_for_caps (SocialwebPage   *page,
+			 const char     **caps,
+			 SocialwebPlugin *plugin)
+{
+	GtkWidget *label;
+	char *msg;
+	gboolean can_send;
+
+	/* Remove existing widget */
+	if (page->bar != NULL) {
+		gtk_widget_hide (page->bar);
+		gtk_widget_destroy (page->bar);
+		page->bar = NULL;
+	}
+
+	can_send = FALSE;
+
+	if (sw_client_service_has_cap (caps, IS_CONFIGURED) == FALSE) {
+		page->bar = g_object_new (GTK_TYPE_INFO_BAR,
+					  "message-type", GTK_MESSAGE_QUESTION,
+					  NULL);
+		msg = g_strdup_printf (_("Service '%s' is not configured."),
+				       sw_client_service_get_display_name (page->service));
+		gtk_info_bar_add_button (GTK_INFO_BAR (page->bar),
+					 _("_Configure"),
+					 1);
+	} else if (sw_client_service_has_cap (caps, CAN_VERIFY_CREDENTIALS)) {
+		if (sw_client_service_has_cap (caps, CREDENTIALS_VALID)) {
+			msg = g_strdup_printf (_("Logged in to service '%s'."),
+						 sw_client_service_get_display_name (page->service));
+			page->bar = g_object_new (GTK_TYPE_INFO_BAR,
+						  "message-type", GTK_MESSAGE_INFO,
+						  NULL);
+			can_send = TRUE;
+		} else {
+			page->bar = g_object_new (GTK_TYPE_INFO_BAR,
+						  "message-type", GTK_MESSAGE_ERROR,
+						  NULL);
+			msg = g_strdup_printf (_("Could not log in to service '%s'."),
+					       sw_client_service_get_display_name (page->service));
+			gtk_info_bar_add_button (GTK_INFO_BAR (page->bar),
+						 _("_Configure"),
+						 1);
+		}
+	} else {
+		page->bar = g_object_new (GTK_TYPE_INFO_BAR,
+					  "message-type", GTK_MESSAGE_INFO,
+					  NULL);
+		msg = g_strdup_printf (_("Logged in to service '%s'."),
+				       sw_client_service_get_display_name (page->service));
+		can_send = TRUE;
+	}
+
+	/* So that the button knows where it belongs to */
+	g_object_set_data (G_OBJECT (page->bar),
+			   "id", (gpointer) sw_client_service_get_name (page->service));
+
+	g_assert (msg);
+	label = gtk_label_new (msg);
+	g_free (msg);
+	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (page->bar))),
+			   label);
+	gtk_box_pack_start (GTK_BOX (page->page), page->bar,
+			    FALSE, FALSE, 0);
+	gtk_widget_show_all (page->page);
+
+	g_signal_connect (page->bar, "response",
+			  G_CALLBACK (infobar_response_cb), plugin);
+
+	return can_send;
+}
+
+static void
+got_dynamic_caps_cb (SwClientService *service,
+		     const char     **caps,
+		     const GError    *error,
+		     SocialwebPlugin *plugin)
+{
+	SocialwebPage *page;
+	gboolean can_send;
+
+	g_message ("got_dynamic_caps_cb '%p' for service '%s'", caps, sw_client_service_get_name (service));
+
+	if (caps == NULL) {
+		g_warning ("An error occurred getting caps for service '%s': %s",
+			   sw_client_service_get_name (service), error ? error->message : "No reason");
+		return;
+	}
+
+	page = create_widget (service);
+	can_send = update_infobar_for_caps (page, caps, plugin);
+
+	g_hash_table_insert (plugin->pages,
+			     (gpointer) sw_client_service_get_name (service),
+			     page);
+
+	g_signal_emit_by_name (G_OBJECT (plugin),
+			       "add-widget",
+			       sw_client_service_get_display_name (service),
+			       NULL, /* FIXME, icon name, see http://bugs.meego.com/show_bug.cgi?id=5944 */
+			       sw_client_service_get_name (service),
+			       page->page);
+
+	g_signal_emit_by_name (G_OBJECT (plugin),
+			       "can-send",
+			       sw_client_service_get_name (service),
+			       can_send);
+}
+
+static void
+service_capability_changed (SwClientService  *service,
+			    const char      **caps,
+			    SocialwebPlugin  *plugin)
+{
+	SocialwebPage *page;
+	gboolean can_send;
+
+	page = g_hash_table_lookup (plugin->pages,
+				    sw_client_service_get_name (service));
+	if (page == NULL)
+		return;
+
+	can_send = update_infobar_for_caps (page, caps, plugin);
+	g_signal_emit_by_name (G_OBJECT (plugin),
+			       "can-send",
+			       sw_client_service_get_name (service),
+			       can_send);
+}
+
+static void
+got_static_caps_cb (SwClientService *service,
+		    const char     **caps,
+		    const GError    *error,
+		    SocialwebPlugin *plugin)
+{
+	g_message ("got_static_caps_cb '%p' for service '%s'", caps, sw_client_service_get_name (service));
+
+	if (sw_client_service_has_cap (caps, "has-photo-upload-iface") != FALSE) {
+		sw_client_service_get_dynamic_capabilities (service,
+							    (SwClientServiceGetCapabilitiesCallback) got_dynamic_caps_cb,
+							    plugin);
+		g_signal_connect (G_OBJECT (service), "capabilities-changed",
+				  G_CALLBACK (service_capability_changed), plugin);
+	}
+}
+
+static void
+get_services_cb (SwClient        *client,
+		 const GList     *services,
+		 SocialwebPlugin *plugin)
+{
+	const GList *l;
+
+	g_message ("got services cb '%p'", services);
+
+	for (l = services; l != NULL; l = l->next) {
+		SwClientService *service;
+
+		service = sw_client_get_service (plugin->client, (char*)l->data);
+		g_message ("checking service '%s' for static caps", sw_client_service_get_name (service));
+
+		sw_client_service_get_static_capabilities (service,
+							   (SwClientServiceGetCapabilitiesCallback) got_static_caps_cb,
+							   plugin);
+	}
+}
+
+static gboolean
+socialweb_plugin_supports_mime_types (NautilusSendtoPlugin *plugin,
+				      GList                *file_list,
+				      const char          **mime_types)
+{
+	SocialwebPlugin *p = (SocialwebPlugin *) plugin;
+	gboolean retval = FALSE;
+
+	if (g_strv_length ((char **) mime_types) != 1) {
+		g_message ("more than one mime type");
+		return FALSE;
+	} else if (g_str_equal (mime_types[0], "image/jpeg")) {
+		retval = TRUE;
+	} else if (g_content_type_is_a (mime_types[0], "image/*")) {
+		/* Some of the plugins, such as Facebook,
+		 * don't support sending non-JPEG images */
+		p->has_non_photos = TRUE;
+		retval = TRUE;
+	} else {
+		return FALSE;
+	}
+
+	sw_client_get_services (p->client,
+				(SwClientGetServicesCallback) get_services_cb,
+				plugin);
+
+	return retval;
+}
+
+static void
+destroy_page (gpointer data)
+{
+	SocialwebPage *page = (SocialwebPage *) data;
+
+	g_object_unref (page->service);
+	/* The widgets will be destroyed when
+	 * the dialogue is destroyed */
+	page = NULL;
+}
+
+static void
+socialweb_plugin_init (SocialwebPlugin *p)
+{
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+	p->client = sw_client_new ();
+	p->pages = g_hash_table_new_full (g_str_hash, g_str_equal,
+					  NULL, destroy_page);
+	/* FIXME use is-online? */
+}
+
+static void
+socialweb_plugin_finalize (GObject *object)
+{
+	SocialwebPlugin *p = SOCIALWEB_PLUGIN (object);
+
+	g_hash_table_destroy (p->pages);
+	p->pages = NULL;
+
+	G_OBJECT_CLASS (socialweb_plugin_parent_class)->finalize (object);
+}
+
diff --git a/src/plugins/evolution/evolution.nst-plugin.in b/src/plugins/socialweb/socialweb.nst-plugin
similarity index 55%
rename from src/plugins/evolution/evolution.nst-plugin.in
rename to src/plugins/socialweb/socialweb.nst-plugin
index bcd313f..a746fbf 100644
--- a/src/plugins/evolution/evolution.nst-plugin.in
+++ b/src/plugins/socialweb/socialweb.nst-plugin
@@ -1,6 +1,6 @@
 [Nst Plugin]
-Module=nstevolution
+Module=nstsocialweb
 IAge=1
-_Name=Email
+Name=Flickr
 Authors=Bastien Nocera <hadess hadess net>
-Icon=emblem-mail
+Icon=folder-remote



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