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 folder_win32 = g_object_new (GTK_TYPE_FILE_FOLDER_WIN32, NULL);
349 folder_win32->filename = filename;
350 folder_win32->types = types;
352 return GTK_FILE_FOLDER (folder_win32);
356 gtk_file_system_win32_create_folder (GtkFileSystem *file_system,
357 const GtkFilePath *path,
363 filename = filename_from_path (path);
364 g_return_val_if_fail (filename != NULL, FALSE);
366 result = mkdir (filename, 0777) != 0;
370 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
372 GTK_FILE_SYSTEM_ERROR,
373 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
374 _("error creating directory '%s': %s"),
375 filename_utf8 ? filename_utf8 : "???",
377 g_free (filename_utf8);
386 gtk_file_system_win32_volume_free (GtkFileSystem *file_system,
387 GtkFileSystemVolume *volume)
389 g_free (volume->drive);
394 gtk_file_system_win32_volume_get_base_path (GtkFileSystem *file_system,
395 GtkFileSystemVolume *volume)
397 return (GtkFilePath *) g_strdup (volume->drive);
401 gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem *file_system,
402 GtkFileSystemVolume *volume)
404 return volume->is_mounted;
408 gtk_file_system_win32_volume_mount (GtkFileSystem *file_system,
409 GtkFileSystemVolume *volume,
413 GTK_FILE_SYSTEM_ERROR,
414 GTK_FILE_SYSTEM_ERROR_FAILED,
415 _("This file system does not support mounting"));
420 gtk_file_system_win32_volume_get_display_name (GtkFileSystem *file_system,
421 GtkFileSystemVolume *volume)
423 gchar *real_display_name;
424 gunichar2 *wdrive = g_utf8_to_utf16 (volume->drive, -1, NULL, NULL, NULL);
427 g_return_val_if_fail (wdrive != NULL, NULL);
429 if (GetVolumeInformationW (wdrive,
430 wname, G_N_ELEMENTS(wname),
431 NULL, /* serial number */
432 NULL, /* max. component length */
434 NULL, 0) /* fs type like FAT, NTFS */
437 gchar *name = g_utf16_to_utf8 (wname, -1, NULL, NULL, NULL);
438 real_display_name = g_strconcat (name, " (", volume->drive, ")", NULL);
442 real_display_name = g_strdup (volume->drive);
446 return real_display_name;
450 gtk_file_system_win32_volume_render_icon (GtkFileSystem *file_system,
451 GtkFileSystemVolume *volume,
456 GtkIconSet *icon_set = NULL;
457 DWORD dt = GetDriveType (volume->drive);
461 case DRIVE_REMOVABLE :
462 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
465 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
468 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
471 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
474 /*FIXME: need a ram stock icon
475 gtk_file_info_set_icon_type (info, GTK_STOCK_OPEN);*/
478 g_assert_not_reached ();
481 return gtk_icon_set_render_icon (icon_set,
483 gtk_widget_get_direction (widget),
485 GTK_ICON_SIZE_BUTTON,
490 gtk_file_system_win32_get_parent (GtkFileSystem *file_system,
491 const GtkFilePath *path,
492 GtkFilePath **parent,
495 gchar *filename = filename_from_path (path);
496 g_return_val_if_fail (filename != NULL, FALSE);
498 if (filename_is_root (filename))
504 gchar *parent_filename = g_path_get_dirname (filename);
505 *parent = filename_to_path (parent_filename);
506 g_free (parent_filename);
515 gtk_file_system_win32_make_path (GtkFileSystem *file_system,
516 const GtkFilePath *base_path,
517 const gchar *display_name,
520 const char *base_filename;
522 gchar *full_filename;
523 GError *tmp_error = NULL;
526 base_filename = gtk_file_path_get_string (base_path);
527 g_return_val_if_fail (base_filename != NULL, NULL);
528 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
530 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
534 GTK_FILE_SYSTEM_ERROR,
535 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
539 g_error_free (tmp_error);
544 full_filename = g_build_filename (base_filename, filename, NULL);
545 result = filename_to_path (full_filename);
547 g_free (full_filename);
552 /* If this was a publically exported function, it should return
553 * a dup'ed result, but we make it modify-in-place for efficiency
554 * here, and because it works for us.
557 canonicalize_filename (gchar *filename)
560 gboolean last_was_slash = FALSE;
567 if (*p == G_DIR_SEPARATOR)
570 *q++ = G_DIR_SEPARATOR;
572 last_was_slash = TRUE;
576 if (last_was_slash && *p == '.')
578 if (*(p + 1) == G_DIR_SEPARATOR ||
581 if (*(p + 1) == '\0')
586 else if (*(p + 1) == '.' &&
587 (*(p + 2) == G_DIR_SEPARATOR ||
590 if (q > filename + 1)
593 while (q > filename + 1 &&
594 *(q - 1) != G_DIR_SEPARATOR)
598 if (*(p + 2) == '\0')
606 last_was_slash = FALSE;
612 last_was_slash = FALSE;
619 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
626 gtk_file_system_win32_parse (GtkFileSystem *file_system,
627 const GtkFilePath *base_path,
629 GtkFilePath **folder,
633 const char *base_filename;
635 gboolean result = FALSE;
637 base_filename = gtk_file_path_get_string (base_path);
638 g_return_val_if_fail (base_filename != NULL, FALSE);
639 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
641 last_slash = strrchr (str, G_DIR_SEPARATOR);
644 *folder = gtk_file_path_copy (base_path);
645 *file_part = g_strdup (str);
652 GError *tmp_error = NULL;
654 if (last_slash == str)
655 folder_part = g_strdup ("/");
657 folder_part = g_filename_from_utf8 (str, last_slash - str,
658 NULL, NULL, &tmp_error);
663 GTK_FILE_SYSTEM_ERROR,
664 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
667 g_error_free (tmp_error);
671 if (folder_part[1] == ':')
672 folder_path = folder_part;
675 folder_path = g_build_filename (base_filename, folder_part, NULL);
676 g_free (folder_part);
679 canonicalize_filename (folder_path);
681 *folder = filename_to_path (folder_path);
682 *file_part = g_strdup (last_slash + 1);
684 g_free (folder_path);
694 gtk_file_system_win32_path_to_uri (GtkFileSystem *file_system,
695 const GtkFilePath *path)
697 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
701 gtk_file_system_win32_path_to_filename (GtkFileSystem *file_system,
702 const GtkFilePath *path)
704 return g_strdup (gtk_file_path_get_string (path));
708 gtk_file_system_win32_uri_to_path (GtkFileSystem *file_system,
711 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
713 return gtk_file_path_new_steal (filename);
719 gtk_file_system_win32_filename_to_path (GtkFileSystem *file_system,
720 const gchar *filename)
722 return gtk_file_path_new_dup (filename);
726 bookmarks_serialize (GSList **bookmarks,
734 GSList *list = *bookmarks;
736 filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
740 gchar *contents = NULL;
745 if (g_file_test (filename, G_FILE_TEST_EXISTS))
747 if (g_file_get_contents (filename, &contents, &len, error))
749 gchar **lines = g_strsplit (contents, "\n", -1);
752 for (i = 0; lines[i] != NULL; i++)
754 if (lines[i][0] && !g_slist_find_custom (list, lines[i], (GCompareFunc) strcmp))
755 list = g_slist_append (list, g_strdup (lines[i]));
762 if (ok && (f = fopen (filename, "wb")) != NULL)
764 entry = g_slist_find_custom (list, uri, (GCompareFunc) strcmp);
767 /* g_slist_insert() and our insert semantics are
768 * compatible, but maybe we should check for
773 list = g_slist_insert (list, g_strdup (uri), position);
777 GTK_FILE_SYSTEM_ERROR,
778 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
779 "%s already exists in the bookmarks list",
786 /* to remove the given uri */
788 list = g_slist_delete_link(list, entry);
789 for (entry = list; entry != NULL; entry = entry->next)
791 fputs (entry->data, f);
797 else if (ok && error)
800 GTK_FILE_SYSTEM_ERROR,
801 GTK_FILE_SYSTEM_ERROR_FAILED,
802 _("Bookmark saving failed (%s)"),
811 extract_icon (const char* filename)
813 GdkPixbuf *pixbuf = NULL;
817 if (!filename || !filename[0])
820 hicon = ExtractAssociatedIcon (GetModuleHandle (NULL), filename, &iicon);
821 if (hicon > (HICON)1)
825 if (GetIconInfo (hicon, &ii))
832 if (!GetBitmapDimensionEx (ii.hbmColor, &size))
833 g_warning ("GetBitmapDimensionEx failed.");
835 if (size.cx < 1) size.cx = 32;
836 if (size.cy < 1) size.cy = 32;
838 pixmap = gdk_pixmap_new (NULL, size.cx, size.cy,
839 gdk_screen_get_system_visual (gdk_screen_get_default ())->depth);
840 gc = gdk_gc_new (pixmap);
841 hdc = gdk_win32_hdc_get (GDK_DRAWABLE (pixmap), gc, 0);
843 if (!DrawIcon (hdc, 0, 0, hicon))
844 g_warning ("DrawIcon failed");
846 gdk_win32_hdc_release (GDK_DRAWABLE (pixmap), gc, 0);
848 pixbuf = gdk_pixbuf_get_from_drawable (
850 gdk_screen_get_system_colormap (gdk_screen_get_default ()),
851 0, 0, 0, 0, size.cx, size.cy);
852 g_object_unref (pixmap);
856 g_print ("GetIconInfo failed: %s\n", g_win32_error_message (GetLastError ()));
858 if (!DestroyIcon (hicon))
859 g_warning ("DestroyIcon failed");
862 g_print ("ExtractAssociatedIcon failed: %s\n", g_win32_error_message (GetLastError ()));
868 win32_pseudo_mime_lookup (const char* name)
870 static GHashTable *mime_hash = NULL;
871 GtkIconSet *is = NULL;
872 char *p = strrchr(name, '.');
873 char *extension = p ? g_ascii_strdown (p, -1) : g_strdup ("");
876 mime_hash = g_hash_table_new (g_str_hash, g_str_equal);
878 /* do we already have it ? */
879 is = g_hash_table_lookup (mime_hash, extension);
885 /* create icon and set */
887 GdkPixbuf *pixbuf = extract_icon (name);
890 GtkIconSource* source = gtk_icon_source_new ();
892 is = gtk_icon_set_new_from_pixbuf (pixbuf);
893 gtk_icon_source_set_pixbuf (source, pixbuf);
894 gtk_icon_set_add_source (is, source);
896 gtk_icon_source_free (source);
899 g_hash_table_insert (mime_hash, extension, is);
905 gtk_file_system_win32_render_icon (GtkFileSystem *file_system,
906 const GtkFilePath *path,
911 GtkIconSet *icon_set = NULL;
912 const char* filename = gtk_file_path_get_string (path);
914 /* handle drives with stock icons */
915 if (filename_is_root (filename))
917 gchar *filename2 = g_strconcat(filename, "\\", NULL);
918 DWORD dt = GetDriveType (filename2);
922 case DRIVE_REMOVABLE :
923 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
926 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
928 case DRIVE_FIXED : /* need a hard disk icon */
929 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
936 else if (g_file_test (filename, G_FILE_TEST_IS_DIR))
938 if (0 == strcmp (g_get_home_dir(), filename))
939 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HOME);
941 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_OPEN);
943 else if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE))
945 /* don't lookup all executable icons */
946 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_EXECUTE);
948 else if (g_file_test (filename, G_FILE_TEST_EXISTS))
950 icon_set = win32_pseudo_mime_lookup (filename);
956 GTK_FILE_SYSTEM_ERROR,
957 GTK_FILE_SYSTEM_ERROR_FAILED,
958 _("This file system does not support icons for everything"));
962 // FIXME : I'd like to get from pixel_size (=20) back to
963 // icon size, which is an index, but there appears to be no way ?
964 return gtk_icon_set_render_icon (icon_set,
966 gtk_widget_get_direction (widget),
968 GTK_ICON_SIZE_BUTTON,
972 static GSList *_bookmarks = NULL;
975 gtk_file_system_win32_insert_bookmark (GtkFileSystem *file_system,
976 const GtkFilePath *path,
980 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
981 gboolean ret = bookmarks_serialize (&_bookmarks, uri, TRUE, position, error);
983 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
990 gtk_file_system_win32_remove_bookmark (GtkFileSystem *file_system,
991 const GtkFilePath *path,
994 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
995 gboolean ret = bookmarks_serialize (&_bookmarks, uri, FALSE, 0, error);
997 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1003 gtk_file_system_win32_list_bookmarks (GtkFileSystem *file_system)
1005 GSList *list = NULL;
1009 if (bookmarks_serialize (&_bookmarks, "", FALSE, 0, NULL))
1011 for (entry = _bookmarks; entry != NULL; entry = entry->next)
1013 GtkFilePath *path = gtk_file_system_win32_uri_to_path (
1014 file_system, (gchar *)entry->data);
1016 list = g_slist_append (list, path);
1024 * GtkFileFolderWin32
1027 gtk_file_folder_win32_get_type (void)
1029 static GType file_folder_win32_type = 0;
1031 if (!file_folder_win32_type)
1033 static const GTypeInfo file_folder_win32_info =
1035 sizeof (GtkFileFolderWin32Class),
1036 NULL, /* base_init */
1037 NULL, /* base_finalize */
1038 (GClassInitFunc) gtk_file_folder_win32_class_init,
1039 NULL, /* class_finalize */
1040 NULL, /* class_data */
1041 sizeof (GtkFileFolderWin32),
1042 0, /* n_preallocs */
1043 (GInstanceInitFunc) gtk_file_folder_win32_init,
1046 static const GInterfaceInfo file_folder_info =
1048 (GInterfaceInitFunc) gtk_file_folder_win32_iface_init, /* interface_init */
1049 NULL, /* interface_finalize */
1050 NULL /* interface_data */
1053 file_folder_win32_type = g_type_register_static (G_TYPE_OBJECT,
1054 "GtkFileFolderWin32",
1055 &file_folder_win32_info, 0);
1056 g_type_add_interface_static (file_folder_win32_type,
1057 GTK_TYPE_FILE_FOLDER,
1061 return file_folder_win32_type;
1065 gtk_file_folder_win32_class_init (GtkFileFolderWin32Class *class)
1067 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1069 folder_parent_class = g_type_class_peek_parent (class);
1071 gobject_class->finalize = gtk_file_folder_win32_finalize;
1075 gtk_file_folder_win32_iface_init (GtkFileFolderIface *iface)
1077 iface->get_info = gtk_file_folder_win32_get_info;
1078 iface->list_children = gtk_file_folder_win32_list_children;
1082 gtk_file_folder_win32_init (GtkFileFolderWin32 *impl)
1087 gtk_file_folder_win32_finalize (GObject *object)
1089 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (object);
1091 g_free (folder_win32->filename);
1093 folder_parent_class->finalize (object);
1096 static GtkFileInfo *
1097 gtk_file_folder_win32_get_info (GtkFileFolder *folder,
1098 const GtkFilePath *path,
1101 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1108 g_return_val_if_fail (filename_is_root (folder_win32->filename), NULL);
1111 info = filename_get_info (folder_win32->filename, folder_win32->types, error);
1116 filename = filename_from_path (path);
1117 g_return_val_if_fail (filename != NULL, NULL);
1120 dirname = g_path_get_dirname (filename);
1121 g_return_val_if_fail (strcmp (dirname, folder_win32->filename) == 0, NULL);
1125 info = filename_get_info (filename, folder_win32->types, error);
1133 gtk_file_folder_win32_list_children (GtkFileFolder *folder,
1137 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1138 GError *tmp_error = NULL;
1143 dir = g_dir_open (folder_win32->filename, 0, &tmp_error);
1147 GTK_FILE_SYSTEM_ERROR,
1148 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1150 tmp_error->message);
1152 g_error_free (tmp_error);
1159 const gchar *filename = g_dir_read_name (dir);
1165 fullname = g_build_filename (folder_win32->filename, filename, NULL);
1166 *children = g_slist_prepend (*children, filename_to_path (fullname));
1172 *children = g_slist_reverse (*children);
1177 static GtkFileInfo *
1178 filename_get_info (const gchar *filename,
1179 GtkFileInfoType types,
1183 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1184 GtkFileIconType icon_type = GTK_FILE_ICON_REGULAR;
1186 WIN32_FILE_ATTRIBUTE_DATA wfad;
1188 if (!GetFileAttributesEx (filename, GetFileExInfoStandard, &wfad))
1190 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
1192 GTK_FILE_SYSTEM_ERROR,
1193 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1194 _("error getting information for '%s': %s"),
1195 filename_utf8 ? filename_utf8 : "???",
1196 g_win32_error_message (GetLastError ()));
1197 g_free (filename_utf8);
1202 info = gtk_file_info_new ();
1204 if (filename_is_root (filename))
1206 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1207 gtk_file_info_set_display_name (info, filename);
1209 if (types & GTK_FILE_INFO_IS_HIDDEN)
1210 gtk_file_info_set_is_hidden (info, FALSE);
1214 gchar *basename = g_path_get_basename (filename);
1216 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1218 gchar *display_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1220 display_name = g_strescape (basename, NULL);
1222 gtk_file_info_set_display_name (info, display_name);
1224 g_free (display_name);
1227 if (types & GTK_FILE_INFO_IS_HIDDEN)
1229 /* win32 convention ... */
1230 gboolean is_hidden = basename[0] == '.';
1231 /* ... _and_ windoze attribute */
1232 is_hidden = is_hidden || !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
1233 gtk_file_info_set_is_hidden (info, is_hidden);
1239 if (types & GTK_FILE_INFO_IS_FOLDER)
1241 gtk_file_info_set_is_folder (info, !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1244 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1245 if (types & GTK_FILE_INFO_ICON)
1247 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1248 icon_type = GTK_FILE_ICON_DIRECTORY;
1250 gtk_file_info_set_icon_type (info, icon_type);
1254 if ((types & GTK_FILE_INFO_MIME_TYPE)
1255 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1256 || ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR)
1261 const char *mime_type = xdg_mime_get_mime_type_for_file (filename);
1262 gtk_file_info_set_mime_type (info, mime_type);
1264 if ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR &&
1265 (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
1266 (strcmp (mime_type, XDG_MIME_TYPE_UNKNOWN) == 0 ||
1267 strcmp (mime_type, "application/x-executable") == 0 ||
1268 strcmp (mime_type, "application/x-shellscript") == 0))
1269 gtk_file_info_set_icon_type (info, GTK_FILE_ICON_EXECUTABLE);
1273 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1275 GtkFileTime time = wfad.ftLastWriteTime.dwLowDateTime
1276 | ((guint64)wfad.ftLastWriteTime.dwHighDateTime) << 32;
1277 /* 100-nanosecond intervals since January 1, 1601, urgh! */
1278 time /= G_GINT64_CONSTANT (10000000); /* now seconds */
1279 time -= G_GINT64_CONSTANT (134774) * 24 * 3600; /* good old Unix time */
1280 gtk_file_info_set_modification_time (info, time);
1283 if (types & GTK_FILE_INFO_SIZE)
1285 gint64 size = wfad.nFileSizeLow | ((guint64)wfad.nFileSizeHigh) << 32;
1286 gtk_file_info_set_size (info, size);
1293 filename_from_path (const GtkFilePath *path)
1295 return g_strdup (gtk_file_path_get_string (path));
1298 static GtkFilePath *
1299 filename_to_path (const char *filename)
1301 return gtk_file_path_new_dup (filename);
1305 filename_is_root (const char *filename)
1307 guint len = strlen(filename);
1309 /* accept both forms */
1311 return ( (len == 2 && filename[1] == ':')
1312 || (len == 3 && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/')));