Index:sylpheed-0.8.1-dnd/src/Makefile.am *** sylpheed-0.8.1/src/Makefile.am Thu Jul 11 11:24:39 2002 --- sylpheed-0.8.1-dnd/src/Makefile.am Tue Jul 30 14:07:38 2002 *************** *** 108,114 **** manual.c manual.h \ stringtable.c stringtable.h \ quote_fmt_lex.l quote_fmt_lex.h \ ! quote_fmt_parse.y quote_fmt.h BUILT_SOURCES = \ quote_fmt_lex.c \ --- 108,115 ---- manual.c manual.h \ stringtable.c stringtable.h \ quote_fmt_lex.l quote_fmt_lex.h \ ! quote_fmt_parse.y quote_fmt.h \ ! dnd_filesel.c dnd_filesel.h BUILT_SOURCES = \ quote_fmt_lex.c \ Index:sylpheed-0.8.1-dnd/src/Makefile.in *** sylpheed-0.8.1/src/Makefile.in Thu Jul 25 07:43:33 2002 --- sylpheed-0.8.1-dnd/src/Makefile.in Tue Jul 30 14:09:40 2002 *************** *** 128,134 **** bin_PROGRAMS = sylpheed ! sylpheed_SOURCES = intl.h defs.h version.h main.c main.h mainwindow.c mainwindow.h folderview.c folderview.h summaryview.c summaryview.h messageview.c messageview.h headerview.c headerview.h textview.c textview.h imageview.c imageview.h mimeview.c mimeview.h summary_search.c summary_search.h message_search.c message_search.h colorlabel.c colorlabel.h folder.c folder.h procmsg.c procmsg.h procheader.c procheader.h filter.c filter.h compose.c compose.h gtkshruler.c gtkshruler.h gtksctree.c gtksctree.h gtkstext.c gtkstext.h menu.c menu.h stock_pixmap.c stock_pixmap.h prefs.c prefs.h prefs_common.c prefs_common.h prefs_filter.c prefs_filter.h prefs_account.c prefs_account.h prefs_folder_item.c prefs_folder_item.h prefs_display_header.c prefs_display_header.h prefs_customheader.c prefs_customheader.h prefs_summary_column.c prefs_summary_column.h prefs_template.c prefs_template.h prefs_actions.c prefs_actions.h account.c account.h displayheader.c displayheader.h customheader.c customheader.h template.c template.h addressbook.c addressbook.h addr_compl.c addr_compl.h addressitem.h addritem.c addritem.h addrcache.c addrcache.h addrbook.c addrbook.h addrindex.c addrindex.h mgutils.c mgutils.h vcard.c vcard.h ldif.c ldif.h importldif.c importldif.h jpilot.c jpilot.h syldap.c syldap.h editbook.c editbook.h editgroup.c editgroup.h editaddress.c editaddress.h editvcard.c editvcard.h editjpilot.c editjpilot.h editldap.c editldap.h editldap_basedn.c editldap_basedn.h addressadd.c addressadd.h filesel.c filesel.h foldersel.c foldersel.h statusbar.c statusbar.h logwindow.c logwindow.h sourcewindow.c sourcewindow.h manage_window.c manage_window.h undo.c undo.h alertpanel.c alertpanel.h inputdialog.c inputdialog.h progressdialog.c progressdialog.h grouplistdialog.c grouplistdialog.h about.c about.h setup.c setup.h utils.c utils.h gtkutils.c gtkutils.h codeconv.c codeconv.h unmime.c unmime.h base64.c base64.h uuencode.c uuencode.h md5.c md5.h socket.c socket.h ssl.c ssl.h automaton.c automaton.h session.c session.h smtp.c smtp.h pop.c pop.h mh.c mh.h mbox.c mbox.h send.c send.h recv.c recv.h inc.c inc.h import.c import.h export.c export.h nntp.c nntp.h news.c news.h imap.c imap.h xml.c xml.h html.c html.h procmime.c procmime.h rfc2015.c rfc2015.h passphrase.c passphrase.h select-keys.c select-keys.h sigstatus.c sigstatus.h simple-gettext.c manual.c manual.h stringtable.c stringtable.h quote_fmt_lex.l quote_fmt_lex.h quote_fmt_parse.y quote_fmt.h BUILT_SOURCES = quote_fmt_lex.c quote_fmt_parse.c quote_fmt_parse.h --- 128,134 ---- bin_PROGRAMS = sylpheed ! sylpheed_SOURCES = intl.h defs.h version.h main.c main.h mainwindow.c mainwindow.h folderview.c folderview.h summaryview.c summaryview.h messageview.c messageview.h headerview.c headerview.h textview.c textview.h imageview.c imageview.h mimeview.c mimeview.h summary_search.c summary_search.h message_search.c message_search.h colorlabel.c colorlabel.h folder.c folder.h procmsg.c procmsg.h procheader.c procheader.h filter.c filter.h compose.c compose.h gtkshruler.c gtkshruler.h gtksctree.c gtksctree.h gtkstext.c gtkstext.h menu.c menu.h stock_pixmap.c stock_pixmap.h prefs.c prefs.h prefs_common.c prefs_common.h prefs_filter.c prefs_filter.h prefs_account.c prefs_account.h prefs_folder_item.c prefs_folder_item.h prefs_display_header.c prefs_display_header.h prefs_customheader.c prefs_customheader.h prefs_summary_column.c prefs_summary_column.h prefs_template.c prefs_template.h prefs_actions.c prefs_actions.h account.c account.h displayheader.c displayheader.h customheader.c customheader.h template.c template.h addressbook.c addressbook.h addr_compl.c addr_compl.h addressitem.h addritem.c addritem.h addrcache.c addrcache.h addrbook.c addrbook.h addrindex.c addrindex.h mgutils.c mgutils.h vcard.c vcard.h ldif.c ldif.h importldif.c importldif.h jpilot.c jpilot.h syldap.c syldap.h editbook.c editbook.h editgroup.c editgroup.h editaddress.c editaddress.h editvcard.c editvcard.h editjpilot.c editjpilot.h editldap.c editldap.h editldap_basedn.c editldap_basedn.h addressadd.c addressadd.h filesel.c filesel.h foldersel.c foldersel.h statusbar.c statusbar.h logwindow.c logwindow.h sourcewindow.c sourcewindow.h manage_window.c manage_window.h undo.c undo.h alertpanel.c alertpanel.h inputdialog.c inputdialog.h progressdialog.c progressdialog.h grouplistdialog.c grouplistdialog.h about.c about.h setup.c setup.h utils.c utils.h gtkutils.c gtkutils.h codeconv.c codeconv.h unmime.c unmime.h base64.c base64.h uuencode.c uuencode.h md5.c md5.h socket.c socket.h ssl.c ssl.h automaton.c automaton.h session.c session.h smtp.c smtp.h pop.c pop.h mh.c mh.h mbox.c mbox.h send.c send.h recv.c recv.h inc.c inc.h import.c import.h export.c export.h nntp.c nntp.h news.c news.h imap.c imap.h xml.c xml.h html.c html.h procmime.c procmime.h rfc2015.c rfc2015.h passphrase.c passphrase.h select-keys.c select-keys.h sigstatus.c sigstatus.h simple-gettext.c manual.c manual.h stringtable.c stringtable.h quote_fmt_lex.l quote_fmt_lex.h quote_fmt_parse.y quote_fmt.h dnd_filesel.c dnd_filesel.h BUILT_SOURCES = quote_fmt_lex.c quote_fmt_parse.c quote_fmt_parse.h *************** *** 190,196 **** procmime.$(OBJEXT) rfc2015.$(OBJEXT) passphrase.$(OBJEXT) \ select-keys.$(OBJEXT) sigstatus.$(OBJEXT) simple-gettext.$(OBJEXT) \ manual.$(OBJEXT) stringtable.$(OBJEXT) quote_fmt_lex.$(OBJEXT) \ ! quote_fmt_parse.$(OBJEXT) sylpheed_DEPENDENCIES = sylpheed_LDFLAGS = LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ --- 190,196 ---- procmime.$(OBJEXT) rfc2015.$(OBJEXT) passphrase.$(OBJEXT) \ select-keys.$(OBJEXT) sigstatus.$(OBJEXT) simple-gettext.$(OBJEXT) \ manual.$(OBJEXT) stringtable.$(OBJEXT) quote_fmt_lex.$(OBJEXT) \ ! quote_fmt_parse.$(OBJEXT) dnd_filesel.$(OBJEXT) sylpheed_DEPENDENCIES = sylpheed_LDFLAGS = LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ Index:sylpheed-0.8.1-dnd/src/compose.c *** sylpheed-0.8.1/src/compose.c Mon Jul 15 02:51:13 2002 --- sylpheed-0.8.1-dnd/src/compose.c Tue Jul 30 14:07:38 2002 *************** *** 4866,4872 **** Compose *compose = (Compose *)data; gchar *file; ! file = filesel_select_file(_("Select file"), NULL); if (file) { compose_attach_append(compose, file, file, NULL); --- 4866,4872 ---- Compose *compose = (Compose *)data; gchar *file; ! file = filesel_select_file(_("Select file"), NULL, FALSE); if (file) { compose_attach_append(compose, file, file, NULL); *************** *** 4880,4886 **** Compose *compose = (Compose *)data; gchar *file; ! file = filesel_select_file(_("Select file"), NULL); if (file) compose_insert_file(compose, file); --- 4880,4886 ---- Compose *compose = (Compose *)data; gchar *file; ! file = filesel_select_file(_("Select file"), NULL, FALSE); if (file) compose_insert_file(compose, file); Index:sylpheed-0.8.1-dnd/src/dnd_filesel.c *** sylpheed-0.8.1/src/dnd_filesel.c Tue Jul 30 14:34:49 2002 --- sylpheed-0.8.1-dnd/src/dnd_filesel.c Tue Jul 30 14:08:10 2002 *************** *** 0 **** --- 1,982 ---- + /* + * $Id: dnd_filesel.c,v 1.4 2002/02/20 16:04:24 stephen Exp $ + * + * dnd_filesel.c - arrange for GtkFileSelection widgets to perform drag & + * drop file saving and loading. + * + * Adapted by Stephen Watson, , from code + * written by Thomas Leonard, . + */ + + /* + * We assume we have a reasonable libc and the GTK+ 1.2.10 libraries available. + * We do not use any other libraries, no matter how useful they would be... + * + * Use dnd_setup_load_sel(filesel, udata) to enable drag & drop loading for the + * file selector. Use dnd_setup_save_sel(filesel, udata) to enable drag & drop + * saving for the file selector. + * + * They work by processing the DnD protocol until the filename has been + * determined, then using gtk_file_selection_set_filename to store it and + * triggering the "clicked" event for the OK button. In each case the udata + * parameter should be the same as that for the "clicked" signal handler for + * the OK button. + * + * See test_dnd.c for an example. + */ + + #include + #include + #include + #include + + #include + + #include + + #include "dnd_filesel.h" + + /* XPM of icon to use for dragging. This is Choices/MIME-icons/text.xpm from + rox-base + */ + /* XPM */ + static char * unknown_xpm[] = { + "29 34 84 1", + " c None", + ". c #121212", + "+ c #000000", + "@ c #050505", + "# c #151515", + "$ c #030303", + "% c #FCFCFC", + "& c #F9F9F9", + "* c #F8F8F8", + "= c #FAFAFA", + "- c #FBFBFB", + "; c #F7F7F7", + "> c #FEFEFE", + ", c #F4F4F4", + "' c #D5D5D5", + ") c #0B0B0B", + "! c #060606", + "~ c #F5F5F5", + "{ c #F6F6F6", + "] c #F0F0F0", + "^ c #F3F3F3", + "/ c #E5E5E5", + "( c #C6C6C6", + "_ c #F2F2F2", + ": c #F1F1F1", + "< c #EBEBEB", + "[ c #EEEEEE", + "} c #EDEDED", + "| c #E7E7E7", + "1 c #D3D3D3", + "2 c #B4B4B4", + "3 c #070707", + "4 c #EFEFEF", + "5 c #EAEAEA", + "6 c #ECECEC", + "7 c #E6E6E6", + "8 c #CACACA", + "9 c #ABABAB", + "0 c #010101", + "a c #E9E9E9", + "b c #C8C8C8", + "c c #A9A9A9", + "d c #090909", + "e c #CDCDCD", + "f c #080808", + "g c #D0D0D0", + "h c #FDFDFD", + "i c #FFFFFF", + "j c #CECECE", + "k c #ACACAC", + "l c #AAAAAA", + "m c #040404", + "n c #E8E8E8", + "o c #CCCCCC", + "p c #CBCBCB", + "q c #E4E4E4", + "r c #A8A8A8", + "s c #E2E2E2", + "t c #C7C7C7", + "u c #A6A6A6", + "v c #E1E1E1", + "w c #E3E3E3", + "x c #C5C5C5", + "y c #A4A4A4", + "z c #0C0C0C", + "A c #A5A5A5", + "B c #020202", + "C c #E0E0E0", + "D c #DFDFDF", + "E c #C4C4C4", + "F c #DDDDDD", + "G c #D9D9D9", + "H c #DADADA", + "I c #C2C2C2", + "J c #A7A7A7", + "K c #C9C9C9", + "L c #C0C0C0", + "M c #B7B7B7", + "N c #DBDBDB", + "O c #A1A1A1", + "P c #A2A2A2", + "Q c #A3A3A3", + "R c #A0A0A0", + "S c #9D9D9D", + ".+@#$@@@@@@@@@@@@@@@@@@@@@@@@", + "@%&*=&&===&&*----====&;>=&,')", + "!%*~{;;***;;{*;;;{{{~~]~^]/($", + "!-{__,~~{{~~,,^^__::::<[}|12+", + "3-{::^,~~~~~,^^_::]]4:5<67890", + "!%;^^,~{;;;;{~~,,^_:::66}abc3", + "!%*~~{;;*&&&&**;{~,^^4[66<8cd", + "!%*{;;;*&====&&*;~,^^[_}5}ecf", + "!-*{;;;*&=--=&*;{~^^_4~454gc!", + "@%&{;*&=%h>>i&&*{~,^_]:466jk!", + "@%&{;*&-%h>>i=&*;~,^^]:466jk!", + "!%*{{&=-%h>>>==&;{~,^]:466j9!", + "!%*~{&&-%hhhh==&*{~,^4:[<flags=flags; + rdata->uris=uris; + rdata->udata=udata; + rdata->uri=NULL; + + gtk_signal_connect(GTK_OBJECT(widget), "drag_drop", + GTK_SIGNAL_FUNC(drag_drop), rdata); + gtk_signal_connect(GTK_OBJECT(widget), "drag_data_received", + GTK_SIGNAL_FUNC(drag_data_received), rdata); + } + + /* Use dnd_register_dest on the given fs. drop_for_filesel does the clever + stuff */ + void dnd_setup_load_sel(GtkWidget *fs, gpointer udata) + { + dnd_register_dest(fs, DND_DEFAULT, drop_for_filesel, udata); + do_hide(fs); + } + + /* Set up a draggable icon for saving, using XDS */ + void dnd_setup_save_sel(GtkWidget *fs, gpointer udata) + { + GtkWidget *pmap; + GtkWidget *box; + GtkWidget *vbox; + + check_init(); + + g_return_if_fail(fs!=0); + g_return_if_fail(GTK_IS_FILE_SELECTION(fs)); + + /* Make the pixmap (if needed) from the default XPM */ + if(!pixmap) { + gtk_widget_realize(fs); + make_icon_pixmap(fs, NULL); + } + + vbox=GTK_FILE_SELECTION(fs)->action_area; + + box=gtk_event_box_new(); + gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 2); + gtk_widget_show(box); + gtk_widget_add_events(box, GDK_BUTTON_PRESS_MASK); + gtk_signal_connect(GTK_OBJECT(box), "button_press_event", + GTK_SIGNAL_FUNC(press_on_icon), fs); + /*gtk_signal_connect(GTK_OBJECT(fs), "drag_end", + GTK_SIGNAL_FUNC(drag_end), fs);*/ + gtk_signal_connect(GTK_OBJECT(fs), "drag_data_get", + GTK_SIGNAL_FUNC(drag_data_get), fs); + + pmap=gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(box), pmap); + gtk_widget_show(pmap); + + gtk_object_set_data(GTK_OBJECT(fs), "dnd_icon", pmap); + gtk_object_set_data(GTK_OBJECT(fs), "dnd_user_data", udata); + + do_hide(fs); + } + + /* Set the icon to use for this filesel, based on mime type */ + void dnd_set_mime_type(GtkWidget *widget, const char *type) + { + GtkFileSelection *fs; + GtkWidget *pmap, *box; + + g_return_if_fail(GTK_IS_FILE_SELECTION(widget)); + if(!type) + return; + + /* Get the old icon. If one wasn't set, return without doing anything */ + fs=GTK_FILE_SELECTION(widget); + pmap=gtk_object_get_data(GTK_OBJECT(fs), "dnd_icon"); + if(!pmap) + return; + g_return_if_fail(GTK_IS_PIXMAP(pmap)); + + /* Make the pixmap of the new icon */ + if(!GTK_WIDGET_REALIZED(widget)) + gtk_widget_realize(widget); + make_icon_pixmap(widget, type); + + /* Remove the old icon, put the new one in its place */ + box=pmap->parent; + g_return_if_fail(GTK_IS_CONTAINER(box)); + gtk_container_remove(GTK_CONTAINER(box), pmap); + /* gtk_widget_unref(pmap); */ + pmap=gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(box), pmap); + gtk_widget_show(pmap); + gtk_object_set_data(GTK_OBJECT(fs), "dnd_icon", pmap); + } + + /* + * Private functions + */ + + /* This is the error reporting routine, customize it for the program + you are modifing */ + static void dnd_error(const char *fmt, ...) + { + gchar *message; + va_list args; + + va_start(args, fmt); + message=g_strdup_vprintf(fmt, args); + va_end(args); + + /* Deal with the message how you see fit. + By default we use g_warning and beep. + */ + g_warning(message); + gdk_beep(); + + g_free(message); + } + + /* Initialise our atoms */ + static void init(void) + { + XdndDirectSave0=gdk_atom_intern("XdndDirectSave0", FALSE); + xa_text_plain=gdk_atom_intern("text/plain", FALSE); + text_uri_list=gdk_atom_intern("text/uri-list", FALSE); + application_octet_stream=gdk_atom_intern("application/octet-stream", + FALSE); + xa_string=gdk_atom_intern ("STRING", FALSE); + + done_init=TRUE; + } + + static void do_hide(GtkWidget *widget) + { + GtkFileSelection *fs; + + g_return_if_fail(GTK_IS_FILE_SELECTION(widget)); + + fs=GTK_FILE_SELECTION(widget); + + if(hide_lists) { + gtk_file_selection_hide_fileop_buttons(fs); + + /* Need hide the scrolling window the lists are in, not just the + list itself */ + gtk_widget_hide(fs->dir_list->parent); + gtk_widget_hide(fs->file_list->parent); + + gtk_widget_hide(fs->history_pulldown); + + } else { + gtk_widget_show(fs->dir_list->parent); + gtk_widget_show(fs->file_list->parent); + + gtk_widget_show(fs->history_pulldown); + } + } + + /* Is the sender willing to supply this target type? */ + static gboolean provides(GdkDragContext *context, GdkAtom target) + { + GList *targets = context->targets; + + while (targets && ((GdkAtom) targets->data != target)) + targets = targets->next; + + return targets != NULL; + } + + static char *get_xds_prop(GdkDragContext *context) + { + guchar *prop_text; + gint length; + + if(gdk_property_get(context->source_window, + XdndDirectSave0, + xa_text_plain, + 0, MAXURILEN, + FALSE, + NULL, NULL, + &length, &prop_text) && prop_text) { + /* Terminate the string */ + prop_text = g_realloc(prop_text, length + 1); + prop_text[length] = '\0'; + return prop_text; + } + + return NULL; + } + + /* Set the XdndDirectSave0 property on the source window for this context */ + static void set_xds_prop(GdkDragContext *context, char *text) + { + gdk_property_change(context->source_window, + XdndDirectSave0, + xa_text_plain, 8, + GDK_PROP_MODE_REPLACE, + text, + strlen(text)); + } + + /* Convert a list of URIs into a list of strings. + * Lines beginning with # are skipped. + * The text block passed in is zero terminated (after the final CRLF) + */ + static GSList *uri_list_to_gslist(char *uri_list) + { + GSList *list = NULL; + + while (*uri_list) { + char *linebreak; + char *uri; + int length; + + linebreak = strchr(uri_list, 13); + + if (!linebreak || linebreak[1] != 10) { + return list; + } + + length = linebreak - uri_list; + + if (length && uri_list[0] != '#') { + uri = g_malloc(sizeof(char) * (length + 1)); + strncpy(uri, uri_list, length); + uri[length] = 0; + list = g_slist_append(list, uri); + } + + uri_list = linebreak + 2; + } + + return list; + } + + /* User has tried to drop some data on us. Decide what format we would + * like the data in. + */ + static gboolean drag_drop(GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time, gpointer data) + { + char *leafname=NULL; + static gchar *path=NULL; + GdkAtom target = GDK_NONE; + ClientData *rdata=(ClientData *) data; + + if(provides(context, XdndDirectSave0)) { + leafname = get_xds_prop(context); + if (leafname) { + gchar *uri; + char host[1025]; + + if(!path) { + path=g_strdup_printf("/tmp/xds_scrap_%d", getuid()); + mkdir(path, 0700); + } + + gethostname(host, sizeof(host)); + uri=g_strconcat("file://", host, path, "/", leafname, NULL); + set_xds_prop(context, uri); + if(rdata->uri) + g_free(rdata->uri); + rdata->uri=uri; + + /* Clean up the temp file when we exit */ + if(!tmp_fnames) + atexit(cleanup); + tmp_fnames=g_slist_prepend(tmp_fnames, + g_strconcat(path, "/", leafname, NULL)); + + target = XdndDirectSave0; + g_dataset_set_data_full(context, "leafname", leafname, g_free); + /*printf("drag drop %s %s\n", uri, leafname);*/ + } + } else if(provides(context, text_uri_list)) + target = text_uri_list; + + gtk_drag_get_data(widget, context, target, time); + + return TRUE; + } + + /* We've got a list of URIs from somewhere (probably a filer window). + * If the files are on the local machine then use the name, + */ + static void got_uri_list(GtkWidget *widget, GdkDragContext *context, + GtkSelectionData *selection_data, + guint32 time, ClientData *rdata) + { + GSList *uri_list; + char *error = NULL; + gboolean ok; + + uri_list = uri_list_to_gslist(selection_data->data); + + if (!uri_list) { + ok=FALSE; + error = "No URIs in the text/uri-list (nothing to do!)"; + } else if(rdata && rdata->uris) { + GSList *file; + + ok=TRUE; + for(file=uri_list; file; file=g_slist_next(file)) { + ok=ok && rdata->uris(widget, file->data, rdata->udata); + } + } + + if (error) { + dnd_error("Can't process URI list: %s", error); + } + gtk_drag_finish(context, ok, FALSE, time); + + g_slist_foreach(uri_list, (GFunc) g_free, NULL); + g_slist_free(uri_list); + } + + static char *dnd_get_local(const char *uri) + { + char *host; + char *end; + char hostn[256]; + const char *orig=uri; + + if(strncmp(uri, "file:", 5)==0) + uri+=5; + + if(uri[0]=='/') { + if(uri[1]!='/') + return g_strdup(uri); + if(uri[2]=='/') + return g_strdup(uri+2); + + host=(char *) uri+2; + end=strchr(host, '/'); + host=g_strndup(host, end-host); + + if(strcmp(host, "localhost")==0) { + g_free(host); + return g_strdup(end); + } + + if(gethostname(hostn, sizeof(hostn))==0 && strcmp(host, hostn)==0) { + g_free(host); + return g_strdup(end); + } + + g_free(host); + } + + return NULL; + } + + static void got_xds(GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint32 time, + ClientData *rdata) + { + char response=*selection_data->data; + gboolean saved=FALSE; + + /*printf("got_xds response=%c %d\n", response, response);*/ + switch(response) { + case 'F': + /* Sender couldn't save there - ask for another + * type if possible. + */ + if (provides(context, text_uri_list)) { + gtk_drag_get_data(widget, context, text_uri_list, time); + return; + } else { + dnd_error("Drag & drop error: sender can't provide data"); + } + break; + + case 'S': + saved=TRUE; + + if(rdata->uris) { + if(!rdata->uris(widget, rdata->uri, rdata->udata)) + saved=FALSE; + } + break; + + case 'E': + break; + + default: + dnd_error("XDS protocol error, '%c' should be S, F or E", response); + break; + } + + if(!saved) + gtk_drag_finish(context, FALSE, FALSE, time); + else + gtk_drag_finish(context, TRUE, FALSE, time); + } + + /* Called when some data arrives from the remote app (which we asked for + * in drag_drop). + */ + static void drag_data_received(GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint32 time, + gpointer user_data) + { + if (!selection_data->data) { + /* Timeout? */ + gtk_drag_finish(context, FALSE, FALSE, time); /* Failure */ + return; + } + + switch(info) { + case TARGET_XDS: + got_xds(widget, context, selection_data, time, (ClientData *) user_data); + break; + case TARGET_URI_LIST: + got_uri_list(widget, context, selection_data, time, + (ClientData *) user_data); + break; + default: + dnd_error("drag_data_received: unknown target %u", info); + gtk_drag_finish(context, FALSE, FALSE, time); + break; + } + } + + static int drop_for_filesel(GtkWidget* widget, + const char *uri, + void *udata) + { + char *local; + + local=dnd_get_local(uri); + /*printf("%s %s\n", uri, local? local: "(NULL)");*/ + if(local) { + gboolean state=FALSE; + + if(GTK_IS_FILE_SELECTION(widget)) { + gtk_file_selection_set_filename(GTK_FILE_SELECTION (widget), local); + gtk_signal_emit_by_name(GTK_OBJECT(GTK_FILE_SELECTION(widget)->ok_button), + "clicked", udata); + state=TRUE; + } + + g_free(local); + + return state; + } else { + dnd_error("Cannot handle non-local URI's (%s)", uri); + } + + return FALSE; + } + + /* This is where we act as the source */ + static void make_icon_pixmap(GtkWidget *window, const char *mime_type) + { + GtkStyle *style; + gchar *xpm_file; + + style=gtk_widget_get_style(window); + + if(pixmap) { + gdk_pixmap_unref(pixmap); + gdk_bitmap_unref(mask); + pixmap=NULL; + } + + xpm_file=find_xpm_for_mime_type(mime_type); + if(xpm_file) { + pixmap=gdk_pixmap_create_from_xpm(GTK_WIDGET(window)->window, &mask, + &style->bg[GTK_STATE_NORMAL], + xpm_file); + g_free(xpm_file); + } + + if(!pixmap) { + pixmap=gdk_pixmap_create_from_xpm_d(GTK_WIDGET(window)->window, &mask, + &style->bg[GTK_STATE_NORMAL], + (gchar **) unknown_xpm); + } + } + + static void press_on_icon(GtkWidget *ebox, GdkEventButton *ev, + GtkFileSelection *fs) + { + gchar *path, *leaf; + GdkDragContext *context; + GtkWidget *icon; + GtkTargetEntry targent[] = { + {"XdndDirectSave0", 0, MY_XDS_TARGET}, + /*{"text/uri-list", 0, MY_XDND_TARGET}*/ + }; + + if(!targets) { + targets=gtk_target_list_new(targent, sizeof(targent)/sizeof(*targent)); + } + + path=gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs)); + leaf=strrchr(path, '/'); + if(leaf) + leaf++; + else + leaf=path; + leaf=g_strdup(leaf); + + context=gtk_drag_begin(GTK_WIDGET(fs), targets, GDK_ACTION_COPY, + ev->button, (GdkEvent *) ev); + icon=GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(fs), "dnd_icon")); + gtk_drag_set_icon_pixmap(context, gtk_widget_get_colormap(icon), + pixmap, mask, ev->x, ev->y); + + gdk_property_change(context->source_window, XdndDirectSave0, + xa_text_plain, 8, GDK_PROP_MODE_REPLACE, + leaf, strlen(leaf)); + } + + static void drag_end(GtkWidget *widget, GdkDragContext *context, + GtkFileSelection *fs) + { + GList *targets; + + for(targets=context->targets; targets; targets=g_list_next(targets)) { + GdkAtom atom=(GdkAtom) targets->data; + gchar *name=gdk_atom_name(atom); + + /* Do something? */ + + g_free(name); + } + } + + static void drag_data_get(GtkWidget *widget, GdkDragContext *context, + GtkSelectionData *data, guint info, guint time, + GtkFileSelection *fs) + { + GList *targets; + gchar *name; + GdkAtom prop; + gint format, length; + guchar *cdata=NULL; + char xds_reply='E'; + gpointer udata; + + udata=gtk_object_get_data(GTK_OBJECT(fs), "dnd_user_data"); + + if(gdk_property_get(context->source_window, XdndDirectSave0, xa_text_plain, + 0, 1024, FALSE, &prop, &format, &length, &cdata)) { + if(cdata && format==8) + cdata[length]=0; + name=gdk_atom_name(prop); + /*printf("drag_data_get name=%s cdata=%p %s\n", name, cdata, + cdata? (char *) cdata: "");*/ + + if(cdata && format==8 && strncmp(cdata, "file://", 7)==0) { + char *path; + char *sep; + + path=dnd_get_local(cdata); + + if(!path) { + xds_reply='F'; + } else { + gtk_file_selection_set_filename(GTK_FILE_SELECTION (fs), path); + gtk_signal_emit_by_name(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), + "clicked", udata); + xds_reply='S'; + g_free(path); + } + } + g_free(name); + g_free(cdata); + } + + gtk_selection_data_set(data, xa_string, 8, &xds_reply, 1); + } + + static gchar *find_xpm_for_mime_type(const char *mime_type) + { + gchar *fname=NULL; + gchar **tok, *leaf=NULL; + + if(!mime_type) + return NULL; + + tok=g_strsplit(mime_type, "/", 3); + if(tok[2] && tok[2][0]) { + g_strfreev(tok); + return NULL; + } + + if(tok[1] && tok[1][0]) { + leaf=g_strconcat(tok[0], "_", tok[1], ".xpm", NULL); + fname=choices_find_path_load(leaf, "MIME-icons"); + g_free(leaf); + } + if(!fname && tok[0] && tok[0][0]) { + leaf=g_strconcat(tok[0], ".xpm", NULL); + fname=choices_find_path_load(leaf, "MIME-icons"); + g_free(leaf); + } + + g_strfreev(tok); + return fname; + } + + static void cleanup(void) + { + while(tmp_fnames) { + unlink((const char *) tmp_fnames->data); + tmp_fnames=g_slist_next(tmp_fnames); + } + } + + /* Short choices implementation */ + static gchar **dir_list = NULL; + + /* Reads in CHOICESPATH and constructs the directory list table. + * You must call this before using any other choices_* functions. + * + * If CHOICESPATH does not exist then a suitable default is used. + */ + static void choices_init(void) + { + char *choices; + + if(dir_list) + return; + + choices = getenv("CHOICESPATH"); + + if (choices) + { + while (*choices == ':') + choices++; + + if (*choices == '\0') + { + dir_list = g_new(char *, 1); + dir_list[0] = NULL; + } + else + dir_list = g_strsplit(choices, ":", 0); + } + else + { + dir_list = g_new(gchar *, 4); + dir_list[0] = g_strconcat(getenv("HOME"), "/Choices", NULL); + dir_list[1] = g_strdup("/usr/local/share/Choices"); + dir_list[2] = g_strdup("/usr/share/Choices"); + dir_list[3] = NULL; + } + + } + + /* Get the pathname of a choices file to load. Eg: + * + * choices_find_path_load("menus", "ROX-Filer") + * -> "/usr/local/share/Choices/ROX-Filer/menus". + * + * The return values may be NULL - use built-in defaults - otherwise + * g_free() the result. + */ + gchar *choices_find_path_load(const char *leaf, const char *dir) + { + gchar **cdir; + + if(!dir_list) + choices_init(); + + cdir = dir_list; + + while (*cdir) + { + gchar *path; + + path = g_strconcat(*cdir, "/", dir, "/", leaf, NULL); + + if (exists(path)) + return path; + + g_free(path); + + cdir++; + } + + return NULL; + } + + /* Returns TRUE if the object exists, FALSE if it doesn't */ + static gboolean exists(const char *path) + { + struct stat info; + + return stat(path, &info) == 0; + } + + + /* + * $Log: dnd_filesel.c,v $ + * Revision 1.4 2002/02/20 16:04:24 stephen + * Allow for use by C++ + * Tidy up temp files on exit. + * + * Revision 1.3 2002/02/01 12:53:50 stephen + * Incorporated some suggestions from rox-devel. + * Call this release 0.1.1 + * + */ + Index:sylpheed-0.8.1-dnd/src/dnd_filesel.h *** sylpheed-0.8.1/src/dnd_filesel.h Tue Jul 30 14:34:51 2002 --- sylpheed-0.8.1-dnd/src/dnd_filesel.h Tue Jul 30 14:08:10 2002 *************** *** 0 **** --- 1,78 ---- + /* + * $Id: dnd_filesel.h,v 1.4 2002/02/20 16:04:24 stephen Exp $ + * + * Adapted by Stephen Watson, , from code + * written by Thomas Leonard, . + */ + + #ifndef _dnd_filesel_h + #define _dnd_filesel_h + + #ifdef __cplusplus + extern "C" { + #endif + + /* + * We assume we have a reasonable libc and the GTK+ 1.2.10 libraries available. + * We do not use any other libraries, no matter how useful they would be... + * + * Use dnd_setup_load_sel(filesel, udata) to enable drag & drop loading for the + * file selector. Use dnd_setup_save_sel(filesel, udata) to enable drag & drop + * saving for the file selector. + * + * They work by processing the DnD protocol until the filename has been + * determined, then using gtk_file_selection_set_filename to store it and + * triggering the "clicked" event for the OK button. In each case the udata + * parameter should be the same as that for the "clicked" signal handler for + * the OK button. + * + * See test_dnd.c for an example. + */ + + /* Flags for dnd_register_dest */ + #define DND_DEFAULT 0u /* Standard options */ + #define DND_ALLOW_MOVE 1u /* The file can be moved */ + + /* + * Function which responds to drop on a widget by processing a URI. + * Return TRUE if handled successfully, FALSE otherwise. + * May get called multiple times if multiple file drops + */ + typedef int (*dnd_handle_uri)(GtkWidget* widget, + const char *uri, + gpointer udata); + + /* Register a widget to handle a drop */ + extern void dnd_register_dest(GtkWidget* widget, unsigned int flags, + dnd_handle_uri, gpointer udata); + + /* Set up a GtkFileSelection to handle drops. udata is the value to pass as + the second parameter to the OK button's clicked signal */ + extern void dnd_setup_load_sel(GtkWidget *fs, gpointer udata); + extern void dnd_setup_save_sel(GtkWidget *fs, gpointer udata); + + /* If hide is true then the widget's file lists are hidden when + dnd_setup_load_sel or dnd_setup_save_sel is called */ + extern void dnd_hide_file_lists(gboolean hide); + + /* Set the icon to use for saving by specifing the mime type. Call it + after dnd_setup_save_sel, but before showing the widget */ + extern void dnd_set_mime_type(GtkWidget *fs, const char *type); + + #ifdef __cplusplus + } + #endif + + #endif + + /* + * $Log: dnd_filesel.h,v $ + * Revision 1.4 2002/02/20 16:04:24 stephen + * Allow for use by C++ + * Tidy up temp files on exit. + * + * Revision 1.3 2002/02/01 12:53:50 stephen + * Incorporated some suggestions from rox-devel. + * Call this release 0.1.1 + * + */ Index:sylpheed-0.8.1-dnd/src/export.c *** sylpheed-0.8.1/src/export.c Fri Apr 5 04:09:20 2002 --- sylpheed-0.8.1-dnd/src/export.c Tue Jul 30 14:07:38 2002 *************** *** 216,222 **** { gchar *filename; ! filename = filesel_select_file(_("Select exporting file"), NULL); if (filename) gtk_entry_set_text(GTK_ENTRY(file_entry), filename); } --- 216,223 ---- { gchar *filename; ! filename = filesel_select_file(_("Select exporting file"), NULL, ! TRUE); if (filename) gtk_entry_set_text(GTK_ENTRY(file_entry), filename); } Index:sylpheed-0.8.1-dnd/src/filesel.c *** sylpheed-0.8.1/src/filesel.c Tue Jun 4 04:43:04 2002 --- sylpheed-0.8.1-dnd/src/filesel.c Tue Jul 30 14:07:38 2002 *************** *** 30,35 **** --- 30,37 ---- #include "manage_window.h" #include "gtkutils.h" + #include "dnd_filesel.h" + static GtkWidget *filesel; static gboolean filesel_ack; *************** *** 39,45 **** static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data); static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data); ! gchar *filesel_select_file(const gchar *title, const gchar *file) { static gchar *filename = NULL; static gchar *cwd = NULL; --- 41,48 ---- static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data); static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data); ! gchar *filesel_select_file(const gchar *title, const gchar *file, ! gboolean is_save) { static gchar *filename = NULL; static gchar *cwd = NULL; *************** *** 66,71 **** --- 69,80 ---- 0, -1); } + if(is_save) { + dnd_setup_save_sel(filesel, NULL); + dnd_set_mime_type(filesel, "text/plain"); + } else + dnd_setup_load_sel(filesel, NULL); + gtk_widget_show(filesel); gtk_main(); Index:sylpheed-0.8.1-dnd/src/filesel.h *** sylpheed-0.8.1/src/filesel.h Mon Sep 25 16:25:46 2000 --- sylpheed-0.8.1-dnd/src/filesel.h Tue Jul 30 14:07:38 2002 *************** *** 22,27 **** #include ! gchar *filesel_select_file(const gchar *title, const gchar *file); #endif /* __FILESEL_H__ */ --- 22,28 ---- #include ! gchar *filesel_select_file(const gchar *title, const gchar *file, ! gboolean is_save); #endif /* __FILESEL_H__ */ Index:sylpheed-0.8.1-dnd/src/import.c *** sylpheed-0.8.1/src/import.c Fri Apr 5 04:41:02 2002 --- sylpheed-0.8.1-dnd/src/import.c Tue Jul 30 14:07:38 2002 *************** *** 221,227 **** { gchar *filename; ! filename = filesel_select_file(_("Select importing file"), NULL); if (filename) gtk_entry_set_text(GTK_ENTRY(file_entry), filename); } --- 221,228 ---- { gchar *filename; ! filename = filesel_select_file(_("Select importing file"), NULL, ! FALSE); if (filename) gtk_entry_set_text(GTK_ENTRY(file_entry), filename); } Index:sylpheed-0.8.1-dnd/src/mimeview.c *** sylpheed-0.8.1/src/mimeview.c Mon May 27 06:15:07 2002 --- sylpheed-0.8.1-dnd/src/mimeview.c Tue Jul 30 14:07:38 2002 *************** *** 795,801 **** subst_for_filename(defname); } ! filename = filesel_select_file(_("Save as"), defname); if (!filename) return; if (is_file_exist(filename)) { AlertValue aval; --- 795,801 ---- subst_for_filename(defname); } ! filename = filesel_select_file(_("Save as"), defname, TRUE); if (!filename) return; if (is_file_exist(filename)) { AlertValue aval; Index:sylpheed-0.8.1-dnd/src/summaryview.c *** sylpheed-0.8.1/src/summaryview.c Fri Jun 28 08:40:41 2002 --- sylpheed-0.8.1-dnd/src/summaryview.c Tue Jul 30 14:07:38 2002 *************** *** 2631,2637 **** Xstrdup_a(filename, msginfo->subject, return); subst_for_filename(filename); } ! dest = filesel_select_file(_("Save as"), filename); if (!dest) return; if (is_file_exist(dest)) { AlertValue aval; --- 2631,2637 ---- Xstrdup_a(filename, msginfo->subject, return); subst_for_filename(filename); } ! dest = filesel_select_file(_("Save as"), filename, TRUE); if (!dest) return; if (is_file_exist(dest)) { AlertValue aval;