#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h> /* For gethostname */
+#endif
#include "fnmatch.h"
#include "gtklistitem.h"
#include "gtkmain.h"
#include "gtkscrolledwindow.h"
+#include "gtkstock.h"
#include "gtksignal.h"
#include "gtkvbox.h"
#include "gtkmenu.h"
#include "gtkoptionmenu.h"
#include "gtkclist.h"
#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
#define FILE_LIST_WIDTH 180
#define FILE_LIST_HEIGHT 180
+/* The Hurd doesn't define either PATH_MAX or MAXPATHLEN, so we put this
+ * in here, since the rest of the code in the file does require some
+ * fixed maximum.
+ */
+#ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else
+# define MAXPATHLEN 2048
+# endif
+#endif
+
/* I've put this here so it doesn't get confused with the
* file completion interface */
typedef struct _HistoryCallbackArg HistoryCallbackArg;
#define FNMATCH_FLAGS (FNM_PATHNAME | FNM_PERIOD)
#define CMPL_ERRNO_TOO_LONG ((1<<16)-1)
+#define CMPL_ERRNO_DID_NOT_CONVERT ((1<<16)-2)
/* This structure contains all the useful information about a directory
* for the purposes of filename completion. These structures are cached
struct _CompletionUserDir *user_directories;
};
+enum {
+ PROP_0,
+ PROP_SHOW_FILEOPS,
+ PROP_FILENAME
+};
/* File completion functions which would be external, were they used
* outside of this file.
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,
/* 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. */
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,
CompletionState* cmpl_state);
static void gtk_file_selection_class_init (GtkFileSelectionClass *klass);
+static void gtk_file_selection_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_file_selection_get_property (GObject *object,
+ guint prop_id,
+ 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,
gpointer user_data);
+static gint gtk_file_selection_insert_text (GtkWidget *widget,
+ const gchar *new_text,
+ gint new_text_length,
+ gint *position,
+ gpointer user_data);
static void gtk_file_selection_file_button (GtkWidget *widget,
gint row,
(GtkClassInitFunc) NULL,
};
- file_selection_type = gtk_type_unique (GTK_TYPE_WINDOW, &filesel_info);
+ file_selection_type = gtk_type_unique (GTK_TYPE_DIALOG, &filesel_info);
}
return file_selection_type;
static void
gtk_file_selection_class_init (GtkFileSelectionClass *class)
{
+ GObjectClass *gobject_class;
GtkObjectClass *object_class;
+ gobject_class = (GObjectClass*) class;
object_class = (GtkObjectClass*) class;
- parent_class = gtk_type_class (GTK_TYPE_WINDOW);
-
+ 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;
+
+ g_object_class_install_property (gobject_class,
+ PROP_FILENAME,
+ g_param_spec_string ("filename",
+ _("Filename"),
+ _("The currently selected filename."),
+ NULL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (gobject_class,
+ PROP_SHOW_FILEOPS,
+ g_param_spec_boolean ("show_fileops",
+ _("Show file operations"),
+ _("Whether buttons for creating/manipulating files should be displayed."),
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE));
object_class->destroy = gtk_file_selection_destroy;
}
+static void gtk_file_selection_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFileSelection *filesel;
+
+ filesel = GTK_FILE_SELECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILENAME:
+ gtk_file_selection_set_filename (filesel,
+ g_value_get_string (value));
+ break;
+
+ case PROP_SHOW_FILEOPS:
+ if (g_value_get_boolean (value))
+ gtk_file_selection_show_fileop_buttons (filesel);
+ else
+ gtk_file_selection_hide_fileop_buttons (filesel);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gtk_file_selection_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkFileSelection *filesel;
+
+ filesel = GTK_FILE_SELECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_FILENAME:
+ g_value_set_string (value,
+ gtk_file_selection_get_filename(filesel));
+ break;
+
+ case PROP_SHOW_FILEOPS:
+ /* This is a little bit hacky, but doing otherwise would require
+ * adding a field to the object.
+ */
+ g_value_set_boolean (value, (filesel->fileop_c_dir &&
+ filesel->fileop_del_file &&
+ filesel->fileop_ren_file));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+grab_default (GtkWidget *widget)
+{
+ gtk_widget_grab_default (widget);
+ return FALSE;
+}
+
static void
gtk_file_selection_init (GtkFileSelection *filesel)
{
GtkWidget *confirm_area;
GtkWidget *pulldown_hbox;
GtkWidget *scrolled_win;
-
+ GtkWidget *eventbox;
+ GtkDialog *dialog;
+
char *dir_title [2];
char *file_title [2];
-
+
+ dialog = GTK_DIALOG (filesel);
+
filesel->cmpl_state = cmpl_init_state ();
/* The dialog-sized vertical box */
- filesel->main_vbox = gtk_vbox_new (FALSE, 10);
+ filesel->main_vbox = dialog->vbox;
gtk_container_set_border_width (GTK_CONTAINER (filesel), 10);
- gtk_container_add (GTK_CONTAINER (filesel), filesel->main_vbox);
- gtk_widget_show (filesel->main_vbox);
/* The horizontal box containing create, rename etc. buttons */
filesel->button_area = gtk_hbutton_box_new ();
gtk_button_box_set_layout (GTK_BUTTON_BOX (filesel->button_area), GTK_BUTTONBOX_START);
- gtk_button_box_set_spacing (GTK_BUTTON_BOX (filesel->button_area), 0);
+ gtk_box_set_spacing (GTK_BOX (filesel->button_area), 0);
gtk_box_pack_start (GTK_BOX (filesel->main_vbox), filesel->button_area,
FALSE, FALSE, 0);
gtk_widget_show (filesel->button_area);
gtk_widget_show (filesel->action_area);
/* The OK/Cancel button area */
- confirm_area = gtk_hbutton_box_new ();
- gtk_button_box_set_layout (GTK_BUTTON_BOX (confirm_area), GTK_BUTTONBOX_END);
- gtk_button_box_set_spacing (GTK_BUTTON_BOX (confirm_area), 5);
- gtk_box_pack_end (GTK_BOX (filesel->main_vbox), confirm_area, FALSE, FALSE, 0);
- gtk_widget_show (confirm_area);
+ confirm_area = dialog->action_area;
/* The OK button */
- filesel->ok_button = gtk_button_new_with_label (_("OK"));
- GTK_WIDGET_SET_FLAGS (filesel->ok_button, GTK_CAN_DEFAULT);
- gtk_box_pack_start (GTK_BOX (confirm_area), filesel->ok_button, TRUE, TRUE, 0);
+ filesel->ok_button = gtk_dialog_add_button (dialog,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+
gtk_widget_grab_default (filesel->ok_button);
- gtk_widget_show (filesel->ok_button);
/* The Cancel button */
- filesel->cancel_button = gtk_button_new_with_label (_("Cancel"));
- GTK_WIDGET_SET_FLAGS (filesel->cancel_button, GTK_CAN_DEFAULT);
- gtk_box_pack_start (GTK_BOX (confirm_area), filesel->cancel_button, TRUE, TRUE, 0);
- gtk_widget_show (filesel->cancel_button);
+ filesel->cancel_button = gtk_dialog_add_button (dialog,
+ 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, 0);
+ 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",
(GtkSignalFunc) gtk_file_selection_key_press, filesel);
+ gtk_signal_connect (GTK_OBJECT (filesel->selection_entry), "insert_text",
+ (GtkSignalFunc) gtk_file_selection_insert_text, NULL);
gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "focus_in_event",
- (GtkSignalFunc) gtk_widget_grab_default,
+ (GtkSignalFunc) grab_default,
GTK_OBJECT (filesel->ok_button));
gtk_signal_connect_object (GTK_OBJECT (filesel->selection_entry), "activate",
(GtkSignalFunc) gtk_button_clicked,
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)
{
filesel = gtk_type_new (GTK_TYPE_FILE_SELECTION);
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 */
filesel->fileop_ren_file, TRUE, TRUE, 0);
gtk_widget_show (filesel->fileop_ren_file);
}
-
+ g_object_notify (G_OBJECT (filesel), "show_fileops");
gtk_widget_queue_resize (GTK_WIDGET (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)
gtk_widget_destroy (filesel->fileop_c_dir);
filesel->fileop_c_dir = NULL;
}
+ g_object_notify (G_OBJECT (filesel), "show_fileops");
}
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);
if (filesel->selection_entry)
gtk_entry_set_text (GTK_ENTRY (filesel->selection_entry), name);
g_free (buf);
-}
-
-gchar*
+ g_object_notify (G_OBJECT (filesel), "filename");
+}
+
+/**
+ * gtk_file_selection_get_filename:
+ * @filesel: a #GtkFileSelection
+ *
+ * This function returns the selected filename in the C runtime's
+ * multibyte string encoding, which may or may not be the same as that
+ * used by GTK+ (UTF-8). To convert to UTF-8, call g_filename_to_utf8().
+ * The returned string points to a statically allocated buffer and
+ * should be copied if you plan to keep it around.
+ *
+ * Return value: currently-selected filename in locale's encoding
+ **/
+G_CONST_RETURN gchar*
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
text = gtk_entry_get_text (GTK_ENTRY (filesel->selection_entry));
if (text)
{
- sys_filename = g_filename_from_utf8 (cmpl_completion_fullname (text, filesel->cmpl_state));
+ sys_filename = g_filename_from_utf8 (cmpl_completion_fullname (text, filesel->cmpl_state), -1, NULL, NULL, NULL);
+ if (!sys_filename)
+ return nothing;
strncpy (something, sys_filename, sizeof (something));
g_free (sys_filename);
return something;
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);
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
gtk_file_selection_fileop_error (GtkFileSelection *fs,
gchar *error_message)
{
- GtkWidget *label;
- GtkWidget *vbox;
- GtkWidget *button;
GtkWidget *dialog;
-
+
g_return_if_fail (error_message != NULL);
-
- /* main dialog */
- dialog = gtk_dialog_new ();
- /*
- gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
- (GtkSignalFunc) gtk_file_selection_fileop_destroy,
- (gpointer) fs);
- */
- gtk_window_set_title (GTK_WINDOW (dialog), _("Error"));
- gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
-
- /* If file dialog is grabbed, make this dialog modal too */
- /* When error dialog is closed, file dialog will be grabbed again */
- if (GTK_WINDOW (fs)->modal)
- gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox,
- FALSE, FALSE, 0);
- gtk_widget_show (vbox);
- label = gtk_label_new (error_message);
- gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
- gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5);
- gtk_widget_show (label);
+ /* main dialog */
+ dialog = gtk_message_dialog_new (GTK_WINDOW (fs),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "%s", error_message);
/* yes, we free it */
g_free (error_message);
-
- /* close button */
- button = gtk_button_new_with_label (_("Close"));
- gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+
+ gtk_signal_connect_object (GTK_OBJECT (dialog), "response",
(GtkSignalFunc) gtk_widget_destroy,
(gpointer) dialog);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
- button, TRUE, TRUE, 0);
- GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
- gtk_widget_grab_default (button);
- gtk_widget_show (button);
gtk_widget_show (dialog);
}
{
GtkFileSelection *fs = data;
- g_return_if_fail (fs != NULL);
g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
fs->fileop_dialog = NULL;
gpointer data)
{
GtkFileSelection *fs = data;
- gchar *dirname;
+ const gchar *dirname;
gchar *path;
gchar *full_path;
gchar *sys_full_path;
gchar *buf;
+ 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));
path = cmpl_reference_position (cmpl_state);
full_path = g_strconcat (path, G_DIR_SEPARATOR_S, dirname, NULL);
- sys_full_path = g_filename_from_utf8 (full_path);
+ sys_full_path = g_filename_from_utf8 (full_path, -1, NULL, NULL, &error);
+ if (error)
+ {
+ if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+ buf = g_strdup_printf (_("The directory name \"%s\" contains symbols that are not allowed in filenames"), dirname);
+ else
+ buf = g_strdup_printf (_("Error creating directory \"%s\": %s\n%s"), dirname, error->message,
+ _("You probably used symbols not allowed in filenames."));
+ gtk_file_selection_fileop_error (fs, buf);
+ g_error_free (error);
+ goto out;
+ }
+
if (mkdir (sys_full_path, 0755) < 0)
{
- buf = g_strconcat ("Error creating directory \"", dirname, "\": ",
- g_strerror (errno), NULL);
+ buf = g_strdup_printf (_("Error creating directory \"%s\": %s\n"), dirname,
+ g_strerror (errno));
gtk_file_selection_fileop_error (fs, buf);
}
+
+ out:
g_free (full_path);
g_free (sys_full_path);
GtkWidget *vbox;
GtkWidget *button;
- g_return_if_fail (fs != NULL);
g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
if (fs->fileop_dialog)
FALSE, FALSE, 0);
gtk_widget_show( vbox);
- label = gtk_label_new (_("Directory name:"));
+ label = gtk_label_new_with_mnemonic (_("_Directory name:"));
gtk_misc_set_alignment(GTK_MISC (label), 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5);
gtk_widget_show (label);
/* The directory entry widget */
fs->fileop_entry = gtk_entry_new ();
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), fs->fileop_entry);
gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry,
TRUE, TRUE, 5);
GTK_WIDGET_SET_FLAGS (fs->fileop_entry, GTK_CAN_DEFAULT);
gchar *path;
gchar *full_path;
gchar *sys_full_path;
+ 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;
path = cmpl_reference_position (cmpl_state);
full_path = g_strconcat (path, G_DIR_SEPARATOR_S, fs->fileop_file, NULL);
- sys_full_path = g_filename_from_utf8 (full_path);
+ sys_full_path = g_filename_from_utf8 (full_path, -1, NULL, NULL, &error);
+ if (error)
+ {
+ if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+ buf = g_strdup_printf (_("The filename \"%s\" contains symbols that are not allowed in filenames"),
+ fs->fileop_file);
+ else
+ buf = g_strdup_printf (_("Error deleting file \"%s\": %s\n%s"),
+ fs->fileop_file, error->message,
+ _("It probably contains symbols not allowed in filenames."));
+
+ gtk_file_selection_fileop_error (fs, buf);
+ g_error_free (error);
+ goto out;
+ }
+
if (unlink (sys_full_path) < 0)
{
- buf = g_strconcat ("Error deleting file \"", fs->fileop_file, "\": ",
- g_strerror (errno), NULL);
+ buf = g_strdup_printf (_("Error deleting file \"%s\": %s"),
+ fs->fileop_file, g_strerror (errno));
gtk_file_selection_fileop_error (fs, buf);
}
+
+ out:
g_free (full_path);
g_free (sys_full_path);
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)
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 ();
{
GtkFileSelection *fs = data;
gchar *buf;
- gchar *file;
+ const gchar *file;
gchar *path;
gchar *new_filename;
gchar *old_filename;
gchar *sys_new_filename;
gchar *sys_old_filename;
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));
new_filename = g_strconcat (path, G_DIR_SEPARATOR_S, file, NULL);
old_filename = g_strconcat (path, G_DIR_SEPARATOR_S, fs->fileop_file, NULL);
- sys_new_filename = g_filename_from_utf8 (new_filename);
- sys_old_filename = g_filename_from_utf8 (old_filename);
+ sys_new_filename = g_filename_from_utf8 (new_filename, -1, NULL, NULL, &error);
+ if (error)
+ {
+ if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+ buf = g_strdup_printf (_("The file name \"%s\" contains symbols that are not allowed in filenames"), new_filename);
+ else
+ buf = g_strdup_printf (_("Error renaming file to \"%s\": %s\n%s"),
+ new_filename, error->message,
+ _("You probably used symbols not allowed in filenames."));
+ gtk_file_selection_fileop_error (fs, buf);
+ g_error_free (error);
+ goto out1;
+ }
+ sys_old_filename = g_filename_from_utf8 (old_filename, -1, NULL, NULL, &error);
+ if (error)
+ {
+ if (g_error_matches (error, G_CONVERT_ERROR, G_CONVERT_ERROR_ILLEGAL_SEQUENCE))
+ buf = g_strdup_printf (_("The file name \"%s\" contains symbols that are not allowed in filenames"), old_filename);
+ else
+ buf = g_strdup_printf (_("Error renaming file \"%s\": %s\n%s"),
+ old_filename, error->message,
+ _("It probably contains symbols not allowed in filenames."));
+ gtk_file_selection_fileop_error (fs, buf);
+ g_error_free (error);
+ goto out2;
+ }
+
if (rename (sys_old_filename, sys_new_filename) < 0)
{
- buf = g_strconcat ("Error renaming file \"", file, "\": ",
- g_strerror (errno), NULL);
+ buf = g_strdup_printf (_("Error renaming file \"%s\" to \"%s\": %s"),
+ sys_old_filename, sys_new_filename,
+ g_strerror (errno));
gtk_file_selection_fileop_error (fs, buf);
}
+
+ out2:
+ g_free (sys_old_filename);
+
+ out1:
g_free (new_filename);
g_free (old_filename);
g_free (sys_new_filename);
- g_free (sys_old_filename);
gtk_widget_destroy (fs->fileop_dialog);
gtk_file_selection_populate (fs, "", FALSE);
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;
gtk_widget_show (dialog);
}
+static gint
+gtk_file_selection_insert_text (GtkWidget *widget,
+ const gchar *new_text,
+ gint new_text_length,
+ gint *position,
+ gpointer user_data)
+{
+ gchar *filename;
+
+ filename = g_filename_from_utf8 (new_text, new_text_length, NULL, NULL, NULL);
+
+ if (!filename)
+ {
+ gdk_beep ();
+ gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "insert_text");
+ return FALSE;
+ }
+
+ g_free (filename);
+
+ return TRUE;
+}
static gint
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);
g_free (text);
- gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
-
return TRUE;
}
HistoryCallbackArg *callback_arg;
GList *list;
- g_return_if_fail (fs != NULL);
g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
list = fs->history_list;
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);
gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
(GtkSignalFunc) gtk_file_selection_history_callback,
(gpointer) fs);
- gtk_menu_append (GTK_MENU (fs->history_menu), menu_item);
+ gtk_menu_shell_append (GTK_MENU_SHELL (fs->history_menu), menu_item);
gtk_widget_show (menu_item);
}
}
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);
#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)
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);
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;
}
static gchar*
-cmpl_completion_fullname (gchar *text,
+cmpl_completion_fullname (const gchar *text,
CompletionState *cmpl_state)
{
static char nothing[2] = "";
/* g_get_current_dir() returns a string in the "system" charset */
sys_getcwd_buf = g_get_current_dir ();
- utf8_cwd = g_filename_to_utf8 (sys_getcwd_buf);
+ utf8_cwd = g_filename_to_utf8 (sys_getcwd_buf, -1, NULL, NULL, NULL);
g_free (sys_getcwd_buf);
tryagain:
{
/* If no possible candidates, use the cwd */
gchar *sys_curdir = g_get_current_dir ();
- gchar *utf8_curdir = g_filename_to_utf8 (sys_curdir);
+ gchar *utf8_curdir = g_filename_to_utf8 (sys_curdir, -1, NULL, NULL, NULL);
g_free (sys_curdir);
/* 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;
if (!cmp_len)
{
/* ~/ */
- gchar *homedir = g_get_home_dir ();
- gchar *utf8_homedir = g_filename_to_utf8 (homedir);
-
- g_free (homedir);
+ const gchar *homedir = g_get_home_dir ();
+ gchar *utf8_homedir = g_filename_to_utf8 (homedir, -1, NULL, NULL, NULL);
if (utf8_homedir)
result = open_dir (utf8_homedir, cmpl_state);
cmpl_errno = errno;
return NULL;
}
- utf8_dir = g_filename_to_utf8 (pwd->pw_dir);
+ utf8_dir = g_filename_to_utf8 (pwd->pw_dir, -1, NULL, NULL, NULL);
result = open_dir (utf8_dir, cmpl_state);
g_free (utf8_dir);
}
DIR *directory;
struct dirent *dirent_ptr;
gint entry_count = 0;
+ gint n_entries = 0;
gint i;
struct stat ent_sbuf;
GString *path;
path = g_string_sized_new (2*MAXPATHLEN + 10);
- sys_dir_name = g_filename_from_utf8 (dir_name);
+ sys_dir_name = g_filename_from_utf8 (dir_name, -1, NULL, NULL, NULL);
+ if (!sys_dir_name)
+ {
+ cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT;
+ return NULL;
+ }
+
directory = opendir (sys_dir_name);
-
if (!directory)
{
cmpl_errno = errno;
return NULL;
}
- sent->entries[i].entry_name = g_filename_to_utf8 (dirent_ptr->d_name);
+ sent->entries[n_entries].entry_name = g_filename_to_utf8 (dirent_ptr->d_name, -1, NULL, NULL, NULL);
+ if (!g_utf8_validate (sent->entries[n_entries].entry_name, -1, NULL))
+ {
+ g_warning (_("The filename %s couldn't be converted to UTF-8. Try setting the environment variable G_BROKEN_FILENAMES."), dirent_ptr->d_name);
+ continue;
+ }
g_string_assign (path, sys_dir_name);
if (path->str[path->len-1] != G_DIR_SEPARATOR)
{
/* Here we know path->str is a "system charset" string */
if (stat (path->str, &ent_sbuf) >= 0 && S_ISDIR (ent_sbuf.st_mode))
- sent->entries[i].is_dir = TRUE;
+ sent->entries[n_entries].is_dir = TRUE;
else
/* stat may fail, and we don't mind, since it could be a
* dangling symlink. */
- sent->entries[i].is_dir = FALSE;
+ sent->entries[n_entries].is_dir = FALSE;
}
else
- sent->entries[i].is_dir = 1;
- }
+ sent->entries[n_entries].is_dir = 1;
+ n_entries++;
+ }
+ sent->entry_count = n_entries;
+
g_free (sys_dir_name);
g_string_free (path, TRUE);
qsort (sent->entries, sent->entry_count, sizeof (CompletionDirEntry), compare_cmpl_dir);
}
}
- sys_dir_name = g_filename_from_utf8 (dir_name);
+ sys_dir_name = g_filename_from_utf8 (dir_name, -1, NULL, NULL, NULL);
+ if (!sys_dir_name)
+ {
+ cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT;
+ return FALSE;
+ }
+
if (stat (sys_dir_name, result) < 0)
{
g_free (sys_dir_name);
return TRUE;
}
- sys_filename = g_filename_from_utf8 (cmpl_dir->fullname);
+ sys_filename = g_filename_from_utf8 (cmpl_dir->fullname, -1, NULL, NULL, NULL);
+ if (!sys_filename)
+ {
+ cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT;
+ return FALSE;
+ }
+
if (stat (sys_filename, &sbuf) < 0)
{
g_free (sys_filename);
return TRUE;
}
- sys_filename = g_filename_from_utf8 (cmpl_dir->fullname);
+ sys_filename = g_filename_from_utf8 (cmpl_dir->fullname, -1, NULL, NULL, NULL);
+ if (!sys_filename)
+ {
+ cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT;
+ return FALSE;
+ }
+
if (stat (sys_filename, &sbuf) < 0)
{
g_free (sys_filename);
last_slash[1] = 0;
}
- sys_filename = g_filename_from_utf8 (cmpl_dir->fullname);
+ sys_filename = g_filename_from_utf8 (cmpl_dir->fullname, -1, NULL, NULL, NULL);
+ if (!sys_filename)
+ {
+ cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT;
+ if (!c)
+ last_slash[0] = G_DIR_SEPARATOR;
+ return FALSE;
+ }
+
if (stat (sys_filename, &parbuf) < 0)
{
g_free (sys_filename);
gchar *sys_dirname;
sys_orig_dir = g_get_current_dir ();
- sys_dirname = g_filename_from_utf8 (dirname);
+ sys_dirname = g_filename_from_utf8 (dirname, -1, NULL, NULL, NULL);
+ if (!sys_dirname)
+ {
+ g_free (sys_orig_dir);
+ cmpl_errno = CMPL_ERRNO_DID_NOT_CONVERT;
+ return NULL;
+ }
+
if (chdir (sys_dirname) != 0 || chdir ("..") != 0)
{
g_free (sys_dirname);
g_free (sys_dirname);
sys_cwd = g_get_current_dir ();
- result = g_filename_to_utf8 (sys_cwd);
+ result = g_filename_to_utf8 (sys_cwd, -1, NULL, NULL, NULL);
g_free (sys_cwd);
if (chdir (sys_orig_dir) != 0)
while ((pwd_ptr = getpwent ()) != NULL)
{
- utf8 = g_filename_to_utf8 (pwd_ptr->pw_name);
+ utf8 = g_filename_to_utf8 (pwd_ptr->pw_name, -1, NULL, NULL, NULL);
len += strlen (utf8);
g_free (utf8);
- utf8 = g_filename_to_utf8 (pwd_ptr->pw_dir);
+ utf8 = g_filename_to_utf8 (pwd_ptr->pw_dir, -1, NULL, NULL, NULL);
len += strlen (utf8);
g_free (utf8);
len += 2;
goto error;
}
- utf8 = g_filename_to_utf8 (pwd_ptr->pw_name);
+ utf8 = g_filename_to_utf8 (pwd_ptr->pw_name, -1, NULL, NULL, NULL);
strcpy (buf_ptr, utf8);
g_free (utf8);
buf_ptr += strlen (buf_ptr);
buf_ptr += 1;
- utf8 = g_filename_to_utf8 (pwd_ptr->pw_dir);
+ utf8 = g_filename_to_utf8 (pwd_ptr->pw_dir, -1, NULL, NULL, NULL);
strcpy (buf_ptr, utf8);
g_free (utf8);
return cmpl_state && cmpl_state->reference_dir;
}
-static gchar*
+static const gchar*
cmpl_strerror (gint err)
{
if (err == CMPL_ERRNO_TOO_LONG)
- return "Name too long";
+ return _("Name too long");
+ else if (err == CMPL_ERRNO_DID_NOT_CONVERT)
+ return _("Couldn't convert filename");
else
return g_strerror (err);
}