]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilesel.c
Updates.
[~andy/gtk] / gtk / gtkfilesel.c
index 70cc81aadbd197afeb8e9f4ac9c41b71c3013f02..902272b14e4e426e708009acf89cd4b78230acb0 100644 (file)
@@ -44,6 +44,9 @@
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
+#ifdef HAVE_WINSOCK_H
+#include <winsock.h>           /* For gethostname */
+#endif
 
 #include "fnmatch.h"
 
@@ -58,6 +61,7 @@
 #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;
@@ -121,6 +140,7 @@ typedef struct _PossibleCompletion PossibleCompletion;
 #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
@@ -210,6 +230,11 @@ struct _CompletionState
   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.
@@ -218,7 +243,7 @@ struct _CompletionState
 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,
@@ -271,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. */
@@ -286,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,
@@ -324,11 +349,25 @@ static void update_cmpl(PossibleCompletion* poss,
                        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, 
@@ -443,7 +482,7 @@ gtk_file_selection_get_type (void)
         (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;
@@ -452,15 +491,101 @@ gtk_file_selection_get_type (void)
 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)
 {
@@ -470,22 +595,24 @@ 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);
@@ -555,40 +682,40 @@ gtk_file_selection_init (GtkFileSelection *filesel)
   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,
@@ -612,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)
 {
@@ -619,14 +964,16 @@ 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 */
@@ -662,14 +1009,13 @@ gtk_file_selection_show_fileop_buttons (GtkFileSelection *filesel)
                          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)
@@ -689,6 +1035,7 @@ gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel)
       gtk_widget_destroy (filesel->fileop_c_dir);
       filesel->fileop_c_dir = NULL;
     }
+  g_object_notify (G_OBJECT (filesel), "show_fileops");
 }
 
 
@@ -700,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);
 
@@ -723,17 +1069,29 @@ gtk_file_selection_set_filename (GtkFileSelection *filesel,
   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
@@ -742,7 +1100,9 @@ gtk_file_selection_get_filename (GtkFileSelection *filesel)
   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;
@@ -755,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);
 
@@ -804,58 +1163,39 @@ 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
 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);
 }
@@ -866,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;
@@ -878,14 +1217,14 @@ 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;
   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));
@@ -893,13 +1232,27 @@ gtk_file_selection_create_dir_confirmed (GtkWidget *widget,
   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);
   
@@ -917,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)
@@ -943,13 +1295,14 @@ gtk_file_selection_create_dir (GtkWidget *widget,
                     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);
@@ -987,22 +1340,39 @@ gtk_file_selection_delete_file_confirmed (GtkWidget *widget,
   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);
   
@@ -1019,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)
@@ -1036,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 ();
@@ -1094,15 +1464,15 @@ 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;
   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));
@@ -1112,19 +1482,49 @@ gtk_file_selection_rename_file_confirmed (GtkWidget *widget,
   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);
@@ -1141,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;
   
@@ -1211,6 +1611,28 @@ gtk_file_selection_rename_file (GtkWidget *widget,
   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,
@@ -1223,22 +1645,20 @@ 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;
     }
 
@@ -1254,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;
@@ -1283,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);
   
@@ -1344,7 +1762,7 @@ gtk_file_selection_update_history_menu (GtkFileSelection *fs,
          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);
        }
     }
@@ -1367,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);
@@ -1375,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)
@@ -1416,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);
@@ -1501,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;
@@ -1675,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] = "";
@@ -1760,7 +2176,7 @@ cmpl_init_state (void)
 
   /* 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:
@@ -2052,7 +2468,7 @@ open_ref_dir (gchar           *text_to_complete,
        {
          /* 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);
 
@@ -2086,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;
@@ -2105,10 +2521,8 @@ open_user_dir (gchar           *text_to_complete,
   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);
@@ -2133,7 +2547,7 @@ open_user_dir (gchar           *text_to_complete,
          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);
     }
@@ -2176,6 +2590,7 @@ open_new_dir (gchar       *dir_name,
   DIR *directory;
   struct dirent *dirent_ptr;
   gint entry_count = 0;
+  gint n_entries = 0;
   gint i;
   struct stat ent_sbuf;
   GString *path;
@@ -2188,9 +2603,14 @@ open_new_dir (gchar       *dir_name,
 
   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;
@@ -2218,7 +2638,12 @@ open_new_dir (gchar       *dir_name,
          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)
@@ -2231,16 +2656,19 @@ open_new_dir (gchar       *dir_name,
        {
          /* 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);
@@ -2286,7 +2714,13 @@ check_dir (gchar       *dir_name,
        }
     }
 
-  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);
@@ -2419,7 +2853,13 @@ correct_dir_fullname (CompletionDir* cmpl_dir)
          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);
@@ -2447,7 +2887,13 @@ correct_dir_fullname (CompletionDir* cmpl_dir)
          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);
@@ -2495,7 +2941,15 @@ correct_parent (CompletionDir *cmpl_dir,
       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);
@@ -2542,7 +2996,14 @@ find_parent_dir_fullname (gchar* dirname)
   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);
@@ -2553,7 +3014,7 @@ find_parent_dir_fullname (gchar* 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)
@@ -2947,10 +3408,10 @@ get_pwdb (CompletionState* cmpl_state)
 
   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;
@@ -2974,7 +3435,7 @@ get_pwdb (CompletionState* cmpl_state)
          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);
 
@@ -2983,7 +3444,7 @@ get_pwdb (CompletionState* cmpl_state)
       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);
 
@@ -3044,11 +3505,13 @@ 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)
-    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);
 }