1 /* GTK - The GIMP Toolkit
2 * gtkfilesystemwin32.c: Default implementation of GtkFileSystem for Windows
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 #include "gtkfilesystem.h"
23 #include "gtkfilesystemwin32.h"
26 #include "gtkiconfactory.h"
32 #include <sys/types.h>
35 #define WIN32_LEAN_AND_MEAN
37 #include <shellapi.h> /* ExtractAssociatedIcon */
40 #define mkdir(p,m) _mkdir(p)
41 #include <gdk/win32/gdkwin32.h> /* gdk_win32_hdc_get */
43 #error "The implementation is win32 only."
44 #endif /* G_OS_WIN32 */
46 typedef struct _GtkFileSystemWin32Class GtkFileSystemWin32Class;
48 #define GTK_FILE_SYSTEM_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_WIN32, GtkFileSystemWin32Class))
49 #define GTK_IS_FILE_SYSTEM_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_WIN32))
50 #define GTK_FILE_SYSTEM_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_WIN32, GtkFileSystemWin32Class))
52 struct _GtkFileSystemWin32Class
54 GObjectClass parent_class;
57 struct _GtkFileSystemWin32
59 GObject parent_instance;
62 #define GTK_TYPE_FILE_FOLDER_WIN32 (gtk_file_folder_win32_get_type ())
63 #define GTK_FILE_FOLDER_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_WIN32, GtkFileFolderWin32))
64 #define GTK_IS_FILE_FOLDER_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_WIN32))
65 #define GTK_FILE_FOLDER_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_WIN32, GtkFileFolderWin32Class))
66 #define GTK_IS_FILE_FOLDER_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_WIN32))
67 #define GTK_FILE_FOLDER_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_WIN32, GtkFileFolderWin32Class))
69 typedef struct _GtkFileFolderWin32 GtkFileFolderWin32;
70 typedef struct _GtkFileFolderWin32Class GtkFileFolderWin32Class;
72 struct _GtkFileFolderWin32Class
74 GObjectClass parent_class;
77 struct _GtkFileFolderWin32
79 GObject parent_instance;
81 GtkFileInfoType types;
85 static GObjectClass *system_parent_class;
86 static GObjectClass *folder_parent_class;
88 static void gtk_file_system_win32_class_init (GtkFileSystemWin32Class *class);
89 static void gtk_file_system_win32_iface_init (GtkFileSystemIface *iface);
90 static void gtk_file_system_win32_init (GtkFileSystemWin32 *impl);
91 static void gtk_file_system_win32_finalize (GObject *object);
93 static GSList * gtk_file_system_win32_list_volumes (GtkFileSystem *file_system);
94 static GtkFileSystemVolume *gtk_file_system_win32_get_volume_for_path (GtkFileSystem *file_system,
95 const GtkFilePath *path);
97 static GtkFileFolder *gtk_file_system_win32_get_folder (GtkFileSystem *file_system,
98 const GtkFilePath *path,
99 GtkFileInfoType types,
101 static gboolean gtk_file_system_win32_create_folder (GtkFileSystem *file_system,
102 const GtkFilePath *path,
105 static void gtk_file_system_win32_volume_free (GtkFileSystem *file_system,
106 GtkFileSystemVolume *volume);
107 static GtkFilePath *gtk_file_system_win32_volume_get_base_path (GtkFileSystem *file_system,
108 GtkFileSystemVolume *volume);
109 static gboolean gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem *file_system,
110 GtkFileSystemVolume *volume);
111 static gboolean gtk_file_system_win32_volume_mount (GtkFileSystem *file_system,
112 GtkFileSystemVolume *volume,
114 static gchar * gtk_file_system_win32_volume_get_display_name (GtkFileSystem *file_system,
115 GtkFileSystemVolume *volume);
116 static GdkPixbuf * gtk_file_system_win32_volume_render_icon (GtkFileSystem *file_system,
117 GtkFileSystemVolume *volume,
122 static gboolean gtk_file_system_win32_get_parent (GtkFileSystem *file_system,
123 const GtkFilePath *path,
124 GtkFilePath **parent,
126 static GtkFilePath * gtk_file_system_win32_make_path (GtkFileSystem *file_system,
127 const GtkFilePath *base_path,
128 const gchar *display_name,
130 static gboolean gtk_file_system_win32_parse (GtkFileSystem *file_system,
131 const GtkFilePath *base_path,
133 GtkFilePath **folder,
136 static gchar * gtk_file_system_win32_path_to_uri (GtkFileSystem *file_system,
137 const GtkFilePath *path);
138 static gchar * gtk_file_system_win32_path_to_filename (GtkFileSystem *file_system,
139 const GtkFilePath *path);
140 static GtkFilePath * gtk_file_system_win32_uri_to_path (GtkFileSystem *file_system,
142 static GtkFilePath * gtk_file_system_win32_filename_to_path (GtkFileSystem *file_system,
143 const gchar *filename);
144 static GdkPixbuf *gtk_file_system_win32_render_icon (GtkFileSystem *file_system,
145 const GtkFilePath *path,
150 static gboolean gtk_file_system_win32_insert_bookmark (GtkFileSystem *file_system,
151 const GtkFilePath *path,
154 static gboolean gtk_file_system_win32_remove_bookmark (GtkFileSystem *file_system,
155 const GtkFilePath *path,
157 static GSList * gtk_file_system_win32_list_bookmarks (GtkFileSystem *file_system);
158 static GType gtk_file_folder_win32_get_type (void);
159 static void gtk_file_folder_win32_class_init (GtkFileFolderWin32Class *class);
160 static void gtk_file_folder_win32_iface_init (GtkFileFolderIface *iface);
161 static void gtk_file_folder_win32_init (GtkFileFolderWin32 *impl);
162 static void gtk_file_folder_win32_finalize (GObject *object);
163 static GtkFileInfo * gtk_file_folder_win32_get_info (GtkFileFolder *folder,
164 const GtkFilePath *path,
166 static gboolean gtk_file_folder_win32_list_children (GtkFileFolder *folder,
170 static gchar * filename_from_path (const GtkFilePath *path);
171 static GtkFilePath * filename_to_path (const gchar *filename);
173 static gboolean filename_is_root (const char *filename);
174 static GtkFileInfo * filename_get_info (const gchar *filename,
175 GtkFileInfoType types,
178 /* some info kept together for volumes */
179 struct _GtkFileSystemVolume
189 gtk_file_system_win32_get_type (void)
191 static GType file_system_win32_type = 0;
193 if (!file_system_win32_type)
195 static const GTypeInfo file_system_win32_info =
197 sizeof (GtkFileSystemWin32Class),
198 NULL, /* base_init */
199 NULL, /* base_finalize */
200 (GClassInitFunc) gtk_file_system_win32_class_init,
201 NULL, /* class_finalize */
202 NULL, /* class_data */
203 sizeof (GtkFileSystemWin32),
205 (GInstanceInitFunc) gtk_file_system_win32_init,
208 static const GInterfaceInfo file_system_info =
210 (GInterfaceInitFunc) gtk_file_system_win32_iface_init, /* interface_init */
211 NULL, /* interface_finalize */
212 NULL /* interface_data */
215 file_system_win32_type = g_type_register_static (G_TYPE_OBJECT,
216 "GtkFileSystemWin32",
217 &file_system_win32_info, 0);
218 g_type_add_interface_static (file_system_win32_type,
219 GTK_TYPE_FILE_SYSTEM,
223 return file_system_win32_type;
227 * gtk_file_system_win32_new:
229 * Creates a new #GtkFileSystemWin32 object. #GtkFileSystemWin32
230 * implements the #GtkFileSystem interface with direct access to
231 * the filesystem using Windows API calls
233 * Return value: the new #GtkFileSystemWin32 object
236 gtk_file_system_win32_new (void)
238 return g_object_new (GTK_TYPE_FILE_SYSTEM_WIN32, NULL);
242 gtk_file_system_win32_class_init (GtkFileSystemWin32Class *class)
244 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
246 system_parent_class = g_type_class_peek_parent (class);
248 gobject_class->finalize = gtk_file_system_win32_finalize;
252 gtk_file_system_win32_iface_init (GtkFileSystemIface *iface)
254 iface->list_volumes = gtk_file_system_win32_list_volumes;
255 iface->get_volume_for_path = gtk_file_system_win32_get_volume_for_path;
256 iface->get_folder = gtk_file_system_win32_get_folder;
257 iface->create_folder = gtk_file_system_win32_create_folder;
258 iface->volume_free = gtk_file_system_win32_volume_free;
259 iface->volume_get_base_path = gtk_file_system_win32_volume_get_base_path;
260 iface->volume_get_is_mounted = gtk_file_system_win32_volume_get_is_mounted;
261 iface->volume_mount = gtk_file_system_win32_volume_mount;
262 iface->volume_get_display_name = gtk_file_system_win32_volume_get_display_name;
263 iface->volume_render_icon = gtk_file_system_win32_volume_render_icon;
264 iface->get_parent = gtk_file_system_win32_get_parent;
265 iface->make_path = gtk_file_system_win32_make_path;
266 iface->parse = gtk_file_system_win32_parse;
267 iface->path_to_uri = gtk_file_system_win32_path_to_uri;
268 iface->path_to_filename = gtk_file_system_win32_path_to_filename;
269 iface->uri_to_path = gtk_file_system_win32_uri_to_path;
270 iface->filename_to_path = gtk_file_system_win32_filename_to_path;
271 iface->render_icon = gtk_file_system_win32_render_icon;
272 iface->insert_bookmark = gtk_file_system_win32_insert_bookmark;
273 iface->remove_bookmark = gtk_file_system_win32_remove_bookmark;
274 iface->list_bookmarks = gtk_file_system_win32_list_bookmarks;
278 gtk_file_system_win32_init (GtkFileSystemWin32 *system_win32)
283 gtk_file_system_win32_finalize (GObject *object)
285 system_parent_class->finalize (object);
289 gtk_file_system_win32_list_volumes (GtkFileSystem *file_system)
292 gchar drive[4] = "A:\\";
295 drives = GetLogicalDrives();
298 g_warning ("GetLogicalDrives failed.");
300 while (drives && drive[0] <= 'Z')
304 GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
305 if (drive[0] == 'A' || drive[0] == 'B')
306 vol->is_mounted = FALSE; /* skip floppy */
308 vol->is_mounted = TRUE; /* handle other removable drives special, too? */
310 vol->drive = g_strdup (drive);
311 list = g_slist_append (list, vol);
319 static GtkFileSystemVolume *
320 gtk_file_system_win32_get_volume_for_path (GtkFileSystem *file_system,
321 const GtkFilePath *path)
323 GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
324 gchar* p = g_strndup (gtk_file_path_get_string (path), 3);
326 g_return_val_if_fail (p != NULL, NULL);
328 /*FIXME: gtk_file_path_compare() is case sensitive, we are not*/
329 p[0] = g_ascii_toupper (p[0]);
331 vol->is_mounted = (p[0] != 'A' && p[0] != 'B');
336 static GtkFileFolder *
337 gtk_file_system_win32_get_folder (GtkFileSystem *file_system,
338 const GtkFilePath *path,
339 GtkFileInfoType types,
342 GtkFileFolderWin32 *folder_win32;
345 filename = filename_from_path (path);
346 g_return_val_if_fail (filename != NULL, NULL);
348 if (!g_file_test (filename, G_FILE_TEST_IS_DIR))
350 int save_errno = errno;
351 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
353 /* If g_file_test() returned FALSE but not due to an error, it means
354 * that the filename is not a directory.
359 GTK_FILE_SYSTEM_ERROR,
360 GTK_FILE_SYSTEM_ERROR_NOT_FOLDER,
362 filename_utf8 ? filename_utf8 : "???",
363 g_strerror (ENOTDIR));
366 GTK_FILE_SYSTEM_ERROR,
367 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
368 _("error getting information for '%s': %s"),
369 filename_utf8 ? filename_utf8 : "???",
370 g_strerror (save_errno));
372 g_free (filename_utf8);
376 folder_win32 = g_object_new (GTK_TYPE_FILE_FOLDER_WIN32, NULL);
377 folder_win32->filename = filename;
378 folder_win32->types = types;
380 return GTK_FILE_FOLDER (folder_win32);
384 gtk_file_system_win32_create_folder (GtkFileSystem *file_system,
385 const GtkFilePath *path,
391 filename = filename_from_path (path);
392 g_return_val_if_fail (filename != NULL, FALSE);
394 result = mkdir (filename, 0777) != 0;
398 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
400 GTK_FILE_SYSTEM_ERROR,
401 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
402 _("error creating directory '%s': %s"),
403 filename_utf8 ? filename_utf8 : "???",
405 g_free (filename_utf8);
414 gtk_file_system_win32_volume_free (GtkFileSystem *file_system,
415 GtkFileSystemVolume *volume)
417 g_free (volume->drive);
422 gtk_file_system_win32_volume_get_base_path (GtkFileSystem *file_system,
423 GtkFileSystemVolume *volume)
425 return (GtkFilePath *) g_strdup (volume->drive);
429 gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem *file_system,
430 GtkFileSystemVolume *volume)
432 return volume->is_mounted;
436 gtk_file_system_win32_volume_mount (GtkFileSystem *file_system,
437 GtkFileSystemVolume *volume,
441 GTK_FILE_SYSTEM_ERROR,
442 GTK_FILE_SYSTEM_ERROR_FAILED,
443 _("This file system does not support mounting"));
448 gtk_file_system_win32_volume_get_display_name (GtkFileSystem *file_system,
449 GtkFileSystemVolume *volume)
451 gchar *real_display_name;
452 gunichar2 *wdrive = g_utf8_to_utf16 (volume->drive, -1, NULL, NULL, NULL);
455 g_return_val_if_fail (wdrive != NULL, NULL);
457 if (GetVolumeInformationW (wdrive,
458 wname, G_N_ELEMENTS(wname),
459 NULL, /* serial number */
460 NULL, /* max. component length */
462 NULL, 0) /* fs type like FAT, NTFS */
465 gchar *name = g_utf16_to_utf8 (wname, -1, NULL, NULL, NULL);
466 real_display_name = g_strconcat (name, " (", volume->drive, ")", NULL);
470 real_display_name = g_strdup (volume->drive);
474 return real_display_name;
478 gtk_file_system_win32_volume_render_icon (GtkFileSystem *file_system,
479 GtkFileSystemVolume *volume,
484 GtkIconSet *icon_set = NULL;
485 DWORD dt = GetDriveType (volume->drive);
489 case DRIVE_REMOVABLE :
490 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
493 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
496 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
499 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
502 /*FIXME: need a ram stock icon
503 gtk_file_info_set_icon_type (info, GTK_STOCK_OPEN);*/
506 g_assert_not_reached ();
509 return gtk_icon_set_render_icon (icon_set,
511 gtk_widget_get_direction (widget),
513 GTK_ICON_SIZE_BUTTON,
518 gtk_file_system_win32_get_parent (GtkFileSystem *file_system,
519 const GtkFilePath *path,
520 GtkFilePath **parent,
523 gchar *filename = filename_from_path (path);
524 g_return_val_if_fail (filename != NULL, FALSE);
526 if (filename_is_root (filename))
532 gchar *parent_filename = g_path_get_dirname (filename);
533 *parent = filename_to_path (parent_filename);
534 g_free (parent_filename);
543 gtk_file_system_win32_make_path (GtkFileSystem *file_system,
544 const GtkFilePath *base_path,
545 const gchar *display_name,
548 const char *base_filename;
550 gchar *full_filename;
551 GError *tmp_error = NULL;
554 base_filename = gtk_file_path_get_string (base_path);
555 g_return_val_if_fail (base_filename != NULL, NULL);
556 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
558 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
562 GTK_FILE_SYSTEM_ERROR,
563 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
567 g_error_free (tmp_error);
572 full_filename = g_build_filename (base_filename, filename, NULL);
573 result = filename_to_path (full_filename);
575 g_free (full_filename);
580 /* If this was a publically exported function, it should return
581 * a dup'ed result, but we make it modify-in-place for efficiency
582 * here, and because it works for us.
585 canonicalize_filename (gchar *filename)
588 gboolean last_was_slash = FALSE;
595 if (*p == G_DIR_SEPARATOR)
598 *q++ = G_DIR_SEPARATOR;
600 last_was_slash = TRUE;
604 if (last_was_slash && *p == '.')
606 if (*(p + 1) == G_DIR_SEPARATOR ||
609 if (*(p + 1) == '\0')
614 else if (*(p + 1) == '.' &&
615 (*(p + 2) == G_DIR_SEPARATOR ||
618 if (q > filename + 1)
621 while (q > filename + 1 &&
622 *(q - 1) != G_DIR_SEPARATOR)
626 if (*(p + 2) == '\0')
634 last_was_slash = FALSE;
640 last_was_slash = FALSE;
647 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
654 gtk_file_system_win32_parse (GtkFileSystem *file_system,
655 const GtkFilePath *base_path,
657 GtkFilePath **folder,
661 const char *base_filename;
663 gboolean result = FALSE;
665 base_filename = gtk_file_path_get_string (base_path);
666 g_return_val_if_fail (base_filename != NULL, FALSE);
667 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
669 last_slash = strrchr (str, G_DIR_SEPARATOR);
672 *folder = gtk_file_path_copy (base_path);
673 *file_part = g_strdup (str);
680 GError *tmp_error = NULL;
682 if (last_slash == str)
683 folder_part = g_strdup ("/");
685 folder_part = g_filename_from_utf8 (str, last_slash - str,
686 NULL, NULL, &tmp_error);
691 GTK_FILE_SYSTEM_ERROR,
692 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
695 g_error_free (tmp_error);
699 if (folder_part[1] == ':')
700 folder_path = folder_part;
703 folder_path = g_build_filename (base_filename, folder_part, NULL);
704 g_free (folder_part);
707 canonicalize_filename (folder_path);
709 *folder = filename_to_path (folder_path);
710 *file_part = g_strdup (last_slash + 1);
712 g_free (folder_path);
722 gtk_file_system_win32_path_to_uri (GtkFileSystem *file_system,
723 const GtkFilePath *path)
725 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
729 gtk_file_system_win32_path_to_filename (GtkFileSystem *file_system,
730 const GtkFilePath *path)
732 return g_strdup (gtk_file_path_get_string (path));
736 gtk_file_system_win32_uri_to_path (GtkFileSystem *file_system,
739 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
741 return gtk_file_path_new_steal (filename);
747 gtk_file_system_win32_filename_to_path (GtkFileSystem *file_system,
748 const gchar *filename)
750 return gtk_file_path_new_dup (filename);
754 bookmarks_serialize (GSList **bookmarks,
762 GSList *list = *bookmarks;
764 filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
768 gchar *contents = NULL;
773 if (g_file_test (filename, G_FILE_TEST_EXISTS))
775 if (g_file_get_contents (filename, &contents, &len, error))
777 gchar **lines = g_strsplit (contents, "\n", -1);
780 for (i = 0; lines[i] != NULL; i++)
782 if (lines[i][0] && !g_slist_find_custom (list, lines[i], (GCompareFunc) strcmp))
783 list = g_slist_append (list, g_strdup (lines[i]));
790 if (ok && (f = fopen (filename, "wb")) != NULL)
792 entry = g_slist_find_custom (list, uri, (GCompareFunc) strcmp);
795 /* g_slist_insert() and our insert semantics are
796 * compatible, but maybe we should check for
801 list = g_slist_insert (list, g_strdup (uri), position);
805 GTK_FILE_SYSTEM_ERROR,
806 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
807 "%s already exists in the bookmarks list",
814 /* to remove the given uri */
816 list = g_slist_delete_link(list, entry);
817 for (entry = list; entry != NULL; entry = entry->next)
819 fputs (entry->data, f);
825 else if (ok && error)
828 GTK_FILE_SYSTEM_ERROR,
829 GTK_FILE_SYSTEM_ERROR_FAILED,
830 _("Bookmark saving failed (%s)"),
839 extract_icon (const char* filename)
841 GdkPixbuf *pixbuf = NULL;
845 if (!filename || !filename[0])
848 hicon = ExtractAssociatedIcon (GetModuleHandle (NULL), filename, &iicon);
849 if (hicon > (HICON)1)
853 if (GetIconInfo (hicon, &ii))
860 if (!GetBitmapDimensionEx (ii.hbmColor, &size))
861 g_warning ("GetBitmapDimensionEx failed.");
863 if (size.cx < 1) size.cx = 32;
864 if (size.cy < 1) size.cy = 32;
866 pixmap = gdk_pixmap_new (NULL, size.cx, size.cy,
867 gdk_screen_get_system_visual (gdk_screen_get_default ())->depth);
868 gc = gdk_gc_new (pixmap);
869 hdc = gdk_win32_hdc_get (GDK_DRAWABLE (pixmap), gc, 0);
871 if (!DrawIcon (hdc, 0, 0, hicon))
872 g_warning ("DrawIcon failed");
874 gdk_win32_hdc_release (GDK_DRAWABLE (pixmap), gc, 0);
876 pixbuf = gdk_pixbuf_get_from_drawable (
878 gdk_screen_get_system_colormap (gdk_screen_get_default ()),
879 0, 0, 0, 0, size.cx, size.cy);
880 g_object_unref (pixmap);
884 g_print ("GetIconInfo failed: %s\n", g_win32_error_message (GetLastError ()));
886 if (!DestroyIcon (hicon))
887 g_warning ("DestroyIcon failed");
890 g_print ("ExtractAssociatedIcon failed: %s\n", g_win32_error_message (GetLastError ()));
896 win32_pseudo_mime_lookup (const char* name)
898 static GHashTable *mime_hash = NULL;
899 GtkIconSet *is = NULL;
900 char *p = strrchr(name, '.');
901 char *extension = p ? g_ascii_strdown (p, -1) : g_strdup ("");
904 mime_hash = g_hash_table_new (g_str_hash, g_str_equal);
906 /* do we already have it ? */
907 is = g_hash_table_lookup (mime_hash, extension);
913 /* create icon and set */
915 GdkPixbuf *pixbuf = extract_icon (name);
918 GtkIconSource* source = gtk_icon_source_new ();
920 is = gtk_icon_set_new_from_pixbuf (pixbuf);
921 gtk_icon_source_set_pixbuf (source, pixbuf);
922 gtk_icon_set_add_source (is, source);
924 gtk_icon_source_free (source);
927 g_hash_table_insert (mime_hash, extension, is);
933 gtk_file_system_win32_render_icon (GtkFileSystem *file_system,
934 const GtkFilePath *path,
939 GtkIconSet *icon_set = NULL;
940 const char* filename = gtk_file_path_get_string (path);
942 /* handle drives with stock icons */
943 if (filename_is_root (filename))
945 gchar *filename2 = g_strconcat(filename, "\\", NULL);
946 DWORD dt = GetDriveType (filename2);
950 case DRIVE_REMOVABLE :
951 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
954 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
956 case DRIVE_FIXED : /* need a hard disk icon */
957 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
964 else if (g_file_test (filename, G_FILE_TEST_IS_DIR))
966 if (0 == strcmp (g_get_home_dir(), filename))
967 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HOME);
969 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_OPEN);
971 else if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE))
973 /* don't lookup all executable icons */
974 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_EXECUTE);
976 else if (g_file_test (filename, G_FILE_TEST_EXISTS))
978 icon_set = win32_pseudo_mime_lookup (filename);
984 GTK_FILE_SYSTEM_ERROR,
985 GTK_FILE_SYSTEM_ERROR_FAILED,
986 _("This file system does not support icons for everything"));
990 // FIXME : I'd like to get from pixel_size (=20) back to
991 // icon size, which is an index, but there appears to be no way ?
992 return gtk_icon_set_render_icon (icon_set,
994 gtk_widget_get_direction (widget),
996 GTK_ICON_SIZE_BUTTON,
1000 static GSList *_bookmarks = NULL;
1003 gtk_file_system_win32_insert_bookmark (GtkFileSystem *file_system,
1004 const GtkFilePath *path,
1008 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
1009 gboolean ret = bookmarks_serialize (&_bookmarks, uri, TRUE, position, error);
1011 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1018 gtk_file_system_win32_remove_bookmark (GtkFileSystem *file_system,
1019 const GtkFilePath *path,
1022 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
1023 gboolean ret = bookmarks_serialize (&_bookmarks, uri, FALSE, 0, error);
1025 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1031 gtk_file_system_win32_list_bookmarks (GtkFileSystem *file_system)
1033 GSList *list = NULL;
1037 if (bookmarks_serialize (&_bookmarks, "", FALSE, 0, NULL))
1039 for (entry = _bookmarks; entry != NULL; entry = entry->next)
1041 GtkFilePath *path = gtk_file_system_win32_uri_to_path (
1042 file_system, (gchar *)entry->data);
1044 list = g_slist_append (list, path);
1052 * GtkFileFolderWin32
1055 gtk_file_folder_win32_get_type (void)
1057 static GType file_folder_win32_type = 0;
1059 if (!file_folder_win32_type)
1061 static const GTypeInfo file_folder_win32_info =
1063 sizeof (GtkFileFolderWin32Class),
1064 NULL, /* base_init */
1065 NULL, /* base_finalize */
1066 (GClassInitFunc) gtk_file_folder_win32_class_init,
1067 NULL, /* class_finalize */
1068 NULL, /* class_data */
1069 sizeof (GtkFileFolderWin32),
1070 0, /* n_preallocs */
1071 (GInstanceInitFunc) gtk_file_folder_win32_init,
1074 static const GInterfaceInfo file_folder_info =
1076 (GInterfaceInitFunc) gtk_file_folder_win32_iface_init, /* interface_init */
1077 NULL, /* interface_finalize */
1078 NULL /* interface_data */
1081 file_folder_win32_type = g_type_register_static (G_TYPE_OBJECT,
1082 "GtkFileFolderWin32",
1083 &file_folder_win32_info, 0);
1084 g_type_add_interface_static (file_folder_win32_type,
1085 GTK_TYPE_FILE_FOLDER,
1089 return file_folder_win32_type;
1093 gtk_file_folder_win32_class_init (GtkFileFolderWin32Class *class)
1095 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1097 folder_parent_class = g_type_class_peek_parent (class);
1099 gobject_class->finalize = gtk_file_folder_win32_finalize;
1103 gtk_file_folder_win32_iface_init (GtkFileFolderIface *iface)
1105 iface->get_info = gtk_file_folder_win32_get_info;
1106 iface->list_children = gtk_file_folder_win32_list_children;
1110 gtk_file_folder_win32_init (GtkFileFolderWin32 *impl)
1115 gtk_file_folder_win32_finalize (GObject *object)
1117 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (object);
1119 g_free (folder_win32->filename);
1121 folder_parent_class->finalize (object);
1124 static GtkFileInfo *
1125 gtk_file_folder_win32_get_info (GtkFileFolder *folder,
1126 const GtkFilePath *path,
1129 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1136 g_return_val_if_fail (filename_is_root (folder_win32->filename), NULL);
1139 info = filename_get_info (folder_win32->filename, folder_win32->types, error);
1144 filename = filename_from_path (path);
1145 g_return_val_if_fail (filename != NULL, NULL);
1148 dirname = g_path_get_dirname (filename);
1149 g_return_val_if_fail (strcmp (dirname, folder_win32->filename) == 0, NULL);
1153 info = filename_get_info (filename, folder_win32->types, error);
1161 gtk_file_folder_win32_list_children (GtkFileFolder *folder,
1165 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1166 GError *tmp_error = NULL;
1171 dir = g_dir_open (folder_win32->filename, 0, &tmp_error);
1175 GTK_FILE_SYSTEM_ERROR,
1176 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1178 tmp_error->message);
1180 g_error_free (tmp_error);
1187 const gchar *filename = g_dir_read_name (dir);
1193 fullname = g_build_filename (folder_win32->filename, filename, NULL);
1194 *children = g_slist_prepend (*children, filename_to_path (fullname));
1200 *children = g_slist_reverse (*children);
1205 static GtkFileInfo *
1206 filename_get_info (const gchar *filename,
1207 GtkFileInfoType types,
1211 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1212 GtkFileIconType icon_type = GTK_FILE_ICON_REGULAR;
1214 WIN32_FILE_ATTRIBUTE_DATA wfad;
1216 if (!GetFileAttributesEx (filename, GetFileExInfoStandard, &wfad))
1218 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
1220 GTK_FILE_SYSTEM_ERROR,
1221 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1222 _("error getting information for '%s': %s"),
1223 filename_utf8 ? filename_utf8 : "???",
1224 g_win32_error_message (GetLastError ()));
1225 g_free (filename_utf8);
1230 info = gtk_file_info_new ();
1232 if (filename_is_root (filename))
1234 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1235 gtk_file_info_set_display_name (info, filename);
1237 if (types & GTK_FILE_INFO_IS_HIDDEN)
1238 gtk_file_info_set_is_hidden (info, FALSE);
1242 gchar *basename = g_path_get_basename (filename);
1244 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1246 gchar *display_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1248 display_name = g_strescape (basename, NULL);
1250 gtk_file_info_set_display_name (info, display_name);
1252 g_free (display_name);
1255 if (types & GTK_FILE_INFO_IS_HIDDEN)
1257 /* win32 convention ... */
1258 gboolean is_hidden = basename[0] == '.';
1259 /* ... _and_ windoze attribute */
1260 is_hidden = is_hidden || !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
1261 gtk_file_info_set_is_hidden (info, is_hidden);
1267 if (types & GTK_FILE_INFO_IS_FOLDER)
1269 gtk_file_info_set_is_folder (info, !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1272 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1273 if (types & GTK_FILE_INFO_ICON)
1275 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1276 icon_type = GTK_FILE_ICON_DIRECTORY;
1278 gtk_file_info_set_icon_type (info, icon_type);
1282 if ((types & GTK_FILE_INFO_MIME_TYPE)
1283 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1284 || ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR)
1289 const char *mime_type = xdg_mime_get_mime_type_for_file (filename);
1290 gtk_file_info_set_mime_type (info, mime_type);
1292 if ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR &&
1293 (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
1294 (strcmp (mime_type, XDG_MIME_TYPE_UNKNOWN) == 0 ||
1295 strcmp (mime_type, "application/x-executable") == 0 ||
1296 strcmp (mime_type, "application/x-shellscript") == 0))
1297 gtk_file_info_set_icon_type (info, GTK_FILE_ICON_EXECUTABLE);
1301 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1303 GtkFileTime time = wfad.ftLastWriteTime.dwLowDateTime
1304 | ((guint64)wfad.ftLastWriteTime.dwHighDateTime) << 32;
1305 /* 100-nanosecond intervals since January 1, 1601, urgh! */
1306 time /= G_GINT64_CONSTANT (10000000); /* now seconds */
1307 time -= G_GINT64_CONSTANT (134774) * 24 * 3600; /* good old Unix time */
1308 gtk_file_info_set_modification_time (info, time);
1311 if (types & GTK_FILE_INFO_SIZE)
1313 gint64 size = wfad.nFileSizeLow | ((guint64)wfad.nFileSizeHigh) << 32;
1314 gtk_file_info_set_size (info, size);
1321 filename_from_path (const GtkFilePath *path)
1323 return g_strdup (gtk_file_path_get_string (path));
1326 static GtkFilePath *
1327 filename_to_path (const char *filename)
1329 return gtk_file_path_new_dup (filename);
1333 filename_is_root (const char *filename)
1335 guint len = strlen(filename);
1337 /* accept both forms */
1339 return ( (len == 2 && filename[1] == ':')
1340 || (len == 3 && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/')));