]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkfilesel.c
Fix #149547, Markus Lausser:
[~andy/gtk] / gtk / gtkfilesel.c
index 7bbafa89a86e31b9470acdaf026bcdd994cdf844..ad0516c1096b709e3fbc4254e918b0dae0e76aca 100644 (file)
@@ -24,7 +24,7 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <pwd.h>
 #endif
 
-#include <glib.h>              /* Include early to get G_OS_WIN32 and
-                                * G_WITH_CYGWIN */
+#include <glib.h>              /* Include early to get G_OS_WIN32 etc */
 
-#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
+#if defined(G_PLATFORM_WIN32)
 #include <ctype.h>
 #define STRICT
 #include <windows.h>
 #undef STRICT
-#endif /* G_OS_WIN32 || G_WITH_CYGWIN */
+#endif /* G_PLATFORM_WIN32 */
 #ifdef G_OS_WIN32
 #include <winsock.h>           /* For gethostname */
 #endif
 
 #include "gdk/gdkkeysyms.h"
+#include "gtkalias.h"
 #include "gtkbutton.h"
 #include "gtkcellrenderertext.h"
 #include "gtkentry.h"
 #include "gtkfilesel.h"
 #include "gtkhbox.h"
 #include "gtkhbbox.h"
+#include "gtkintl.h"
 #include "gtklabel.h"
 #include "gtkliststore.h"
 #include "gtkmain.h"
 #include "gtkvbox.h"
 #include "gtkmenu.h"
 #include "gtkmenuitem.h"
-#include "gtkoptionmenu.h"
 #include "gtkdialog.h"
 #include "gtkmessagedialog.h"
-#include "gtkintl.h"
 #include "gtkdnd.h"
 #include "gtkeventbox.h"
 
+#undef GTK_DISABLE_DEPRECATED
+#include "gtkoptionmenu.h"
+#define GTK_DISABLE_DEPRECATED
+
 #define WANT_HPANED 1
 #include "gtkhpaned.h"
 
@@ -150,9 +153,11 @@ typedef struct _PossibleCompletion PossibleCompletion;
  */
 struct _CompletionDirSent
 {
+#ifndef G_PLATFORM_WIN32
   ino_t inode;
   time_t mtime;
   dev_t device;
+#endif
 
   gint entry_count;
   struct _CompletionDirEntry *entries;
@@ -300,22 +305,27 @@ static gboolean            cmpl_updated_dir        (CompletionState* cmpl_state)
  */
 static gchar*              cmpl_reference_position (CompletionState* cmpl_state);
 
+#if 0
+/* This doesn't work currently and would require changes
+ * to fnmatch.c to get working.
+ */
 /* backing up: if cmpl_completion_matches returns NULL, you may query
  * the index of the last completable character into cmpl_updated_text.
  */
 static gint                cmpl_last_valid_char    (CompletionState* cmpl_state);
+#endif
 
 /* When the user selects a non-directory, call cmpl_completion_fullname
  * to get the full name of the selected file.
  */
-static const gchar*        cmpl_completion_fullname (const gchar*, CompletionState* cmpl_state);
+static gchar*              cmpl_completion_fullname (const gchar*, CompletionState* cmpl_state);
 
 
 /* Directory operations. */
 static CompletionDir* open_ref_dir         (gchar* text_to_complete,
                                            gchar** remaining_text,
                                            CompletionState* cmpl_state);
-#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
+#ifndef G_PLATFORM_WIN32
 static gboolean       check_dir            (gchar *dir_name, 
                                            struct stat *result, 
                                            gboolean *stat_subdirs);
@@ -334,7 +344,7 @@ static CompletionDirSent* open_new_dir     (gchar* dir_name,
 static gint           correct_dir_fullname (CompletionDir* cmpl_dir);
 static gint           correct_parent       (CompletionDir* cmpl_dir,
                                            struct stat *sbuf);
-#ifndef G_OS_WIN32
+#ifndef G_PLATFORM_WIN32
 static gchar*         find_parent_dir_fullname    (gchar* dirname);
 #endif
 static CompletionDir* attach_dir           (CompletionDirSent* sent,
@@ -413,12 +423,50 @@ static void gtk_file_selection_rename_file (GtkWidget *widget, gpointer data);
 
 static void free_selected_names (GPtrArray *names);
 
-#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
-#define compare_filenames(a, b) strcmp(a, b)
+#ifndef G_PLATFORM_WIN32
+
+#define compare_utf8_filenames(a, b) strcmp(a, b)
+#define compare_sys_filenames(a, b) strcmp(a, b)
+
 #else
-#define compare_filenames(a, b) g_ascii_strcasecmp(a, b)
-#endif
 
+static gint
+compare_utf8_filenames (const gchar *a,
+                       const gchar *b)
+{
+  gchar *a_folded, *b_folded;
+  gint retval;
+
+  a_folded = g_utf8_strdown (a, -1);
+  b_folded = g_utf8_strdown (b, -1);
+
+  retval = strcmp (a_folded, b_folded);
+
+  g_free (a_folded);
+  g_free (b_folded);
+
+  return retval;
+}
+
+static gint
+compare_sys_filenames (const gchar *a,
+                      const gchar *b)
+{
+  gchar *a_utf8, *b_utf8;
+  gint retval;
+
+  a_utf8 = g_filename_to_utf8 (a, -1, NULL, NULL, NULL);
+  b_utf8 = g_filename_to_utf8 (b, -1, NULL, NULL, NULL);
+
+  retval = compare_utf8_filenames (a_utf8, b_utf8);
+
+  g_free (a_utf8);
+  g_free (b_utf8);
+
+  return retval;
+}
+
+#endif
 
 static GtkWindowClass *parent_class = NULL;
 
@@ -429,7 +477,7 @@ static gint cmpl_errno;
 /*
  * Take the path currently in the file selection
  * entry field and translate as necessary from
- * a WIN32 style to CYGWIN32 style path.  For
+ * a Win32 style to Cygwin style path.  For
  * instance translate:
  * x:\somepath\file.jpg
  * to:
@@ -509,23 +557,23 @@ gtk_file_selection_class_init (GtkFileSelectionClass *class)
   g_object_class_install_property (gobject_class,
                                    PROP_FILENAME,
                                    g_param_spec_string ("filename",
-                                                        _("Filename"),
-                                                        _("The currently selected filename"),
+                                                        P_("Filename"),
+                                                        P_("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"),
+                                                        P_("Show file operations"),
+                                                        P_("Whether buttons for creating/manipulating files should be displayed"),
                                                         FALSE,
                                                         G_PARAM_READABLE |
                                                         G_PARAM_WRITABLE));
   g_object_class_install_property (gobject_class,
                                   PROP_SELECT_MULTIPLE,
                                   g_param_spec_boolean ("select_multiple",
-                                                        _("Select multiple"),
-                                                        _("Whether to allow multiple files to be selected"),
+                                                        P_("Select multiple"),
+                                                        P_("Whether to allow multiple files to be selected"),
                                                         FALSE,
                                                         G_PARAM_READABLE |
                                                         G_PARAM_WRITABLE));
@@ -1137,6 +1185,10 @@ gtk_file_selection_hide_fileop_buttons (GtkFileSelection *filesel)
  * directory path, then the requestor will open with that path as its
  * current working directory.
  *
+ * This has the consequence that in order to open the requestor with a 
+ * working directory and an empty filename, @filename must have a trailing
+ * directory separator.
+ *
  * The encoding of @filename is the on-disk encoding, which
  * may not be UTF-8. See g_filename_from_utf8().
  **/
@@ -1208,7 +1260,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), -1, NULL, NULL, NULL);
+      gchar *fullname = cmpl_completion_fullname (text, filesel->cmpl_state);
+      sys_filename = g_filename_from_utf8 (fullname, -1, NULL, NULL, NULL);
+      g_free (fullname);
       if (!sys_filename)
        return nothing;
       strncpy (something, sys_filename, sizeof (something));
@@ -1318,7 +1372,7 @@ gtk_file_selection_fileop_error (GtkFileSelection *fs,
   dialog = gtk_message_dialog_new (GTK_WINDOW (fs),
                                   GTK_DIALOG_DESTROY_WITH_PARENT,
                                   GTK_MESSAGE_ERROR,
-                                  GTK_BUTTONS_CLOSE,
+                                  GTK_BUTTONS_OK,
                                   "%s", error_message);
 
   /* yes, we free it */
@@ -1392,7 +1446,7 @@ gtk_file_selection_create_dir_confirmed (GtkWidget *widget,
       goto out;
     }
 
-  if (mkdir (sys_full_path, 0755) < 0) 
+  if (mkdir (sys_full_path, 0777) < 0)
     {
       buf = g_strdup_printf (_("Error creating folder \"%s\": %s\n"), dirname,
                             g_strerror (errno));
@@ -1454,22 +1508,20 @@ gtk_file_selection_create_dir (GtkWidget *widget,
   gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, 
                      TRUE, TRUE, 5);
   GTK_WIDGET_SET_FLAGS (fs->fileop_entry, GTK_CAN_DEFAULT);
+  gtk_entry_set_activates_default (GTK_ENTRY (fs->fileop_entry), TRUE); 
   gtk_widget_show (fs->fileop_entry);
   
   /* buttons */
-  button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
+  button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
+                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
   g_signal_connect_swapped (button, "clicked",
                            G_CALLBACK (gtk_widget_destroy),
                            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_grab_focus (fs->fileop_entry);
 
-  button = gtk_button_new_with_mnemonic (_("C_reate"));
+  button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
+                                 _("C_reate"), GTK_RESPONSE_OK);
   gtk_widget_set_sensitive (button, FALSE);
   g_signal_connect (button, "clicked",
                    G_CALLBACK (gtk_file_selection_create_dir_confirmed),
@@ -1478,10 +1530,7 @@ gtk_file_selection_create_dir (GtkWidget *widget,
                     G_CALLBACK (gtk_file_selection_fileop_entry_changed),
                    button);
 
-  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_show (button);
+  gtk_widget_grab_default (button);
   
   gtk_widget_show (dialog);
 }
@@ -1572,7 +1621,7 @@ gtk_file_selection_delete_file (GtkWidget *widget,
                             GTK_WINDOW (fs)->modal ? GTK_DIALOG_MODAL : 0,
                             GTK_MESSAGE_QUESTION,
                             GTK_BUTTONS_NONE,
-                            _("Really delete file \"%s\" ?"), filename);
+                            _("Really delete file \"%s\"?"), filename);
 
   g_signal_connect (dialog, "destroy",
                    G_CALLBACK (gtk_file_selection_fileop_destroy),
@@ -1723,6 +1772,7 @@ gtk_file_selection_rename_file (GtkWidget *widget,
   gtk_box_pack_start (GTK_BOX (vbox), fs->fileop_entry, 
                      TRUE, TRUE, 5);
   GTK_WIDGET_SET_FLAGS (fs->fileop_entry, GTK_CAN_DEFAULT);
+  gtk_entry_set_activates_default (GTK_ENTRY (fs->fileop_entry), TRUE); 
   gtk_widget_show (fs->fileop_entry);
   
   gtk_entry_set_text (GTK_ENTRY (fs->fileop_entry), fs->fileop_file);
@@ -1730,19 +1780,16 @@ gtk_file_selection_rename_file (GtkWidget *widget,
                              0, strlen (fs->fileop_file));
 
   /* buttons */
-  button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
+  button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
+                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
   g_signal_connect_swapped (button, "clicked",
                            G_CALLBACK (gtk_widget_destroy),
                            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_grab_focus (fs->fileop_entry);
 
-  button = gtk_button_new_with_mnemonic (_("_Rename"));
+  button = gtk_dialog_add_button (GTK_DIALOG (dialog), 
+                                 _("_Rename"), GTK_RESPONSE_OK);
   g_signal_connect (button, "clicked",
                    G_CALLBACK (gtk_file_selection_rename_file_confirmed),
                    fs);
@@ -1750,10 +1797,7 @@ gtk_file_selection_rename_file (GtkWidget *widget,
                    G_CALLBACK (gtk_file_selection_fileop_entry_changed),
                    button);
 
-  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_show (button);
+  gtk_widget_grab_default (button);
   
   gtk_widget_show (dialog);
 }
@@ -2002,7 +2046,7 @@ gtk_file_selection_dir_activate (GtkTreeView       *tree_view,
   g_free (filename);
 }
 
-#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
+#ifdef G_PLATFORM_WIN32
 
 static void
 win32_gtk_add_drives_to_dir_list (GtkListStore *model)
@@ -2020,7 +2064,7 @@ win32_gtk_add_drives_to_dir_list (GtkListStore *model)
   while (*textPtr != '\0')
     {
       /* Ignore floppies (?) */
-      if ((tolower (textPtr[0]) != 'a') && (tolower (textPtr[0]) != 'b'))
+      if (GetDriveType (textPtr) != DRIVE_REMOVABLE)
        {
          /* Build the actual displayable string */
          g_snprintf (formatBuffer, sizeof (formatBuffer), "%c:\\", toupper (textPtr[0]));
@@ -2066,7 +2110,6 @@ gtk_file_selection_populate (GtkFileSelection *fs,
   gchar* sel_text;
   gint did_recurse = FALSE;
   gint possible_count = 0;
-  gint selection_index = -1;
   
   g_return_if_fail (GTK_IS_FILE_SELECTION (fs));
 
@@ -2121,7 +2164,7 @@ gtk_file_selection_populate (GtkFileSelection *fs,
       poss = cmpl_next_completion (cmpl_state);
     }
 
-#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
+#ifdef G_PLATFORM_WIN32
   /* For Windows, add drives as potential selections */
   win32_gtk_add_drives_to_dir_list (dir_model);
 #endif
@@ -2160,8 +2203,6 @@ gtk_file_selection_populate (GtkFileSelection *fs,
         }
       else
         {
-          selection_index = cmpl_last_valid_char (cmpl_state) -
-                            (strlen (rel_path) - strlen (rem_path));
          if (fs->selection_entry)
            gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), rem_path);
         }
@@ -2174,9 +2215,8 @@ gtk_file_selection_populate (GtkFileSelection *fs,
 
   if (!did_recurse)
     {
-      if (fs->selection_entry)
-       gtk_editable_set_position (GTK_EDITABLE (fs->selection_entry),
-                                  selection_index);
+      if (fs->selection_entry && try_complete)
+       gtk_editable_set_position (GTK_EDITABLE (fs->selection_entry), -1);
 
       if (fs->selection_entry)
        {
@@ -2324,8 +2364,8 @@ gtk_file_selection_file_changed (GtkTreeSelection *selection,
          /* A common case is selecting a range of files from top to bottom,
           * so quickly check for that to avoid looping over the entire list
           */
-         if (compare_filenames (g_ptr_array_index (old_names, old_names->len - 1),
-                                g_ptr_array_index (new_names, new_names->len - 1)) != 0)
+         if (compare_utf8_filenames (g_ptr_array_index (old_names, old_names->len - 1),
+                                     g_ptr_array_index (new_names, new_names->len - 1)) != 0)
            index = new_names->len - 1;
          else
            {
@@ -2336,8 +2376,8 @@ gtk_file_selection_file_changed (GtkTreeSelection *selection,
               */
              while (i < old_names->len && j < new_names->len)
                {
-                 cmp = compare_filenames (g_ptr_array_index (old_names, i),
-                                          g_ptr_array_index (new_names, j));
+                 cmp = compare_utf8_filenames (g_ptr_array_index (old_names, i),
+                                               g_ptr_array_index (new_names, j));
                  if (cmp < 0)
                    {
                      i++;
@@ -2366,8 +2406,8 @@ gtk_file_selection_file_changed (GtkTreeSelection *selection,
           * So search up from there.
           */
          if (fs->last_selected &&
-             compare_filenames (fs->last_selected,
-                                g_ptr_array_index (new_names, 0)) == 0)
+             compare_utf8_filenames (fs->last_selected,
+                                     g_ptr_array_index (new_names, 0)) == 0)
            index = new_names->len - 1;
          else
            index = 0;
@@ -2401,7 +2441,7 @@ maybe_clear_entry:
 
   entry = gtk_entry_get_text (GTK_ENTRY (fs->selection_entry));
   if ((entry != NULL) && (fs->last_selected != NULL) &&
-      (compare_filenames (entry, fs->last_selected) == 0))
+      (compare_utf8_filenames (entry, fs->last_selected) == 0))
     gtk_entry_set_text (GTK_ENTRY (fs->selection_entry), "");
 }
 
@@ -2464,7 +2504,7 @@ gtk_file_selection_get_selections (GtkFileSelection *filesel)
 
          selections[count++] = current;
 
-         if (unselected_entry && compare_filenames (current, filename) == 0)
+         if (unselected_entry && compare_sys_filenames (current, filename) == 0)
            unselected_entry = FALSE;
        }
 
@@ -2505,25 +2545,28 @@ cmpl_reference_position (CompletionState *cmpl_state)
   return cmpl_state->reference_dir->fullname;
 }
 
+#if 0
+/* This doesn't work currently and would require changes
+ * to fnmatch.c to get working.
+ */
 static gint
 cmpl_last_valid_char (CompletionState *cmpl_state)
 {
   return cmpl_state->last_valid_char;
 }
+#endif
 
-static const gchar*
+static gchar*
 cmpl_completion_fullname (const gchar     *text,
                          CompletionState *cmpl_state)
 {
-  static const char nothing[2] = "";
-
   if (!cmpl_state_okay (cmpl_state))
     {
-      return nothing;
+      return g_strdup ("");
     }
   else if (g_path_is_absolute (text))
     {
-      strcpy (cmpl_state->updated_text, text);
+      return g_strdup (text);
     }
 #ifdef HAVE_PWD_H
   else if (text[0] == '~')
@@ -2533,33 +2576,19 @@ cmpl_completion_fullname (const gchar     *text,
 
       dir = open_user_dir (text, cmpl_state);
 
-      if (!dir)
+      if (dir)
        {
-         /* spencer says just return ~something, so
-          * for now just do it. */
-         strcpy (cmpl_state->updated_text, text);
-       }
-      else
-       {
-
-         strcpy (cmpl_state->updated_text, dir->fullname);
-
          slash = strchr (text, G_DIR_SEPARATOR);
-
-         if (slash)
-           strcat (cmpl_state->updated_text, slash);
+         
+         /* slash may be NULL, that works too */
+         return g_strconcat (dir->fullname, slash, NULL);
        }
     }
 #endif
-  else
-    {
-      strcpy (cmpl_state->updated_text, cmpl_state->reference_dir->fullname);
-      if (cmpl_state->updated_text[strlen (cmpl_state->updated_text) - 1] != G_DIR_SEPARATOR)
-       strcat (cmpl_state->updated_text, G_DIR_SEPARATOR_S);
-      strcat (cmpl_state->updated_text, text);
-    }
-
-  return cmpl_state->updated_text;
+  
+  return g_build_filename (cmpl_state->reference_dir->fullname,
+                          text,
+                          NULL);
 }
 
 /* The three completion selectors
@@ -2586,19 +2615,55 @@ cmpl_is_a_completion (PossibleCompletion* pc)
 /*                      Construction, deletion                       */
 /**********************************************************************/
 
+/* Get the nearest parent of the current directory for which
+ * we can convert the filename into UTF-8. With paranoia.
+ * Returns "." when all goes wrong.
+ */
+static gchar *
+get_current_dir_utf8 (void)
+{
+  gchar *dir = g_get_current_dir ();
+  gchar *dir_utf8 = NULL;
+
+  while (TRUE)
+    {
+      gchar *last_slash;
+
+      dir_utf8 = g_filename_to_utf8 (dir, -1, NULL, NULL, NULL);
+      if (dir_utf8)
+       break;
+
+      last_slash = strrchr (dir, G_DIR_SEPARATOR);
+      if (!last_slash)         /* g_get_current_dir() wasn't absolute! */
+       break;
+
+      if (last_slash + 1 == g_path_skip_root (dir)) /* Parent directory is a root directory */
+       {
+         if (last_slash[1] == '\0') /* Root misencoded! */
+           break;
+         else
+           last_slash[1] = '\0';
+       }
+      else
+       last_slash[0] = '\0';
+      
+      g_assert (last_slash);
+    }
+
+  g_free (dir);
+  
+  return dir_utf8 ? dir_utf8 : g_strdup (".");
+}
+
 static CompletionState*
 cmpl_init_state (void)
 {
-  gchar *sys_getcwd_buf;
   gchar *utf8_cwd;
   CompletionState *new_state;
 
   new_state = g_new (CompletionState, 1);
 
-  /* 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, -1, NULL, NULL, NULL);
-  g_free (sys_getcwd_buf);
+  utf8_cwd = get_current_dir_utf8 ();
 
 tryagain:
 
@@ -2736,7 +2801,9 @@ cmpl_completion_matches (gchar           *text_to_complete,
                         gchar          **remaining_text,
                         CompletionState *cmpl_state)
 {
+#ifdef HAVE_PWD_H
   gchar* first_slash;
+#endif
   PossibleCompletion *poss;
 
   prune_memory_usage (cmpl_state);
@@ -2878,24 +2945,20 @@ open_ref_dir (gchar           *text_to_complete,
       p = strrchr (tmp, G_DIR_SEPARATOR);
       if (p)
        {
-         if (p == tmp)
+         if (p + 1 == g_path_skip_root (tmp))
            p++;
       
          *p = '\0';
-
          new_dir = open_dir (tmp, cmpl_state);
 
          if (new_dir)
            *remaining_text = text_to_complete + 
-             ((p == tmp + 1) ? (p - tmp) : (p + 1 - tmp));
+             ((p == g_path_skip_root (tmp)) ? (p - tmp) : (p + 1 - tmp));
        }
       else
        {
          /* If no possible candidates, use the cwd */
-         gchar *sys_curdir = g_get_current_dir ();
-         gchar *utf8_curdir = g_filename_to_utf8 (sys_curdir, -1, NULL, NULL, NULL);
-
-         g_free (sys_curdir);
+         gchar *utf8_curdir = get_current_dir_utf8 ();
 
          new_dir = open_dir (utf8_curdir, cmpl_state);
 
@@ -3023,10 +3086,11 @@ open_new_dir (gchar       *dir_name,
   gchar *sys_dir_name;
 
   sent = g_new (CompletionDirSent, 1);
+#ifndef G_PLATFORM_WIN32
   sent->mtime = sbuf->st_mtime;
   sent->inode = sbuf->st_ino;
   sent->device = sbuf->st_dev;
-
+#endif
   path = g_string_sized_new (2*MAXPATHLEN + 10);
 
   sys_dir_name = g_filename_from_utf8 (dir_name, -1, NULL, NULL, NULL);
@@ -3046,7 +3110,6 @@ open_new_dir (gchar       *dir_name,
 
   while ((dirent = g_dir_read_name (directory)) != NULL)
     entry_count++;
-
   entry_count += 2;            /* For ".",".." */
 
   sent->entries = g_new (CompletionDirEntry, entry_count);
@@ -3074,10 +3137,10 @@ open_new_dir (gchar       *dir_name,
          || !g_utf8_validate (sent->entries[n_entries].entry_name, -1, NULL))
        {
          gchar *escaped_str = g_strescape (dirent, NULL);
-         g_message (_("The filename \"%s\" couldn't be converted to UTF-8 "
-                      "(try setting the environment variable G_BROKEN_FILENAMES): %s"),
+         g_message (_("The filename \"%s\" couldn't be converted to UTF-8. "
+                      "(try setting the environment variable G_FILENAME_ENCODING): %s"),
                     escaped_str,
-                    error->message ? error->message : _("Invalid Utf-8"));
+                    error->message ? error->message : _("Invalid UTF-8"));
          g_free (escaped_str);
          g_clear_error (&error);
          continue;
@@ -3119,7 +3182,7 @@ open_new_dir (gchar       *dir_name,
   return sent;
 }
 
-#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
+#ifndef G_PLATFORM_WIN32
 
 static gboolean
 check_dir (gchar       *dir_name,
@@ -3192,12 +3255,14 @@ static CompletionDir*
 open_dir (gchar           *dir_name,
          CompletionState *cmpl_state)
 {
+#ifndef G_PLATFORM_WIN32
   struct stat sbuf;
   gboolean stat_subdirs;
-  CompletionDirSent *sent;
   GList* cdsl;
+#endif
+  CompletionDirSent *sent;
 
-#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
+#ifndef G_PLATFORM_WIN32
   if (!check_dir (dir_name, &sbuf, &stat_subdirs))
     return NULL;
 
@@ -3214,11 +3279,11 @@ open_dir (gchar           *dir_name,
 
       cdsl = cdsl->next;
     }
-#else
-  stat_subdirs = TRUE;
-#endif
 
   sent = open_new_dir (dir_name, &sbuf, stat_subdirs);
+#else
+  sent = open_new_dir (dir_name, NULL, TRUE);
+#endif
 
   if (sent)
     {
@@ -3362,7 +3427,9 @@ correct_parent (CompletionDir *cmpl_dir,
   struct stat parbuf;
   gchar *last_slash;
   gchar *first_slash;
+#ifndef G_PLATFORM_WIN32
   gchar *new_name;
+#endif
   gchar *sys_filename;
   gchar c = 0;
 
@@ -3402,7 +3469,7 @@ correct_parent (CompletionDir *cmpl_dir,
     }
   g_free (sys_filename);
 
-#ifndef G_OS_WIN32             /* No inode numbers on Win32 */
+#ifndef G_PLATFORM_WIN32       /* No inode numbers on Win32 */
   if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev)
     /* it wasn't a link */
     return TRUE;
@@ -3427,7 +3494,7 @@ correct_parent (CompletionDir *cmpl_dir,
   return TRUE;
 }
 
-#ifndef G_OS_WIN32
+#ifndef G_PLATFORM_WIN32
 
 static gchar*
 find_parent_dir_fullname (gchar* dirname)
@@ -3539,7 +3606,12 @@ attempt_homedir_completion (gchar           *text_to_complete,
 
 #endif
 
-#if defined(G_OS_WIN32) || defined(G_WITH_CYGWIN)
+#ifdef G_PLATFORM_WIN32
+/* FIXME: determine whether we should casefold all Unicode letters
+ * here, too (and in in first_diff_index() walk through the strings with
+ * g_utf8_next_char()), or if this folding isn't actually needed at
+ * all.
+ */
 #define FOLD(c) (tolower(c))
 #else
 #define FOLD(c) (c)
@@ -3623,7 +3695,7 @@ find_completion_dir (gchar          *text_to_complete,
       for (i = 0; i < dir->sent->entry_count; i += 1)
        {
          if (dir->sent->entries[i].is_dir &&
-             _gtk_fnmatch (pat_buf, dir->sent->entries[i].entry_name))
+             _gtk_fnmatch (pat_buf, dir->sent->entries[i].entry_name, TRUE))
            {
              if (found)
                {
@@ -3684,10 +3756,10 @@ update_cmpl (PossibleCompletion *poss,
 
   if (cmpl_state->updated_text_alloc < cmpl_len + 1)
     {
+      cmpl_state->updated_text_alloc = 2*cmpl_len;
       cmpl_state->updated_text =
        (gchar*)g_realloc (cmpl_state->updated_text,
                           cmpl_state->updated_text_alloc);
-      cmpl_state->updated_text_alloc = 2*cmpl_len;
     }
 
   if (cmpl_state->updated_text_len < 0)
@@ -3773,7 +3845,7 @@ attempt_file_completion (CompletionState *cmpl_state)
     {
       if (dir->sent->entries[dir->cmpl_index].is_dir)
        {
-         if (_gtk_fnmatch (pat_buf, dir->sent->entries[dir->cmpl_index].entry_name))
+         if (_gtk_fnmatch (pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, TRUE))
            {
              CompletionDir* new_dir;
 
@@ -3821,7 +3893,7 @@ attempt_file_completion (CompletionState *cmpl_state)
       append_completion_text (dir->sent->entries[dir->cmpl_index].entry_name, cmpl_state);
 
       cmpl_state->the_completion.is_a_completion =
-       _gtk_fnmatch (pat_buf, dir->sent->entries[dir->cmpl_index].entry_name);
+       _gtk_fnmatch (pat_buf, dir->sent->entries[dir->cmpl_index].entry_name, TRUE);
 
       cmpl_state->the_completion.is_directory = dir->sent->entries[dir->cmpl_index].is_dir;
       if (dir->sent->entries[dir->cmpl_index].is_dir)