]> Pileus Git - ~andy/gtk/commitdiff
Add -lole32, needed for CoTaskMemFree in get_special_folder() below.
authorTor Lillqvist <tml@iki.fi>
Sun, 2 Jan 2005 23:15:21 +0000 (23:15 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Sun, 2 Jan 2005 23:15:21 +0000 (23:15 +0000)
2005-01-02  Tor Lillqvist  <tml@iki.fi>

* gtk/Makefile.am (libgtk_target_ldflags): Add -lole32, needed for
CoTaskMemFree in get_special_folder() below.

* gtk/gtkfilesystem.h: Implement case-insensitive path compare on
Win32 using _gtk_file_system_win32_path_compare().

* gtk/gtk.symbols: Add _gtk_file_system_win32_path_compare.

* gtk/gtkfilechooserbutton.c (model_add_special)
* gtk/gtkfilechooserdefault.c (shortcuts_append_desktop): Use
_gtk_file_system_win32_get_desktop() to get correct Desktop folder
on Win32. (#144003)

* gtk/gtkfilesystemwin32.c: Remove unnecessary includes. Do
consider all drives "mounted", including floppies. Trying to
inspect the contents of a nonexistent floppy will cause errors
later that are handled normally, no need to avoid them
completely. Keep the drive type in the GtkFileSystemVolume.
Support UNC paths. (#161797) Fix error message capitalizations
as in gtkfilesystemunix.c.

(gtk_file_system_win32_init): Start one timeout per
GtkFileSystemWin32.

(gtk_file_system_win32_finalize): Remove the timeout.

(get_special_folder): Copied from GLib.

(_gtk_file_system_win32_get_desktop): New function, uses
get_special_folder().

(gtk_file_system_win32_list_volumes): Don't start a timeout at
each call to this function. Don't assume A: and B: are floppies.

(gtk_file_system_win32_get_volume_for_path): Don't assume all
volumes are drive roots, i.e. support share roots of UNC paths
(\\server\share).

(gtk_file_system_win32_get_folder): Don't assume errno is set
after g_file_test() returns FALSE. It isn't on Win32 (and even on
Unix I don't think one should assume anything about errno after
g_file_test()).

(gtk_file_system_win32_volume_get_is_mounted): Always return TRUE.

(gtk_file_system_win32_volume_get_display_name): Don't call
GetVolumeInformation() on drives A: or B: if they are removable,
as they might then be floppies, causing an unnecessary
delay. (#157820)

(gtk_file_system_win32_volume_render_icon): Use network icon for
unrecognized drive types.

(canonicalize_filename, gtk_file_system_win32_parse): Don't get
confused by UNC paths.

(bookmarks_serialize): Use _gtk_file_system_win32_path_compare()
for case-insensitive UTF-8 path comparison.

(extract_icon): Use SHGetFileInfo() which is faster than
ExtractAssociatedIcon(). Icon extraction is still slow, though,
needs work.

(win32_pseudo_mime_lookup): Don't use the same icon for all
shortcuts or executables. Cache only other file type icons.

(gtk_file_system_win32_render_icon): Use network stock icon for
remote drives and UNC server share roots. Compare home directory
case-insensitively. Do lookup icons also for executable files,
after all, it's these files that can have individual icons in the
first place. Yes, it can be slow. Needs work.

(filename_is_drive_root): Require also the slash after the colon.

(filename_is_server_share): New function.

(_gtk_file_system_win32_path_compare): New function, does
case-folded UTF-8 comparison.

* gtk/gtkfilesystemwin32.h: Declare
_gtk_file_system_win32_path_compare().

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/Makefile.am
gtk/gtk.symbols
gtk/gtkfilechooserbutton.c
gtk/gtkfilechooserdefault.c
gtk/gtkfilesystem.h
gtk/gtkfilesystemwin32.c
gtk/gtkfilesystemwin32.h

index eb3dac94dfcf15058e69be88770a82e0eed52af5..e9dfccb3967e6db40056018e9898a4980324e9b6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,87 @@
+2005-01-02  Tor Lillqvist  <tml@iki.fi>
+
+       * gtk/Makefile.am (libgtk_target_ldflags): Add -lole32, needed for
+       CoTaskMemFree in get_special_folder() below.
+
+       * gtk/gtkfilesystem.h: Implement case-insensitive path compare on
+       Win32 using _gtk_file_system_win32_path_compare().
+
+       * gtk/gtk.symbols: Add _gtk_file_system_win32_path_compare.
+
+       * gtk/gtkfilechooserbutton.c (model_add_special)
+       * gtk/gtkfilechooserdefault.c (shortcuts_append_desktop): Use
+       _gtk_file_system_win32_get_desktop() to get correct Desktop folder
+       on Win32. (#144003)
+
+       * gtk/gtkfilesystemwin32.c: Remove unnecessary includes. Do
+       consider all drives "mounted", including floppies. Trying to
+       inspect the contents of a nonexistent floppy will cause errors
+       later that are handled normally, no need to avoid them
+       completely. Keep the drive type in the GtkFileSystemVolume.
+       Support UNC paths. (#161797) Fix error message capitalizations
+       as in gtkfilesystemunix.c.
+
+       (gtk_file_system_win32_init): Start one timeout per
+       GtkFileSystemWin32.
+
+       (gtk_file_system_win32_finalize): Remove the timeout.
+
+       (get_special_folder): Copied from GLib.
+
+       (_gtk_file_system_win32_get_desktop): New function, uses
+       get_special_folder().
+
+       (gtk_file_system_win32_list_volumes): Don't start a timeout at
+       each call to this function. Don't assume A: and B: are floppies.
+
+       (gtk_file_system_win32_get_volume_for_path): Don't assume all
+       volumes are drive roots, i.e. support share roots of UNC paths
+       (\\server\share).
+
+       (gtk_file_system_win32_get_folder): Don't assume errno is set
+       after g_file_test() returns FALSE. It isn't on Win32 (and even on
+       Unix I don't think one should assume anything about errno after
+       g_file_test()).
+
+       (gtk_file_system_win32_volume_get_is_mounted): Always return TRUE.
+
+       (gtk_file_system_win32_volume_get_display_name): Don't call
+       GetVolumeInformation() on drives A: or B: if they are removable,
+       as they might then be floppies, causing an unnecessary
+       delay. (#157820)
+
+       (gtk_file_system_win32_volume_render_icon): Use network icon for
+       unrecognized drive types.
+
+       (canonicalize_filename, gtk_file_system_win32_parse): Don't get
+       confused by UNC paths.
+
+       (bookmarks_serialize): Use _gtk_file_system_win32_path_compare()
+       for case-insensitive UTF-8 path comparison.
+
+       (extract_icon): Use SHGetFileInfo() which is faster than
+       ExtractAssociatedIcon(). Icon extraction is still slow, though,
+       needs work.
+
+       (win32_pseudo_mime_lookup): Don't use the same icon for all
+       shortcuts or executables. Cache only other file type icons.
+
+       (gtk_file_system_win32_render_icon): Use network stock icon for
+       remote drives and UNC server share roots. Compare home directory
+       case-insensitively. Do lookup icons also for executable files,
+       after all, it's these files that can have individual icons in the
+       first place. Yes, it can be slow. Needs work.
+
+       (filename_is_drive_root): Require also the slash after the colon.
+
+       (filename_is_server_share): New function.
+
+       (_gtk_file_system_win32_path_compare): New function, does
+       case-folded UTF-8 comparison.
+
+       * gtk/gtkfilesystemwin32.h: Declare
+       _gtk_file_system_win32_path_compare().
+
 2005-01-01  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkbutton.c (gtk_button_set_image): Allow unsetting the
index eb3dac94dfcf15058e69be88770a82e0eed52af5..e9dfccb3967e6db40056018e9898a4980324e9b6 100644 (file)
@@ -1,3 +1,87 @@
+2005-01-02  Tor Lillqvist  <tml@iki.fi>
+
+       * gtk/Makefile.am (libgtk_target_ldflags): Add -lole32, needed for
+       CoTaskMemFree in get_special_folder() below.
+
+       * gtk/gtkfilesystem.h: Implement case-insensitive path compare on
+       Win32 using _gtk_file_system_win32_path_compare().
+
+       * gtk/gtk.symbols: Add _gtk_file_system_win32_path_compare.
+
+       * gtk/gtkfilechooserbutton.c (model_add_special)
+       * gtk/gtkfilechooserdefault.c (shortcuts_append_desktop): Use
+       _gtk_file_system_win32_get_desktop() to get correct Desktop folder
+       on Win32. (#144003)
+
+       * gtk/gtkfilesystemwin32.c: Remove unnecessary includes. Do
+       consider all drives "mounted", including floppies. Trying to
+       inspect the contents of a nonexistent floppy will cause errors
+       later that are handled normally, no need to avoid them
+       completely. Keep the drive type in the GtkFileSystemVolume.
+       Support UNC paths. (#161797) Fix error message capitalizations
+       as in gtkfilesystemunix.c.
+
+       (gtk_file_system_win32_init): Start one timeout per
+       GtkFileSystemWin32.
+
+       (gtk_file_system_win32_finalize): Remove the timeout.
+
+       (get_special_folder): Copied from GLib.
+
+       (_gtk_file_system_win32_get_desktop): New function, uses
+       get_special_folder().
+
+       (gtk_file_system_win32_list_volumes): Don't start a timeout at
+       each call to this function. Don't assume A: and B: are floppies.
+
+       (gtk_file_system_win32_get_volume_for_path): Don't assume all
+       volumes are drive roots, i.e. support share roots of UNC paths
+       (\\server\share).
+
+       (gtk_file_system_win32_get_folder): Don't assume errno is set
+       after g_file_test() returns FALSE. It isn't on Win32 (and even on
+       Unix I don't think one should assume anything about errno after
+       g_file_test()).
+
+       (gtk_file_system_win32_volume_get_is_mounted): Always return TRUE.
+
+       (gtk_file_system_win32_volume_get_display_name): Don't call
+       GetVolumeInformation() on drives A: or B: if they are removable,
+       as they might then be floppies, causing an unnecessary
+       delay. (#157820)
+
+       (gtk_file_system_win32_volume_render_icon): Use network icon for
+       unrecognized drive types.
+
+       (canonicalize_filename, gtk_file_system_win32_parse): Don't get
+       confused by UNC paths.
+
+       (bookmarks_serialize): Use _gtk_file_system_win32_path_compare()
+       for case-insensitive UTF-8 path comparison.
+
+       (extract_icon): Use SHGetFileInfo() which is faster than
+       ExtractAssociatedIcon(). Icon extraction is still slow, though,
+       needs work.
+
+       (win32_pseudo_mime_lookup): Don't use the same icon for all
+       shortcuts or executables. Cache only other file type icons.
+
+       (gtk_file_system_win32_render_icon): Use network stock icon for
+       remote drives and UNC server share roots. Compare home directory
+       case-insensitively. Do lookup icons also for executable files,
+       after all, it's these files that can have individual icons in the
+       first place. Yes, it can be slow. Needs work.
+
+       (filename_is_drive_root): Require also the slash after the colon.
+
+       (filename_is_server_share): New function.
+
+       (_gtk_file_system_win32_path_compare): New function, does
+       case-folded UTF-8 comparison.
+
+       * gtk/gtkfilesystemwin32.h: Declare
+       _gtk_file_system_win32_path_compare().
+
 2005-01-01  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkbutton.c (gtk_button_set_image): Allow unsetting the
index eb3dac94dfcf15058e69be88770a82e0eed52af5..e9dfccb3967e6db40056018e9898a4980324e9b6 100644 (file)
@@ -1,3 +1,87 @@
+2005-01-02  Tor Lillqvist  <tml@iki.fi>
+
+       * gtk/Makefile.am (libgtk_target_ldflags): Add -lole32, needed for
+       CoTaskMemFree in get_special_folder() below.
+
+       * gtk/gtkfilesystem.h: Implement case-insensitive path compare on
+       Win32 using _gtk_file_system_win32_path_compare().
+
+       * gtk/gtk.symbols: Add _gtk_file_system_win32_path_compare.
+
+       * gtk/gtkfilechooserbutton.c (model_add_special)
+       * gtk/gtkfilechooserdefault.c (shortcuts_append_desktop): Use
+       _gtk_file_system_win32_get_desktop() to get correct Desktop folder
+       on Win32. (#144003)
+
+       * gtk/gtkfilesystemwin32.c: Remove unnecessary includes. Do
+       consider all drives "mounted", including floppies. Trying to
+       inspect the contents of a nonexistent floppy will cause errors
+       later that are handled normally, no need to avoid them
+       completely. Keep the drive type in the GtkFileSystemVolume.
+       Support UNC paths. (#161797) Fix error message capitalizations
+       as in gtkfilesystemunix.c.
+
+       (gtk_file_system_win32_init): Start one timeout per
+       GtkFileSystemWin32.
+
+       (gtk_file_system_win32_finalize): Remove the timeout.
+
+       (get_special_folder): Copied from GLib.
+
+       (_gtk_file_system_win32_get_desktop): New function, uses
+       get_special_folder().
+
+       (gtk_file_system_win32_list_volumes): Don't start a timeout at
+       each call to this function. Don't assume A: and B: are floppies.
+
+       (gtk_file_system_win32_get_volume_for_path): Don't assume all
+       volumes are drive roots, i.e. support share roots of UNC paths
+       (\\server\share).
+
+       (gtk_file_system_win32_get_folder): Don't assume errno is set
+       after g_file_test() returns FALSE. It isn't on Win32 (and even on
+       Unix I don't think one should assume anything about errno after
+       g_file_test()).
+
+       (gtk_file_system_win32_volume_get_is_mounted): Always return TRUE.
+
+       (gtk_file_system_win32_volume_get_display_name): Don't call
+       GetVolumeInformation() on drives A: or B: if they are removable,
+       as they might then be floppies, causing an unnecessary
+       delay. (#157820)
+
+       (gtk_file_system_win32_volume_render_icon): Use network icon for
+       unrecognized drive types.
+
+       (canonicalize_filename, gtk_file_system_win32_parse): Don't get
+       confused by UNC paths.
+
+       (bookmarks_serialize): Use _gtk_file_system_win32_path_compare()
+       for case-insensitive UTF-8 path comparison.
+
+       (extract_icon): Use SHGetFileInfo() which is faster than
+       ExtractAssociatedIcon(). Icon extraction is still slow, though,
+       needs work.
+
+       (win32_pseudo_mime_lookup): Don't use the same icon for all
+       shortcuts or executables. Cache only other file type icons.
+
+       (gtk_file_system_win32_render_icon): Use network stock icon for
+       remote drives and UNC server share roots. Compare home directory
+       case-insensitively. Do lookup icons also for executable files,
+       after all, it's these files that can have individual icons in the
+       first place. Yes, it can be slow. Needs work.
+
+       (filename_is_drive_root): Require also the slash after the colon.
+
+       (filename_is_server_share): New function.
+
+       (_gtk_file_system_win32_path_compare): New function, does
+       case-folded UTF-8 comparison.
+
+       * gtk/gtkfilesystemwin32.h: Declare
+       _gtk_file_system_win32_path_compare().
+
 2005-01-01  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkbutton.c (gtk_button_set_image): Allow unsetting the
index eb3dac94dfcf15058e69be88770a82e0eed52af5..e9dfccb3967e6db40056018e9898a4980324e9b6 100644 (file)
@@ -1,3 +1,87 @@
+2005-01-02  Tor Lillqvist  <tml@iki.fi>
+
+       * gtk/Makefile.am (libgtk_target_ldflags): Add -lole32, needed for
+       CoTaskMemFree in get_special_folder() below.
+
+       * gtk/gtkfilesystem.h: Implement case-insensitive path compare on
+       Win32 using _gtk_file_system_win32_path_compare().
+
+       * gtk/gtk.symbols: Add _gtk_file_system_win32_path_compare.
+
+       * gtk/gtkfilechooserbutton.c (model_add_special)
+       * gtk/gtkfilechooserdefault.c (shortcuts_append_desktop): Use
+       _gtk_file_system_win32_get_desktop() to get correct Desktop folder
+       on Win32. (#144003)
+
+       * gtk/gtkfilesystemwin32.c: Remove unnecessary includes. Do
+       consider all drives "mounted", including floppies. Trying to
+       inspect the contents of a nonexistent floppy will cause errors
+       later that are handled normally, no need to avoid them
+       completely. Keep the drive type in the GtkFileSystemVolume.
+       Support UNC paths. (#161797) Fix error message capitalizations
+       as in gtkfilesystemunix.c.
+
+       (gtk_file_system_win32_init): Start one timeout per
+       GtkFileSystemWin32.
+
+       (gtk_file_system_win32_finalize): Remove the timeout.
+
+       (get_special_folder): Copied from GLib.
+
+       (_gtk_file_system_win32_get_desktop): New function, uses
+       get_special_folder().
+
+       (gtk_file_system_win32_list_volumes): Don't start a timeout at
+       each call to this function. Don't assume A: and B: are floppies.
+
+       (gtk_file_system_win32_get_volume_for_path): Don't assume all
+       volumes are drive roots, i.e. support share roots of UNC paths
+       (\\server\share).
+
+       (gtk_file_system_win32_get_folder): Don't assume errno is set
+       after g_file_test() returns FALSE. It isn't on Win32 (and even on
+       Unix I don't think one should assume anything about errno after
+       g_file_test()).
+
+       (gtk_file_system_win32_volume_get_is_mounted): Always return TRUE.
+
+       (gtk_file_system_win32_volume_get_display_name): Don't call
+       GetVolumeInformation() on drives A: or B: if they are removable,
+       as they might then be floppies, causing an unnecessary
+       delay. (#157820)
+
+       (gtk_file_system_win32_volume_render_icon): Use network icon for
+       unrecognized drive types.
+
+       (canonicalize_filename, gtk_file_system_win32_parse): Don't get
+       confused by UNC paths.
+
+       (bookmarks_serialize): Use _gtk_file_system_win32_path_compare()
+       for case-insensitive UTF-8 path comparison.
+
+       (extract_icon): Use SHGetFileInfo() which is faster than
+       ExtractAssociatedIcon(). Icon extraction is still slow, though,
+       needs work.
+
+       (win32_pseudo_mime_lookup): Don't use the same icon for all
+       shortcuts or executables. Cache only other file type icons.
+
+       (gtk_file_system_win32_render_icon): Use network stock icon for
+       remote drives and UNC server share roots. Compare home directory
+       case-insensitively. Do lookup icons also for executable files,
+       after all, it's these files that can have individual icons in the
+       first place. Yes, it can be slow. Needs work.
+
+       (filename_is_drive_root): Require also the slash after the colon.
+
+       (filename_is_server_share): New function.
+
+       (_gtk_file_system_win32_path_compare): New function, does
+       case-folded UTF-8 comparison.
+
+       * gtk/gtkfilesystemwin32.h: Declare
+       _gtk_file_system_win32_path_compare().
+
 2005-01-01  Matthias Clasen  <mclasen@redhat.com>
 
        * gtk/gtkbutton.c (gtk_button_set_image): Allow unsetting the
index 6cb2e7108f8be4a4b5d0c39d8dddaca103c883d9..2e0b8a50f6e66438b607c019d5bebea576926f00 100644 (file)
@@ -665,7 +665,7 @@ libgtk_win32_2_0_la_LIBADD = $(libadd) $(gtk_win32res_lo)
 libgtk_win32_2_0_la_DEPENDENCIES = $(gtk_def) $(gtk_win32res_lo)
 
 if USE_WIN32
-libgtk_target_ldflags = $(gtk_win32_symbols) -lwsock32
+libgtk_target_ldflags = $(gtk_win32_symbols) -lole32 -lwsock32
 endif
 EXTRA_LTLIBRARIES = libgtk-x11-2.0.la libgtk-linux-fb-2.0.la libgtk-win32-2.0.la
 
index 809a09583e2d274ac7e7948db69bc0706114a774..902da3b546727407420e8d455bfaededd07bb0b3 100644 (file)
@@ -3009,3 +3009,6 @@ gtk_window_unfullscreen
 gtk_window_unmaximize
 gtk_window_unstick
 gtk_wrap_mode_get_type G_GNUC_CONST
+#ifdef G_OS_WIN32
+_gtk_file_system_win32_path_compare
+#endif
index 7ca26a22d953007c20a8810d51c31160646acd20..3f684a3bd0dc085083ca52a920340976fe09a7e9 100644 (file)
@@ -52,6 +52,9 @@
 
 #include "gtkfilechooserbutton.h"
 
+#ifdef G_OS_WIN32
+#include "gtkfilesystemwin32.h"
+#endif
 
 /* **************** *
  *  Private Macros  *
@@ -1273,27 +1276,26 @@ static inline void
 model_add_special (GtkFileChooserButton *button)
 {
   const gchar *homedir;
+  gchar *desktopdir = NULL;
+  GtkListStore *store;
+  GtkTreeIter iter;
+  GtkFilePath *path;
+  GdkPixbuf *pixbuf;
+  gint pos;
+
+  store = GTK_LIST_STORE (button->priv->model);
+  pos = model_get_type_position (button, ROW_TYPE_SPECIAL);
 
   homedir = g_get_home_dir ();
 
   if (homedir)
     {
-      GtkListStore *store;
-      GtkTreeIter iter;
-      GtkFilePath *path;
-      GdkPixbuf *pixbuf;
-      gchar *desktopdir;
-      gint pos;
-
-      store = GTK_LIST_STORE (button->priv->model);
-
-      pos = model_get_type_position (button, ROW_TYPE_SPECIAL);
-
       path = gtk_file_system_filename_to_path (button->priv->fs, homedir);
       pixbuf = gtk_file_system_render_icon (button->priv->fs, path,
                                            GTK_WIDGET (button),
                                            button->priv->icon_size, NULL);
       gtk_list_store_insert (store, &iter, pos);
+      pos++;
       gtk_list_store_set (store, &iter,
                          ICON_COLUMN, pixbuf,
                          DISPLAY_NAME_COLUMN, _(HOME_DISPLAY_NAME),
@@ -1304,15 +1306,24 @@ model_add_special (GtkFileChooserButton *button)
       g_object_unref (pixbuf);
       button->priv->n_special++;
 
+#ifndef G_OS_WIN32
       desktopdir = g_build_filename (homedir, DESKTOP_DISPLAY_NAME, NULL);
-      pos++;
+#endif
+    }
+
+#ifdef G_OS_WIN32
+  desktopdir = _gtk_file_system_win32_get_desktop ();
+#endif
 
+  if (desktopdir)
+    {
       path = gtk_file_system_filename_to_path (button->priv->fs, desktopdir);
       g_free (desktopdir);
       pixbuf = gtk_file_system_render_icon (button->priv->fs, path,
                                            GTK_WIDGET (button),
                                            button->priv->icon_size, NULL);
       gtk_list_store_insert (store, &iter, pos);
+      pos++;
       gtk_list_store_set (store, &iter,
                          TYPE_COLUMN, ROW_TYPE_SPECIAL,
                          ICON_COLUMN, pixbuf,
index 4cd013f0022d3074c855186de0646a81490688ce..d1351969176bf5065a3621dc890659afdf1e25f7 100644 (file)
@@ -1235,15 +1235,19 @@ shortcuts_append_home (GtkFileChooserDefault *impl)
 static void
 shortcuts_append_desktop (GtkFileChooserDefault *impl)
 {
-  const char *home;
   char *name;
   GtkFilePath *path;
 
-  home = g_get_home_dir ();
+#ifdef G_OS_WIN32
+  name = _gtk_file_system_win32_get_desktop ();
+#else
+  const char *home = g_get_home_dir ();
   if (home == NULL)
     return;
 
   name = g_build_filename (home, "Desktop", NULL);
+#endif
+
   path = gtk_file_system_filename_to_path (impl->file_system, name);
   g_free (name);
 
index 83ec6f63a3e5db8f02febd0fd48a9e10e2689ece..ab8ab0ac08ebf96d7cbda015e6af8690082eec22 100644 (file)
@@ -345,8 +345,16 @@ GType   gtk_file_path_get_type (void) G_GNUC_CONST;
 #endif/* __GNUC__ */
 
 #define gtk_file_path_copy(path)       gtk_file_path_new_dup (gtk_file_path_get_string(path))
+#ifdef G_OS_WIN32
+int _gtk_file_system_win32_path_compare (const gchar *path1,
+                                        const gchar *path2);
+#define gtk_file_path_compare(path1,path2) \
+  _gtk_file_system_win32_path_compare (gtk_file_path_get_string (path1), \
+                                      gtk_file_path_get_string (path2))
+#else
 #define gtk_file_path_compare(path1,path2) strcmp (gtk_file_path_get_string (path1), \
                                                   gtk_file_path_get_string (path2))
+#endif
 
 GSList *gtk_file_paths_sort (GSList *paths);
 GSList *gtk_file_paths_copy (GSList *paths);
index d63e2bd6530827fbdbb8e88464ed3955a0c5fe06..ff366aa0de64e4c5e94b3379d9f4ccc0fbe0f256 100644 (file)
 
 #ifdef G_OS_WIN32
 #define WIN32_LEAN_AND_MEAN
+#define STRICT
 #include <windows.h>
-#include <shellapi.h> /* ExtractAssociatedIcon */
-#include <direct.h>
-#include <io.h>
-#include <gdk/win32/gdkwin32.h> /* gdk_win32_hdc_get */
+#undef STRICT
+#include <shlobj.h>
+#include <shellapi.h>
 #else
 #error "The implementation is win32 only."
 #endif /* G_OS_WIN32 */
 
-#ifndef G_IS_DIR_SEPARATOR
-#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
-#endif
-
 typedef struct _GtkFileSystemWin32Class GtkFileSystemWin32Class;
 
 #define GTK_FILE_SYSTEM_WIN32_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_WIN32, GtkFileSystemWin32Class))
@@ -65,8 +61,9 @@ struct _GtkFileSystemWin32
 {
   GObject parent_instance;
 
-  guint32     drives; /* bitmask as returned by GetLogicalDrives() */
+  guint32 drives;              /* bitmask as returned by GetLogicalDrives() */
   GHashTable *folder_hash;
+  guint timeout;
 };
 
 #define GTK_TYPE_FILE_FOLDER_WIN32             (gtk_file_folder_win32_get_type ())
@@ -182,6 +179,7 @@ static gchar *        filename_from_path                     (const GtkFilePath
 static GtkFilePath *  filename_to_path                       (const gchar              *filename);
 
 static gboolean       filename_is_drive_root                 (const char               *filename);
+static gboolean       filename_is_server_share               (const char               *filename);
 static gboolean       filename_is_some_root                  (const char               *filename);
 static GtkFileInfo *  filename_get_info                      (const gchar              *filename,
                                                              GtkFileInfoType           types,
@@ -190,8 +188,8 @@ static GtkFileInfo *  filename_get_info                      (const gchar
 /* some info kept together for volumes */
 struct _GtkFileSystemVolume
 {
-  gchar    *drive;
-  gboolean  is_mounted;
+  gchar *drive;
+  int drive_type;
 };
 
 /*
@@ -286,9 +284,32 @@ gtk_file_system_win32_iface_init (GtkFileSystemIface *iface)
   iface->list_bookmarks = gtk_file_system_win32_list_bookmarks;
 }
 
+static gboolean
+check_volumes (gpointer data)
+{
+  GtkFileSystemWin32 *system_win32 = GTK_FILE_SYSTEM_WIN32 (data);
+
+  g_return_val_if_fail (system_win32, FALSE);
+
+#if 0
+  printf("check_volumes: system_win32=%p\n", system_win32);
+#endif
+  if (system_win32->drives != GetLogicalDrives())
+    g_signal_emit_by_name (system_win32, "volumes-changed", 0);
+
+  return TRUE;
+}
+
 static void
 gtk_file_system_win32_init (GtkFileSystemWin32 *system_win32)
 {
+#if 0
+  printf("gtk_file_system_win32_init: %p\n", system_win32);
+#endif
+
+  /* set up an idle handler for volume changes, every second should be enough */
+  system_win32->timeout = g_timeout_add_full (0, 1000, check_volumes, system_win32, NULL);
+
   system_win32->folder_hash = g_hash_table_new (g_str_hash, g_str_equal);
 }
 
@@ -299,23 +320,56 @@ gtk_file_system_win32_finalize (GObject *object)
 
   system_win32 = GTK_FILE_SYSTEM_WIN32 (object);
 
+#if 0
+  printf("gtk_file_system_win32_finalize: %p\n", system_win32);
+#endif
+
+  g_source_remove (system_win32->timeout);
+
   /* FIXME: assert that the hash is empty? */
   g_hash_table_destroy (system_win32->folder_hash);
 
   system_parent_class->finalize (object);
 }
 
-static gboolean
-check_volumes (gpointer data)
-{
-  GtkFileSystemWin32 *fs_win32 = GTK_FILE_SYSTEM_WIN32 (data);
-
-  g_return_val_if_fail (fs_win32, FALSE);
+/* Lifted from GLib */
 
-  if (fs_win32->drives != GetLogicalDrives())
-    g_signal_emit_by_name (fs_win32, "volumes-changed", 0);
+static gchar *
+get_special_folder (int csidl)
+{
+  union {
+    char c[MAX_PATH+1];
+    wchar_t wc[MAX_PATH+1];
+  } path;
+  HRESULT hr;
+  LPITEMIDLIST pidl = NULL;
+  BOOL b;
+  gchar *retval = NULL;
+
+  hr = SHGetSpecialFolderLocation (NULL, csidl, &pidl);
+  if (hr == S_OK)
+    {
+      if (G_WIN32_HAVE_WIDECHAR_API ())
+       {
+         b = SHGetPathFromIDListW (pidl, path.wc);
+         if (b)
+           retval = g_utf16_to_utf8 (path.wc, -1, NULL, NULL, NULL);
+       }
+      else
+       {
+         b = SHGetPathFromIDListA (pidl, path.c);
+         if (b)
+           retval = g_locale_to_utf8 (path.c, -1, NULL, NULL, NULL);
+       }
+      CoTaskMemFree (pidl);
+    }
+  return retval;
+}
 
-  return TRUE;
+gchar *
+_gtk_file_system_win32_get_desktop (void)
+{
+  return get_special_folder (CSIDL_DESKTOPDIRECTORY);
 }
 
 static GSList *
@@ -324,14 +378,11 @@ gtk_file_system_win32_list_volumes (GtkFileSystem *file_system)
   DWORD   drives;
   gchar   drive[4] = "A:\\";
   GSList *list = NULL;
-  GtkFileSystemWin32 *fs_win32 = (GtkFileSystemWin32 *)file_system;
+  GtkFileSystemWin32 *system_win32 = (GtkFileSystemWin32 *)file_system;
 
   drives = GetLogicalDrives();
 
-  fs_win32->drives = drives;
-  /* set up an idle handler for volume changes, every second should be enough */
-  g_timeout_add_full (0, 1000, check_volumes, fs_win32, NULL);
-
+  system_win32->drives = drives;
   if (!drives)
     g_warning ("GetLogicalDrives failed.");
 
@@ -340,12 +391,8 @@ gtk_file_system_win32_list_volumes (GtkFileSystem *file_system)
       if (drives & 1)
       {
        GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
-       if (drive[0] == 'A' || drive[0] == 'B')
-         vol->is_mounted = FALSE; /* skip floppy */
-       else
-         vol->is_mounted = TRUE; /* handle other removable drives special, too? */
-
        vol->drive = g_strdup (drive);
+       vol->drive_type = GetDriveType (drive);
        list = g_slist_append (list, vol);
       }
       drives >>= 1;
@@ -359,15 +406,50 @@ gtk_file_system_win32_get_volume_for_path (GtkFileSystem     *file_system,
                                            const GtkFilePath *path)
 {
   GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
-  gchar* p = g_strndup (gtk_file_path_get_string (path), 3);
+  const gchar *p;
 
-  g_return_val_if_fail (p != NULL, NULL);
+  g_return_val_if_fail (path != NULL, NULL);
 
-  /*FIXME: gtk_file_path_compare() is case sensitive, we are not*/
-  p[0] = g_ascii_toupper (p[0]);
-  vol->drive = p;
-  vol->is_mounted = (p[0] != 'A' && p[0] != 'B');
+  p = gtk_file_path_get_string (path);
 
+  if (!g_path_is_absolute (p))
+    {
+      if (g_ascii_isalpha (p[0]) && p[1] == ':')
+       vol->drive = g_strdup_printf ("%c:\\", p[0]);
+      else
+       vol->drive = g_strdup ("\\");
+      vol->drive_type = GetDriveType (vol->drive);
+    }
+  else
+    {
+      const gchar *q = g_path_skip_root (p);
+      vol->drive = g_strndup (p, q - p);
+      if (!G_IS_DIR_SEPARATOR (q[-1]))
+       {
+         /* Make sure "drive" always ends in a slash */
+         gchar *tem = vol->drive;
+         vol->drive = g_strconcat (vol->drive, "\\", NULL);
+         g_free (tem);
+       }
+      
+      if (filename_is_drive_root (vol->drive))
+       {
+         vol->drive[0] = g_ascii_toupper (vol->drive[0]);
+         vol->drive_type = GetDriveType (vol->drive);
+       }
+      else if (G_WIN32_HAVE_WIDECHAR_API ())
+       {
+         wchar_t *wdrive = g_utf8_to_utf16 (vol->drive, -1, NULL, NULL, NULL);
+         vol->drive_type = GetDriveTypeW (wdrive);
+         g_free (wdrive);
+       }
+      else
+       {
+         gchar *cpdrive = g_locale_from_utf8 (vol->drive, -1, NULL, NULL, NULL);
+         vol->drive_type = GetDriveTypeA (cpdrive);
+         g_free (cpdrive);
+       }
+    }
   return vol;
 }
 
@@ -391,30 +473,28 @@ gtk_file_system_win32_get_folder (GtkFileSystem     *file_system,
   if (folder_win32)
     return g_object_ref (folder_win32);
 
+  if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+    {
+      gchar *display_filename = g_filename_display_name (filename);
+      g_set_error (error,
+                  GTK_FILE_SYSTEM_ERROR,
+                  GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
+                  _("Error getting information for '%s': %s"),
+                  display_filename,
+                  g_strerror (ENOENT));
+      g_free (display_filename);
+      return NULL;
+    }
   if (!g_file_test (filename, G_FILE_TEST_IS_DIR))
     {
-      int save_errno = errno;
       gchar *display_filename = g_filename_display_name (filename);
 
-      /* If g_file_test() returned FALSE but not due to an error, it means
-       * that the filename is not a directory.
-       */
-      if (save_errno == 0)
-       /* ENOTDIR */
-       g_set_error (error,
-                    GTK_FILE_SYSTEM_ERROR,
-                    GTK_FILE_SYSTEM_ERROR_NOT_FOLDER,
-                    _("%s: %s"),
-                    display_filename,
-                    g_strerror (ENOTDIR));
-      else
-       g_set_error (error,
-                    GTK_FILE_SYSTEM_ERROR,
-                    GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
-                    _("error getting information for '%s': %s"),
-                    display_filename,
-                    g_strerror (save_errno));
-
+      g_set_error (error,
+                  GTK_FILE_SYSTEM_ERROR,
+                  GTK_FILE_SYSTEM_ERROR_NOT_FOLDER,
+                  _("Error getting information for '%s': %s"),
+                  display_filename,
+                  g_strerror (ENOTDIR));
       g_free (display_filename);
       return NULL;
     }
@@ -443,21 +523,23 @@ gtk_file_system_win32_create_folder (GtkFileSystem     *file_system,
 
   filename = filename_from_path (path);
   g_return_val_if_fail (filename != NULL, FALSE);
+  g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
 
   result = g_mkdir (filename, 0777) == 0;
 
   if (!result)
     {
+      int save_errno = errno;
       gchar *display_filename = g_filename_display_name (filename);
       g_set_error (error,
                   GTK_FILE_SYSTEM_ERROR,
                   GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
-                  _("error creating directory '%s': %s"),
+                  _("Error creating directory '%s': %s"),
                   display_filename,
-                  g_strerror (errno));
+                  g_strerror (save_errno));
       g_free (display_filename);
     }
-  else if (!filename_is_drive_root (filename))
+  else if (!filename_is_some_root (filename))
     {
       parent = g_path_get_dirname (filename);
       if (parent)
@@ -501,7 +583,7 @@ static gboolean
 gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem        *file_system,
                                             GtkFileSystemVolume  *volume)
 {
-  return volume->is_mounted;
+  return TRUE;
 }
 
 static gboolean
@@ -521,28 +603,33 @@ gtk_file_system_win32_volume_get_display_name (GtkFileSystem       *file_system,
                                               GtkFileSystemVolume *volume)
 {
   gchar *real_display_name;
-  gunichar2 *wdrive = g_utf8_to_utf16 (volume->drive, -1, NULL, NULL, NULL);
-  gunichar2  wname[80];
-
-  g_return_val_if_fail (wdrive != NULL, NULL);
-
-  if (GetVolumeInformationW (wdrive,
-                            wname, G_N_ELEMENTS(wname), 
-                            NULL, /* serial number */
-                            NULL, /* max. component length */
-                            NULL, /* fs flags */
-                            NULL, 0) /* fs type like FAT, NTFS */
-      && wname[0])
+
+  g_return_val_if_fail (volume->drive != NULL, NULL);
+
+  if ((filename_is_drive_root (volume->drive) && volume->drive[0] >= 'C') ||
+      volume->drive_type != DRIVE_REMOVABLE)
     {
-      gchar *name = g_utf16_to_utf8 (wname, -1, NULL, NULL, NULL);
-      real_display_name = g_strconcat (name, " (", volume->drive, ")", NULL);
-      g_free (name);
+      gunichar2 *wdrive = g_utf8_to_utf16 (volume->drive, -1, NULL, NULL, NULL);
+      gunichar2 wname[80];
+      if (GetVolumeInformationW (wdrive,
+                                wname, G_N_ELEMENTS(wname), 
+                                NULL, /* serial number */
+                                NULL, /* max. component length */
+                                NULL, /* fs flags */
+                                NULL, 0) /* fs type like FAT, NTFS */ &&
+         wname[0])
+       {
+         gchar *name = g_utf16_to_utf8 (wname, -1, NULL, NULL, NULL);
+         real_display_name = g_strconcat (name, " (", volume->drive, ")", NULL);
+         g_free (name);
+       }
+      else
+       real_display_name = g_strdup (volume->drive);
+      g_free (wdrive);
     }
   else
     real_display_name = g_strdup (volume->drive);
 
-  g_free (wdrive);
-
   return real_display_name;
 }
 
@@ -554,28 +641,31 @@ gtk_file_system_win32_volume_render_icon (GtkFileSystem        *file_system,
                                          GError              **error)
 {
   GtkIconSet *icon_set = NULL;
-  DWORD dt = GetDriveType (volume->drive);
 
-  switch (dt)
+  switch (volume->drive_type)
     {
-    case DRIVE_REMOVABLE :
+    case DRIVE_REMOVABLE:
       icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
       break;
-    case DRIVE_CDROM :
+    case DRIVE_CDROM:
       icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
       break;
-    case DRIVE_REMOTE :
+    case DRIVE_REMOTE:
       icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
       break;
-    case DRIVE_FIXED :
+    case DRIVE_FIXED:
       icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
       break;
-    case DRIVE_RAMDISK :
-      /*FIXME: need a ram stock icon
-      gtk_file_info_set_icon_type (info, GTK_STOCK_OPEN);*/
+    case DRIVE_RAMDISK:
+#if 0
+      /*FIXME: need a ram stock icon?? */
+      gtk_file_info_set_icon_type (info, GTK_STOCK_RAMDISK);
       break;
+#endif
     default :
-      g_assert_not_reached ();
+      /* Use network icon as a guess */ 
+      icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
+      break;
     }
 
   return gtk_icon_set_render_icon (icon_set, 
@@ -648,16 +738,9 @@ canonicalize_filename (gchar *filename)
   printf("canonicalize_filename: %s ", filename);
 #endif
 
-  p = filename;
-  q = filename;
+  past_root = g_path_skip_root (filename);
 
-  if (g_ascii_isalpha (*filename) &&
-      filename[1] == ':' &&
-      G_IS_DIR_SEPARATOR (filename[2]))
-    past_root = filename + 3;
-  else
-    past_root = filename + 1;
-  
+  q = p = past_root;
 
   while (*p)
     {
@@ -758,7 +841,6 @@ gtk_file_system_win32_parse (GtkFileSystem     *file_system,
     {
       gchar *folder_part;
       gchar *folder_path;
-      GError *tmp_error = NULL;
 
       if (last_slash == str)
        {
@@ -772,37 +854,31 @@ gtk_file_system_win32_parse (GtkFileSystem     *file_system,
               str[1] == ':' &&
               G_IS_DIR_SEPARATOR (str[2]))
        folder_part = g_strndup (str, last_slash - str + 1);
+      else if (G_IS_DIR_SEPARATOR (str[0]) &&
+              G_IS_DIR_SEPARATOR (str[1]) &&
+              (!str[2] || !G_IS_DIR_SEPARATOR (str[2])))
+       folder_part = g_strdup (str);
       else
        folder_part = g_strndup (str, last_slash - str);
 
-      if (!folder_part)
-       {
-         g_set_error (error,
-                      GTK_FILE_SYSTEM_ERROR,
-                      GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
-                      "%s",
-                      tmp_error->message);
-         g_error_free (tmp_error);
-       }
+      g_assert (folder_part);
+
+      if (g_path_is_absolute (folder_part))
+       folder_path = folder_part;
       else
        {
-         if (g_path_is_absolute (folder_part))
-           folder_path = folder_part;
-         else
-           {
-             folder_path = g_build_filename (base_filename, folder_part, NULL);
-             g_free (folder_part);
-           }
-
-         canonicalize_filename (folder_path);
-         
-         *folder = filename_to_path (folder_path);
-         *file_part = g_strdup (last_slash + 1);
-
-         g_free (folder_path);
-
-         result = TRUE;
+         folder_path = g_build_filename (base_filename, folder_part, NULL);
+         g_free (folder_part);
        }
+      
+      canonicalize_filename (folder_path);
+      
+      *folder = filename_to_path (folder_path);
+      *file_part = g_strdup (last_slash + 1);
+      
+      g_free (folder_path);
+      
+      result = TRUE;
     }
 
 #if 0
@@ -877,7 +953,7 @@ bookmarks_serialize (GSList  **bookmarks,
 
              for (i = 0; lines[i] != NULL; i++)
                {
-                 if (lines[i][0] && !g_slist_find_custom (list, lines[i], (GCompareFunc) strcmp))
+                 if (lines[i][0] && !g_slist_find_custom (list, lines[i], (GCompareFunc) _gtk_file_system_win32_path_compare))
                    list = g_slist_append (list, g_strdup (lines[i]));
                }
              g_strfreev (lines);
@@ -887,7 +963,7 @@ bookmarks_serialize (GSList  **bookmarks,
        }
       if (ok && (f = g_fopen (filename, "wb")) != NULL)
         {
-         entry = g_slist_find_custom (list, uri, (GCompareFunc) strcmp);
+         entry = g_slist_find_custom (list, uri, (GCompareFunc) _gtk_file_system_win32_path_compare);
          if (add)
            {
              /* g_slist_insert() and our insert semantics are 
@@ -902,7 +978,7 @@ bookmarks_serialize (GSList  **bookmarks,
                  g_set_error (error,
                               GTK_FILE_SYSTEM_ERROR,
                               GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
-                              "%s already exists in the bookmarks list",
+                              "'%s' already exists in the bookmarks list",
                               uri);
                  ok = FALSE;
                }
@@ -925,7 +1001,7 @@ bookmarks_serialize (GSList  **bookmarks,
          g_set_error (error,
                       GTK_FILE_SYSTEM_ERROR,
                       GTK_FILE_SYSTEM_ERROR_FAILED,
-                      _("Bookmark saving failed (%s)"),
+                      _("Bookmark saving failed: %s"),
                       g_strerror (errno));
        }
     }
@@ -937,99 +1013,166 @@ static GdkPixbuf*
 extract_icon (const char* filename)
 {
   GdkPixbuf *pixbuf = NULL;
-  WORD iicon;
   HICON hicon;
-  char filename_copy[MAX_PATH];
+  ICONINFO ii;
   
   if (!filename || !filename[0])
     return NULL;
 
-  /* the ugly ExtractAssociatedIcon modifies filename in place - at least on win98 */
-  strcpy(filename_copy, filename);
-  hicon = ExtractAssociatedIcon (GetModuleHandle (NULL), filename_copy, &iicon);
-  if (hicon > (HICON)1)
+#if 0
+  /* ExtractAssociatedIconW() is about twice as slow as SHGetFileInfoW() */
+
+  /* The ugly ExtractAssociatedIcon modifies filename in place. It
+   * doesn't even take any argument saying how large the buffer is?
+   * Let's hope MAX_PATH will be large enough. What dork designed that
+   * API?
+   */
+  if (G_WIN32_HAVE_WIDECHAR_API ())
     {
-      ICONINFO ii;
+      WORD iicon;
+      wchar_t *wfn;
+      wchar_t filename_copy[MAX_PATH];
 
-      if (GetIconInfo (hicon, &ii))
-        {
-         struct
-         {
-           BITMAPINFOHEADER bi;
-           RGBQUAD colors[2];
-         } bmi;
-         HDC hdc;
-
-         memset (&bmi, 0, sizeof (bmi));
-         bmi.bi.biSize = sizeof (bmi.bi);
-         hdc = CreateCompatibleDC (NULL);
-
-          if (GetDIBits (hdc, ii.hbmColor, 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS))
+      wfn = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      if (wcslen (wfn) >= MAX_PATH)
+       {
+         g_free (wfn);
+         return NULL;
+       }
+      wcscpy (filename_copy, wfn);
+      g_free (wfn);
+      hicon = ExtractAssociatedIconW (GetModuleHandle (NULL), filename_copy, &iicon);
+    }
+  else
+    {
+      WORD iicon;
+      char *cpfn;
+      char filename_copy[MAX_PATH];
+
+      cpfn = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      if (cpfn == NULL)
+       return NULL;
+      if (strlen (cpfn) >= MAX_PATH)
+       {
+         g_free (cpfn);
+         return NULL;
+       }
+      strcpy (filename_copy, cpfn);
+      g_free (cpfn);
+      hicon = ExtractAssociatedIconA (GetModuleHandle (NULL), filename_copy, &iicon);
+    }
+
+  if (!hicon)
+    {
+      g_warning (G_STRLOC ":ExtractAssociatedIcon(%s) failed: %s", filename, g_win32_error_message (GetLastError ()));
+      return NULL;
+    }
+
+#else
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      SHFILEINFOW shfi;
+      wchar_t *wfn = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int rc;
+
+      rc = (int) SHGetFileInfoW (wfn, 0, &shfi, sizeof (shfi),
+                                SHGFI_ICON|SHGFI_LARGEICON);
+      g_free (wfn);
+      if (!rc)
+       return NULL;
+      hicon = shfi.hIcon;
+    }
+  else
+    {
+      SHFILEINFOA shfi;
+      char *cpfn = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int rc;
+
+      rc = (int) SHGetFileInfoA (cpfn, 0, &shfi, sizeof (shfi),
+                                SHGFI_ICON|SHGFI_LARGEICON);
+      g_free (cpfn);
+      if (!rc)
+       return NULL;
+      hicon = shfi.hIcon;
+    }
+#endif
+  
+  if (GetIconInfo (hicon, &ii))
+    {
+      struct
+      {
+       BITMAPINFOHEADER bi;
+       RGBQUAD colors[2];
+      } bmi;
+      HDC hdc;
+      
+      memset (&bmi, 0, sizeof (bmi));
+      bmi.bi.biSize = sizeof (bmi.bi);
+      hdc = CreateCompatibleDC (NULL);
+      
+      if (GetDIBits (hdc, ii.hbmColor, 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS))
+       {
+         gchar *pixels, *bits;
+         gint rowstride, x, y, w = bmi.bi.biWidth, h = bmi.bi.biHeight;
+         gboolean no_alpha;
+         
+         bmi.bi.biBitCount = 32;
+         bmi.bi.biCompression = BI_RGB;
+         bmi.bi.biHeight = -h;
+         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
+         bits = g_malloc0 (4 * w * h);
+         
+         /* color data */
+         if (!GetDIBits (hdc, ii.hbmColor, 0, h, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS))
+           g_warning (G_STRLOC ": Failed to get dibits");
+         
+         pixels = gdk_pixbuf_get_pixels (pixbuf);
+         rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+         no_alpha = TRUE;
+         for (y = 0; y < h; y++)
            {
-               gchar *pixels, *bits;
-               gint rowstride, x, y, w = bmi.bi.biWidth, h = bmi.bi.biHeight;
-               gboolean no_alpha;
-
-               bmi.bi.biBitCount = 32;
-               bmi.bi.biCompression = BI_RGB;
-               bmi.bi.biHeight = -h;
-               pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h);
-               bits = g_malloc0 (4 * w * h);
-
-               /* color data */
-               if (!GetDIBits (hdc, ii.hbmColor, 0, h, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS))
-                 g_warning(G_STRLOC ": Failed to get dibits");
-
-               pixels = gdk_pixbuf_get_pixels (pixbuf);
-               rowstride = gdk_pixbuf_get_rowstride (pixbuf);
-               no_alpha = TRUE;
-               for (y = 0; y < h; y++)
-                 {
-                   for (x = 0; x < w; x++)
-                     {
-                         pixels[2] = bits[(x+y*w) * 4];
-                         pixels[1] = bits[(x+y*w) * 4 + 1];
-                         pixels[0] = bits[(x+y*w) * 4 + 2];
-                         pixels[3] = bits[(x+y*w) * 4 + 3];
-                         if (no_alpha && pixels[3] > 0) no_alpha = FALSE;
-                         pixels += 4;
-                     }
-                   pixels += (w * 4 - rowstride);
-                 }
-               /* mask */
-               if (no_alpha) {
-                 if (!GetDIBits (hdc, ii.hbmMask, 0, h, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS))
-                   g_warning(G_STRLOC ": Failed to get dibits");
-                 pixels = gdk_pixbuf_get_pixels (pixbuf);
-                 for (y = 0; y < h; y++)
-                   {
-                     for (x = 0; x < w; x++)
-                       {
-                         pixels[3] = 255 - bits[(x + y * w) * 4];
-                         pixels += 4;
-                       }
-                     pixels += (w * 4 - rowstride);
-                   }
-               
-                 /* release temporary resources */
-                 g_free (bits);
-                 if (!DeleteObject (ii.hbmColor) || !DeleteObject (ii.hbmMask))
-                   g_warning(G_STRLOC ": Leaking Icon Bitmaps ?");
+             for (x = 0; x < w; x++)
+               {
+                 pixels[2] = bits[(x+y*w) * 4];
+                 pixels[1] = bits[(x+y*w) * 4 + 1];
+                 pixels[0] = bits[(x+y*w) * 4 + 2];
+                 pixels[3] = bits[(x+y*w) * 4 + 3];
+                 if (no_alpha && pixels[3] > 0) no_alpha = FALSE;
+                 pixels += 4;
                }
+             pixels += (w * 4 - rowstride);
            }
-         else
-           g_warning(G_STRLOC ": GetDIBits () failed, %s", g_win32_error_message (GetLastError ()));
-
-         DeleteDC (hdc);
-        }
+         /* mask */
+         if (no_alpha) {
+           if (!GetDIBits (hdc, ii.hbmMask, 0, h, bits, (BITMAPINFO *)&bmi, DIB_RGB_COLORS))
+             g_warning (G_STRLOC ": Failed to get dibits");
+           pixels = gdk_pixbuf_get_pixels (pixbuf);
+           for (y = 0; y < h; y++)
+             {
+               for (x = 0; x < w; x++)
+                 {
+                   pixels[3] = 255 - bits[(x + y * w) * 4];
+                   pixels += 4;
+                 }
+               pixels += (w * 4 - rowstride);
+             }
+           
+           /* release temporary resources */
+           g_free (bits);
+           if (!DeleteObject (ii.hbmColor) || !DeleteObject (ii.hbmMask))
+             g_warning (G_STRLOC ": Leaking Icon Bitmaps ?");
+         }
+       }
       else
-        g_warning(G_STRLOC ": GetIconInfo failed: %s\n", g_win32_error_message (GetLastError ())); 
-
-      if (!DestroyIcon (hicon))
-        g_warning(G_STRLOC ": DestroyIcon failed");
+       g_warning (G_STRLOC ": GetDIBits () failed, %s", g_win32_error_message (GetLastError ()));
+      
+      DeleteDC (hdc);
     }
   else
-    g_warning (G_STRLOC ":ExtractAssociatedIcon(%s) failed: %s", filename, g_win32_error_message (GetLastError ()));
+    g_warning (G_STRLOC ": GetIconInfo failed: %s\n", g_win32_error_message (GetLastError ())); 
+  
+  if (!DestroyIcon (hicon))
+    g_warning (G_STRLOC ": DestroyIcon failed: %s\n", g_win32_error_message (GetLastError ()));
 
   return pixbuf;
 }
@@ -1037,38 +1180,52 @@ extract_icon (const char* filename)
 static GtkIconSet *
 win32_pseudo_mime_lookup (const char* name)
 {
+  gboolean use_cache = TRUE;
   static GHashTable *mime_hash = NULL;
   GtkIconSet *is = NULL;
   char *p = strrchr(name, '.');
-  char *extension = p ? g_ascii_strdown (p, -1) : g_strdup ("");
-
-  if (!mime_hash)
-    mime_hash = g_hash_table_new (g_str_hash, g_str_equal);
+  char *extension = p ? g_utf8_casefold (p, -1) : g_strdup ("");
+  GdkPixbuf *pixbuf;
 
-  /* do we already have it ? */
-  is = g_hash_table_lookup (mime_hash, extension);
-  if (is)
+  /* Don't cache icons for files that might have embedded icons */
+  if (strcmp (extension, ".lnk") == 0 ||
+      strcmp (extension, ".exe") == 0 ||
+      strcmp (extension, ".dll") == 0)
     {
+      use_cache = FALSE;
       g_free (extension);
-      return is;
     }
-  /* create icon and set */
-  {
-    GdkPixbuf *pixbuf = extract_icon (name);
-    if (pixbuf)
-      {
-        GtkIconSource* source = gtk_icon_source_new ();
-
-        is = gtk_icon_set_new_from_pixbuf (pixbuf);
-       gtk_icon_source_set_pixbuf (source, pixbuf);
-       gtk_icon_set_add_source (is, source);
+  else
+    {
+      if (!mime_hash)
+       mime_hash = g_hash_table_new (g_str_hash, g_str_equal);
 
-       gtk_icon_source_free (source);
-      }
+      /* do we already have it ? */
+      is = g_hash_table_lookup (mime_hash, extension);
+      if (is)
+       {
+         g_free (extension);
+         return is;
+       }
+    }
 
+  /* create icon and set */
+  pixbuf = extract_icon (name);
+  if (pixbuf)
+    {
+      GtkIconSource* source = gtk_icon_source_new ();
+      
+      is = gtk_icon_set_new_from_pixbuf (pixbuf);
+      gtk_icon_source_set_pixbuf (source, pixbuf);
+      gtk_icon_set_add_source (is, source);
+      
+      gtk_icon_source_free (source);
+    }
+  
+  if (use_cache)
     g_hash_table_insert (mime_hash, extension, is);
-    return is;
-  }
+
+  return is;
 }
 
 static GdkPixbuf *
@@ -1098,6 +1255,9 @@ gtk_file_system_win32_render_icon (GtkFileSystem     *file_system,
         case DRIVE_CDROM :
           icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
           break;
+       case DRIVE_REMOTE :
+         icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
+         break;
         case DRIVE_FIXED :
           icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
           break;
@@ -1105,32 +1265,29 @@ gtk_file_system_win32_render_icon (GtkFileSystem     *file_system,
           break;
         }
     }
+  else if (filename_is_server_share (filename))
+    {
+      icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
+    }
   else if (g_file_test (filename, G_FILE_TEST_IS_DIR))
     {
       const gchar *home = g_get_home_dir ();
-      if (home != NULL && 0 == strcmp (home, filename))
+
+      if (home != NULL && 0 == _gtk_file_system_win32_path_compare (home, filename))
         icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HOME);
       else
         icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_DIRECTORY);
     }
-  else if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE))
-    {
-      /* don't lookup all executable icons */
-      icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_EXECUTE);
-    }
   else if (g_file_test (filename, G_FILE_TEST_EXISTS))
     {
       icon_set = win32_pseudo_mime_lookup (filename);
     }
 
   if (!icon_set)
-    {
-       g_set_error (error,
-                 GTK_FILE_SYSTEM_ERROR,
-                 GTK_FILE_SYSTEM_ERROR_FAILED,
-                 _("This file system does not support icons for everything"));
-       return NULL;
-    }
+    if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE))
+       icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_EXECUTE);
+    else
+      icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FILE);
 
   // FIXME : I'd like to get from pixel_size (=20) back to
   // icon size, which is an index, but there appears to be no way ?
@@ -1146,9 +1303,9 @@ static GSList *_bookmarks = NULL;
 
 static gboolean
 gtk_file_system_win32_insert_bookmark (GtkFileSystem     *file_system,
-                                   const GtkFilePath *path,
-                                   gint               position,
-                                   GError           **error)
+                                      const GtkFilePath *path,
+                                      gint               position,
+                                      GError            **error)
 {
   gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
   gboolean ret = bookmarks_serialize (&_bookmarks, uri, TRUE, position, error);
@@ -1303,24 +1460,13 @@ gtk_file_folder_win32_list_children (GtkFileFolder  *folder,
                                     GError        **error)
 {
   GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
-  GError *tmp_error = NULL;
   GDir *dir;
 
   *children = NULL;
 
-  dir = g_dir_open (folder_win32->filename, 0, &tmp_error);
+  dir = g_dir_open (folder_win32->filename, 0, error);
   if (!dir)
-    {
-      g_set_error (error,
-                  GTK_FILE_SYSTEM_ERROR,
-                  GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
-                  "%s",
-                  tmp_error->message);
-      
-      g_error_free (tmp_error);
-
-      return FALSE;
-    }
+    return FALSE;
 
   while (TRUE)
     {
@@ -1348,7 +1494,7 @@ filename_get_info (const gchar     *filename,
                   GError         **error)
 {
   GtkFileInfo *info;
-#if 0 /* it's dead in GtkFileSystemUnix.c, too */
+#if 0 /* it's dead in gtkfilesystemunix.c, too */
   GtkFileIconType icon_type = GTK_FILE_ICON_REGULAR;
 #endif
   WIN32_FILE_ATTRIBUTE_DATA wfad;
@@ -1381,7 +1527,7 @@ filename_get_info (const gchar     *filename,
       g_set_error (error,
                   GTK_FILE_SYSTEM_ERROR,
                   GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
-                  _("error getting information for '%s': %s"),
+                  _("Error getting information for '%s': %s"),
                   display_filename,
                   g_win32_error_message (GetLastError ()));
       g_free (display_filename);
@@ -1427,7 +1573,7 @@ filename_get_info (const gchar     *filename,
       gtk_file_info_set_is_folder (info, !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
    }
 
-#if 0 /* it's dead in GtkFileSystemUnix.c, too */
+#if 0 /* it's dead in gtkfilesystemunix.c, too */
   if (types & GTK_FILE_INFO_ICON)
     {
       if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@@ -1438,7 +1584,7 @@ filename_get_info (const gchar     *filename,
 #endif
 
   if ((types & GTK_FILE_INFO_MIME_TYPE)
-#if 0 /* it's dead in GtkFileSystemUnix.c, too */
+#if 0 /* it's dead in gtkfilesystemunix.c, too */
       || ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR)
 #endif
      )
@@ -1492,12 +1638,73 @@ filename_is_drive_root (const char *filename)
 {
   guint len = strlen (filename);
 
-  return (len == 3 && filename[1] == ':' && G_IS_DIR_SEPARATOR (filename[2]));
+  return (len == 3 &&
+         g_ascii_isalpha (filename[0]) &&
+         filename[1] == ':' &&
+         G_IS_DIR_SEPARATOR (filename[2]));
+}
+
+static gboolean
+filename_is_server_share (const char *filename)
+{
+  /* Check if filename is of the form \\server\share or \\server\share\ */
+
+  const char *p, *q, *r;
+
+  if (!(G_IS_DIR_SEPARATOR (filename[0]) &&
+       filename[1] == filename[0]))
+    return FALSE;
+
+  p = strchr (filename + 2, '\\');
+  q = strchr (filename + 2, '/');
+
+  if (p == NULL || (q != NULL && q < p))
+    p = q;
+
+  if (p == NULL)
+    return FALSE;
+
+  if (!p[1] || G_IS_DIR_SEPARATOR (p[1]))
+    return FALSE;
+
+  q = strchr (p + 1, '\\');
+  r = strchr (p + 1, '/');
+
+  if (q == NULL || (r != NULL && r < q))
+    q = r;
+
+  if (q == NULL ||
+      q[1] == '\0')
+    return TRUE;
+
+  return FALSE;
 }
 
 static gboolean
 filename_is_some_root (const char *filename)
 {
-  return (G_IS_DIR_SEPARATOR (filename[0]) && filename[1] == '\0') ||
-         filename_is_drive_root (filename);
+#if 0
+  return ((G_IS_DIR_SEPARATOR (filename[0]) && filename[1] == '\0') ||
+         filename_is_server_share (filename) ||
+         filename_is_drive_root (filename));
+#else
+  return (g_path_is_absolute (filename) &&
+         *(g_path_skip_root (filename)) == '\0');
+#endif
 }    
+
+int
+_gtk_file_system_win32_path_compare (const gchar *path1,
+                                    const gchar *path2)
+{
+  int retval;
+  gchar *folded_path1 = g_utf8_casefold (path1, -1);
+  gchar *folded_path2 = g_utf8_casefold (path2, -1);
+
+  retval = strcmp (folded_path1, folded_path2);
+
+  g_free (folded_path1);
+  g_free (folded_path2);
+
+  return retval;
+}
index a8704e6bd39d2c9215f14c45a0d95e44cd2d88c3..e68a89e5d0f5b92c2a47a3b43ec43a8c3528f0b4 100644 (file)
@@ -35,6 +35,8 @@ typedef struct _GtkFileSystemWin32      GtkFileSystemWin32;
 GtkFileSystem *gtk_file_system_win32_new      (void);
 GType          gtk_file_system_win32_get_type (void) G_GNUC_CONST;
      
+gchar         *_gtk_file_system_win32_get_desktop (void);
+
 G_END_DECLS
 
 #endif /* __GTK_FILE_SYSTEM_WIN32_H__ */