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.
21 #include "gtkfilesystem.h"
22 #include "gtkfilesystemwin32.h"
25 #include "gtkiconfactory.h"
30 #include <sys/types.h>
33 #define WIN32_LEAN_AND_MEAN
35 #include <shellapi.h> /* ExtractAssociatedIcon */
38 #define mkdir(p,m) _mkdir(p)
39 #include <gdk/win32/gdkwin32.h> /* gdk_win32_hdc_get */
41 #error "The implementation is win32 only yet."
42 #endif /* G_OS_WIN32 */
44 typedef struct _GtkFileSystemWin32Class GtkFileSystemWin32Class;
46 #define GTK_FILE_SYSTEM_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_WIN32, GtkFileSystemWin32Class))
47 #define GTK_IS_FILE_SYSTEM_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_WIN32))
48 #define GTK_FILE_SYSTEM_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_WIN32, GtkFileSystemWin32Class))
50 struct _GtkFileSystemWin32Class
52 GObjectClass parent_class;
55 struct _GtkFileSystemWin32
57 GObject parent_instance;
60 #define GTK_TYPE_FILE_FOLDER_WIN32 (gtk_file_folder_win32_get_type ())
61 #define GTK_FILE_FOLDER_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_WIN32, GtkFileFolderWin32))
62 #define GTK_IS_FILE_FOLDER_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_WIN32))
63 #define GTK_FILE_FOLDER_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_WIN32, GtkFileFolderWin32Class))
64 #define GTK_IS_FILE_FOLDER_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_WIN32))
65 #define GTK_FILE_FOLDER_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_WIN32, GtkFileFolderWin32Class))
67 typedef struct _GtkFileFolderWin32 GtkFileFolderWin32;
68 typedef struct _GtkFileFolderWin32Class GtkFileFolderWin32Class;
70 struct _GtkFileFolderWin32Class
72 GObjectClass parent_class;
75 struct _GtkFileFolderWin32
77 GObject parent_instance;
79 GtkFileInfoType types;
83 static GObjectClass *system_parent_class;
84 static GObjectClass *folder_parent_class;
86 static void gtk_file_system_win32_class_init (GtkFileSystemWin32Class *class);
87 static void gtk_file_system_win32_iface_init (GtkFileSystemIface *iface);
88 static void gtk_file_system_win32_init (GtkFileSystemWin32 *impl);
89 static void gtk_file_system_win32_finalize (GObject *object);
91 static GSList * gtk_file_system_win32_list_volumes (GtkFileSystem *file_system);
92 static GtkFileSystemVolume *gtk_file_system_win32_get_volume_for_path (GtkFileSystem *file_system,
93 const GtkFilePath *path);
95 static GtkFileFolder *gtk_file_system_win32_get_folder (GtkFileSystem *file_system,
96 const GtkFilePath *path,
97 GtkFileInfoType types,
99 static gboolean gtk_file_system_win32_create_folder (GtkFileSystem *file_system,
100 const GtkFilePath *path,
103 static void gtk_file_system_win32_volume_free (GtkFileSystem *file_system,
104 GtkFileSystemVolume *volume);
105 static GtkFilePath *gtk_file_system_win32_volume_get_base_path (GtkFileSystem *file_system,
106 GtkFileSystemVolume *volume);
107 static gboolean gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem *file_system,
108 GtkFileSystemVolume *volume);
109 static gboolean gtk_file_system_win32_volume_mount (GtkFileSystem *file_system,
110 GtkFileSystemVolume *volume,
112 static gchar * gtk_file_system_win32_volume_get_display_name (GtkFileSystem *file_system,
113 GtkFileSystemVolume *volume);
114 static GdkPixbuf * gtk_file_system_win32_volume_render_icon (GtkFileSystem *file_system,
115 GtkFileSystemVolume *volume,
120 static gboolean gtk_file_system_win32_get_parent (GtkFileSystem *file_system,
121 const GtkFilePath *path,
122 GtkFilePath **parent,
124 static GtkFilePath * gtk_file_system_win32_make_path (GtkFileSystem *file_system,
125 const GtkFilePath *base_path,
126 const gchar *display_name,
128 static gboolean gtk_file_system_win32_parse (GtkFileSystem *file_system,
129 const GtkFilePath *base_path,
131 GtkFilePath **folder,
134 static gchar * gtk_file_system_win32_path_to_uri (GtkFileSystem *file_system,
135 const GtkFilePath *path);
136 static gchar * gtk_file_system_win32_path_to_filename (GtkFileSystem *file_system,
137 const GtkFilePath *path);
138 static GtkFilePath * gtk_file_system_win32_uri_to_path (GtkFileSystem *file_system,
140 static GtkFilePath * gtk_file_system_win32_filename_to_path (GtkFileSystem *file_system,
141 const gchar *filename);
142 static GdkPixbuf *gtk_file_system_win32_render_icon (GtkFileSystem *file_system,
143 const GtkFilePath *path,
148 static gboolean gtk_file_system_win32_add_bookmark (GtkFileSystem *file_system,
149 const GtkFilePath *path,
151 static gboolean gtk_file_system_win32_remove_bookmark (GtkFileSystem *file_system,
152 const GtkFilePath *path,
154 static GSList * gtk_file_system_win32_list_bookmarks (GtkFileSystem *file_system);
155 static GType gtk_file_folder_win32_get_type (void);
156 static void gtk_file_folder_win32_class_init (GtkFileFolderWin32Class *class);
157 static void gtk_file_folder_win32_iface_init (GtkFileFolderIface *iface);
158 static void gtk_file_folder_win32_init (GtkFileFolderWin32 *impl);
159 static void gtk_file_folder_win32_finalize (GObject *object);
160 static GtkFileInfo * gtk_file_folder_win32_get_info (GtkFileFolder *folder,
161 const GtkFilePath *path,
163 static gboolean gtk_file_folder_win32_list_children (GtkFileFolder *folder,
167 static gchar * filename_from_path (const GtkFilePath *path);
168 static GtkFilePath * filename_to_path (const gchar *filename);
170 static gboolean filename_is_root (const char *filename);
171 static GtkFileInfo * filename_get_info (const gchar *filename,
172 GtkFileInfoType types,
175 /* some info kept together for volumes */
176 struct _GtkFileSystemVolume
186 gtk_file_system_win32_get_type (void)
188 static GType file_system_win32_type = 0;
190 if (!file_system_win32_type)
192 static const GTypeInfo file_system_win32_info =
194 sizeof (GtkFileSystemWin32Class),
195 NULL, /* base_init */
196 NULL, /* base_finalize */
197 (GClassInitFunc) gtk_file_system_win32_class_init,
198 NULL, /* class_finalize */
199 NULL, /* class_data */
200 sizeof (GtkFileSystemWin32),
202 (GInstanceInitFunc) gtk_file_system_win32_init,
205 static const GInterfaceInfo file_system_info =
207 (GInterfaceInitFunc) gtk_file_system_win32_iface_init, /* interface_init */
208 NULL, /* interface_finalize */
209 NULL /* interface_data */
212 file_system_win32_type = g_type_register_static (G_TYPE_OBJECT,
213 "GtkFileSystemWin32",
214 &file_system_win32_info, 0);
215 g_type_add_interface_static (file_system_win32_type,
216 GTK_TYPE_FILE_SYSTEM,
220 return file_system_win32_type;
224 * gtk_file_system_win32_new:
226 * Creates a new #GtkFileSystemWin32 object. #GtkFileSystemWin32
227 * implements the #GtkFileSystem interface with direct access to
228 * the filesystem using Windows API calls
230 * Return value: the new #GtkFileSystemWin32 object
233 gtk_file_system_win32_new (void)
235 return g_object_new (GTK_TYPE_FILE_SYSTEM_WIN32, NULL);
239 gtk_file_system_win32_class_init (GtkFileSystemWin32Class *class)
241 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
243 system_parent_class = g_type_class_peek_parent (class);
245 gobject_class->finalize = gtk_file_system_win32_finalize;
249 gtk_file_system_win32_iface_init (GtkFileSystemIface *iface)
251 iface->list_volumes = gtk_file_system_win32_list_volumes;
252 iface->get_volume_for_path = gtk_file_system_win32_get_volume_for_path;
253 iface->get_folder = gtk_file_system_win32_get_folder;
254 iface->create_folder = gtk_file_system_win32_create_folder;
255 iface->volume_free = gtk_file_system_win32_volume_free;
256 iface->volume_get_base_path = gtk_file_system_win32_volume_get_base_path;
257 iface->volume_get_is_mounted = gtk_file_system_win32_volume_get_is_mounted;
258 iface->volume_mount = gtk_file_system_win32_volume_mount;
259 iface->volume_get_display_name = gtk_file_system_win32_volume_get_display_name;
260 iface->volume_render_icon = gtk_file_system_win32_volume_render_icon;
261 iface->get_parent = gtk_file_system_win32_get_parent;
262 iface->make_path = gtk_file_system_win32_make_path;
263 iface->parse = gtk_file_system_win32_parse;
264 iface->path_to_uri = gtk_file_system_win32_path_to_uri;
265 iface->path_to_filename = gtk_file_system_win32_path_to_filename;
266 iface->uri_to_path = gtk_file_system_win32_uri_to_path;
267 iface->filename_to_path = gtk_file_system_win32_filename_to_path;
268 iface->render_icon = gtk_file_system_win32_render_icon;
269 iface->add_bookmark = gtk_file_system_win32_add_bookmark;
270 iface->remove_bookmark = gtk_file_system_win32_remove_bookmark;
271 iface->list_bookmarks = gtk_file_system_win32_list_bookmarks;
275 gtk_file_system_win32_init (GtkFileSystemWin32 *system_win32)
280 gtk_file_system_win32_finalize (GObject *object)
282 system_parent_class->finalize (object);
286 gtk_file_system_win32_list_volumes (GtkFileSystem *file_system)
293 len = GetLogicalDriveStrings(sizeof(drives), drives);
296 g_warning("No drive strings available!");
299 while ((len = strlen(p)) != 0)
301 GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
302 if (p[0] == 'a' || p[0] == 'b')
303 vol->is_mounted = FALSE; /* skip floppy */
305 vol->is_mounted = TRUE;
307 /*FIXME: gtk_file_path_compare() is case sensitive, we are not*/
308 p[0] = toupper (p[0]);
309 vol->drive = g_strdup (p);
311 list = g_slist_append (list, vol);
318 static GtkFileSystemVolume *
319 gtk_file_system_win32_get_volume_for_path (GtkFileSystem *file_system,
320 const GtkFilePath *path)
322 GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
323 gchar* p = g_strndup (path, 3);
325 g_return_val_if_fail (p != NULL, NULL);
327 /*FIXME: gtk_file_path_compare() is case sensitive, we are not*/
328 p[0] = toupper (p[0]);
330 vol->is_mounted = (p[0] != 'a' && p[0] != 'b');
335 static GtkFileFolder *
336 gtk_file_system_win32_get_folder (GtkFileSystem *file_system,
337 const GtkFilePath *path,
338 GtkFileInfoType types,
341 GtkFileFolderWin32 *folder_win32;
344 filename = filename_from_path (path);
345 g_return_val_if_fail (filename != NULL, NULL);
347 folder_win32 = g_object_new (GTK_TYPE_FILE_FOLDER_WIN32, NULL);
348 folder_win32->filename = filename;
349 folder_win32->types = types;
351 return GTK_FILE_FOLDER (folder_win32);
355 gtk_file_system_win32_create_folder (GtkFileSystem *file_system,
356 const GtkFilePath *path,
362 filename = filename_from_path (path);
363 g_return_val_if_fail (filename != NULL, FALSE);
365 result = mkdir (filename, 0777) != 0;
369 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
371 GTK_FILE_SYSTEM_ERROR,
372 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
373 _("error creating directory '%s': %s"),
374 filename_utf8 ? filename_utf8 : "???",
376 g_free (filename_utf8);
385 gtk_file_system_win32_volume_free (GtkFileSystem *file_system,
386 GtkFileSystemVolume *volume)
388 g_free (volume->drive);
393 gtk_file_system_win32_volume_get_base_path (GtkFileSystem *file_system,
394 GtkFileSystemVolume *volume)
396 return (GtkFilePath *) g_strndup (volume->drive, 2);
400 gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem *file_system,
401 GtkFileSystemVolume *volume)
403 return volume->is_mounted;
407 gtk_file_system_win32_volume_mount (GtkFileSystem *file_system,
408 GtkFileSystemVolume *volume,
412 GTK_FILE_SYSTEM_ERROR,
413 GTK_FILE_SYSTEM_ERROR_FAILED,
414 _("This file system does not support mounting"));
419 gtk_file_system_win32_volume_get_display_name (GtkFileSystem *file_system,
420 GtkFileSystemVolume *volume)
422 gchar display_name[80];
424 if (GetVolumeInformation (volume->drive,
425 display_name, sizeof(display_name),
426 NULL, /* serial number */
427 NULL, /* max. component length */
429 NULL, 0)) /* fs type like FAT, NTFS */
431 gchar* real_display_name = g_strconcat (display_name, " (", volume->drive, ")", NULL);
433 return real_display_name;
436 return g_strdup (volume->drive);
440 gtk_file_system_win32_volume_render_icon (GtkFileSystem *file_system,
441 GtkFileSystemVolume *volume,
446 GtkIconSet *icon_set = NULL;
447 DWORD dt = GetDriveType (volume->drive);
451 case DRIVE_REMOVABLE :
452 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
455 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
458 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
461 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
464 /*FIXME: need a ram stock icon
465 gtk_file_info_set_icon_type (info, GTK_STOCK_OPEN);*/
468 g_assert_not_reached ();
471 return gtk_icon_set_render_icon (icon_set,
473 gtk_widget_get_direction (widget),
475 GTK_ICON_SIZE_BUTTON,
480 gtk_file_system_win32_get_parent (GtkFileSystem *file_system,
481 const GtkFilePath *path,
482 GtkFilePath **parent,
485 gchar *filename = filename_from_path (path);
486 g_return_val_if_fail (filename != NULL, FALSE);
488 if (filename_is_root (filename))
494 gchar *parent_filename = g_path_get_dirname (filename);
495 *parent = filename_to_path (parent_filename);
496 g_free (parent_filename);
505 gtk_file_system_win32_make_path (GtkFileSystem *file_system,
506 const GtkFilePath *base_path,
507 const gchar *display_name,
510 gchar *base_filename;
512 gchar *full_filename;
513 GError *tmp_error = NULL;
516 base_filename = filename_from_path (base_path);
517 g_return_val_if_fail (base_filename != NULL, NULL);
519 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
523 GTK_FILE_SYSTEM_ERROR,
524 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
528 g_error_free (tmp_error);
529 g_free (base_filename);
534 full_filename = g_build_filename (base_filename, filename, NULL);
535 result = filename_to_path (full_filename);
536 g_free (base_filename);
538 g_free (full_filename);
543 /* If this was a publically exported function, it should return
544 * a dup'ed result, but we make it modify-in-place for efficiency
545 * here, and because it works for us.
548 canonicalize_filename (gchar *filename)
551 gboolean last_was_slash = FALSE;
558 if (*p == G_DIR_SEPARATOR)
561 *q++ = G_DIR_SEPARATOR;
563 last_was_slash = TRUE;
567 if (last_was_slash && *p == '.')
569 if (*(p + 1) == G_DIR_SEPARATOR ||
572 if (*(p + 1) == '\0')
577 else if (*(p + 1) == '.' &&
578 (*(p + 2) == G_DIR_SEPARATOR ||
581 if (q > filename + 1)
584 while (q > filename + 1 &&
585 *(q - 1) != G_DIR_SEPARATOR)
589 if (*(p + 2) == '\0')
597 last_was_slash = FALSE;
603 last_was_slash = FALSE;
610 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
617 gtk_file_system_win32_parse (GtkFileSystem *file_system,
618 const GtkFilePath *base_path,
620 GtkFilePath **folder,
626 gboolean result = FALSE;
628 base_filename = filename_from_path (base_path);
629 g_return_val_if_fail (base_filename != NULL, FALSE);
631 last_slash = strrchr (str, G_DIR_SEPARATOR);
634 *folder = gtk_file_path_copy (base_path);
635 *file_part = g_strdup (str);
642 GError *tmp_error = NULL;
644 if (last_slash == str)
645 folder_part = g_strdup ("/");
647 folder_part = g_filename_from_utf8 (str, last_slash - str,
648 NULL, NULL, &tmp_error);
653 GTK_FILE_SYSTEM_ERROR,
654 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
657 g_error_free (tmp_error);
661 if (folder_part[1] == ':')
662 folder_path = folder_part;
665 folder_path = g_build_filename (base_filename, folder_part, NULL);
666 g_free (folder_part);
669 canonicalize_filename (folder_path);
671 *folder = filename_to_path (folder_path);
672 *file_part = g_strdup (last_slash + 1);
674 g_free (folder_path);
680 g_free (base_filename);
686 gtk_file_system_win32_path_to_uri (GtkFileSystem *file_system,
687 const GtkFilePath *path)
689 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
693 gtk_file_system_win32_path_to_filename (GtkFileSystem *file_system,
694 const GtkFilePath *path)
696 return g_strdup (gtk_file_path_get_string (path));
700 gtk_file_system_win32_uri_to_path (GtkFileSystem *file_system,
703 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
705 return gtk_file_path_new_steal (filename);
711 gtk_file_system_win32_filename_to_path (GtkFileSystem *file_system,
712 const gchar *filename)
714 return gtk_file_path_new_dup (filename);
718 bookmarks_serialize (GSList **bookmarks,
725 GSList *list = *bookmarks;
727 filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
731 gchar *contents = NULL;
736 if (g_file_test (filename, G_FILE_TEST_EXISTS))
738 if (g_file_get_contents (filename, &contents, &len, error))
740 gchar **lines = g_strsplit (contents, "\n", -1);
743 for (i = 0; lines[i] != NULL; i++)
745 if (lines[i][0] && !g_slist_find_custom (list, lines[i], strcmp))
746 list = g_slist_append (list, g_strdup (lines[i]));
753 if (ok && (f = fopen (filename, "wb")) != NULL)
755 for (entry = list; entry != NULL; entry = entry->next)
757 gchar *line = entry->data;
759 if (strcmp (line, uri) != 0)
772 else if (ok && error)
775 GTK_FILE_SYSTEM_ERROR,
776 GTK_FILE_SYSTEM_ERROR_FAILED,
777 _("Bookmark saving failed (%s)"),
786 extract_icon (const char* filename)
788 GdkPixbuf *pixbuf = NULL;
792 if (!filename || !filename[0])
795 hicon = ExtractAssociatedIcon (GetModuleHandle (NULL), filename, &iicon);
796 if (hicon > (HICON)1)
800 if (GetIconInfo (hicon, &ii))
807 if (!GetBitmapDimensionEx (ii.hbmColor, &size))
808 g_warning ("GetBitmapDimensionEx failed.");
810 if (size.cx < 1) size.cx = 32;
811 if (size.cy < 1) size.cy = 32;
813 pixmap = gdk_pixmap_new (NULL, size.cx, size.cy,
814 gdk_screen_get_system_visual (gdk_screen_get_default ())->depth);
815 gc = gdk_gc_new (pixmap);
816 hdc = gdk_win32_hdc_get (GDK_DRAWABLE (pixmap), gc, 0);
818 if (!DrawIcon (hdc, 0, 0, hicon))
819 g_warning ("DrawIcon failed");
821 gdk_win32_hdc_release (GDK_DRAWABLE (pixmap), gc, 0);
823 pixbuf = gdk_pixbuf_get_from_drawable (
825 gdk_screen_get_system_colormap (gdk_screen_get_default ()),
826 0, 0, 0, 0, size.cx, size.cy);
827 g_object_unref (pixmap);
831 g_print ("GetIconInfo failed: %s\n", g_win32_error_message (GetLastError ()));
833 if (!DestroyIcon (hicon))
834 g_warning ("DestroyIcon failed");
837 g_print ("ExtractAssociatedIcon failed: %s\n", g_win32_error_message (GetLastError ()));
843 win32_pseudo_mime_lookup (const char* name)
845 static GHashTable *mime_hash = NULL;
846 GtkIconSet *is = NULL;
847 char *p = strrchr(name, '.');
848 char *extension = p ? g_ascii_strdown (p, -1) : g_strdup ("");
851 mime_hash = g_hash_table_new (g_str_hash, g_str_equal);
853 /* do we already have it ? */
854 is = g_hash_table_lookup (mime_hash, extension);
860 /* create icon and set */
862 GdkPixbuf *pixbuf = extract_icon (name);
865 GtkIconSource* source = gtk_icon_source_new ();
867 is = gtk_icon_set_new_from_pixbuf (pixbuf);
868 gtk_icon_source_set_pixbuf (source, pixbuf);
869 gtk_icon_set_add_source (is, source);
871 gtk_icon_source_free (source);
874 g_hash_table_insert (mime_hash, extension, is);
880 gtk_file_system_win32_render_icon (GtkFileSystem *file_system,
881 const GtkFilePath *path,
886 GtkIconSet *icon_set = NULL;
887 const char* filename = gtk_file_path_get_string (path);
889 /* handle drives with stock icons */
890 if (filename_is_root (filename))
892 gchar *filename2 = g_strconcat(filename, "\\", NULL);
893 DWORD dt = GetDriveType (filename2);
897 case DRIVE_REMOVABLE :
898 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
901 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
903 case DRIVE_FIXED : /* need a hard disk icon */
904 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
911 else if (g_file_test (filename, G_FILE_TEST_IS_DIR))
913 if (0 == strcmp (g_get_home_dir(), filename))
914 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HOME);
916 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_OPEN);
918 else if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE))
920 /* don't lookup all executable icons */
921 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_EXECUTE);
923 else if (g_file_test (filename, G_FILE_TEST_EXISTS))
925 icon_set = win32_pseudo_mime_lookup (filename);
931 GTK_FILE_SYSTEM_ERROR,
932 GTK_FILE_SYSTEM_ERROR_FAILED,
933 _("This file system does not support icons for everything"));
937 // FIXME : I'd like to get from pixel_size (=20) back to
938 // icon size, which is an index, but there appears to be no way ?
939 return gtk_icon_set_render_icon (icon_set,
941 gtk_widget_get_direction (widget),
943 GTK_ICON_SIZE_BUTTON,
947 static GSList *_bookmarks = NULL;
950 gtk_file_system_win32_add_bookmark (GtkFileSystem *file_system,
951 const GtkFilePath *path,
954 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
955 gboolean ret = bookmarks_serialize (&_bookmarks, uri, TRUE, error);
962 gtk_file_system_win32_remove_bookmark (GtkFileSystem *file_system,
963 const GtkFilePath *path,
966 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
967 gboolean ret = bookmarks_serialize (&_bookmarks, uri, FALSE, error);
973 gtk_file_system_win32_list_bookmarks (GtkFileSystem *file_system)
979 if (bookmarks_serialize (&_bookmarks, "", FALSE, NULL))
981 for (entry = _bookmarks; entry != NULL; entry = entry->next)
983 GtkFilePath *path = gtk_file_system_win32_uri_to_path (
984 file_system, (gchar *)entry->data);
986 list = g_slist_append (list, path);
997 gtk_file_folder_win32_get_type (void)
999 static GType file_folder_win32_type = 0;
1001 if (!file_folder_win32_type)
1003 static const GTypeInfo file_folder_win32_info =
1005 sizeof (GtkFileFolderWin32Class),
1006 NULL, /* base_init */
1007 NULL, /* base_finalize */
1008 (GClassInitFunc) gtk_file_folder_win32_class_init,
1009 NULL, /* class_finalize */
1010 NULL, /* class_data */
1011 sizeof (GtkFileFolderWin32),
1012 0, /* n_preallocs */
1013 (GInstanceInitFunc) gtk_file_folder_win32_init,
1016 static const GInterfaceInfo file_folder_info =
1018 (GInterfaceInitFunc) gtk_file_folder_win32_iface_init, /* interface_init */
1019 NULL, /* interface_finalize */
1020 NULL /* interface_data */
1023 file_folder_win32_type = g_type_register_static (G_TYPE_OBJECT,
1024 "GtkFileFolderWin32",
1025 &file_folder_win32_info, 0);
1026 g_type_add_interface_static (file_folder_win32_type,
1027 GTK_TYPE_FILE_FOLDER,
1031 return file_folder_win32_type;
1035 gtk_file_folder_win32_class_init (GtkFileFolderWin32Class *class)
1037 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1039 folder_parent_class = g_type_class_peek_parent (class);
1041 gobject_class->finalize = gtk_file_folder_win32_finalize;
1045 gtk_file_folder_win32_iface_init (GtkFileFolderIface *iface)
1047 iface->get_info = gtk_file_folder_win32_get_info;
1048 iface->list_children = gtk_file_folder_win32_list_children;
1052 gtk_file_folder_win32_init (GtkFileFolderWin32 *impl)
1057 gtk_file_folder_win32_finalize (GObject *object)
1059 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (object);
1061 g_free (folder_win32->filename);
1063 folder_parent_class->finalize (object);
1066 static GtkFileInfo *
1067 gtk_file_folder_win32_get_info (GtkFileFolder *folder,
1068 const GtkFilePath *path,
1071 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1076 filename = filename_from_path (path);
1077 g_return_val_if_fail (filename != NULL, NULL);
1080 dirname = g_path_get_dirname (filename);
1081 g_return_val_if_fail (strcmp (dirname, folder_win32->filename) == 0, NULL);
1085 info = filename_get_info (filename, folder_win32->types, error);
1093 gtk_file_folder_win32_list_children (GtkFileFolder *folder,
1097 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1098 GError *tmp_error = NULL;
1103 dir = g_dir_open (folder_win32->filename, 0, &tmp_error);
1107 GTK_FILE_SYSTEM_ERROR,
1108 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1110 tmp_error->message);
1112 g_error_free (tmp_error);
1119 const gchar *filename = g_dir_read_name (dir);
1125 fullname = g_build_filename (folder_win32->filename, filename, NULL);
1126 *children = g_slist_prepend (*children, filename_to_path (fullname));
1132 *children = g_slist_reverse (*children);
1137 static GtkFileInfo *
1138 filename_get_info (const gchar *filename,
1139 GtkFileInfoType types,
1143 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1144 GtkFileIconType icon_type = GTK_FILE_ICON_REGULAR;
1146 WIN32_FILE_ATTRIBUTE_DATA wfad;
1148 if (!GetFileAttributesEx (filename, GetFileExInfoStandard, &wfad))
1150 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
1152 GTK_FILE_SYSTEM_ERROR,
1153 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1154 _("error getting information for '%s': %s"),
1155 filename_utf8 ? filename_utf8 : "???",
1156 g_win32_error_message (GetLastError ()));
1157 g_free (filename_utf8);
1162 info = gtk_file_info_new ();
1164 if (filename_is_root (filename))
1166 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1167 gtk_file_info_set_display_name (info, filename);
1169 if (types & GTK_FILE_INFO_IS_HIDDEN)
1170 gtk_file_info_set_is_hidden (info, FALSE);
1174 gchar *basename = g_path_get_basename (filename);
1176 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1178 gchar *display_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1180 display_name = g_strescape (basename, NULL);
1182 gtk_file_info_set_display_name (info, display_name);
1184 g_free (display_name);
1187 if (types & GTK_FILE_INFO_IS_HIDDEN)
1189 /* win32 convention ... */
1190 gboolean is_hidden = basename[0] == '.';
1191 /* ... _and_ windoze attribute */
1192 is_hidden = is_hidden || !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
1193 gtk_file_info_set_is_hidden (info, is_hidden);
1199 if (types & GTK_FILE_INFO_IS_FOLDER)
1201 gtk_file_info_set_is_folder (info, !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1204 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1205 if (types & GTK_FILE_INFO_ICON)
1207 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1208 icon_type = GTK_FILE_ICON_DIRECTORY;
1210 gtk_file_info_set_icon_type (info, icon_type);
1214 if ((types & GTK_FILE_INFO_MIME_TYPE)
1215 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1216 || ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR)
1221 const char *mime_type = xdg_mime_get_mime_type_for_file (filename);
1222 gtk_file_info_set_mime_type (info, mime_type);
1224 if ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR &&
1225 (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
1226 (strcmp (mime_type, XDG_MIME_TYPE_UNKNOWN) == 0 ||
1227 strcmp (mime_type, "application/x-executable") == 0 ||
1228 strcmp (mime_type, "application/x-shellscript") == 0))
1229 gtk_file_info_set_icon_type (info, GTK_FILE_ICON_EXECUTABLE);
1233 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1235 GtkFileTime time = wfad.ftLastWriteTime.dwLowDateTime
1236 | ((guint64)wfad.ftLastWriteTime.dwHighDateTime) << 32;
1237 /* 100-nanosecond intervals since January 1, 1601, urgh! */
1238 time /= 10000000I64; /* now seconds */
1239 time -= 134774I64 * 24 * 3600; /* good old Unix time */
1240 gtk_file_info_set_modification_time (info, time);
1243 if (types & GTK_FILE_INFO_SIZE)
1245 gint64 size = wfad.nFileSizeLow | ((guint64)wfad.nFileSizeHigh) << 32;
1246 gtk_file_info_set_size (info, size);
1253 filename_from_path (const GtkFilePath *path)
1255 return g_strdup (gtk_file_path_get_string (path));
1258 static GtkFilePath *
1259 filename_to_path (const char *filename)
1261 return gtk_file_path_new_dup (filename);
1265 filename_is_root (const char *filename)
1267 guint len = strlen(filename);
1269 /* accept both forms */
1271 return ( (len == 2 && filename[1] == ':')
1272 || (len == 3 && filename[1] == ':' && filename[2] == '\\'));