diff options
-rw-r--r-- | composer/ChangeLog | 10 | ||||
-rw-r--r-- | composer/e-msg-composer.c | 169 |
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); |