evolution r37488 - in branches/kill-bonobo: . composer e-util mail plugins/save-attachments widgets/misc



Author: mbarnes
Date: Wed Apr  1 22:58:10 2009
New Revision: 37488
URL: http://svn.gnome.org/viewvc/evolution?rev=37488&view=rev

Log:
Finish attachment drag and drop.

Expunge em-popup.c of dead code.  Not much left.

Kill the save-attachments (experimental) plugin.
The attachment bar can already save all at once.


Removed:
   branches/kill-bonobo/plugins/save-attachments/
   branches/kill-bonobo/widgets/misc/e-mime-part-utils.c
   branches/kill-bonobo/widgets/misc/e-mime-part-utils.h
Modified:
   branches/kill-bonobo/composer/e-msg-composer.c
   branches/kill-bonobo/configure.in
   branches/kill-bonobo/e-util/e-util.c
   branches/kill-bonobo/e-util/e-util.h
   branches/kill-bonobo/mail/e-attachment-handler-mail.c
   branches/kill-bonobo/mail/em-popup.c
   branches/kill-bonobo/widgets/misc/Makefile.am
   branches/kill-bonobo/widgets/misc/e-attachment-handler.c
   branches/kill-bonobo/widgets/misc/e-attachment-handler.h
   branches/kill-bonobo/widgets/misc/e-attachment-paned.c
   branches/kill-bonobo/widgets/misc/e-attachment-paned.h
   branches/kill-bonobo/widgets/misc/e-attachment-store.c
   branches/kill-bonobo/widgets/misc/e-attachment-store.h
   branches/kill-bonobo/widgets/misc/e-attachment-view.c
   branches/kill-bonobo/widgets/misc/e-attachment-view.h
   branches/kill-bonobo/widgets/misc/e-attachment.c

Modified: branches/kill-bonobo/composer/e-msg-composer.c
==============================================================================
--- branches/kill-bonobo/composer/e-msg-composer.c	(original)
+++ branches/kill-bonobo/composer/e-msg-composer.c	Wed Apr  1 22:58:10 2009
@@ -133,39 +133,6 @@
 	LAST_SIGNAL
 };
 
-enum {
-	DND_TYPE_MESSAGE_RFC822,
-	DND_TYPE_X_UID_LIST,
-	DND_TYPE_TEXT_URI_LIST,
-	DND_TYPE_NETSCAPE_URL,
-	DND_TYPE_TEXT_VCARD,
-	DND_TYPE_TEXT_CALENDAR
-};
-
-static GtkTargetEntry drop_types[] = {
-	{ "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 },
-	{ "x-uid-list",     0, DND_TYPE_X_UID_LIST },
-	{ "text/uri-list",  0, DND_TYPE_TEXT_URI_LIST },
-	{ "_NETSCAPE_URL",  0, DND_TYPE_NETSCAPE_URL },
-	{ "text/x-vcard",   0, DND_TYPE_TEXT_VCARD },
-	{ "text/calendar",  0, DND_TYPE_TEXT_CALENDAR }
-};
-
-static struct {
-	gchar *target;
-	GdkAtom atom;
-	guint32 actions;
-} drag_info[] = {
-	{ "message/rfc822", NULL, GDK_ACTION_COPY },
-	{ "x-uid-list",     NULL, GDK_ACTION_ASK |
-                                  GDK_ACTION_MOVE |
-                                  GDK_ACTION_COPY },
-	{ "text/uri-list",  NULL, GDK_ACTION_COPY },
-	{ "_NETSCAPE_URL",  NULL, GDK_ACTION_COPY },
-	{ "text/x-vcard",   NULL, GDK_ACTION_COPY },
-	{ "text/calendar",  NULL, GDK_ACTION_COPY }
-};
-
 static gpointer parent_class;
 static guint signals[LAST_SIGNAL];
 
@@ -1844,8 +1811,13 @@
 	composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget));
 	view = e_msg_composer_get_attachment_view (composer);
 
-	e_attachment_view_drag_data_received (
-		view, context, x, y, selection, info, time);
+	/* Forward the data to the attachment view.  Note that calling
+	 * e_attachment_view_drag_data_received() will not work because
+	 * that function only handles the case where all the other drag
+	 * handlers have failed. */
+	e_attachment_paned_drag_data_received (
+		E_ATTACHMENT_PANED (view),
+		context, x, y, selection, info, time);
 }
 
 static void
@@ -1900,7 +1872,6 @@
 	GtkWidget *widget;
 	gchar *filename;
 	gchar *uri;
-	gint fd;
 	GError *error = NULL;
 
 	composer = E_MSG_COMPOSER (editor);
@@ -1924,14 +1895,13 @@
 		goto chainup;
 
 	/* Reserve a temporary file. */
-	fd = e_file_open_tmp (&filename, &error);
-	if (error != NULL) {
-		g_warning ("%s", error->message);
+	filename = e_mktemp (NULL);
+	if (filename == NULL) {
+		g_warning ("%s", g_strerror (errno));
 		g_object_unref (pixbuf);
 		g_error_free (error);
 		return;
 	}
-	close (fd);
 
 	/* Save the pixbuf as a temporary file in image/png format. */
 	if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) {
@@ -2197,11 +2167,6 @@
 	GtkObjectClass *gtk_object_class;
 	GtkWidgetClass *widget_class;
 	GtkhtmlEditorClass *editor_class;
-	gint ii;
-
-	for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
-		drag_info[ii].atom =
-			gdk_atom_intern (drag_info[ii].target, FALSE);
 
 	parent_class = g_type_class_peek_parent (class);
 	g_type_class_add_private (class, sizeof (EMsgComposerPrivate));
@@ -2265,10 +2230,14 @@
 	EAttachmentView *view;
 	EAttachmentStore *store;
 	EComposerHeaderTable *table;
+	GdkDragAction drag_actions;
+	GtkTargetList *target_list;
+	GtkTargetEntry *targets;
 	GtkUIManager *manager;
 	GtkhtmlEditor *editor;
 	GtkHTML *html;
 	const gchar *id;
+	gint n_targets;
 
 	composer->priv = E_MSG_COMPOSER_GET_PRIVATE (composer);
 
@@ -2277,6 +2246,7 @@
 	editor = GTKHTML_EDITOR (composer);
 	html = gtkhtml_editor_get_html (editor);
 	manager = gtkhtml_editor_get_ui_manager (editor);
+	view = e_msg_composer_get_attachment_view (composer);
 	all_composers = g_slist_prepend (all_composers, composer);
 	table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
 
@@ -2285,16 +2255,20 @@
 
 	/* Drag-and-Drop Support */
 
-#if 0  /* KILL-BONOBO */
+	target_list = e_attachment_view_get_target_list (view);
+	drag_actions = e_attachment_view_get_drag_actions (view);
+
+	targets = gtk_target_table_new_from_list (target_list, &n_targets);
+
 	gtk_drag_dest_set (
 		GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL,
-		drop_types, G_N_ELEMENTS (drop_types),
-		GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE);
+		targets, n_targets, drag_actions);
 
 	g_signal_connect (
 		html, "drag-data-received",
 		G_CALLBACK (msg_composer_drag_data_received), NULL);
-#endif
+
+	gtk_target_table_free (targets, n_targets);
 
 	/* Configure Headers */
 
@@ -2336,7 +2310,6 @@
 
 	/* Attachments */
 
-	view = e_msg_composer_get_attachment_view (composer);
 	store = e_attachment_view_get_store (view);
 
 	g_signal_connect_swapped (

Modified: branches/kill-bonobo/configure.in
==============================================================================
--- branches/kill-bonobo/configure.in	(original)
+++ branches/kill-bonobo/configure.in	Wed Apr  1 22:58:10 2009
@@ -1785,12 +1785,12 @@
 plugins_standard="$plugins_standard_always"
 all_plugins_standard="$plugins_standard"
 
-plugins_experimental_always="folder-unsubscribe mail-to-meeting save-attachments external-editor hula-account-setup"
+plugins_experimental_always="folder-unsubscribe mail-to-meeting external-editor hula-account-setup"
 plugins_experimental="$plugins_experimental_always $IPOD_SYNC $TNEF_ATTACHMENTS $PYTHON_PLUGIN"
 all_plugins_experimental="$plugins_experimental_always ipod-sync tnef-attachments"
 
 dnl Temporary KILL-BONOBO hack
-enable_plugins="attachment-reminder addressbook-file audio-inline bbdb bogo-junk-plugin caldav calendar-file calendar-http copy-tool default-source external-editor google-account-setup hula-account-setup imap-features mail-notification mail-to-meeting mark-all-read plugin-manager profiler sa-junk-plugin save-attachments save-calendar subject-thread tnef-attachments vcard-inline webdav-account-setup"
+enable_plugins="attachment-reminder addressbook-file audio-inline bbdb bogo-junk-plugin caldav calendar-file calendar-http copy-tool default-source external-editor google-account-setup hula-account-setup imap-features mail-notification mail-to-meeting mark-all-read plugin-manager profiler sa-junk-plugin save-calendar subject-thread tnef-attachments vcard-inline webdav-account-setup"
 
 dnl PLUGINS NOT BUILDING YET
 dnl ------------------------

Modified: branches/kill-bonobo/e-util/e-util.c
==============================================================================
--- branches/kill-bonobo/e-util/e-util.c	(original)
+++ branches/kill-bonobo/e-util/e-util.c	Wed Apr  1 22:58:10 2009
@@ -186,33 +186,6 @@
 }
 
 /**
- * e_file_open_tmp:
- * @name_used: location to store the actual named used, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Convenience function wraps g_file_open_tmp() but chooses a suitable
- * filename template using both the package name and the user name.
- *
- * Returns: A file handle (as from open()) to the file opened for reading
- *          and writing.  The file is opened in binary mode on platforms
- *          where there is a difference.  The file handle should be closed
- *          with close().  In case of errors, -1 is returned and @error
- *          will be set.
- **/
-gint
-e_file_open_tmp (gchar **name_used,
-                 GError **error)
-{
-	static gchar *template = NULL;
-
-	if (G_UNLIKELY (template == NULL))
-		template = g_strdup_printf (
-			PACKAGE "-%s-XXXXXX", g_get_user_name ());
-
-	return g_file_open_tmp (template, name_used, error);
-}
-
-/**
  * e_lookup_action:
  * @ui_manager: a #GtkUIManager
  * @action_name: the name of an action

Modified: branches/kill-bonobo/e-util/e-util.h
==============================================================================
--- branches/kill-bonobo/e-util/e-util.h	(original)
+++ branches/kill-bonobo/e-util/e-util.h	Wed Apr  1 22:58:10 2009
@@ -47,8 +47,6 @@
 						 const gchar *uri);
 void		e_display_help			(GtkWindow *parent,
 						 const gchar *link_id);
-gint		e_file_open_tmp			(gchar **name_used,
-						 GError **error);
 GtkAction *	e_lookup_action			(GtkUIManager *ui_manager,
 						 const gchar *action_name);
 GtkActionGroup *e_lookup_action_group		(GtkUIManager *ui_manager,

Modified: branches/kill-bonobo/mail/e-attachment-handler-mail.c
==============================================================================
--- branches/kill-bonobo/mail/e-attachment-handler-mail.c	(original)
+++ branches/kill-bonobo/mail/e-attachment-handler-mail.c	Wed Apr  1 22:58:10 2009
@@ -23,6 +23,7 @@
 
 #include <config.h>
 #include <glib/gi18n.h>
+#include <camel/camel-stream-mem.h>
 
 #include "mail/em-composer-utils.h"
 
@@ -47,17 +48,21 @@
 "  </popup>"
 "</ui>";
 
+/* Note: Do not use the info field. */
+static GtkTargetEntry target_table[] = {
+	{ "message/rfc822",	0, 0 },
+	{ "x-uid-list",		0, 0 }
+};
+
 static void
-action_mail_forward_cb (GtkAction *action,
-                        EAttachmentHandler *handler)
+attachment_handler_mail_forward (GtkAction *action,
+                                 EAttachmentView *view)
 {
-	EAttachmentView *view;
 	EAttachment *attachment;
 	CamelMimePart *mime_part;
 	CamelDataWrapper *wrapper;
 	GList *selected;
 
-	view = e_attachment_handler_get_view (handler);
 	selected = e_attachment_view_get_selected_attachments (view);
 	g_return_if_fail (g_list_length (selected) == 1);
 
@@ -72,16 +77,14 @@
 }
 
 static void
-action_mail_reply_all_cb (GtkAction *action,
-                          EAttachmentHandler *handler)
+attachment_handler_mail_reply_all (GtkAction *action,
+                                   EAttachmentView *view)
 {
-	EAttachmentView *view;
 	EAttachment *attachment;
 	CamelMimePart *mime_part;
 	CamelDataWrapper *wrapper;
 	GList *selected;
 
-	view = e_attachment_handler_get_view (handler);
 	selected = e_attachment_view_get_selected_attachments (view);
 	g_return_if_fail (g_list_length (selected) == 1);
 
@@ -98,16 +101,14 @@
 }
 
 static void
-action_mail_reply_sender_cb (GtkAction *action,
-                             EAttachmentHandler *handler)
+attachment_handler_mail_reply_sender (GtkAction *action,
+                                      EAttachmentView *view)
 {
-	EAttachmentView *view;
 	EAttachment *attachment;
 	CamelMimePart *mime_part;
 	CamelDataWrapper *wrapper;
 	GList *selected;
 
-	view = e_attachment_handler_get_view (handler);
 	selected = e_attachment_view_get_selected_attachments (view);
 	g_return_if_fail (g_list_length (selected) == 1);
 
@@ -130,26 +131,109 @@
 	  N_("_Forward"),
 	  NULL,
 	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_mail_forward_cb) },
+	  G_CALLBACK (attachment_handler_mail_forward) },
 
 	{ "mail-reply-all",
 	  "mail-reply-all",
 	  N_("Reply to _All"),
 	  NULL,
 	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_mail_reply_all_cb) },
+	  G_CALLBACK (attachment_handler_mail_reply_all) },
 
 	{ "mail-reply-sender",
 	  "mail-reply-sender",
 	  N_("_Reply to Sender"),
 	  NULL,
 	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_mail_reply_sender_cb) }
+	  G_CALLBACK (attachment_handler_mail_reply_sender) }
 };
 
 static void
-attachment_handler_mail_update_actions_cb (EAttachmentView *view,
-                                           EAttachmentHandler *handler)
+attachment_handler_mail_message_rfc822 (EAttachmentView *view,
+                                        GdkDragContext *drag_context,
+                                        gint x,
+                                        gint y,
+                                        GtkSelectionData *selection_data,
+                                        guint info,
+                                        guint time)
+{
+	static GdkAtom atom = GDK_NONE;
+	EAttachmentStore *store;
+	EAttachment *attachment;
+	CamelMimeMessage *message;
+	CamelDataWrapper *wrapper;
+	CamelStream *stream;
+	const gchar *data;
+	gboolean success = FALSE;
+	gpointer parent;
+	gint length;
+
+	if (G_UNLIKELY (atom == GDK_NONE))
+		atom = gdk_atom_intern_static_string ("message/rfc822");
+
+	if (gtk_selection_data_get_target (selection_data) != atom)
+		return;
+
+	g_signal_stop_emission_by_name (view, "drag-data-received");
+
+	data = (const gchar *) gtk_selection_data_get_data (selection_data);
+	length = gtk_selection_data_get_length (selection_data);
+
+	stream = camel_stream_mem_new ();
+	camel_stream_write (stream, data, length);
+	camel_stream_reset (stream);
+
+	message = camel_mime_message_new ();
+	wrapper = CAMEL_DATA_WRAPPER (message);
+
+	if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1)
+		goto exit;
+
+	store = e_attachment_view_get_store (view);
+
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+	attachment = e_attachment_new_for_message (message);
+	e_attachment_store_add_attachment (store, attachment);
+	e_attachment_load_async (
+		attachment, (GAsyncReadyCallback)
+		e_attachment_load_handle_error, parent);
+	g_object_unref (attachment);
+
+	success = TRUE;
+
+exit:
+	camel_object_unref (message);
+	camel_object_unref (stream);
+
+	gtk_drag_finish (drag_context, success, FALSE, time);
+}
+
+static void
+attachment_handler_mail_x_uid_list (EAttachmentView *view,
+                                    GdkDragContext *drag_context,
+                                    gint x,
+                                    gint y,
+                                    GtkSelectionData *selection_data,
+                                    guint info,
+                                    guint time)
+{
+	static GdkAtom atom = GDK_NONE;
+
+	if (G_UNLIKELY (atom == GDK_NONE))
+		atom = gdk_atom_intern_static_string ("x-uid-list");
+
+	if (gtk_selection_data_get_target (selection_data) != atom)
+		return;
+
+	return;  /* REMOVE ME */
+
+	g_signal_stop_emission_by_name (view, "drag-data-received");
+}
+
+static void
+attachment_handler_mail_update_actions (EAttachmentView *view)
 {
 	EAttachment *attachment;
 	CamelMimePart *mime_part;
@@ -184,7 +268,6 @@
 static void
 attachment_handler_mail_constructed (GObject *object)
 {
-	EAttachmentHandlerMailPrivate *priv;
 	EAttachmentHandler *handler;
 	EAttachmentView *view;
 	GtkActionGroup *action_group;
@@ -193,7 +276,6 @@
 	GError *error = NULL;
 
 	handler = E_ATTACHMENT_HANDLER (object);
-	priv = E_ATTACHMENT_HANDLER_MAIL_GET_PRIVATE (object);
 
 	/* Chain up to parent's constructed() method. */
 	G_OBJECT_CLASS (parent_class)->constructed (object);
@@ -205,7 +287,7 @@
 	gtk_action_group_set_translation_domain (action_group, domain);
 	gtk_action_group_add_actions (
 		action_group, standard_entries,
-		G_N_ELEMENTS (standard_entries), object);
+		G_N_ELEMENTS (standard_entries), view);
 	gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 	g_object_unref (action_group);
 
@@ -218,20 +300,51 @@
 
 	g_signal_connect (
 		view, "update-actions",
-		G_CALLBACK (attachment_handler_mail_update_actions_cb),
-		object);
+		G_CALLBACK (attachment_handler_mail_update_actions),
+		NULL);
+
+	g_signal_connect (
+		view, "drag-data-received",
+		G_CALLBACK (attachment_handler_mail_message_rfc822),
+		NULL);
+
+	g_signal_connect (
+		view, "drag-data-received",
+		G_CALLBACK (attachment_handler_mail_x_uid_list),
+		NULL);
+}
+
+static GdkDragAction
+attachment_handler_mail_get_drag_actions (EAttachmentHandler *handler)
+{
+	return GDK_ACTION_COPY;
+}
+
+static const GtkTargetEntry *
+attachment_handler_mail_get_target_table (EAttachmentHandler *handler,
+                                          guint *n_targets)
+{
+	if (n_targets != NULL)
+		*n_targets = G_N_ELEMENTS (target_table);
+
+	return target_table;
 }
 
 static void
 attachment_handler_mail_class_init (EAttachmentHandlerMailClass *class)
 {
 	GObjectClass *object_class;
+	EAttachmentHandlerClass *handler_class;
 
 	parent_class = g_type_class_peek_parent (class);
 	g_type_class_add_private (class, sizeof (EAttachmentHandlerMailPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
 	object_class->constructed = attachment_handler_mail_constructed;
+
+	handler_class = E_ATTACHMENT_HANDLER_CLASS (class);
+	handler_class->get_drag_actions = attachment_handler_mail_get_drag_actions;
+	handler_class->get_target_table = attachment_handler_mail_get_target_table;
 }
 
 static void
@@ -261,8 +374,7 @@
 
 		type = g_type_register_static (
 			E_TYPE_ATTACHMENT_HANDLER,
-			"EAttachmentHandlerMail",
-			&type_info, 0);
+			"EAttachmentHandlerMail", &type_info, 0);
 	}
 
 	return type;

Modified: branches/kill-bonobo/mail/em-popup.c
==============================================================================
--- branches/kill-bonobo/mail/em-popup.c	(original)
+++ branches/kill-bonobo/mail/em-popup.c	Wed Apr  1 22:58:10 2009
@@ -55,8 +55,6 @@
 #include <e-util/e-util.h>
 #include "e-attachment.h"
 
-static void emp_standard_menu_factory(EPopup *emp, void *data);
-
 static GObjectClass *emp_parent;
 
 static void
@@ -116,10 +114,6 @@
 {
 	klass->finalize = emp_finalise;
 	((EPopupClass *)klass)->target_free = emp_target_free;
-
-#if 0  /* KILL-BONOBO */
-	e_popup_class_add_factory((EPopupClass *)klass, NULL, emp_standard_menu_factory, NULL);
-#endif
 }
 
 GType
@@ -363,568 +357,6 @@
 	return t;
 }
 
-#if 0  /* KILL-BONOBO */
-/**
- * em_popup_target_new_attachments:
- * @emp:
- * @attachments: A list of EMsgComposerAttachment objects, reffed for
- * the list.  Will be unreff'd once finished with.
- *
- * Owns the list @attachments and their items after they're passed in.
- *
- * Return value:
- **/
-EMPopupTargetAttachments *
-em_popup_target_new_attachments(EMPopup *emp, GSList *attachments)
-{
-	EMPopupTargetAttachments *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_ATTACHMENTS, sizeof(*t));
-	guint32 mask = ~0;
-	int len = g_slist_length(attachments);
-
-	t->attachments = attachments;
-	if (len > 0)
-		mask &= ~ EM_POPUP_ATTACHMENTS_MANY;
-	if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) {
-		EAttachment *attachment;
-		CamelMimePart *mime_part;
-		CamelContentType *mime_type;
-		CamelDataWrapper *data_wrapper;
-
-		attachment = attachments->data;
-		mime_part = e_attachment_get_mime_part (attachment);
-		mime_type = CAMEL_DATA_WRAPPER (mime_part)->mime_type;
-		data_wrapper = camel_medium_get_content_object (
-			CAMEL_MEDIUM (mime_part));
-
-		if (camel_content_type_is (mime_type, "image", "*"))
-			mask &= ~ EM_POPUP_ATTACHMENTS_IMAGE;
-		if (CAMEL_IS_MIME_MESSAGE (data_wrapper))
-			mask &= ~EM_POPUP_ATTACHMENTS_MESSAGE;
-
-		mask &= ~ EM_POPUP_ATTACHMENTS_ONE;
-	}
-	if (len > 1)
-		mask &= ~ EM_POPUP_ATTACHMENTS_MULTIPLE;
-	t->target.mask = mask;
-
-	return t;
-}
-#endif
-
-/* ********************************************************************** */
-
-#if 0  /* KILL-BONOBO */
-static void
-emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	CamelMimePart *part = NULL;
-	GtkWidget *widget;
-	gpointer parent;
-
-	/* If it is of type EM_POPUP_TARGET_ATTACHMENTS, we can assume the length is one. */
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) t)->part;
-
-	widget = ep->target->widget;
-	parent = gtk_widget_get_toplevel (widget);
-	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
-
-	em_utils_save_part (parent, _("Save As..."), part);
-}
-#endif
-
-#if 0  /* KILL-BONOBO */
-static void
-emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	GConfClient *gconf;
-	char *str, *filename, *path, *extension;
-	unsigned int i=1;
-	CamelMimePart *part = NULL;
-
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) t)->part;
-
-	if (!part)
-		return;
-
-	filename = g_strdup(camel_mime_part_get_filename(part));
-
-	/* if filename is blank, create a default filename based on MIME type */
-	if (!filename || !filename[0]) {
-		CamelContentType *ct;
-
-		ct = camel_mime_part_get_content_type(part);
-		g_free (filename);
-		filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype);
-	}
-
-	e_filename_make_safe(filename);
-
-	path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", filename, NULL);
-
-	extension = strrchr(filename, '.');
-	if (extension)
-		*extension++ = 0;
-
-	/* if file exists, stick a (number) on the end */
-	while (g_file_test(path, G_FILE_TEST_EXISTS)) {
-		char *name;
-		name = g_strdup_printf(extension?"%s (%d).%s":"%s (%d)", filename, i++, extension);
-		g_free(path);
-		path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", name, NULL);
-		g_free(name);
-	}
-
-	g_free(filename);
-
-	if (em_utils_save_part_to_file(ep->target->widget, path, part)) {
-		gconf = gconf_client_get_default();
-
-		/* if the filename hasn't changed, blank the filename before
-		*  setting it so that gconf detects a change and updates it */
-		if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_filename", NULL)) != NULL
-		     && strcmp (str, path) == 0) {
-			gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", "", NULL);
-		}
-
-		g_free (str);
-		gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", path, NULL);
-
-		/* if GNOME currently doesn't display a picture, set to "wallpaper"
-		 * display mode, otherwise leave it alone */
-		if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_options", NULL)) == NULL
-		     || strcmp(str, "none") == 0) {
-			gconf_client_set_string(gconf, "/desktop/gnome/background/picture_options", "wallpaper", NULL);
-		}
-
-		gconf_client_suggest_sync(gconf, NULL);
-
-		g_free(str);
-		g_object_unref(gconf);
-	}
-
-	g_free(path);
-}
-#endif
-
-static void
-emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	CamelMimeMessage *message;
-	CamelMimePart *part;
-
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) t)->part;
-
-	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
-	em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL);
-}
-
-static void
-emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	CamelMimeMessage *message;
-	CamelMimePart *part;
-
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) t)->part;
-
-	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
-	em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL);
-}
-
-static void
-emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	CamelMimeMessage *message;
-	CamelMimePart *part;
-
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) t)->part;
-
-	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part);
-	em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL);
-}
-
-static void
-emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *t = ep->target;
-	CamelMimeMessage *message;
-	CamelMimePart *part;
-
-	if (t->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) t)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) t)->part;
-
-	/* TODO: have a emfv specific override so we can get the parent folder uri */
-	message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) part);
-	em_utils_forward_message(message, NULL);
-}
-
-#if 0  /* KILL-BONOBO */
-static EMPopupItem emp_standard_object_popups[] = {
-	{ E_POPUP_ITEM, "00.part.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 },
-	{ E_POPUP_ITEM, "00.part.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_PART_IMAGE },
-	{ E_POPUP_BAR, "10.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE },
-	{ E_POPUP_ITEM, "10.part.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "mail-reply-sender" , EM_POPUP_PART_MESSAGE },
-	{ E_POPUP_ITEM, "10.part.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_PART_MESSAGE},
-	{ E_POPUP_ITEM, "10.part.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "mail-reply-all", EM_POPUP_PART_MESSAGE},
-	{ E_POPUP_BAR, "20.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE },
-	{ E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_PART_MESSAGE },
-};
-
-static EMPopupItem emp_attachment_object_popups[] = {
-	{ E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 },
-	{ E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_ATTACHMENTS_IMAGE },
-	{ E_POPUP_BAR, "05.attach", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ E_POPUP_ITEM, "05.attach.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "mail-reply-sender" , EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ E_POPUP_ITEM, "05.attach.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE},
-	{ E_POPUP_ITEM, "05.attach.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "mail-reply-all", EM_POPUP_ATTACHMENTS_MESSAGE},
-	{ E_POPUP_BAR, "05.attach.10", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE },
-	{ E_POPUP_ITEM, "05.attach.15", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_ATTACHMENTS_MESSAGE },
-};
-
-static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" };
-#endif
-
-/* ********************************************************************** */
-
-static void
-emp_uri_popup_link_open(EPopup *ep, EPopupItem *item, void *data)
-{
-	EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
-	gchar *unescaped_uri = em_utils_url_unescape_amp (t->uri);
-
-	/* FIXME Pass a parent window. */
-	e_show_uri (NULL, unescaped_uri);
-	g_free (unescaped_uri);
-}
-
-static void
-emp_uri_popup_address_send(EPopup *ep, EPopupItem *item, void *data)
-{
-	EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
-
-	/* TODO: have an emfv specific override to get the from uri */
-	em_utils_compose_new_message_with_mailto(t->uri, NULL);
-}
-
-static void
-emp_uri_popup_address_add(EPopup *ep, EPopupItem *item, void *data)
-{
-	EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target;
-	CamelURL *url;
-
-	url = camel_url_new(t->uri, NULL);
-	if (url == NULL) {
-		g_warning("cannot parse url '%s'", t->uri);
-		return;
-	}
-
-	if (url->path && url->path[0])
-		em_utils_add_address(ep->target->widget, url->path);
-
-	camel_url_free(url);
-}
-
-static EPopupItem emp_standard_uri_popups[] = {
-	{ E_POPUP_ITEM, "00.uri.00", N_("_Open Link in Browser"), emp_uri_popup_link_open, NULL, NULL, EM_POPUP_URI_HTTP },
-	{ E_POPUP_ITEM, "00.uri.10", N_("_Send New Message To..."), emp_uri_popup_address_send, NULL, "mail-message-new", EM_POPUP_URI_MAILTO },
-	{ E_POPUP_ITEM, "00.uri.20", N_("_Add to Address Book"), emp_uri_popup_address_add, NULL, "contact-new", EM_POPUP_URI_MAILTO },
-};
-
-/* ********************************************************************** */
-
-#define LEN(x) (sizeof(x)/sizeof(x[0]))
-
-static void
-emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data)
-{
-	char *path;
-	EPopupTarget *target = ep->target;
-	CamelMimePart *part;
-
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) target)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) target)->part;
-
-	path = em_utils_temp_save_part(target->widget, part, TRUE);
-	if (path) {
-		GAppInfo *app = item->user_data;
-		GList *uris = NULL;
-		GError *error = NULL;
-
-		if (g_app_info_supports_files (app)) {
-			GFile *file = g_file_new_for_path (path);
-
-			uris = g_list_append (uris, file);
-			g_app_info_launch (app, uris, NULL, &error);
-			g_object_unref (file);
-		} else {
-			char *uri;
-
-			uri = e_util_filename_to_uri (path);
-			uris = g_list_append (uris, uri);
-
-			g_app_info_launch_uris (app, uris, NULL, &error);
-			g_free (uri);
-		}
-
-		if (error) {
-			g_warning ("%s", error->message);
-			g_error_free (error);
-		}
-
-		g_list_free (uris);
-		g_free (path);
-	}
-}
-
-static void
-emp_apps_popup_free(EPopup *ep, GSList *free_list, void *data)
-{
-	while (free_list) {
-		GSList *n = free_list->next;
-		EPopupItem *item = free_list->data;
-
-		if (item->user_data && item->activate == emp_apps_open_in)
-			g_object_unref (item->user_data);
-
-		g_free(item->path);
-		g_free(item->label);
-		g_free(item);
-		g_slist_free_1(free_list);
-
-		free_list = n;
-	}
-}
-
-static void
-emp_standard_items_free(EPopup *ep, GSList *items, void *data)
-{
-	g_slist_free(items);
-}
-
-static void
-emp_add_vcard (EPopup *ep, EPopupItem *item, void *data)
-{
-	EPopupTarget *target = ep->target;
-	CamelMimePart *part;
-	CamelDataWrapper *content;
-	CamelStreamMem *mem;
-
-	if (target->type == EM_POPUP_TARGET_ATTACHMENTS) {
-		EAttachment *attachment;
-
-		attachment = E_ATTACHMENT (((EMPopupTargetAttachments *) target)->attachments->data);
-		part = e_attachment_get_mime_part (attachment);
-	} else
-		part = ((EMPopupTargetPart *) target)->part;
-
-	if (!part)
-		return;
-
-	content = camel_medium_get_content_object (CAMEL_MEDIUM (part));
-	mem = CAMEL_STREAM_MEM (camel_stream_mem_new ());
-
-	if (camel_data_wrapper_decode_to_stream (content, CAMEL_STREAM (mem)) == -1 ||
-	    !mem->buffer->data)
-		g_warning ("Read part's content failed!");
-	else {
-		GString *vcard = g_string_new_len ((const gchar *) mem->buffer->data, mem->buffer->len);
-
-		em_utils_add_vcard (target->widget, vcard->str);
-
-		g_string_free (vcard, TRUE);
-	}
-
-	camel_object_unref (mem);
-}
-
-#if 0  /* KILL-BONOBO */
-static void
-emp_standard_menu_factory(EPopup *emp, void *data)
-{
-	int i, len;
-	EPopupItem *items;
-	GSList *menus = NULL;
-	GList *apps = NULL;
-	char *mime_type = NULL;
-	const char *filename = NULL;
-
-	switch (emp->target->type) {
-#if 0
-	case EM_POPUP_TARGET_SELECT:
-		return;
-		items = emp_standard_select_popups;
-		len = LEN(emp_standard_select_popups);
-		break;
-#endif
-	case EM_POPUP_TARGET_URI: {
-		/*EMPopupTargetURI *t = (EMPopupTargetURI *)target;*/
-
-		items = emp_standard_uri_popups;
-		len = LEN(emp_standard_uri_popups);
-		break; }
-	case EM_POPUP_TARGET_PART: {
-		EMPopupTargetPart *t = (EMPopupTargetPart *)emp->target;
-		mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)t->part);
-		filename = camel_mime_part_get_filename(t->part);
-
-		items = emp_standard_object_popups;
-		len = LEN(emp_standard_object_popups);
-		break; }
-	case EM_POPUP_TARGET_ATTACHMENTS: {
-		EMPopupTargetAttachments *t = (EMPopupTargetAttachments *)emp->target;
-		GSList *list = t->attachments;
-		EAttachment *attachment;
-		CamelMimePart *mime_part;
-
-		if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) {
-			items = NULL;
-			len = 0;
-			break;
-		}
-
-		/* Only one attachment selected */
-		attachment = list->data;
-		mime_part = e_attachment_get_mime_part (attachment);
-		mime_type = camel_data_wrapper_get_mime_type (CAMEL_DATA_WRAPPER (mime_part));
-		filename = camel_mime_part_get_filename (mime_part);
-
-		items = emp_attachment_object_popups;
-		len = LEN(emp_attachment_object_popups);
-		break; }
-	default:
-		items = NULL;
-		len = 0;
-	}
-
-	if (mime_type) {
-                gchar *cp;
-
-                /* GIO expects lowercase MIME types. */
-                for (cp = mime_type; *cp != '\0'; cp++)
-                        *cp = g_ascii_tolower (*cp);
-
-		cp = g_content_type_from_mime_type (mime_type);
-		apps = g_app_info_get_all_for_type (cp ? cp : mime_type);
-		g_free (cp);
-
-		if (apps == NULL && strcmp (mime_type, "application/octet-stream") == 0) {
-			if (filename != NULL) {
-				gchar *name_type;
-
-				name_type = e_util_guess_mime_type (filename, FALSE);
-				cp = g_content_type_from_mime_type (name_type);
-				apps = g_app_info_get_all_for_type (cp ? cp : name_type);
-				g_free (cp);
-				g_free (name_type);
-			}
-		}
-
-		if (apps) {
-			GString *label = g_string_new("");
-			GSList *open_menus = NULL;
-			GList *l;
-
-			menus = g_slist_prepend(menus, (void *)&emp_standard_part_apps_bar);
-
-			for (l = apps, i = 0; l; l = l->next, i++) {
-				GAppInfo *app = l->data;
-				EPopupItem *item;
-
-				if (!g_app_info_should_show (app)) {
-					g_object_unref (app);
-					l->data = NULL;
-					continue;
-				}
-
-				item = g_malloc0(sizeof(*item));
-				item->type = E_POPUP_ITEM;
-				item->path = g_strdup_printf("99.object.%02d", i);
-				item->label = g_strdup_printf(_("Open in %s..."), g_app_info_get_name (app));
-				item->activate = emp_apps_open_in;
-				item->user_data = app;
-
-				open_menus = g_slist_prepend(open_menus, item);
-			}
-
-			if (open_menus)
-				e_popup_add_items(emp, open_menus, NULL, emp_apps_popup_free, NULL);
-
-			g_string_free(label, TRUE);
-			g_list_free(apps);
-		}
-
-		if (g_ascii_strcasecmp (mime_type, "text/x-vcard") == 0||
-		    g_ascii_strcasecmp (mime_type, "text/vcard") == 0) {
-			EPopupItem *item;
-
-			item = g_malloc0 (sizeof (*item));
-			item->type = E_POPUP_ITEM;
-			item->path = "00.00.vcf.00"; /* make it first item */
-			item->label = _("_Add to Address Book");
-			item->activate = emp_add_vcard;
-			item->user_data = NULL;
-			item->image = "contact-new";
-
-			e_popup_add_items (emp, g_slist_append (NULL, item), NULL, NULL, NULL);
-		}
-
-		g_free (mime_type);
-	}
-
-	for (i=0;i<len;i++) {
-		if ((items[i].visible & emp->target->mask) == 0)
-			menus = g_slist_prepend(menus, &items[i]);
-	}
-
-	if (menus)
-		e_popup_add_items(emp, menus, NULL, emp_standard_items_free, NULL);
-}
-#endif
-
 /* ********************************************************************** */
 
 /* Popup menu plugin handler */

Modified: branches/kill-bonobo/widgets/misc/Makefile.am
==============================================================================
--- branches/kill-bonobo/widgets/misc/Makefile.am	(original)
+++ branches/kill-bonobo/widgets/misc/Makefile.am	Wed Apr  1 22:58:10 2009
@@ -70,7 +70,6 @@
 	e-image-chooser.h			\
 	e-map.h					\
 	e-menu-tool-button.h			\
-	e-mime-part-utils.h			\
 	e-online-button.h			\
 	e-popup-action.h			\
 	e-popup-menu.h				\
@@ -134,7 +133,6 @@
 	e-image-chooser.c			\
 	e-map.c					\
 	e-menu-tool-button.c			\
-	e-mime-part-utils.c			\
 	e-online-button.c			\
 	e-popup-action.c			\
 	e-popup-menu.c				\

Modified: branches/kill-bonobo/widgets/misc/e-attachment-handler.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-handler.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-handler.c	Wed Apr  1 22:58:10 2009
@@ -155,3 +155,37 @@
 
 	return E_ATTACHMENT_VIEW (handler->priv->view);
 }
+
+GdkDragAction
+e_attachment_handler_get_drag_actions (EAttachmentHandler *handler)
+{
+	EAttachmentHandlerClass *class;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_HANDLER (handler), 0);
+
+	class = E_ATTACHMENT_HANDLER_GET_CLASS (handler);
+
+	if (class->get_drag_actions != NULL)
+		return class->get_drag_actions (handler);
+
+	return 0;
+}
+
+const GtkTargetEntry *
+e_attachment_handler_get_target_table (EAttachmentHandler *handler,
+                                       guint *n_targets)
+{
+	EAttachmentHandlerClass *class;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_HANDLER (handler), NULL);
+
+	class = E_ATTACHMENT_HANDLER_GET_CLASS (handler);
+
+	if (class->get_target_table != NULL)
+		return class->get_target_table (handler, n_targets);
+
+	if (n_targets != NULL)
+		*n_targets = 0;
+
+	return NULL;
+}

Modified: branches/kill-bonobo/widgets/misc/e-attachment-handler.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-handler.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-handler.h	Wed Apr  1 22:58:10 2009
@@ -56,11 +56,22 @@
 
 struct _EAttachmentHandlerClass {
 	GObjectClass parent_class;
+
+	GdkDragAction	(*get_drag_actions)	(EAttachmentHandler *handler);
+	const GtkTargetEntry *
+			(*get_target_table)	(EAttachmentHandler *handler,
+						 guint *n_targets);
 };
 
 GType		e_attachment_handler_get_type	(void);
 EAttachmentView *
 		e_attachment_handler_get_view	(EAttachmentHandler *handler);
+GdkDragAction	e_attachment_handler_get_drag_actions
+						(EAttachmentHandler *handler);
+const GtkTargetEntry *
+		e_attachment_handler_get_target_table
+						(EAttachmentHandler *handler,
+						 guint *n_targets);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/widgets/misc/e-attachment-paned.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-paned.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-paned.c	Wed Apr  1 22:58:10 2009
@@ -729,3 +729,20 @@
 
 	g_object_notify (G_OBJECT (paned), "expanded");
 }
+
+void
+e_attachment_paned_drag_data_received (EAttachmentPaned *paned,
+                                       GdkDragContext *context,
+                                       gint x,
+                                       gint y,
+                                       GtkSelectionData *selection,
+                                       guint info,
+                                       guint time)
+{
+	g_return_if_fail (E_IS_ATTACHMENT_PANED (paned));
+
+	/* XXX Dirty hack for forwarding drop events. */
+	g_signal_emit_by_name (
+		paned->priv->icon_view, "drag-data-received",
+		context, x, y, selection, info, time);
+}

Modified: branches/kill-bonobo/widgets/misc/e-attachment-paned.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-paned.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-paned.h	Wed Apr  1 22:58:10 2009
@@ -70,6 +70,14 @@
 gboolean	e_attachment_paned_get_expanded	(EAttachmentPaned *paned);
 void		e_attachment_paned_set_expanded	(EAttachmentPaned *paned,
 						 gboolean expanded);
+void		e_attachment_paned_drag_data_received
+						(EAttachmentPaned *paned,
+						 GdkDragContext *context,
+						 gint x,
+						 gint y,
+						 GtkSelectionData *selection,
+						 guint info,
+						 guint time);
 
 G_END_DECLS
 

Modified: branches/kill-bonobo/widgets/misc/e-attachment-store.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-store.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-store.c	Wed Apr  1 22:58:10 2009
@@ -21,10 +21,12 @@
 
 #include "e-attachment-store.h"
 
+#include <errno.h>
+#include <config.h>
 #include <glib/gi18n.h>
 
 #include "e-util/e-util.h"
-#include "e-util/gconf-bridge.h"
+#include "e-util/e-mktemp.h"
 
 #define E_ATTACHMENT_STORE_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
@@ -32,8 +34,6 @@
 
 struct _EAttachmentStorePrivate {
 	GHashTable *attachment_index;
-	gchar *background_filename;
-	gchar *background_options;
 	gchar *current_folder;
 
 	guint ignore_row_changed : 1;
@@ -41,8 +41,6 @@
 
 enum {
 	PROP_0,
-	PROP_BACKGROUND_FILENAME,
-	PROP_BACKGROUND_OPTIONS,
 	PROP_CURRENT_FOLDER,
 	PROP_NUM_ATTACHMENTS,
 	PROP_NUM_LOADING,
@@ -51,44 +49,6 @@
 
 static gpointer parent_class;
 
-static const gchar *
-attachment_store_get_background_filename (EAttachmentStore *store)
-{
-	return store->priv->background_filename;
-}
-
-static void
-attachment_store_set_background_filename (EAttachmentStore *store,
-                                          const gchar *background_filename)
-{
-	if (background_filename == NULL)
-		background_filename = "";
-
-	g_free (store->priv->background_filename);
-	store->priv->background_filename = g_strdup (background_filename);
-
-	g_object_notify (G_OBJECT (store), "background-filename");
-}
-
-static const gchar *
-attachment_store_get_background_options (EAttachmentStore *store)
-{
-	return store->priv->background_options;
-}
-
-static void
-attachment_store_set_background_options (EAttachmentStore *store,
-                                         const gchar *background_options)
-{
-	if (background_options == NULL)
-		background_options = "";
-
-	g_free (store->priv->background_options);
-	store->priv->background_options = g_strdup (background_options);
-
-	g_object_notify (G_OBJECT (store), "background-options");
-}
-
 static void
 attachment_store_set_property (GObject *object,
                                guint property_id,
@@ -96,18 +56,6 @@
                                GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_BACKGROUND_FILENAME:
-			attachment_store_set_background_filename (
-				E_ATTACHMENT_STORE (object),
-				g_value_get_string (value));
-			return;
-
-		case PROP_BACKGROUND_OPTIONS:
-			attachment_store_set_background_options (
-				E_ATTACHMENT_STORE (object),
-				g_value_get_string (value));
-			return;
-
 		case PROP_CURRENT_FOLDER:
 			e_attachment_store_set_current_folder (
 				E_ATTACHMENT_STORE (object),
@@ -125,20 +73,6 @@
                                GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_BACKGROUND_FILENAME:
-			g_value_set_string (
-				value,
-				attachment_store_get_background_filename (
-				E_ATTACHMENT_STORE (object)));
-			return;
-
-		case PROP_BACKGROUND_OPTIONS:
-			g_value_set_string (
-				value,
-				attachment_store_get_background_options (
-				E_ATTACHMENT_STORE (object)));
-			return;
-
 		case PROP_CURRENT_FOLDER:
 			g_value_set_string (
 				value,
@@ -193,8 +127,6 @@
 
 	g_hash_table_destroy (priv->attachment_index);
 
-	g_free (priv->background_filename);
-	g_free (priv->background_options);
 	g_free (priv->current_folder);
 
 	/* Chain up to parent's finalize() method. */
@@ -202,26 +134,6 @@
 }
 
 static void
-attachment_store_constructed (GObject *object)
-{
-	EAttachmentStorePrivate *priv;
-	GConfBridge *bridge;
-	const gchar *prop;
-	const gchar *key;
-
-	priv = E_ATTACHMENT_STORE_GET_PRIVATE (object);
-	bridge = gconf_bridge_get ();
-
-	prop = "background-filename";
-	key = "/desktop/gnome/background/picture_filename";
-	gconf_bridge_bind_property (bridge, key, object, prop);
-
-	prop = "background-options";
-	key = "/desktop/gnome/background/picture_options";
-	gconf_bridge_bind_property (bridge, key, object, prop);
-}
-
-static void
 attachment_store_class_init (EAttachmentStoreClass *class)
 {
 	GObjectClass *object_class;
@@ -234,29 +146,6 @@
 	object_class->get_property = attachment_store_get_property;
 	object_class->dispose = attachment_store_dispose;
 	object_class->finalize = attachment_store_finalize;
-	object_class->constructed = attachment_store_constructed;
-
-	g_object_class_install_property (
-		object_class,
-		PROP_BACKGROUND_FILENAME,
-		g_param_spec_string (
-			"background-filename",
-			"Background Filename",
-			NULL,
-			NULL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
-
-	g_object_class_install_property (
-		object_class,
-		PROP_BACKGROUND_OPTIONS,
-		g_param_spec_string (
-			"background-options",
-			"Background Options",
-			NULL,
-			NULL,
-			G_PARAM_READWRITE |
-			G_PARAM_CONSTRUCT));
 
 	g_object_class_install_property (
 		object_class,
@@ -737,101 +626,124 @@
 	return destination;
 }
 
-/******************* e_attachment_store_save_list_async() ********************/
+/******************** e_attachment_store_get_uris_async() ********************/
 
-typedef struct _SaveContext SaveContext;
+typedef struct _UriContext UriContext;
 
-struct _SaveContext {
+struct _UriContext {
 	GSimpleAsyncResult *simple;
 	GList *attachment_list;
 	GError *error;
+	gchar **uris;
+	gint index;
 };
 
-static SaveContext *
-attachment_store_save_context_new (EAttachmentStore *store,
-                                   GList *attachment_list,
-                                   GAsyncReadyCallback callback,
-                                   gpointer user_data)
+static UriContext *
+attachment_store_uri_context_new (EAttachmentStore *store,
+                                  GList *attachment_list,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
 {
-	SaveContext *save_context;
+	UriContext *uri_context;
 	GSimpleAsyncResult *simple;
+	guint length;
+	gchar **uris;
 
 	simple = g_simple_async_result_new (
 		G_OBJECT (store), callback, user_data,
-		e_attachment_store_save_list_async);
+		e_attachment_store_get_uris_async);
 
-	save_context = g_slice_new0 (SaveContext);
-	save_context->simple = simple;
-	save_context->attachment_list = g_list_copy (attachment_list);
+	/* Add one for NULL terminator. */
+	length = g_list_length (attachment_list) + 1;
+	uris = g_malloc0 (sizeof (gchar *) * length);
+
+	uri_context = g_slice_new0 (UriContext);
+	uri_context->simple = simple;
+	uri_context->attachment_list = g_list_copy (attachment_list);
+	uri_context->uris = uris;
 
 	g_list_foreach (
-		save_context->attachment_list,
+		uri_context->attachment_list,
 		(GFunc) g_object_ref, NULL);
 
-	return save_context;
+	return uri_context;
 }
 
 static void
-attachment_store_save_context_free (SaveContext *save_context)
+attachment_store_uri_context_free (UriContext *uri_context)
 {
 	/* Do not free the GSimpleAsyncResult. */
 
 	/* The attachment list should be empty now. */
-	g_warn_if_fail (save_context->attachment_list != NULL);
+	g_warn_if_fail (uri_context->attachment_list == NULL);
 
 	/* So should the error. */
-	g_warn_if_fail (save_context->error != NULL);
+	g_warn_if_fail (uri_context->error == NULL);
 
-	g_slice_free (SaveContext, save_context);
+	g_strfreev (uri_context->uris);
+
+	g_slice_free (UriContext, uri_context);
 }
 
 static void
-attachment_store_save_list_finished_cb (EAttachment *attachment,
-                                        GAsyncResult *result,
-                                        SaveContext *save_context)
+attachment_store_get_uris_save_cb (EAttachment *attachment,
+                                   GAsyncResult *result,
+                                   UriContext *uri_context)
 {
-	GFile *file;
 	GSimpleAsyncResult *simple;
+	GFile *file;
+	gchar **uris;
+	gchar *uri;
 	GError *error = NULL;
 
 	file = e_attachment_save_finish (attachment, result, &error);
-	if (file != NULL)
-		g_object_unref (file);
 
 	/* Remove the attachment from the list. */
-	save_context->attachment_list = g_list_remove (
-		save_context->attachment_list, attachment);
+	uri_context->attachment_list = g_list_remove (
+		uri_context->attachment_list, attachment);
 	g_object_unref (attachment);
 
-	/* If this is the first error, cancel the other jobs. */
-	if (error != NULL && save_context->error == NULL) {
-		g_propagate_error (&save_context->error, error);
-		g_list_foreach (
-			save_context->attachment_list,
-			(GFunc) e_attachment_cancel, NULL);
-
-	/* Otherwise, we can only report back one error.  So if this is
-	 * something other than cancellation, dump it to the terminal. */
-	} else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-		g_warning ("%s", error->message);
+	if (file != NULL) {
+		uri = g_file_get_uri (file);
+		uri_context->uris[uri_context->index++] = uri;
+		g_object_unref (file);
+
+	} else if (error != NULL) {
+		/* If this is the first error, cancel the other jobs. */
+		if (uri_context->error == NULL) {
+			g_propagate_error (&uri_context->error, error);
+			g_list_foreach (
+				uri_context->attachment_list,
+				(GFunc) e_attachment_cancel, NULL);
+
+		/* Otherwise, we can only report back one error.  So if
+		 * this is something other than cancellation, dump it to
+		 * the terminal. */
+		} else if (!g_error_matches (
+			error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+			g_warning ("%s", error->message);
 
-	if (error != NULL)
 		g_error_free (error);
+	}
 
 	/* If there's still jobs running, let them finish. */
-	if (save_context->attachment_list != NULL)
+	if (uri_context->attachment_list != NULL)
 		return;
 
 	/* Steal the result. */
-	simple = save_context->simple;
-	save_context->simple = NULL;
+	simple = uri_context->simple;
+	uri_context->simple = NULL;
 
-	/* Steal the error, too. */
-	error = save_context->error;
-	save_context->error = NULL;
+	/* And the URI list. */
+	uris = uri_context->uris;
+	uri_context->uris = NULL;
+
+	/* And the error. */
+	error = uri_context->error;
+	uri_context->error = NULL;
 
 	if (error == NULL)
-		g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+		g_simple_async_result_set_op_res_gpointer (simple, uris, NULL);
 	else {
 		g_simple_async_result_set_from_error (simple, error);
 		g_error_free (error);
@@ -839,63 +751,109 @@
 
 	g_simple_async_result_complete (simple);
 
-	attachment_store_save_context_free (save_context);
+	attachment_store_uri_context_free (uri_context);
 }
 
 void
-e_attachment_store_save_list_async (EAttachmentStore *store,
-                                    GList *attachment_list,
-                                    GFile *destination,
-                                    GAsyncReadyCallback callback,
-                                    gpointer user_data)
+e_attachment_store_get_uris_async (EAttachmentStore *store,
+                                   GList *attachment_list,
+                                   GAsyncReadyCallback callback,
+                                   gpointer user_data)
 {
-	SaveContext *save_context;
+	GFile *temp_directory;
+	UriContext *uri_context;
+	GList *iter, *trash = NULL;
+	gchar *template;
+	gchar *path;
 
 	g_return_if_fail (E_IS_ATTACHMENT_STORE (store));
-	g_return_if_fail (G_IS_FILE (destination));
 	g_return_if_fail (callback != NULL);
 
-	/* Passing an empty list is silly, but we'll handle it. */
-	if (attachment_list == NULL) {
+	uri_context = attachment_store_uri_context_new (
+		store, attachment_list, callback, user_data);
+
+	/* Grab the copied attachment list. */
+	attachment_list = uri_context->attachment_list;
+
+	/* First scan the list for attachments with a GFile. */
+	for (iter = attachment_list; iter != NULL; iter = iter->next) {
+		EAttachment *attachment = iter->data;
+		GFile *file;
+		gchar *uri;
+
+		file = e_attachment_get_file (attachment);
+		if (file == NULL)
+			continue;
+
+		uri = g_file_get_uri (file);
+		uri_context->uris[uri_context->index++] = uri;
+
+		/* Mark the list node for deletion. */
+		trash = g_list_prepend (trash, iter);
+		g_object_unref (attachment);
+	}
+
+	/* Expunge the list. */
+	for (iter = trash; iter != NULL; iter = iter->next) {
+		GList *link = iter->data;
+		attachment_list = g_list_delete_link (attachment_list, link);
+	}
+	g_list_free (trash);
+
+	uri_context->attachment_list = attachment_list;
+
+	/* Any remaining attachments in the list should have MIME parts
+	 * only, so we need to save them all to a temporary directory.
+	 * We use a directory so the files can retain their basenames. */
+	template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ());
+	path = e_mkdtemp (template);
+	g_free (template);
+
+	if (path == NULL) {
 		GSimpleAsyncResult *simple;
 
-		simple = g_simple_async_result_new (
-			G_OBJECT (store), callback, user_data,
-			e_attachment_store_save_list_async);
-		g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+		/* Steal the result. */
+		simple = uri_context->simple;
+		uri_context->simple = NULL;
+
+		g_simple_async_result_set_error (
+			simple, G_FILE_ERROR,
+			g_file_error_from_errno (errno),
+			"%s", g_strerror (errno));
+
 		g_simple_async_result_complete_in_idle (simple);
+		attachment_store_uri_context_free (uri_context);
 		return;
 	}
 
-	save_context = attachment_store_save_context_new (
-		store, attachment_list, callback, user_data);
+	temp_directory = g_file_new_for_path (path);
 
-	while (attachment_list != NULL) {
+	for (iter = attachment_list; iter != NULL; iter = iter->next)
 		e_attachment_save_async (
-			E_ATTACHMENT (attachment_list->data),
-			destination, (GAsyncReadyCallback)
-			attachment_store_save_list_finished_cb,
-			save_context);
-		attachment_list = g_list_next (attachment_list);
-	}
+			E_ATTACHMENT (iter->data),
+			temp_directory, (GAsyncReadyCallback)
+			attachment_store_get_uris_save_cb,
+			uri_context);
+
+	g_object_unref (temp_directory);
 }
 
-gboolean
-e_attachment_store_save_list_finish (EAttachmentStore *store,
-                                     GAsyncResult *result,
-                                     GError **error)
+gchar **
+e_attachment_store_get_uris_finish (EAttachmentStore *store,
+                                    GAsyncResult *result,
+                                    GError **error)
 {
 	GSimpleAsyncResult *simple;
-	gboolean success;
+	gchar **uris;
 
 	g_return_val_if_fail (
 		g_simple_async_result_is_valid (result, G_OBJECT (store),
-		e_attachment_store_save_list_async), FALSE);
+		e_attachment_store_get_uris_async), FALSE);
 
 	simple = G_SIMPLE_ASYNC_RESULT (result);
-	success = g_simple_async_result_get_op_res_gboolean (simple);
+	uris = g_simple_async_result_get_op_res_gpointer (simple);
 	g_simple_async_result_propagate_error (simple, error);
 	g_object_unref (simple);
 
-	return success;
+	return uris;
 }

Modified: branches/kill-bonobo/widgets/misc/e-attachment-store.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-store.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-store.h	Wed Apr  1 22:58:10 2009
@@ -107,13 +107,12 @@
 						 GtkWindow *parent);
 
 /* Asynchronous Operations */
-void		e_attachment_store_save_list_async
+void		e_attachment_store_get_uris_async
 						(EAttachmentStore *store,
 						 GList *attachment_list,
-						 GFile *destination,
 						 GAsyncReadyCallback callback,
 						 gpointer user_data);
-gboolean	e_attachment_store_save_list_finish
+gchar **	e_attachment_store_get_uris_finish
 						(EAttachmentStore *store,
 						 GAsyncResult *result,
 						 GError **error);

Modified: branches/kill-bonobo/widgets/misc/e-attachment-view.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-view.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-view.c	Wed Apr  1 22:58:10 2009
@@ -36,38 +36,11 @@
 	LAST_SIGNAL
 };
 
-enum {
-	DND_TYPE_MESSAGE_RFC822,
-	DND_TYPE_X_UID_LIST,
-	DND_TYPE_TEXT_URI_LIST,
-	DND_TYPE_NETSCAPE_URL,
-	DND_TYPE_TEXT_VCARD,
-	DND_TYPE_TEXT_CALENDAR
-};
-
-static GtkTargetEntry drop_types[] = {
-	{ "message/rfc822",	0, DND_TYPE_MESSAGE_RFC822 },
-	{ "x-uid-list",		0, DND_TYPE_X_UID_LIST },
-	{ "text/uri-list",	0, DND_TYPE_TEXT_URI_LIST },
-	{ "_NETSCAPE_URL",	0, DND_TYPE_NETSCAPE_URL },
-	{ "text/x-vcard",	0, DND_TYPE_TEXT_VCARD },
-	{ "text/calendar",	0, DND_TYPE_TEXT_CALENDAR }
-};
-
-/* The atoms need initialized at runtime. */
-static struct {
-	const gchar *target;
-	GdkAtom atom;
-	GdkDragAction actions;
-} drag_info[] = {
-	{ "message/rfc822",	NULL,	GDK_ACTION_COPY },
-	{ "x-uid-list",		NULL,	GDK_ACTION_COPY |
-					GDK_ACTION_MOVE |
-					GDK_ACTION_ASK },
-	{ "text/uri-list",	NULL,	GDK_ACTION_COPY },
-	{ "_NETSCAPE_URL",	NULL,	GDK_ACTION_COPY },
-	{ "text/x-vcard",	NULL,	GDK_ACTION_COPY },
-	{ "text/calendar",	NULL,	GDK_ACTION_COPY }
+/* Note: Do not use the info field. */
+static GtkTargetEntry target_table[] = {
+	{ "_NETSCAPE_URL",	0, 0 },
+	{ "text/x-vcard",	0, 0 },
+	{ "text/calendar",	0, 0 }
 };
 
 static const gchar *ui =
@@ -84,12 +57,6 @@
 "    <separator/>"
 "    <placeholder name='open-actions'/>"
 "  </popup>"
-"  <popup name='dnd'>"
-"    <menuitem action='drag-copy'/>"
-"    <menuitem action='drag-move'/>"
-"    <separator/>"
-"    <menuitem action='drag-cancel'/>"
-"  </popup>"
 "</ui>";
 
 static gulong signals[LAST_SIGNAL];
@@ -126,30 +93,6 @@
 }
 
 static void
-action_drag_cancel_cb (GtkAction *action,
-                       EAttachmentView *view)
-{
-	EAttachmentViewPrivate *priv;
-
-	priv = e_attachment_view_get_private (view);
-	gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
-}
-
-static void
-action_drag_copy_cb (GtkAction *action,
-                     EAttachmentView *view)
-{
-	e_attachment_view_drag_action (view, GDK_ACTION_COPY);
-}
-
-static void
-action_drag_move_cb (GtkAction *action,
-                     EAttachmentView *view)
-{
-	e_attachment_view_drag_action (view, GDK_ACTION_MOVE);
-}
-
-static void
 action_open_in_cb (GtkAction *action,
                    EAttachmentView *view)
 {
@@ -312,27 +255,6 @@
 	  NULL,  /* XXX Add a tooltip! */
 	  G_CALLBACK (action_cancel_cb) },
 
-	{ "drag-cancel",
-	  NULL,
-	  N_("Cancel _Drag"),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_drag_cancel_cb) },
-
-	{ "drag-copy",
-	  NULL,
-	  N_("_Copy"),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_drag_copy_cb) },
-
-	{ "drag-move",
-	  NULL,
-	  N_("_Move"),
-	  NULL,
-	  NULL,  /* XXX Add a tooltip! */
-	  G_CALLBACK (action_drag_move_cb) },
-
 	{ "save-all",
 	  GTK_STOCK_SAVE_AS,
 	  N_("S_ave All"),
@@ -382,159 +304,153 @@
 };
 
 static void
-drop_message_rfc822 (EAttachmentView *view,
-                     GtkSelectionData *selection_data,
-                     EAttachmentStore *store,
-                     GdkDragAction action)
+attachment_view_netscape_url (EAttachmentView *view,
+                              GdkDragContext *drag_context,
+                              gint x,
+                              gint y,
+                              GtkSelectionData *selection_data,
+                              guint info,
+                              guint time)
 {
-	EAttachmentViewPrivate *priv;
+	static GdkAtom atom = GDK_NONE;
+	EAttachmentStore *store;
 	EAttachment *attachment;
-	CamelMimeMessage *message;
-	CamelDataWrapper *wrapper;
-	CamelStream *stream;
 	const gchar *data;
-	gboolean success = FALSE;
-	gboolean delete = FALSE;
 	gpointer parent;
+	gchar *copied_data;
+	gchar **strv;
 	gint length;
 
-	priv = e_attachment_view_get_private (view);
+	if (G_UNLIKELY (atom == GDK_NONE))
+		atom = gdk_atom_intern_static_string ("_NETSCAPE_URL");
+
+	if (gtk_selection_data_get_target (selection_data) != atom)
+		return;
+
+	g_signal_stop_emission_by_name (view, "drag-data-received");
+
+	/* _NETSCAPE_URL is represented as "URI\nTITLE" */
 
 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
 	length = gtk_selection_data_get_length (selection_data);
 
-	stream = camel_stream_mem_new ();
-	camel_stream_write (stream, data, length);
-	camel_stream_reset (stream);
-
-	message = camel_mime_message_new ();
-	wrapper = CAMEL_DATA_WRAPPER (message);
+	copied_data = g_strndup (data, length);
+	strv = g_strsplit (copied_data, "\n", 2);
+	g_free (copied_data);
 
-	if (camel_data_wrapper_construct_from_stream (wrapper, stream) == -1)
-		goto exit;
+	store = e_attachment_view_get_store (view);
 
 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 
-	attachment = e_attachment_new_for_message (message);
+	attachment = e_attachment_new_for_uri (strv[0]);
 	e_attachment_store_add_attachment (store, attachment);
 	e_attachment_load_async (
 		attachment, (GAsyncReadyCallback)
 		e_attachment_load_handle_error, parent);
 	g_object_unref (attachment);
 
-	success = TRUE;
-	delete = (action == GDK_ACTION_MOVE);
-
-exit:
-	camel_object_unref (message);
-	camel_object_unref (stream);
+	g_strfreev (strv);
 
-	gtk_drag_finish (priv->drag_context, success, delete, priv->time);
+	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 }
 
 static void
-drop_netscape_url (EAttachmentView *view,
-                   GtkSelectionData *selection_data,
-                   EAttachmentStore *store,
-                   GdkDragAction action)
+attachment_view_text_calendar (EAttachmentView *view,
+                               GdkDragContext *drag_context,
+                               gint x,
+                               gint y,
+                               GtkSelectionData *selection_data,
+                               guint info,
+                               guint time)
 {
-	EAttachmentViewPrivate *priv;
+	static GdkAtom atom = GDK_NONE;
+	EAttachmentStore *store;
 	EAttachment *attachment;
+	CamelMimePart *mime_part;
+	GdkAtom data_type;
 	const gchar *data;
 	gpointer parent;
-	gchar *copied_data;
-	gchar **strv;
+	gchar *content_type;
 	gint length;
 
-	/* _NETSCAPE_URL is represented as "URI\nTITLE" */
+	if (G_UNLIKELY (atom = GDK_NONE))
+		atom = gdk_atom_intern_static_string ("text/calendar");
 
-	priv = e_attachment_view_get_private (view);
+	if (gtk_selection_data_get_target (selection_data) != atom)
+		return;
+
+	g_signal_stop_emission_by_name (view, "drag-data-received");
 
 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
 	length = gtk_selection_data_get_length (selection_data);
+	data_type = gtk_selection_data_get_data_type (selection_data);
 
-	copied_data = g_strndup (data, length);
-	strv = g_strsplit (copied_data, "\n", 2);
-	g_free (copied_data);
+	mime_part = camel_mime_part_new ();
+
+	content_type = gdk_atom_name (data_type);
+	camel_mime_part_set_content (mime_part, data, length, content_type);
+	camel_mime_part_set_disposition (mime_part, "inline");
+	g_free (content_type);
+
+	store = e_attachment_view_get_store (view);
 
 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 
-	attachment = e_attachment_new_for_uri (strv[0]);
+	attachment = e_attachment_new ();
+	e_attachment_set_mime_part (attachment, mime_part);
 	e_attachment_store_add_attachment (store, attachment);
 	e_attachment_load_async (
 		attachment, (GAsyncReadyCallback)
 		e_attachment_load_handle_error, parent);
 	g_object_unref (attachment);
 
-	g_strfreev (strv);
-
-	gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
-}
-
-static void
-drop_text_uri_list (EAttachmentView *view,
-                    GtkSelectionData *selection_data,
-                    EAttachmentStore *store,
-                    GdkDragAction action)
-{
-	EAttachmentViewPrivate *priv;
-	gpointer parent;
-	gchar **uris;
-	gint ii;
-
-	priv = e_attachment_view_get_private (view);
-
-	uris = gtk_selection_data_get_uris (selection_data);
-
-	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
-	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
-
-	for (ii = 0; uris[ii] != NULL; ii++) {
-		EAttachment *attachment;
-
-		attachment = e_attachment_new_for_uri (uris[ii]);
-		e_attachment_store_add_attachment (store, attachment);
-		e_attachment_load_async (
-			attachment, (GAsyncReadyCallback)
-			e_attachment_load_handle_error, parent);
-		g_object_unref (attachment);
-	}
-
-	g_strfreev (uris);
+	camel_object_unref (mime_part);
 
-	gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 }
 
 static void
-drop_text_generic (EAttachmentView *view,
-                   GtkSelectionData *selection_data,
-                   EAttachmentStore *store,
-                   GdkDragAction action)
+attachment_view_text_x_vcard (EAttachmentView *view,
+                              GdkDragContext *drag_context,
+                              gint x,
+                              gint y,
+                              GtkSelectionData *selection_data,
+                              guint info,
+                              guint time)
 {
-	EAttachmentViewPrivate *priv;
+	static GdkAtom atom = GDK_NONE;
+	EAttachmentStore *store;
 	EAttachment *attachment;
 	CamelMimePart *mime_part;
-	GdkAtom atom;
+	GdkAtom data_type;
 	const gchar *data;
 	gpointer parent;
 	gchar *content_type;
 	gint length;
 
-	priv = e_attachment_view_get_private (view);
+	if (G_UNLIKELY (atom = GDK_NONE))
+		atom = gdk_atom_intern_static_string ("text/x-vcard");
+
+	if (gtk_selection_data_get_target (selection_data) != atom)
+		return;
+
+	g_signal_stop_emission_by_name (view, "drag-data-received");
 
 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
 	length = gtk_selection_data_get_length (selection_data);
-	atom = gtk_selection_data_get_data_type (selection_data);
+	data_type = gtk_selection_data_get_data_type (selection_data);
 
 	mime_part = camel_mime_part_new ();
 
-	content_type = gdk_atom_name (atom);
+	content_type = gdk_atom_name (data_type);
 	camel_mime_part_set_content (mime_part, data, length, content_type);
 	camel_mime_part_set_disposition (mime_part, "inline");
 	g_free (content_type);
 
+	store = e_attachment_view_get_store (view);
+
 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
 
@@ -548,22 +464,49 @@
 
 	camel_object_unref (mime_part);
 
-	gtk_drag_finish (priv->drag_context, TRUE, FALSE, priv->time);
+	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 }
 
 static void
-drop_x_uid_list (EAttachmentView *view,
-                 GtkSelectionData *selection_data,
-                 EAttachmentStore *store,
-                 GdkDragAction action)
+attachment_view_uris (EAttachmentView *view,
+                      GdkDragContext *drag_context,
+                      gint x,
+                      gint y,
+                      GtkSelectionData *selection_data,
+                      guint info,
+                      guint time)
 {
-	EAttachmentViewPrivate *priv;
+	EAttachmentStore *store;
+	gpointer parent;
+	gchar **uris;
+	gint ii;
 
-	/* FIXME  Ugh, this looks painful.  Requires mailer stuff. */
+	uris = gtk_selection_data_get_uris (selection_data);
 
-	priv = e_attachment_view_get_private (view);
+	if (uris == NULL)
+		return;
+
+	g_signal_stop_emission_by_name (view, "drag-data-received");
+
+	store = e_attachment_view_get_store (view);
+
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
+	parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL;
+
+	for (ii = 0; uris[ii] != NULL; ii++) {
+		EAttachment *attachment;
+
+		attachment = e_attachment_new_for_uri (uris[ii]);
+		e_attachment_store_add_attachment (store, attachment);
+		e_attachment_load_async (
+			attachment, (GAsyncReadyCallback)
+			e_attachment_load_handle_error, parent);
+		g_object_unref (attachment);
+	}
 
-	gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
+	g_strfreev (uris);
+
+	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 }
 
 static void
@@ -669,10 +612,48 @@
 }
 
 static void
-attachment_view_class_init (EAttachmentViewIface *iface)
+attachment_view_init_handlers (EAttachmentView *view)
 {
-	gint ii;
+	EAttachmentViewPrivate *priv;
+	GtkTargetList *target_list;
+	GType *children;
+	guint ii;
+
+	priv = e_attachment_view_get_private (view);
+
+	target_list = gtk_target_list_new (
+		target_table, G_N_ELEMENTS (target_table));
+
+	gtk_target_list_add_uri_targets (target_list, 0);
+
+	priv->handlers = g_ptr_array_new ();
+	priv->target_list = target_list;
+	priv->drag_actions = GDK_ACTION_COPY;
+
+	children = g_type_children (E_TYPE_ATTACHMENT_HANDLER, NULL);
+
+	for (ii = 0; children[ii] != G_TYPE_INVALID; ii++) {
+		EAttachmentHandler *handler;
+		const GtkTargetEntry *targets;
+		guint n_targets;
+
+		handler = g_object_new (children[ii], "view", view, NULL);
 
+		targets = e_attachment_handler_get_target_table (
+			handler, &n_targets);
+		gtk_target_list_add_table (target_list, targets, n_targets);
+		priv->drag_actions |=
+			e_attachment_handler_get_drag_actions (handler);
+
+		g_ptr_array_add (priv->handlers, handler);
+	}
+
+	g_free (children);
+}
+
+static void
+attachment_view_class_init (EAttachmentViewIface *iface)
+{
 	iface->update_actions = attachment_view_update_actions;
 
 	g_object_interface_install_property (
@@ -693,11 +674,6 @@
 		NULL, NULL,
 		g_cclosure_marshal_VOID__VOID,
 		G_TYPE_NONE, 0);
-
-	for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) {
-		const gchar *target = drag_info[ii].target;
-		drag_info[ii].atom = gdk_atom_intern (target, FALSE);
-	}
 }
 
 GType
@@ -738,15 +714,10 @@
 	GtkUIManager *ui_manager;
 	GtkActionGroup *action_group;
 	const gchar *domain = GETTEXT_PACKAGE;
-	GType *children;
-	guint ii;
 	GError *error = NULL;
 
 	priv = e_attachment_view_get_private (view);
 
-	e_attachment_view_drag_source_set (view);
-	e_attachment_view_drag_dest_set (view);
-
 	ui_manager = gtk_ui_manager_new ();
 	priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 	priv->ui_manager = ui_manager;
@@ -783,14 +754,28 @@
 		G_OBJECT (view), "editable",
 		G_OBJECT (priv->editable_actions), "visible");
 
-	/* Instantiate attachment handlers. */
-	children = g_type_children (E_TYPE_ATTACHMENT_HANDLER, NULL);
-	for (ii = 0; children[ii] != G_TYPE_INVALID; ii++) {
-		EAttachmentHandler *handler;
-		handler = g_object_new (children[ii], "view", view, NULL);
-		priv->handlers = g_list_prepend (priv->handlers, handler);
-	}
-	g_free (children);
+	attachment_view_init_handlers (view);
+
+	e_attachment_view_drag_source_set (view);
+	e_attachment_view_drag_dest_set (view);
+
+	/* Connect built-in drag and drop handlers. */
+
+	g_signal_connect (
+		view, "drag-data-received",
+		G_CALLBACK (attachment_view_netscape_url), NULL);
+
+	g_signal_connect (
+		view, "drag-data-received",
+		G_CALLBACK (attachment_view_text_calendar), NULL);
+
+	g_signal_connect (
+		view, "drag-data-received",
+		G_CALLBACK (attachment_view_text_x_vcard), NULL);
+
+	g_signal_connect (
+		view, "drag-data-received",
+		G_CALLBACK (attachment_view_uris), NULL);
 }
 
 void
@@ -800,9 +785,13 @@
 
 	priv = e_attachment_view_get_private (view);
 
-	g_list_foreach (priv->handlers, (GFunc) g_object_unref, NULL);
-	g_list_free (priv->handlers);
-	priv->handlers = NULL;
+	g_ptr_array_foreach (priv->handlers, (GFunc) g_object_unref, NULL);
+	g_ptr_array_set_size (priv->handlers, 0);
+
+	if (priv->target_list != NULL) {
+		gtk_target_list_unref (priv->target_list);
+		priv->target_list = NULL;
+	}
 
 	if (priv->ui_manager != NULL) {
 		g_object_unref (priv->ui_manager);
@@ -823,11 +812,6 @@
 		g_object_unref (priv->openwith_actions);
 		priv->openwith_actions = NULL;
 	}
-
-	if (priv->drag_context != NULL) {
-		g_object_unref (priv->drag_context);
-		priv->drag_context = NULL;
-	}
 }
 
 void
@@ -837,8 +821,7 @@
 
 	priv = e_attachment_view_get_private (view);
 
-	if (priv->selection_data != NULL)
-		gtk_selection_data_free (priv->selection_data);
+	g_ptr_array_free (priv->handlers, TRUE);
 }
 
 EAttachmentViewPrivate *
@@ -893,6 +876,30 @@
 	g_object_notify (G_OBJECT (view), "editable");
 }
 
+GtkTargetList *
+e_attachment_view_get_target_list (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
+
+	priv = e_attachment_view_get_private (view);
+
+	return priv->target_list;
+}
+
+GdkDragAction
+e_attachment_view_get_drag_actions (EAttachmentView *view)
+{
+	EAttachmentViewPrivate *priv;
+
+	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), 0);
+
+	priv = e_attachment_view_get_private (view);
+
+	return priv->drag_actions;
+}
+
 GList *
 e_attachment_view_get_selected_attachments (EAttachmentView *view)
 {
@@ -1257,6 +1264,24 @@
 	g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
 }
 
+static void
+attachment_view_got_uris_cb (EAttachmentStore *store,
+                             GAsyncResult *result,
+                             gpointer user_data)
+{
+	struct {
+		gchar **uris;
+		gboolean done;
+	} *status = user_data;
+
+	/* XXX Since this is a best-effort function,
+	 *     should we care about errors? */
+	status->uris = e_attachment_store_get_uris_finish (
+		store, result, NULL);
+
+	status->done = TRUE;
+}
+
 void
 e_attachment_view_drag_data_get (EAttachmentView *view,
                                  GdkDragContext *context,
@@ -1264,56 +1289,65 @@
                                  guint info,
                                  guint time)
 {
-	GList *selected, *iter;
-	gchar **uris;
-	gint ii = 0;
+	EAttachmentStore *store;
+	GList *selected;
+
+	struct {
+		gchar **uris;
+		gboolean done;
+	} status;
 
 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
 	g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
 	g_return_if_fail (selection != NULL);
 
+	status.uris = NULL;
+	status.done = FALSE;
+
+	store = e_attachment_view_get_store (view);
+
 	selected = e_attachment_view_get_selected_attachments (view);
 	if (selected == NULL)
 		return;
 
-	uris = g_malloc0 (sizeof (gchar *) * (g_list_length (selected) + 1));
+	e_attachment_store_get_uris_async (
+		store, selected, (GAsyncReadyCallback)
+		attachment_view_got_uris_cb, &status);
 
-	for (iter = selected; iter != NULL; iter = iter->next) {
-		EAttachment *attachment = iter->data;
-		GFile *file;
-
-		/* FIXME Need to handle attachments with no GFile. */
-		file = e_attachment_get_file (attachment);
-		if (file == NULL)
-			continue;
+	g_list_foreach (selected, (GFunc) g_object_unref, NULL);
+	g_list_free (selected);
 
-		uris[ii++] = g_file_get_uri (file);
-	}
+	/* We can't return until we have results, so crank
+	 * the main loop until the callback gets triggered. */
+	while (!status.done)
+		if (gtk_main_iteration ())
+			break;
 
-	gtk_selection_data_set_uris (selection, uris);
+	if (status.uris != NULL)
+		gtk_selection_data_set_uris (selection, status.uris);
 
-	g_strfreev (uris);
+	g_strfreev (status.uris);
 }
 
 void
 e_attachment_view_drag_dest_set (EAttachmentView *view)
 {
+	EAttachmentViewPrivate *priv;
 	GtkTargetEntry *targets;
-	GtkTargetList *list;
 	gint n_targets;
 
 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
 
-	list = gtk_target_list_new (NULL, 0);
-	/* FIXME Add targets here... */
-	targets = gtk_target_table_new_from_list (list, &n_targets);
+	priv = e_attachment_view_get_private (view);
+
+	targets = gtk_target_table_new_from_list (
+		priv->target_list, &n_targets);
 
 	gtk_drag_dest_set (
 		GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL,
-		targets, n_targets, GDK_ACTION_COPY);
+		targets, n_targets, priv->drag_actions);
 
 	gtk_target_table_free (targets, n_targets);
-	gtk_target_list_unref (list);
 }
 
 void
@@ -1324,61 +1358,6 @@
 	gtk_drag_dest_unset (GTK_WIDGET (view));
 }
 
-void
-e_attachment_view_drag_action (EAttachmentView *view,
-                               GdkDragAction action)
-{
-	EAttachmentViewPrivate *priv;
-	GtkSelectionData *selection_data;
-	EAttachmentStore *store;
-	GdkAtom atom;
-	gchar *name;
-
-	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
-
-	priv = e_attachment_view_get_private (view);
-
-	selection_data = priv->selection_data;
-	store = e_attachment_view_get_store (view);
-	atom = gtk_selection_data_get_data_type (selection_data);
-
-	switch (priv->info) {
-		case DND_TYPE_MESSAGE_RFC822:
-			drop_message_rfc822 (
-				view, selection_data, store, action);
-			return;
-
-		case DND_TYPE_NETSCAPE_URL:
-			drop_netscape_url (
-				view, selection_data, store, action);
-			return;
-
-		case DND_TYPE_TEXT_URI_LIST:
-			drop_text_uri_list (
-				view, selection_data, store, action);
-			return;
-
-		case DND_TYPE_TEXT_VCARD:
-		case DND_TYPE_TEXT_CALENDAR:
-			drop_text_generic (
-				view, selection_data, store, action);
-			return;
-
-		case DND_TYPE_X_UID_LIST:
-			drop_x_uid_list (
-				view, selection_data, store, action);
-			return;
-
-		default:
-			name = gdk_atom_name (atom);
-			g_warning ("Unknown drag type: %s", name);
-			g_free (name);
-			break;
-	}
-
-	gtk_drag_finish (priv->drag_context, FALSE, FALSE, priv->time);
-}
-
 gboolean
 e_attachment_view_drag_motion (EAttachmentView *view,
                                GdkDragContext *context,
@@ -1386,27 +1365,20 @@
                                gint y,
                                guint time)
 {
-	GList *iter;
-	GdkDragAction actions = 0;
+	EAttachmentViewPrivate *priv;
+	GdkDragAction actions;
 	GdkDragAction chosen_action;
 
 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
 	g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE);
 
+	priv = e_attachment_view_get_private (view);
+
 	/* Disallow drops if we're not editable. */
 	if (!e_attachment_view_get_editable (view))
 		return FALSE;
 
-	for (iter = context->targets; iter != NULL; iter = iter->next) {
-		GdkAtom atom = iter->data;
-		gint ii;
-
-		for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++)
-			if (atom == drag_info[ii].atom)
-				actions |= drag_info[ii].actions;
-	}
-
-	actions &= context->actions;
+	actions = priv->drag_actions & context->actions;
 	chosen_action = context->suggested_action;
 
 	if (chosen_action == GDK_ACTION_ASK) {
@@ -1441,53 +1413,31 @@
 
 void
 e_attachment_view_drag_data_received (EAttachmentView *view,
-                                      GdkDragContext *context,
+                                      GdkDragContext *drag_context,
                                       gint x,
                                       gint y,
-                                      GtkSelectionData *selection,
+                                      GtkSelectionData *selection_data,
                                       guint info,
                                       guint time)
 {
-	EAttachmentViewPrivate *priv;
-	GtkUIManager *ui_manager;
-	GdkDragAction action;
+	GdkAtom atom;
+	gchar *name;
 
 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
-	g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
-	g_return_if_fail (selection != NULL);
-
-	priv = e_attachment_view_get_private (view);
-	ui_manager = e_attachment_view_get_ui_manager (view);
+	g_return_if_fail (GDK_IS_DRAG_CONTEXT (drag_context));
 
-	action = context->action;
+	/* Drop handlers are supposed to stop further emission of the
+	 * "drag-data-received" signal if they can handle the data.  If
+	 * we get this far it means none of the handlers were successful,
+	 * so report the drop as failed. */
 
-	if (gtk_selection_data_get_data (selection) == NULL)
-		return;
-
-	if (gtk_selection_data_get_length (selection) == -1)
-		return;
-
-	if (priv->drag_context != NULL)
-		g_object_unref (priv->drag_context);
-
-	if (priv->selection_data != NULL)
-		gtk_selection_data_free (priv->selection_data);
+	atom = gtk_selection_data_get_target (selection_data);
 
-	priv->drag_context = g_object_ref (context);
-	priv->selection_data = gtk_selection_data_copy (selection);
-	priv->info = info;
-	priv->time = time;
+	name = gdk_atom_name (atom);
+	g_warning ("Unknown selection target: %s", name);
+	g_free (name);
 
-	if (action == GDK_ACTION_ASK) {
-		GtkWidget *menu;
-
-		menu = gtk_ui_manager_get_widget (ui_manager, "/dnd");
-		g_return_if_fail (GTK_IS_MENU (menu));
-
-		gtk_menu_popup (
-			GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, time);
-	} else
-		e_attachment_view_drag_action (view, action);
+	gtk_drag_finish (drag_context, FALSE, FALSE, time);
 }
 
 GtkAction *

Modified: branches/kill-bonobo/widgets/misc/e-attachment-view.h
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment-view.h	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment-view.h	Wed Apr  1 22:58:10 2009
@@ -93,7 +93,11 @@
 struct _EAttachmentViewPrivate {
 
 	/* Attachment Handlers */
-	GList *handlers;
+	GPtrArray *handlers;
+
+	/* Drag Destination */
+	GtkTargetList *target_list;
+	GdkDragAction drag_actions;
 
 	/* Popup Menu Management */
 	GtkUIManager *ui_manager;
@@ -102,12 +106,6 @@
 	GtkActionGroup *openwith_actions;
 	guint merge_id;
 
-	/* Drag and Drop State */
-	GdkDragContext *drag_context;
-	GtkSelectionData *selection_data;
-	guint info;
-	guint time;
-
 	guint editable : 1;
 };
 
@@ -124,6 +122,10 @@
 gboolean	e_attachment_view_get_editable	(EAttachmentView *view);
 void		e_attachment_view_set_editable	(EAttachmentView *view,
 						 gboolean editable);
+GtkTargetList *	e_attachment_view_get_target_list
+						(EAttachmentView *view);
+GdkDragAction	e_attachment_view_get_drag_actions
+						(EAttachmentView *view);
 GList *		e_attachment_view_get_selected_attachments
 						(EAttachmentView *view);
 void		e_attachment_view_open_path	(EAttachmentView *view,
@@ -182,8 +184,6 @@
 void		e_attachment_view_drag_dest_set	(EAttachmentView *view);
 void		e_attachment_view_drag_dest_unset
 						(EAttachmentView *view);
-void		e_attachment_view_drag_action	(EAttachmentView *view,
-						 GdkDragAction action);
 gboolean	e_attachment_view_drag_motion	(EAttachmentView *view,
 						 GdkDragContext *context,
 						 gint x,

Modified: branches/kill-bonobo/widgets/misc/e-attachment.c
==============================================================================
--- branches/kill-bonobo/widgets/misc/e-attachment.c	(original)
+++ branches/kill-bonobo/widgets/misc/e-attachment.c	Wed Apr  1 22:58:10 2009
@@ -22,6 +22,7 @@
 #include "e-attachment.h"
 
 #include <errno.h>
+#include <config.h>
 #include <glib/gi18n.h>
 #include <camel/camel-iconv.h>
 #include <camel/camel-data-wrapper.h>
@@ -32,6 +33,7 @@
 #include <camel/camel-stream-vfs.h>
 
 #include "e-util/e-util.h"
+#include "e-util/e-mktemp.h"
 #include "e-attachment-store.h"
 
 #define E_ATTACHMENT_GET_PRIVATE(obj) \
@@ -1914,18 +1916,30 @@
 attachment_open_save_temporary (OpenContext *open_context)
 {
 	GFile *file;
+	gchar *template;
 	gchar *path;
-	gint fd;
 	GError *error = NULL;
 
-	fd = e_file_open_tmp (&path, &error);
+	errno = 0;
 
+	/* XXX This could trigger a blocking temp directory cleanup. */
+	template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ());
+	path = e_mktemp (template);
+	g_free (template);
+
+	/* XXX Let's hope errno got set properly. */
+	if (path == NULL)
+		g_set_error (
+			&error, G_FILE_ERROR,
+			g_file_error_from_errno (errno),
+			"%s", g_strerror (errno));
+
+	/* We already know if there's an error, but this does the cleanup. */
 	if (attachment_open_check_for_error (open_context, error))
 		return;
 
 	file = g_file_new_for_path (path);
 
-	close (fd);
 	g_free (path);
 
 	e_attachment_save_async (
@@ -2519,8 +2533,11 @@
 	g_return_if_fail (GTK_IS_WINDOW (parent));
 
 	file = e_attachment_save_finish (attachment, result, &error);
-	if (file != NULL)
+
+	if (file != NULL) {
 		g_object_unref (file);
+		return;
+	}
 
 	/* Ignore cancellations. */
 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))



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