diff options
author | Tor Lillqvist <tml@iki.fi> | 2005-01-02 23:15:21 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 2005-01-02 23:15:21 +0000 |
commit | c668f46d9e3b98617a45273a229f178e859dda33 (patch) | |
tree | 25e7a06a3d8bfb0ef358bba9dd3dfd56a77527fb | |
parent | 0a4ddf1f7f04840acc3fa2776f677cab588dbac4 (diff) | |
download | gtk+-c668f46d9e3b98617a45273a229f178e859dda33.tar.gz |
Add -lole32, needed for CoTaskMemFree in get_special_folder() below.
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().
-rw-r--r-- | ChangeLog | 84 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 84 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 84 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 84 | ||||
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtk.symbols | 3 | ||||
-rw-r--r-- | gtk/gtkfilechooserbutton.c | 35 | ||||
-rw-r--r-- | gtk/gtkfilechooserdefault.c | 8 | ||||
-rw-r--r-- | gtk/gtkfilesystem.h | 8 | ||||
-rw-r--r-- | gtk/gtkfilesystemwin32.c | 735 | ||||
-rw-r--r-- | gtk/gtkfilesystemwin32.h | 2 |
11 files changed, 850 insertions, 279 deletions
@@ -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 diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index eb3dac94df..e9dfccb396 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -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 diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index eb3dac94df..e9dfccb396 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -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 diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index eb3dac94df..e9dfccb396 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -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 diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 6cb2e7108f..2e0b8a50f6 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -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 diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 809a09583e..902da3b546 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -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 diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c index 7ca26a22d9..3f684a3bd0 100644 --- a/gtk/gtkfilechooserbutton.c +++ b/gtk/gtkfilechooserbutton.c @@ -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, diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c index 4cd013f002..d135196917 100644 --- a/gtk/gtkfilechooserdefault.c +++ b/gtk/gtkfilechooserdefault.c @@ -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); diff --git a/gtk/gtkfilesystem.h b/gtk/gtkfilesystem.h index 83ec6f63a3..ab8ab0ac08 100644 --- a/gtk/gtkfilesystem.h +++ b/gtk/gtkfilesystem.h @@ -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); diff --git a/gtk/gtkfilesystemwin32.c b/gtk/gtkfilesystemwin32.c index d63e2bd653..ff366aa0de 100644 --- a/gtk/gtkfilesystemwin32.c +++ b/gtk/gtkfilesystemwin32.c @@ -37,19 +37,15 @@ #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; +} diff --git a/gtk/gtkfilesystemwin32.h b/gtk/gtkfilesystemwin32.h index a8704e6bd3..e68a89e5d0 100644 --- a/gtk/gtkfilesystemwin32.h +++ b/gtk/gtkfilesystemwin32.h @@ -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__ */ |