aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--composer/ChangeLog10
-rw-r--r--composer/e-msg-composer.c169
2 files changed, 169 insertions, 10 deletions
diff --git a/composer/ChangeLog b/composer/ChangeLog
index 0815dbe397..a6649e0df6 100644
--- a/composer/ChangeLog
+++ b/composer/ChangeLog
@@ -1,3 +1,13 @@
+2004-10-01 Not Zed <NotZed@Ximian.com>
+
+ * e-msg-composer.c (create_composer): enable ask drop action and
+ hook onto drag motion.
+ (drag_motion): implement.
+ (drop_action): do the work here now.
+ (drag_data_received): popup a menu if the action is ask.
+ (drop_popup_copy, drop_popup_move, drop_popup_cancel):
+ (drop_popup_free): Popup callbacks.
+
2004-09-30 Kjartan Maraas <kmaraas@gnome.org>
* e-msg-composer.c: (autosave_manager_start),
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 67b3ea8f1c..e80b222f3b 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -117,6 +117,7 @@
#include "mail/mail-ops.h"
#include "mail/mail-mt.h"
#include "mail/mail-session.h"
+#include "mail/em-popup.h"
#include "e-msg-composer.h"
#include "e-msg-composer-attachment-bar.h"
@@ -161,6 +162,19 @@ static GtkTargetEntry drop_types[] = {
#define num_drop_types (sizeof (drop_types) / sizeof (drop_types[0]))
+static struct {
+ char *target;
+ GdkAtom atom;
+ guint32 actions;
+} drag_info[] = {
+ { "message/rfc822", 0, GDK_ACTION_COPY },
+ { "x-uid-list", 0, GDK_ACTION_ASK|GDK_ACTION_MOVE|GDK_ACTION_COPY },
+ { "text/uri-list", 0, GDK_ACTION_COPY },
+ { "_NETSCAPE_URL", 0, GDK_ACTION_COPY },
+ { "text/x-vcard", 0, GDK_ACTION_COPY },
+ { "text/calendar", 0, GDK_ACTION_COPY },
+};
+
static const char *emc_draft_format_names[] = { "pgp-sign", "pgp-encrypt", "smime-sign", "smime-encrypt" };
@@ -2645,10 +2659,24 @@ attach_message(EMsgComposer *composer, CamelMimeMessage *msg)
camel_object_unref(mime_part);
}
+struct _drop_data {
+ EMsgComposer *composer;
+
+ GdkDragContext *context;
+ /* Only selection->data and selection->length are valid */
+ GtkSelectionData *selection;
+
+ guint32 action;
+ guint info;
+ guint time;
+
+ unsigned int move:1;
+ unsigned int moved:1;
+ unsigned int aborted:1;
+};
+
static void
-drag_data_received (EMsgComposer *composer, GdkDragContext *context,
- int x, int y, GtkSelectionData *selection,
- guint info, guint time)
+drop_action(EMsgComposer *composer, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time)
{
char *tmp, *str, **urls;
CamelMimePart *mime_part;
@@ -2656,8 +2684,8 @@ drag_data_received (EMsgComposer *composer, GdkDragContext *context,
CamelURL *url;
CamelMimeMessage *msg;
char *content_type;
- int i;
-
+ int i, success=FALSE, delete=FALSE;
+
switch (info) {
case DND_TYPE_MESSAGE_RFC822:
d(printf ("dropping a message/rfc822\n"));
@@ -2667,8 +2695,11 @@ drag_data_received (EMsgComposer *composer, GdkDragContext *context,
camel_stream_reset (stream);
msg = camel_mime_message_new ();
- if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1)
+ if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) {
attach_message(composer, msg);
+ success = TRUE;
+ delete = action == GDK_ACTION_MOVE;
+ }
camel_object_unref(msg);
camel_object_unref(stream);
@@ -2707,6 +2738,7 @@ drag_data_received (EMsgComposer *composer, GdkDragContext *context,
}
g_free (urls);
+ success = TRUE;
break;
case DND_TYPE_TEXT_VCARD:
case DND_TYPE_TEXT_CALENDAR:
@@ -2724,6 +2756,7 @@ drag_data_received (EMsgComposer *composer, GdkDragContext *context,
camel_object_unref (mime_part);
g_free (content_type);
+ success = TRUE;
break;
case DND_TYPE_X_UID_LIST: {
GPtrArray *uids;
@@ -2788,6 +2821,8 @@ drag_data_received (EMsgComposer *composer, GdkDragContext *context,
camel_object_unref(mime_part);
camel_object_unref(mp);
}
+ success = TRUE;
+ delete = action == GDK_ACTION_MOVE;
fail:
if (camel_exception_is_set(&ex)) {
char *name;
@@ -2813,6 +2848,117 @@ drag_data_received (EMsgComposer *composer, GdkDragContext *context,
d(printf ("dropping an unknown\n"));
break;
}
+
+ printf("Drag finished, success %d delete %d\n", success, delete);
+
+ gtk_drag_finish(context, success, delete, time);
+}
+
+static void
+drop_popup_copy(EPopup *ep, EPopupItem *item, void *data)
+{
+ struct _drop_data *m = data;
+ drop_action(m->composer, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time);
+}
+
+static void
+drop_popup_move(EPopup *ep, EPopupItem *item, void *data)
+{
+ struct _drop_data *m = data;
+ drop_action(m->composer, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time);
+}
+
+static void
+drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data)
+{
+ struct _drop_data *m = data;
+ gtk_drag_finish(m->context, FALSE, FALSE, m->time);
+}
+
+static EPopupItem drop_popup_menu[] = {
+ { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "stock_mail-copy", 0 },
+ { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "stock_mail-move", 0 },
+ { E_POPUP_BAR, "10.emc" },
+ { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 },
+};
+
+static void
+drop_popup_free(EPopup *ep, GSList *items, void *data)
+{
+ struct _drop_data *m = data;
+
+ g_slist_free(items);
+
+ g_object_unref(m->context);
+ g_object_unref(m->composer);
+ g_free(m->selection->data);
+ g_free(m->selection);
+ g_free(m);
+}
+
+static void
+drag_data_received (EMsgComposer *composer, GdkDragContext *context,
+ int x, int y, GtkSelectionData *selection,
+ guint info, guint time)
+{
+ if (selection->data == NULL || selection->length == -1)
+ return;
+
+ if (context->action == GDK_ACTION_ASK) {
+ EMPopup *emp;
+ GSList *menus = NULL;
+ GtkMenu *menu;
+ int i;
+ struct _drop_data *m;
+
+ m = g_malloc0(sizeof(*m));
+ m->context = context;
+ g_object_ref(context);
+ m->composer = composer;
+ g_object_ref(composer);
+ m->action = context->action;
+ m->info = info;
+ m->time = time;
+ m->selection = g_malloc0(sizeof(*m->selection));
+ m->selection->data = g_malloc(selection->length);
+ memcpy(m->selection->data, selection->data, selection->length);
+ m->selection->length = selection->length;
+
+ emp = em_popup_new("com.ximian.mail.composer.popup.drop");
+ for (i=0;i<sizeof(drop_popup_menu)/sizeof(drop_popup_menu[0]);i++)
+ menus = g_slist_append(menus, &drop_popup_menu[i]);
+
+ e_popup_add_items((EPopup *)emp, menus, drop_popup_free, m);
+ menu = e_popup_create_menu_once((EPopup *)emp, NULL, 0, 0);
+ gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, time);
+ } else {
+ drop_action(composer, context, context->action, selection, info, time);
+ }
+}
+
+static gboolean
+drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, EMsgComposer *composer)
+{
+ GList *targets;
+ GdkDragAction action, actions = 0;
+
+ for (targets = context->targets; targets; targets = targets->next) {
+ int i;
+
+ for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
+ if (targets->data == (void *)drag_info[i].atom)
+ actions |= drag_info[i].actions;
+ }
+
+ actions &= context->actions;
+ action = context->suggested_action;
+ /* we default to copy */
+ if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY))
+ action = GDK_ACTION_COPY;
+
+ gdk_drag_status(context, action, time);
+
+ return action != 0;
}
static void
@@ -2821,6 +2967,10 @@ class_init (EMsgComposerClass *klass)
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GObjectClass *gobject_class;
+ int i;
+
+ for (i=0;i<sizeof(drag_info)/sizeof(drag_info[0]);i++)
+ drag_info[i].atom = gdk_atom_intern(drag_info[i].target, FALSE);
gobject_class = G_OBJECT_CLASS(klass);
object_class = GTK_OBJECT_CLASS (klass);
@@ -3178,10 +3328,9 @@ create_composer (int visible_mask)
}
/* DND support */
- gtk_drag_dest_set (GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL,
- drop_types, num_drop_types, GDK_ACTION_COPY);
- g_signal_connect (composer, "drag_data_received",
- G_CALLBACK (drag_data_received), NULL);
+ gtk_drag_dest_set (GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL, drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE);
+ g_signal_connect(composer, "drag_data_received", G_CALLBACK (drag_data_received), NULL);
+ g_signal_connect(composer, "drag-motion", G_CALLBACK(drag_motion), composer);
e_msg_composer_load_config (composer, visible_mask);
setup_ui (composer);