X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkfilesel.c;h=902272b14e4e426e708009acf89cd4b78230acb0;hb=06b4ef65174e56e766e4bde06e08e34c08788272;hp=6da7f1eb23295a84e734e40d88bfc0201c04160e;hpb=7ad364135340a4f685c1a286589d2c90ce4f757d;p=~andy%2Fgtk diff --git a/gtk/gtkfilesel.c b/gtk/gtkfilesel.c index 6da7f1eb2..902272b14 100644 --- a/gtk/gtkfilesel.c +++ b/gtk/gtkfilesel.c @@ -44,6 +44,9 @@ #ifdef HAVE_PWD_H #include #endif +#ifdef HAVE_WINSOCK_H +#include /* For gethostname */ +#endif #include "fnmatch.h" @@ -68,6 +71,8 @@ #include "gtkdialog.h" #include "gtkmessagedialog.h" #include "gtkintl.h" +#include "gtkdnd.h" +#include "gtkeventbox.h" #if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN) #define STRICT @@ -238,7 +243,7 @@ enum { static CompletionState* cmpl_init_state (void); static void cmpl_free_state (CompletionState *cmpl_state); static gint cmpl_state_okay (CompletionState* cmpl_state); -static gchar* cmpl_strerror (gint); +static const gchar* cmpl_strerror (gint); static PossibleCompletion* cmpl_completion_matches(gchar *text_to_complete, gchar **remaining_text, @@ -291,7 +296,7 @@ static gint cmpl_last_valid_char (CompletionState* cmpl_state) /* When the user selects a non-directory, call cmpl_completion_fullname * to get the full name of the selected file. */ -static gchar* cmpl_completion_fullname (gchar*, CompletionState* cmpl_state); +static gchar* cmpl_completion_fullname (const gchar*, CompletionState* cmpl_state); /* Directory operations. */ @@ -306,7 +311,7 @@ static gboolean check_dir (gchar *dir_name, static CompletionDir* open_dir (gchar* dir_name, CompletionState* cmpl_state); #ifdef HAVE_PWD_H -static CompletionDir* open_user_dir (gchar* text_to_complete, +static CompletionDir* open_user_dir (const gchar* text_to_complete, CompletionState *cmpl_state); #endif static CompletionDir* open_relative_dir (gchar* dir_name, CompletionDir* dir, @@ -353,6 +358,7 @@ static void gtk_file_selection_get_property (GObject *object, GValue *value, GParamSpec *pspec); static void gtk_file_selection_init (GtkFileSelection *filesel); +static void gtk_file_selection_finalize (GObject *object); static void gtk_file_selection_destroy (GtkObject *object); static gint gtk_file_selection_key_press (GtkWidget *widget, GdkEventKey *event, @@ -493,6 +499,7 @@ gtk_file_selection_class_init (GtkFileSelectionClass *class) parent_class = gtk_type_class (GTK_TYPE_DIALOG); + gobject_class->finalize = gtk_file_selection_finalize; gobject_class->set_property = gtk_file_selection_set_property; gobject_class->get_property = gtk_file_selection_get_property; @@ -588,6 +595,7 @@ gtk_file_selection_init (GtkFileSelection *filesel) GtkWidget *confirm_area; GtkWidget *pulldown_hbox; GtkWidget *scrolled_win; + GtkWidget *eventbox; GtkDialog *dialog; char *dir_title [2]; @@ -678,25 +686,28 @@ gtk_file_selection_init (GtkFileSelection *filesel) /* The OK button */ filesel->ok_button = gtk_dialog_add_button (dialog, - GTK_STOCK_BUTTON_OK, + GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_widget_grab_default (filesel->ok_button); /* The Cancel button */ filesel->cancel_button = gtk_dialog_add_button (dialog, - GTK_STOCK_BUTTON_CANCEL, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); /* The selection entry widget */ entry_vbox = gtk_vbox_new (FALSE, 2); gtk_box_pack_end (GTK_BOX (filesel->main_vbox), entry_vbox, FALSE, FALSE, 2); gtk_widget_show (entry_vbox); - + + eventbox = gtk_event_box_new (); filesel->selection_text = label = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (entry_vbox), label, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (eventbox), label); + gtk_box_pack_start (GTK_BOX (entry_vbox), eventbox, FALSE, FALSE, 0); gtk_widget_show (label); + gtk_widget_show (eventbox); filesel->selection_entry = gtk_entry_new (); gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "key_press_event", @@ -728,6 +739,224 @@ gtk_file_selection_init (GtkFileSelection *filesel) gtk_widget_grab_focus (filesel->selection_entry); } +static gchar * +uri_list_extract_first_uri (const gchar* uri_list) +{ + const gchar *p, *q; + + g_return_val_if_fail (uri_list != NULL, NULL); + + p = uri_list; + /* We don't actually try to validate the URI according to RFC + * 2396, or even check for allowed characters - we just ignore + * comments and trim whitespace off the ends. We also + * allow LF delimination as well as the specified CRLF. + * + * We do allow comments like specified in RFC 2483. + */ + while (p) + { + if (*p != '#') + { + while (g_ascii_isspace(*p)) + p++; + + q = p; + while (*q && (*q != '\n') && (*q != '\r')) + q++; + + if (q > p) + { + q--; + while (q > p && g_ascii_isspace (*q)) + q--; + + if (q > p) + return g_strndup (p, q - p + 1); + } + } + p = strchr (p, '\n'); + if (p) + p++; + } + return NULL; +} + +static void +dnd_really_drop (GtkWidget *dialog, gint response_id, GtkFileSelection *fs) +{ + gchar *filename; + + if (response_id == GTK_RESPONSE_YES) + { + filename = g_object_get_data (G_OBJECT (dialog), "gtk-fs-dnd-filename"); + + gtk_file_selection_set_filename (fs, filename); + } + + gtk_widget_destroy (dialog); +} + + +static void +filenames_dropped (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time) +{ + char *uri = NULL; + char *filename = NULL; + char *hostname; + char this_hostname[257]; + int res; + GError *error = NULL; + + if (!selection_data->data) + return; + + uri = uri_list_extract_first_uri ((char *)selection_data->data); + + if (!uri) + return; + + filename = g_filename_from_uri (uri, &hostname, &error); + g_free (uri); + + if (!filename) + { + g_warning ("Error getting dropped filename: %s\n", + error->message); + g_error_free (error); + return; + } + + res = gethostname (this_hostname, 256); + this_hostname[256] = 0; + + if ((hostname == NULL) || + (res == 0 && strcmp (hostname, this_hostname) == 0) || + (strcmp (hostname, "localhost") == 0)) + gtk_file_selection_set_filename (GTK_FILE_SELECTION (widget), + filename); + else + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (widget), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + _("The file \"%s\" resides on another machine (called %s) and may not be availible to this program.\n" + "Are you sure that you want to select it?"), filename, hostname); + + g_object_set_data_full (G_OBJECT (dialog), "gtk-fs-dnd-filename", g_strdup (filename), g_free); + + g_signal_connect_data (dialog, "response", + (GCallback) dnd_really_drop, + widget, NULL, 0); + + gtk_widget_show (dialog); + } + + g_free (hostname); + g_free (filename); +} + +enum +{ + TARGET_URILIST, + TARGET_UTF8_STRING, + TARGET_STRING, + TARGET_TEXT, + TARGET_COMPOUND_TEXT +}; + + +static void +filenames_drag_get (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint time, + GtkFileSelection *filesel) +{ + const gchar *file; + gchar *uri_list; + char hostname[256]; + int res; + GError *error; + + file = gtk_file_selection_get_filename (filesel); + + if (file) + { + if (info == TARGET_URILIST) + { + res = gethostname (hostname, 256); + + error = NULL; + uri_list = g_filename_to_uri (file, (!res)?hostname:NULL, &error); + if (!uri_list) + { + g_warning ("Error getting filename: %s\n", + error->message); + g_error_free (error); + return; + } + + gtk_selection_data_set (selection_data, + selection_data->target, 8, + (void *)uri_list, strlen((char *)uri_list)); + g_free (uri_list); + } + else + { + g_print ("Setting text: '%s'\n", file); + gtk_selection_data_set_text (selection_data, file); + } + } +} + +static void +file_selection_setup_dnd (GtkFileSelection *filesel) +{ + GtkWidget *eventbox; + static GtkTargetEntry drop_types[] = { + { "text/uri-list", 0, TARGET_URILIST} + }; + static gint n_drop_types = sizeof(drop_types)/sizeof(drop_types[0]); + static GtkTargetEntry drag_types[] = { + { "text/uri-list", 0, TARGET_URILIST}, + { "UTF8_STRING", 0, TARGET_UTF8_STRING }, + { "STRING", 0, 0 }, + { "TEXT", 0, 0 }, + { "COMPOUND_TEXT", 0, 0 } + }; + static gint n_drag_types = sizeof(drag_types)/sizeof(drag_types[0]); + + gtk_drag_dest_set (GTK_WIDGET (filesel), + GTK_DEST_DEFAULT_ALL, + drop_types, n_drop_types, + GDK_ACTION_COPY); + + gtk_signal_connect (GTK_OBJECT(filesel), "drag_data_received", + GTK_SIGNAL_FUNC(filenames_dropped), NULL); + + eventbox = gtk_widget_get_parent (filesel->selection_text); + gtk_drag_source_set (eventbox, + GDK_BUTTON1_MASK, + drag_types, n_drag_types, + GDK_ACTION_COPY); + + gtk_signal_connect (GTK_OBJECT (eventbox), + "drag_data_get", + GTK_SIGNAL_FUNC (filenames_drag_get), + filesel); +} + GtkWidget* gtk_file_selection_new (const gchar *title) { @@ -737,13 +966,14 @@ gtk_file_selection_new (const gchar *title) gtk_window_set_title (GTK_WINDOW (filesel), title); gtk_dialog_set_has_separator (GTK_DIALOG (filesel), FALSE); + file_selection_setup_dnd (filesel); + return GTK_WIDGET (filesel); } void gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel) { - g_return_if_fail (filesel != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); /* delete, create directory, and rename */ @@ -786,7 +1016,6 @@ gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel) void gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel) { - g_return_if_fail (filesel != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); if (filesel->fileop_ren_file) @@ -818,7 +1047,6 @@ gtk_file_selection_set_filename (GtkFileSelection *filesel, gchar *buf; const char *name, *last_slash; - g_return_if_fail (filesel != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); g_return_if_fail (filename != NULL); @@ -862,9 +1090,8 @@ gtk_file_selection_get_filename (GtkFileSelection *filesel) static gchar nothing[2] = ""; static gchar something[MAXPATHLEN*2]; char *sys_filename; - char *text; + const char *text; - g_return_val_if_fail (filesel != NULL, nothing); g_return_val_if_fail (GTK_IS_FILE_SELECTION (filesel), nothing); #ifdef G_WITH_CYGWIN @@ -888,7 +1115,6 @@ void gtk_file_selection_complete (GtkFileSelection *filesel, const gchar *pattern) { - g_return_if_fail (filesel != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (filesel)); g_return_if_fail (pattern != NULL); @@ -937,6 +1163,14 @@ gtk_file_selection_destroy (GtkObject *object) GTK_OBJECT_CLASS (parent_class)->destroy (object); } +static void +gtk_file_selection_finalize (GObject *object) +{ + GtkFileSelection *filesel = GTK_FILE_SELECTION (object); + + g_free (filesel->fileop_file); +} + /* Begin file operations callbacks */ static void @@ -972,7 +1206,6 @@ gtk_file_selection_fileop_destroy (GtkWidget *widget, { GtkFileSelection *fs = data; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); fs->fileop_dialog = NULL; @@ -984,7 +1217,7 @@ gtk_file_selection_create_dir_confirmed (GtkWidget *widget, gpointer data) { GtkFileSelection *fs = data; - gchar *dirname; + const gchar *dirname; gchar *path; gchar *full_path; gchar *sys_full_path; @@ -992,7 +1225,6 @@ gtk_file_selection_create_dir_confirmed (GtkWidget *widget, GError *error = NULL; CompletionState *cmpl_state; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); dirname = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); @@ -1038,7 +1270,6 @@ gtk_file_selection_create_dir (GtkWidget *widget, GtkWidget *vbox; GtkWidget *button; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); if (fs->fileop_dialog) @@ -1112,7 +1343,6 @@ gtk_file_selection_delete_file_confirmed (GtkWidget *widget, GError *error = NULL; gchar *buf; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); cmpl_state = (CompletionState*) fs->cmpl_state; @@ -1159,10 +1389,9 @@ gtk_file_selection_delete_file (GtkWidget *widget, GtkWidget *vbox; GtkWidget *button; GtkWidget *dialog; - gchar *filename; + const gchar *filename; gchar *buf; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); if (fs->fileop_dialog) @@ -1176,7 +1405,8 @@ gtk_file_selection_delete_file (GtkWidget *widget, if (strlen (filename) < 1) return; - fs->fileop_file = filename; + g_free (fs->fileop_file); + fs->fileop_file = g_strdup (filename); /* main dialog */ fs->fileop_dialog = dialog = gtk_dialog_new (); @@ -1234,7 +1464,7 @@ gtk_file_selection_rename_file_confirmed (GtkWidget *widget, { GtkFileSelection *fs = data; gchar *buf; - gchar *file; + const gchar *file; gchar *path; gchar *new_filename; gchar *old_filename; @@ -1243,7 +1473,6 @@ gtk_file_selection_rename_file_confirmed (GtkWidget *widget, CompletionState *cmpl_state; GError *error = NULL; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); file = gtk_entry_get_text (GTK_ENTRY (fs->fileop_entry)); @@ -1312,13 +1541,13 @@ gtk_file_selection_rename_file (GtkWidget *widget, GtkWidget *button; gchar *buf; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); if (fs->fileop_dialog) return; - fs->fileop_file = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); + g_free (fs->fileop_file); + fs->fileop_file = g_strdup (gtk_entry_get_text (GTK_ENTRY (fs->selection_entry))); if (strlen (fs->fileop_file) < 1) return; @@ -1416,15 +1645,15 @@ gtk_file_selection_key_press (GtkWidget *widget, g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (event != NULL, FALSE); - if (event->keyval == GDK_Tab) + if (event->keyval == GDK_Tab || + event->keyval == GDK_ISO_Left_Tab || + event->keyval == GDK_KP_Tab) { fs = GTK_FILE_SELECTION (user_data); #ifdef G_WITH_CYGWIN translate_win32_path (fs); #endif - text = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry)); - - text = g_strdup (text); + text = g_strdup (gtk_entry_get_text (GTK_ENTRY (fs->selection_entry))); gtk_file_selection_populate (fs, text, TRUE); @@ -1445,7 +1674,6 @@ gtk_file_selection_history_callback (GtkWidget *widget, HistoryCallbackArg *callback_arg; GList *list; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); list = fs->history_list; @@ -1474,7 +1702,6 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs, gint dir_len; gint i; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); g_return_if_fail (current_directory != NULL); @@ -1558,7 +1785,6 @@ gtk_file_selection_file_button (GtkWidget *widget, g_return_if_fail (GTK_IS_CLIST (widget)); fs = user_data; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); gtk_clist_get_text (GTK_CLIST (fs->file_list), row, 0, &temp); @@ -1566,12 +1792,13 @@ gtk_file_selection_file_button (GtkWidget *widget, #ifdef G_WITH_CYGWIN /* Check to see if the selection was a drive selector */ - if (isalpha (filename[0]) && (filename[1] == ':')) { - /* It is... map it to a CYGWIN32 drive */ - gchar *temp_filename = g_strdup_printf ("//%c/", tolower (filename[0])); - g_free(filename); - filename = temp_filename; - } + if (isalpha (filename[0]) && (filename[1] == ':')) + { + /* It is... map it to a CYGWIN32 drive */ + gchar *temp_filename = g_strdup_printf ("//%c/", tolower (filename[0])); + g_free(filename); + filename = temp_filename; + } #endif /* G_WITH_CYGWIN */ if (filename) @@ -1607,7 +1834,6 @@ gtk_file_selection_dir_button (GtkWidget *widget, g_return_if_fail (GTK_IS_CLIST (widget)); fs = GTK_FILE_SELECTION (user_data); - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); gtk_clist_get_text (GTK_CLIST (fs->dir_list), row, 0, &temp); @@ -1692,7 +1918,6 @@ gtk_file_selection_populate (GtkFileSelection *fs, gint possible_count = 0; gint selection_index = -1; - g_return_if_fail (fs != NULL); g_return_if_fail (GTK_IS_FILE_SELECTION (fs)); cmpl_state = (CompletionState*) fs->cmpl_state; @@ -1866,7 +2091,7 @@ cmpl_last_valid_char (CompletionState *cmpl_state) } static gchar* -cmpl_completion_fullname (gchar *text, +cmpl_completion_fullname (const gchar *text, CompletionState *cmpl_state) { static char nothing[2] = ""; @@ -2277,7 +2502,7 @@ open_ref_dir (gchar *text_to_complete, /* open a directory by user name */ static CompletionDir* -open_user_dir (gchar *text_to_complete, +open_user_dir (const gchar *text_to_complete, CompletionState *cmpl_state) { CompletionDir *result; @@ -2296,11 +2521,9 @@ open_user_dir (gchar *text_to_complete, if (!cmp_len) { /* ~/ */ - gchar *homedir = g_get_home_dir (); + const gchar *homedir = g_get_home_dir (); gchar *utf8_homedir = g_filename_to_utf8 (homedir, -1, NULL, NULL, NULL); - g_free (homedir); - if (utf8_homedir) result = open_dir (utf8_homedir, cmpl_state); else @@ -3282,7 +3505,7 @@ cmpl_state_okay (CompletionState* cmpl_state) return cmpl_state && cmpl_state->reference_dir; } -static gchar* +static const gchar* cmpl_strerror (gint err) { if (err == CMPL_ERRNO_TOO_LONG)