1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright (C) 2008 Hans Breuer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Alexander Larsson <alexl@redhat.com>
20 * David Zeuthen <davidz@redhat.com>
21 * Hans Breuer <hans@breuer.org>
22 */
23
24 #include "config.h"
25
26 #include <string.h>
27 #define WIN32_MEAN_AND_LEAN
28 #include <windows.h>
29
30 #include <glib.h>
31 #include "gwin32volumemonitor.h"
32 #include "gwin32mount.h"
33 #include "gmount.h"
34 #include "gfile.h"
35 #include "gmountprivate.h"
36 #include "gvolumemonitor.h"
37 #include "gthemedicon.h"
38 #include "glibintl.h"
39
40
41 struct _GWin32Mount {
42 GObject parent;
43
44 GVolumeMonitor *volume_monitor;
45
46 GWin32Volume *volume; /* owned by volume monitor */
47 int drive_type;
48
49 /* why does all this stuff need to be duplicated? It is in volume already! */
50 char *name;
51 GIcon *icon;
52 GIcon *symbolic_icon;
53 char *mount_path;
54
55 gboolean can_eject;
56 };
57
58 static void g_win32_mount_mount_iface_init (GMountIface *iface);
59
60 #define g_win32_mount_get_type _g_win32_mount_get_type
G_DEFINE_TYPE_WITH_CODE(GWin32Mount,g_win32_mount,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,g_win32_mount_mount_iface_init))61 G_DEFINE_TYPE_WITH_CODE (GWin32Mount, g_win32_mount, G_TYPE_OBJECT,
62 G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
63 g_win32_mount_mount_iface_init))
64
65
66 static void
67 g_win32_mount_finalize (GObject *object)
68 {
69 GWin32Mount *mount;
70
71 mount = G_WIN32_MOUNT (object);
72
73 if (mount->volume_monitor != NULL)
74 g_object_unref (mount->volume_monitor);
75 #if 0
76 if (mount->volume)
77 _g_win32_volume_unset_mount (mount->volume, mount);
78 #endif
79 /* TODO: g_warn_if_fail (volume->volume == NULL); */
80
81 if (mount->icon != NULL)
82 g_object_unref (mount->icon);
83 if (mount->symbolic_icon != NULL)
84 g_object_unref (mount->symbolic_icon);
85
86 g_free (mount->name);
87 g_free (mount->mount_path);
88
89 if (G_OBJECT_CLASS (g_win32_mount_parent_class)->finalize)
90 (*G_OBJECT_CLASS (g_win32_mount_parent_class)->finalize) (object);
91 }
92
93 static void
g_win32_mount_class_init(GWin32MountClass * klass)94 g_win32_mount_class_init (GWin32MountClass *klass)
95 {
96 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
97
98 gobject_class->finalize = g_win32_mount_finalize;
99 }
100
101 static void
g_win32_mount_init(GWin32Mount * win32_mount)102 g_win32_mount_init (GWin32Mount *win32_mount)
103 {
104 }
105
106 static gchar *
_win32_get_displayname(const char * drive)107 _win32_get_displayname (const char *drive)
108 {
109 gunichar2 *wdrive = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL);
110 gchar *name = NULL;
111 SHFILEINFOW sfi;
112 if (SHGetFileInfoW(wdrive, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
113 name = g_utf16_to_utf8 (sfi.szDisplayName, -1, NULL, NULL, NULL);
114
115 g_free (wdrive);
116 return name ? name : g_strdup (drive);
117 }
118
119 /*
120 * _g_win32_mount_new:
121 * @volume_monitor: a #GVolumeMonitor.
122 * @path: a win32 path.
123 * @volume: usually NULL
124 *
125 * Returns: a #GWin32Mount for the given win32 path.
126 **/
127 GWin32Mount *
_g_win32_mount_new(GVolumeMonitor * volume_monitor,const char * path,GWin32Volume * volume)128 _g_win32_mount_new (GVolumeMonitor *volume_monitor,
129 const char *path,
130 GWin32Volume *volume)
131 {
132 GWin32Mount *mount;
133 const gchar *drive = path; //fixme
134 WCHAR *drive_utf16;
135
136 drive_utf16 = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL);
137
138 #if 0
139 /* No volume for mount: Ignore internal things */
140 if (volume == NULL && !g_win32_mount_guess_should_display (mount_entry))
141 return NULL;
142 #endif
143
144 mount = g_object_new (G_TYPE_WIN32_MOUNT, NULL);
145 mount->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL;
146 mount->mount_path = g_strdup (path);
147 mount->drive_type = GetDriveTypeW (drive_utf16);
148 mount->can_eject = FALSE; /* TODO */
149 mount->name = _win32_get_displayname (drive);
150
151 /* need to do this last */
152 mount->volume = volume;
153 #if 0
154 if (volume != NULL)
155 _g_win32_volume_set_mount (volume, mount);
156 #endif
157
158 g_free (drive_utf16);
159
160 return mount;
161 }
162
163 void
_g_win32_mount_unmounted(GWin32Mount * mount)164 _g_win32_mount_unmounted (GWin32Mount *mount)
165 {
166 if (mount->volume != NULL)
167 {
168 #if 0
169 _g_win32_volume_unset_mount (mount->volume, mount);
170 #endif
171 mount->volume = NULL;
172 g_signal_emit_by_name (mount, "changed");
173 /* there's really no need to emit mount_changed on the volume monitor
174 * as we're going to be deleted.. */
175 }
176 }
177
178 void
_g_win32_mount_unset_volume(GWin32Mount * mount,GWin32Volume * volume)179 _g_win32_mount_unset_volume (GWin32Mount *mount,
180 GWin32Volume *volume)
181 {
182 if (mount->volume == volume)
183 {
184 mount->volume = NULL;
185 /* TODO: Emit changed in idle to avoid locking issues */
186 g_signal_emit_by_name (mount, "changed");
187 if (mount->volume_monitor != NULL)
188 g_signal_emit_by_name (mount->volume_monitor, "mount-changed", mount);
189 }
190 }
191
192 static GFile *
g_win32_mount_get_root(GMount * mount)193 g_win32_mount_get_root (GMount *mount)
194 {
195 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
196
197 return g_file_new_for_path (win32_mount->mount_path);
198 }
199
200 static const char *
_win32_drive_type_to_icon(int type,gboolean use_symbolic)201 _win32_drive_type_to_icon (int type, gboolean use_symbolic)
202 {
203 switch (type)
204 {
205 case DRIVE_REMOVABLE : return use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
206 case DRIVE_FIXED : return use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
207 case DRIVE_REMOTE : return use_symbolic ? "folder-remote-symbolic" : "folder-remote";
208 case DRIVE_CDROM : return use_symbolic ? "drive-optical-symbolic" : "drive-optical";
209 default : return use_symbolic ? "folder-symbolic" : "folder";
210 }
211 }
212
213 static GIcon *
g_win32_mount_get_icon(GMount * mount)214 g_win32_mount_get_icon (GMount *mount)
215 {
216 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
217
218 g_return_val_if_fail (win32_mount->mount_path != NULL, NULL);
219
220 /* lazy creation */
221 if (!win32_mount->icon)
222 {
223 SHFILEINFOW shfi;
224 wchar_t *wfn = g_utf8_to_utf16 (win32_mount->mount_path, -1, NULL, NULL, NULL);
225
226 if (SHGetFileInfoW (wfn, 0, &shfi, sizeof (shfi), SHGFI_ICONLOCATION))
227 {
228 gchar *name = g_utf16_to_utf8 (shfi.szDisplayName, -1, NULL, NULL, NULL);
229 gchar *id = g_strdup_printf ("%s,%i", name, shfi.iIcon);
230 win32_mount->icon = g_themed_icon_new (id);
231 g_free (name);
232 g_free (id);
233 }
234 else
235 {
236 win32_mount->icon = g_themed_icon_new_with_default_fallbacks (_win32_drive_type_to_icon (win32_mount->drive_type, FALSE));
237 }
238 }
239
240 return g_object_ref (win32_mount->icon);
241 }
242
243 static GIcon *
g_win32_mount_get_symbolic_icon(GMount * mount)244 g_win32_mount_get_symbolic_icon (GMount *mount)
245 {
246 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
247
248 g_return_val_if_fail (win32_mount->mount_path != NULL, NULL);
249
250 /* lazy creation */
251 if (!win32_mount->symbolic_icon)
252 {
253 win32_mount->symbolic_icon = g_themed_icon_new_with_default_fallbacks (_win32_drive_type_to_icon (win32_mount->drive_type, TRUE));
254 }
255
256 return g_object_ref (win32_mount->symbolic_icon);
257 }
258
259 static char *
g_win32_mount_get_uuid(GMount * mount)260 g_win32_mount_get_uuid (GMount *mount)
261 {
262 return NULL;
263 }
264
265 static char *
g_win32_mount_get_name(GMount * mount)266 g_win32_mount_get_name (GMount *mount)
267 {
268 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
269
270 return g_strdup (win32_mount->name);
271 }
272
273 static GDrive *
g_win32_mount_get_drive(GMount * mount)274 g_win32_mount_get_drive (GMount *mount)
275 {
276 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
277
278 if (win32_mount->volume != NULL)
279 return g_volume_get_drive (G_VOLUME (win32_mount->volume));
280
281 return NULL;
282 }
283
284 static GVolume *
g_win32_mount_get_volume(GMount * mount)285 g_win32_mount_get_volume (GMount *mount)
286 {
287 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
288
289 if (win32_mount->volume)
290 return G_VOLUME (g_object_ref (win32_mount->volume));
291
292 return NULL;
293 }
294
295 static gboolean
g_win32_mount_can_unmount(GMount * mount)296 g_win32_mount_can_unmount (GMount *mount)
297 {
298 return FALSE;
299 }
300
301 static gboolean
g_win32_mount_can_eject(GMount * mount)302 g_win32_mount_can_eject (GMount *mount)
303 {
304 GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
305 return win32_mount->can_eject;
306 }
307
308
309 typedef struct {
310 GWin32Mount *win32_mount;
311 GAsyncReadyCallback callback;
312 gpointer user_data;
313 GCancellable *cancellable;
314 int error_fd;
315 GIOChannel *error_channel;
316 guint error_channel_source_id;
317 GString *error_string;
318 } UnmountEjectOp;
319
320 static void
g_win32_mount_unmount(GMount * mount,GMountUnmountFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)321 g_win32_mount_unmount (GMount *mount,
322 GMountUnmountFlags flags,
323 GCancellable *cancellable,
324 GAsyncReadyCallback callback,
325 gpointer user_data)
326 {
327 }
328
329 static gboolean
g_win32_mount_unmount_finish(GMount * mount,GAsyncResult * result,GError ** error)330 g_win32_mount_unmount_finish (GMount *mount,
331 GAsyncResult *result,
332 GError **error)
333 {
334 return FALSE;
335 }
336
337 static void
g_win32_mount_eject(GMount * mount,GMountUnmountFlags flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)338 g_win32_mount_eject (GMount *mount,
339 GMountUnmountFlags flags,
340 GCancellable *cancellable,
341 GAsyncReadyCallback callback,
342 gpointer user_data)
343 {
344 }
345
346 static gboolean
g_win32_mount_eject_finish(GMount * mount,GAsyncResult * result,GError ** error)347 g_win32_mount_eject_finish (GMount *mount,
348 GAsyncResult *result,
349 GError **error)
350 {
351 return FALSE;
352 }
353
354 static void
g_win32_mount_mount_iface_init(GMountIface * iface)355 g_win32_mount_mount_iface_init (GMountIface *iface)
356 {
357 iface->get_root = g_win32_mount_get_root;
358 iface->get_name = g_win32_mount_get_name;
359 iface->get_icon = g_win32_mount_get_icon;
360 iface->get_symbolic_icon = g_win32_mount_get_symbolic_icon;
361 iface->get_uuid = g_win32_mount_get_uuid;
362 iface->get_drive = g_win32_mount_get_drive;
363 iface->get_volume = g_win32_mount_get_volume;
364 iface->can_unmount = g_win32_mount_can_unmount;
365 iface->can_eject = g_win32_mount_can_eject;
366 iface->unmount = g_win32_mount_unmount;
367 iface->unmount_finish = g_win32_mount_unmount_finish;
368 iface->eject = g_win32_mount_eject;
369 iface->eject_finish = g_win32_mount_eject_finish;
370 }
371