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)
296 len = GetLogicalDriveStrings(sizeof(drives), drives);
299 g_warning("No drive strings available!");
302 while ((len = strlen(p)) != 0)
304 GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
305 if (p[0] == 'a' || p[0] == 'b')
306 vol->is_mounted = FALSE; /* skip floppy */
308 vol->is_mounted = TRUE; /* handle other removable drives special, too? */
310 /*FIXME: gtk_file_path_compare() is case sensitive, we are not*/
311 p[0] = g_ascii_toupper (p[0]);
312 vol->drive = g_strdup (p);
314 list = g_slist_append (list, vol);
321 static GtkFileSystemVolume *
322 gtk_file_system_win32_get_volume_for_path (GtkFileSystem *file_system,
323 const GtkFilePath *path)
325 GtkFileSystemVolume *vol = g_new0 (GtkFileSystemVolume, 1);
326 gchar* p = g_strndup (gtk_file_path_get_string (path), 3);
328 g_return_val_if_fail (p != NULL, NULL);
330 /*FIXME: gtk_file_path_compare() is case sensitive, we are not*/
331 p[0] = g_ascii_toupper (p[0]);
333 vol->is_mounted = (p[0] != 'A' && p[0] != 'B');
338 static GtkFileFolder *
339 gtk_file_system_win32_get_folder (GtkFileSystem *file_system,
340 const GtkFilePath *path,
341 GtkFileInfoType types,
344 GtkFileFolderWin32 *folder_win32;
347 filename = filename_from_path (path);
348 g_return_val_if_fail (filename != NULL, NULL);
350 folder_win32 = g_object_new (GTK_TYPE_FILE_FOLDER_WIN32, NULL);
351 folder_win32->filename = filename;
352 folder_win32->types = types;
354 return GTK_FILE_FOLDER (folder_win32);
358 gtk_file_system_win32_create_folder (GtkFileSystem *file_system,
359 const GtkFilePath *path,
365 filename = filename_from_path (path);
366 g_return_val_if_fail (filename != NULL, FALSE);
368 result = mkdir (filename, 0777) != 0;
372 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
374 GTK_FILE_SYSTEM_ERROR,
375 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
376 _("error creating directory '%s': %s"),
377 filename_utf8 ? filename_utf8 : "???",
379 g_free (filename_utf8);
388 gtk_file_system_win32_volume_free (GtkFileSystem *file_system,
389 GtkFileSystemVolume *volume)
391 g_free (volume->drive);
396 gtk_file_system_win32_volume_get_base_path (GtkFileSystem *file_system,
397 GtkFileSystemVolume *volume)
399 return (GtkFilePath *) g_strdup (volume->drive);
403 gtk_file_system_win32_volume_get_is_mounted (GtkFileSystem *file_system,
404 GtkFileSystemVolume *volume)
406 return volume->is_mounted;
410 gtk_file_system_win32_volume_mount (GtkFileSystem *file_system,
411 GtkFileSystemVolume *volume,
415 GTK_FILE_SYSTEM_ERROR,
416 GTK_FILE_SYSTEM_ERROR_FAILED,
417 _("This file system does not support mounting"));
422 gtk_file_system_win32_volume_get_display_name (GtkFileSystem *file_system,
423 GtkFileSystemVolume *volume)
425 gchar display_name[80];
426 gunichar2 *wdrive = g_utf8_to_utf16 (volume->drive, -1, NULL, NULL, NULL);
429 g_return_val_if_fail (wdrive != NULL, NULL);
431 if (GetVolumeInformationW (wdrive, wname, sizeof(wname),
432 NULL, NULL, NULL, NULL, 0))
434 gchar *name = g_utf16_to_utf8 (wname, -1, NULL, NULL, NULL);
435 gchar *real_display_name = g_strconcat (name, " (", volume->drive, ")", NULL);
439 GTK_NOTE (MISC, g_print ("Wide volume display name: %s\n", real_display_name));
441 return real_display_name;
443 else if (GetVolumeInformation (volume->drive,
444 display_name, sizeof(display_name),
445 NULL, /* serial number */
446 NULL, /* max. component length */
448 NULL, 0)) /* fs type like FAT, NTFS */
450 gchar *name = g_locale_to_utf8 (display_name, -1, NULL, NULL, NULL);
451 gchar *real_display_name = g_strconcat (name, " (", volume->drive, ")", NULL);
454 GTK_NOTE (MISC, g_print ("Locale volume display name: %s\n", real_display_name));
456 return real_display_name;
459 return g_strdup (volume->drive);
463 gtk_file_system_win32_volume_render_icon (GtkFileSystem *file_system,
464 GtkFileSystemVolume *volume,
469 GtkIconSet *icon_set = NULL;
470 DWORD dt = GetDriveType (volume->drive);
474 case DRIVE_REMOVABLE :
475 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
478 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
481 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_NETWORK);
484 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
487 /*FIXME: need a ram stock icon
488 gtk_file_info_set_icon_type (info, GTK_STOCK_OPEN);*/
491 g_assert_not_reached ();
494 return gtk_icon_set_render_icon (icon_set,
496 gtk_widget_get_direction (widget),
498 GTK_ICON_SIZE_BUTTON,
503 gtk_file_system_win32_get_parent (GtkFileSystem *file_system,
504 const GtkFilePath *path,
505 GtkFilePath **parent,
508 gchar *filename = filename_from_path (path);
509 g_return_val_if_fail (filename != NULL, FALSE);
511 if (filename_is_root (filename))
517 gchar *parent_filename = g_path_get_dirname (filename);
518 *parent = filename_to_path (parent_filename);
519 g_free (parent_filename);
528 gtk_file_system_win32_make_path (GtkFileSystem *file_system,
529 const GtkFilePath *base_path,
530 const gchar *display_name,
533 const char *base_filename;
535 gchar *full_filename;
536 GError *tmp_error = NULL;
539 base_filename = gtk_file_path_get_string (base_path);
540 g_return_val_if_fail (base_filename != NULL, NULL);
541 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
543 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
547 GTK_FILE_SYSTEM_ERROR,
548 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
552 g_error_free (tmp_error);
557 full_filename = g_build_filename (base_filename, filename, NULL);
558 result = filename_to_path (full_filename);
560 g_free (full_filename);
565 /* If this was a publically exported function, it should return
566 * a dup'ed result, but we make it modify-in-place for efficiency
567 * here, and because it works for us.
570 canonicalize_filename (gchar *filename)
573 gboolean last_was_slash = FALSE;
580 if (*p == G_DIR_SEPARATOR)
583 *q++ = G_DIR_SEPARATOR;
585 last_was_slash = TRUE;
589 if (last_was_slash && *p == '.')
591 if (*(p + 1) == G_DIR_SEPARATOR ||
594 if (*(p + 1) == '\0')
599 else if (*(p + 1) == '.' &&
600 (*(p + 2) == G_DIR_SEPARATOR ||
603 if (q > filename + 1)
606 while (q > filename + 1 &&
607 *(q - 1) != G_DIR_SEPARATOR)
611 if (*(p + 2) == '\0')
619 last_was_slash = FALSE;
625 last_was_slash = FALSE;
632 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
639 gtk_file_system_win32_parse (GtkFileSystem *file_system,
640 const GtkFilePath *base_path,
642 GtkFilePath **folder,
646 const char *base_filename;
648 gboolean result = FALSE;
650 base_filename = gtk_file_path_get_string (base_path);
651 g_return_val_if_fail (base_filename != NULL, FALSE);
652 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
654 last_slash = strrchr (str, G_DIR_SEPARATOR);
657 *folder = gtk_file_path_copy (base_path);
658 *file_part = g_strdup (str);
665 GError *tmp_error = NULL;
667 if (last_slash == str)
668 folder_part = g_strdup ("/");
670 folder_part = g_filename_from_utf8 (str, last_slash - str,
671 NULL, NULL, &tmp_error);
676 GTK_FILE_SYSTEM_ERROR,
677 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
680 g_error_free (tmp_error);
684 if (folder_part[1] == ':')
685 folder_path = folder_part;
688 folder_path = g_build_filename (base_filename, folder_part, NULL);
689 g_free (folder_part);
692 canonicalize_filename (folder_path);
694 *folder = filename_to_path (folder_path);
695 *file_part = g_strdup (last_slash + 1);
697 g_free (folder_path);
707 gtk_file_system_win32_path_to_uri (GtkFileSystem *file_system,
708 const GtkFilePath *path)
710 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
714 gtk_file_system_win32_path_to_filename (GtkFileSystem *file_system,
715 const GtkFilePath *path)
717 return g_strdup (gtk_file_path_get_string (path));
721 gtk_file_system_win32_uri_to_path (GtkFileSystem *file_system,
724 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
726 return gtk_file_path_new_steal (filename);
732 gtk_file_system_win32_filename_to_path (GtkFileSystem *file_system,
733 const gchar *filename)
735 return gtk_file_path_new_dup (filename);
739 bookmarks_serialize (GSList **bookmarks,
747 GSList *list = *bookmarks;
749 filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
753 gchar *contents = NULL;
758 if (g_file_test (filename, G_FILE_TEST_EXISTS))
760 if (g_file_get_contents (filename, &contents, &len, error))
762 gchar **lines = g_strsplit (contents, "\n", -1);
765 for (i = 0; lines[i] != NULL; i++)
767 if (lines[i][0] && !g_slist_find_custom (list, lines[i], (GCompareFunc) strcmp))
768 list = g_slist_append (list, g_strdup (lines[i]));
775 if (ok && (f = fopen (filename, "wb")) != NULL)
779 /* g_slist_insert() and our insert semantics are
780 * compatible, but maybe we should check for
784 if (!g_slist_find_custom (list, uri, (GCompareFunc) strcmp))
785 list = g_slist_insert (list, g_strdup (uri), position);
789 GTK_FILE_SYSTEM_ERROR,
790 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
791 "%s already exists in the bookmarks list",
796 for (entry = list; entry != NULL; entry = entry->next)
798 gchar *line = entry->data;
800 /* to remove the given uri */
801 if (!add && strcmp (line, uri) != 0)
809 else if (ok && error)
812 GTK_FILE_SYSTEM_ERROR,
813 GTK_FILE_SYSTEM_ERROR_FAILED,
814 _("Bookmark saving failed (%s)"),
823 extract_icon (const char* filename)
825 GdkPixbuf *pixbuf = NULL;
829 if (!filename || !filename[0])
832 hicon = ExtractAssociatedIcon (GetModuleHandle (NULL), filename, &iicon);
833 if (hicon > (HICON)1)
837 if (GetIconInfo (hicon, &ii))
844 if (!GetBitmapDimensionEx (ii.hbmColor, &size))
845 g_warning ("GetBitmapDimensionEx failed.");
847 if (size.cx < 1) size.cx = 32;
848 if (size.cy < 1) size.cy = 32;
850 pixmap = gdk_pixmap_new (NULL, size.cx, size.cy,
851 gdk_screen_get_system_visual (gdk_screen_get_default ())->depth);
852 gc = gdk_gc_new (pixmap);
853 hdc = gdk_win32_hdc_get (GDK_DRAWABLE (pixmap), gc, 0);
855 if (!DrawIcon (hdc, 0, 0, hicon))
856 g_warning ("DrawIcon failed");
858 gdk_win32_hdc_release (GDK_DRAWABLE (pixmap), gc, 0);
860 pixbuf = gdk_pixbuf_get_from_drawable (
862 gdk_screen_get_system_colormap (gdk_screen_get_default ()),
863 0, 0, 0, 0, size.cx, size.cy);
864 g_object_unref (pixmap);
868 g_print ("GetIconInfo failed: %s\n", g_win32_error_message (GetLastError ()));
870 if (!DestroyIcon (hicon))
871 g_warning ("DestroyIcon failed");
874 g_print ("ExtractAssociatedIcon failed: %s\n", g_win32_error_message (GetLastError ()));
880 win32_pseudo_mime_lookup (const char* name)
882 static GHashTable *mime_hash = NULL;
883 GtkIconSet *is = NULL;
884 char *p = strrchr(name, '.');
885 char *extension = p ? g_ascii_strdown (p, -1) : g_strdup ("");
888 mime_hash = g_hash_table_new (g_str_hash, g_str_equal);
890 /* do we already have it ? */
891 is = g_hash_table_lookup (mime_hash, extension);
897 /* create icon and set */
899 GdkPixbuf *pixbuf = extract_icon (name);
902 GtkIconSource* source = gtk_icon_source_new ();
904 is = gtk_icon_set_new_from_pixbuf (pixbuf);
905 gtk_icon_source_set_pixbuf (source, pixbuf);
906 gtk_icon_set_add_source (is, source);
908 gtk_icon_source_free (source);
911 g_hash_table_insert (mime_hash, extension, is);
917 gtk_file_system_win32_render_icon (GtkFileSystem *file_system,
918 const GtkFilePath *path,
923 GtkIconSet *icon_set = NULL;
924 const char* filename = gtk_file_path_get_string (path);
926 /* handle drives with stock icons */
927 if (filename_is_root (filename))
929 gchar *filename2 = g_strconcat(filename, "\\", NULL);
930 DWORD dt = GetDriveType (filename2);
934 case DRIVE_REMOVABLE :
935 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_FLOPPY);
938 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_CDROM);
940 case DRIVE_FIXED : /* need a hard disk icon */
941 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HARDDISK);
948 else if (g_file_test (filename, G_FILE_TEST_IS_DIR))
950 if (0 == strcmp (g_get_home_dir(), filename))
951 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_HOME);
953 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_OPEN);
955 else if (g_file_test (filename, G_FILE_TEST_IS_EXECUTABLE))
957 /* don't lookup all executable icons */
958 icon_set = gtk_style_lookup_icon_set (widget->style, GTK_STOCK_EXECUTE);
960 else if (g_file_test (filename, G_FILE_TEST_EXISTS))
962 icon_set = win32_pseudo_mime_lookup (filename);
968 GTK_FILE_SYSTEM_ERROR,
969 GTK_FILE_SYSTEM_ERROR_FAILED,
970 _("This file system does not support icons for everything"));
974 // FIXME : I'd like to get from pixel_size (=20) back to
975 // icon size, which is an index, but there appears to be no way ?
976 return gtk_icon_set_render_icon (icon_set,
978 gtk_widget_get_direction (widget),
980 GTK_ICON_SIZE_BUTTON,
984 static GSList *_bookmarks = NULL;
987 gtk_file_system_win32_insert_bookmark (GtkFileSystem *file_system,
988 const GtkFilePath *path,
992 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
993 gboolean ret = bookmarks_serialize (&_bookmarks, uri, TRUE, position, error);
995 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1002 gtk_file_system_win32_remove_bookmark (GtkFileSystem *file_system,
1003 const GtkFilePath *path,
1006 gchar *uri = gtk_file_system_win32_path_to_uri (file_system, path);
1007 gboolean ret = bookmarks_serialize (&_bookmarks, uri, FALSE, 0, error);
1009 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1015 gtk_file_system_win32_list_bookmarks (GtkFileSystem *file_system)
1017 GSList *list = NULL;
1021 if (bookmarks_serialize (&_bookmarks, "", FALSE, 0, NULL))
1023 for (entry = _bookmarks; entry != NULL; entry = entry->next)
1025 GtkFilePath *path = gtk_file_system_win32_uri_to_path (
1026 file_system, (gchar *)entry->data);
1028 list = g_slist_append (list, path);
1036 * GtkFileFolderWin32
1039 gtk_file_folder_win32_get_type (void)
1041 static GType file_folder_win32_type = 0;
1043 if (!file_folder_win32_type)
1045 static const GTypeInfo file_folder_win32_info =
1047 sizeof (GtkFileFolderWin32Class),
1048 NULL, /* base_init */
1049 NULL, /* base_finalize */
1050 (GClassInitFunc) gtk_file_folder_win32_class_init,
1051 NULL, /* class_finalize */
1052 NULL, /* class_data */
1053 sizeof (GtkFileFolderWin32),
1054 0, /* n_preallocs */
1055 (GInstanceInitFunc) gtk_file_folder_win32_init,
1058 static const GInterfaceInfo file_folder_info =
1060 (GInterfaceInitFunc) gtk_file_folder_win32_iface_init, /* interface_init */
1061 NULL, /* interface_finalize */
1062 NULL /* interface_data */
1065 file_folder_win32_type = g_type_register_static (G_TYPE_OBJECT,
1066 "GtkFileFolderWin32",
1067 &file_folder_win32_info, 0);
1068 g_type_add_interface_static (file_folder_win32_type,
1069 GTK_TYPE_FILE_FOLDER,
1073 return file_folder_win32_type;
1077 gtk_file_folder_win32_class_init (GtkFileFolderWin32Class *class)
1079 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1081 folder_parent_class = g_type_class_peek_parent (class);
1083 gobject_class->finalize = gtk_file_folder_win32_finalize;
1087 gtk_file_folder_win32_iface_init (GtkFileFolderIface *iface)
1089 iface->get_info = gtk_file_folder_win32_get_info;
1090 iface->list_children = gtk_file_folder_win32_list_children;
1094 gtk_file_folder_win32_init (GtkFileFolderWin32 *impl)
1099 gtk_file_folder_win32_finalize (GObject *object)
1101 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (object);
1103 g_free (folder_win32->filename);
1105 folder_parent_class->finalize (object);
1108 static GtkFileInfo *
1109 gtk_file_folder_win32_get_info (GtkFileFolder *folder,
1110 const GtkFilePath *path,
1113 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1120 g_return_val_if_fail (filename_is_root (folder_win32->filename), NULL);
1123 info = filename_get_info (folder_win32->filename, folder_win32->types, error);
1128 filename = filename_from_path (path);
1129 g_return_val_if_fail (filename != NULL, NULL);
1132 dirname = g_path_get_dirname (filename);
1133 g_return_val_if_fail (strcmp (dirname, folder_win32->filename) == 0, NULL);
1137 info = filename_get_info (filename, folder_win32->types, error);
1145 gtk_file_folder_win32_list_children (GtkFileFolder *folder,
1149 GtkFileFolderWin32 *folder_win32 = GTK_FILE_FOLDER_WIN32 (folder);
1150 GError *tmp_error = NULL;
1155 dir = g_dir_open (folder_win32->filename, 0, &tmp_error);
1159 GTK_FILE_SYSTEM_ERROR,
1160 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1162 tmp_error->message);
1164 g_error_free (tmp_error);
1171 const gchar *filename = g_dir_read_name (dir);
1177 fullname = g_build_filename (folder_win32->filename, filename, NULL);
1178 *children = g_slist_prepend (*children, filename_to_path (fullname));
1184 *children = g_slist_reverse (*children);
1189 static GtkFileInfo *
1190 filename_get_info (const gchar *filename,
1191 GtkFileInfoType types,
1195 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1196 GtkFileIconType icon_type = GTK_FILE_ICON_REGULAR;
1198 WIN32_FILE_ATTRIBUTE_DATA wfad;
1200 if (!GetFileAttributesEx (filename, GetFileExInfoStandard, &wfad))
1202 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
1204 GTK_FILE_SYSTEM_ERROR,
1205 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1206 _("error getting information for '%s': %s"),
1207 filename_utf8 ? filename_utf8 : "???",
1208 g_win32_error_message (GetLastError ()));
1209 g_free (filename_utf8);
1214 info = gtk_file_info_new ();
1216 if (filename_is_root (filename))
1218 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1219 gtk_file_info_set_display_name (info, filename);
1221 if (types & GTK_FILE_INFO_IS_HIDDEN)
1222 gtk_file_info_set_is_hidden (info, FALSE);
1226 gchar *basename = g_path_get_basename (filename);
1228 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1230 gchar *display_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1232 display_name = g_strescape (basename, NULL);
1234 gtk_file_info_set_display_name (info, display_name);
1236 g_free (display_name);
1239 if (types & GTK_FILE_INFO_IS_HIDDEN)
1241 /* win32 convention ... */
1242 gboolean is_hidden = basename[0] == '.';
1243 /* ... _and_ windoze attribute */
1244 is_hidden = is_hidden || !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
1245 gtk_file_info_set_is_hidden (info, is_hidden);
1251 if (types & GTK_FILE_INFO_IS_FOLDER)
1253 gtk_file_info_set_is_folder (info, !!(wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
1256 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1257 if (types & GTK_FILE_INFO_ICON)
1259 if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1260 icon_type = GTK_FILE_ICON_DIRECTORY;
1262 gtk_file_info_set_icon_type (info, icon_type);
1266 if ((types & GTK_FILE_INFO_MIME_TYPE)
1267 #if 0 /* it's dead in GtkFileSystemUnix.c, too */
1268 || ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR)
1273 const char *mime_type = xdg_mime_get_mime_type_for_file (filename);
1274 gtk_file_info_set_mime_type (info, mime_type);
1276 if ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR &&
1277 (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
1278 (strcmp (mime_type, XDG_MIME_TYPE_UNKNOWN) == 0 ||
1279 strcmp (mime_type, "application/x-executable") == 0 ||
1280 strcmp (mime_type, "application/x-shellscript") == 0))
1281 gtk_file_info_set_icon_type (info, GTK_FILE_ICON_EXECUTABLE);
1285 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1287 GtkFileTime time = wfad.ftLastWriteTime.dwLowDateTime
1288 | ((guint64)wfad.ftLastWriteTime.dwHighDateTime) << 32;
1289 /* 100-nanosecond intervals since January 1, 1601, urgh! */
1290 time /= G_GINT64_CONSTANT (10000000); /* now seconds */
1291 time -= G_GINT64_CONSTANT (134774) * 24 * 3600; /* good old Unix time */
1292 gtk_file_info_set_modification_time (info, time);
1295 if (types & GTK_FILE_INFO_SIZE)
1297 gint64 size = wfad.nFileSizeLow | ((guint64)wfad.nFileSizeHigh) << 32;
1298 gtk_file_info_set_size (info, size);
1305 filename_from_path (const GtkFilePath *path)
1307 return g_strdup (gtk_file_path_get_string (path));
1310 static GtkFilePath *
1311 filename_to_path (const char *filename)
1313 return gtk_file_path_new_dup (filename);
1317 filename_is_root (const char *filename)
1319 guint len = strlen(filename);
1321 /* accept both forms */
1323 return ( (len == 2 && filename[1] == ':')
1324 || (len == 3 && filename[1] == ':' && (filename[2] == '\\' || filename[2] == '/')));