3b9f616ae1b22753887cbfe3ac900b738eb6900a
[platform/upstream/glib.git] / gio / gwin32mount.c
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 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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Author: Alexander Larsson <alexl@redhat.com>
22  *         David Zeuthen <davidz@redhat.com>
23  *         Hans Breuer <hans@breuer.org>
24  */
25
26 #include "config.h"
27
28 #include <string.h>
29 #define WIN32_MEAN_AND_LEAN
30 #include <windows.h>
31
32 #include <glib.h>
33 #include "gwin32volumemonitor.h"
34 #include "gwin32mount.h"
35 #include "gmount.h"
36 #include "gfile.h"
37 #include "gmountprivate.h"
38 #include "gvolumemonitor.h"
39 #include "gthemedicon.h"
40 #include "gsimpleasyncresult.h"
41 #include "glibintl.h"
42
43
44 struct _GWin32Mount {
45   GObject parent;
46
47   GVolumeMonitor   *volume_monitor;
48
49   GWin32Volume      *volume; /* owned by volume monitor */
50   int   drive_type;
51
52   /* why does all this stuff need to be duplicated? It is in volume already! */
53   char *name;
54   GIcon *icon;
55   GIcon *symbolic_icon;
56   char *mount_path;
57
58   gboolean can_eject;
59 };
60
61 static void g_win32_mount_mount_iface_init (GMountIface *iface);
62
63 #define g_win32_mount_get_type _g_win32_mount_get_type
64 G_DEFINE_TYPE_WITH_CODE (GWin32Mount, g_win32_mount, G_TYPE_OBJECT,
65                          G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
66                                                 g_win32_mount_mount_iface_init))
67
68
69 static void
70 g_win32_mount_finalize (GObject *object)
71 {
72   GWin32Mount *mount;
73   
74   mount = G_WIN32_MOUNT (object);
75
76   if (mount->volume_monitor != NULL)
77     g_object_unref (mount->volume_monitor);
78 #if 0
79   if (mount->volume)
80     _g_win32_volume_unset_mount (mount->volume, mount);
81 #endif
82   /* TODO: g_warn_if_fail (volume->volume == NULL); */
83
84   if (mount->icon != NULL)
85     g_object_unref (mount->icon);
86   if (mount->symbolic_icon != NULL)
87     g_object_unref (mount->symbolic_icon);
88
89   g_free (mount->name);
90   g_free (mount->mount_path);
91   
92   if (G_OBJECT_CLASS (g_win32_mount_parent_class)->finalize)
93     (*G_OBJECT_CLASS (g_win32_mount_parent_class)->finalize) (object);
94 }
95
96 static void
97 g_win32_mount_class_init (GWin32MountClass *klass)
98 {
99   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
100
101   gobject_class->finalize = g_win32_mount_finalize;
102 }
103
104 static void
105 g_win32_mount_init (GWin32Mount *win32_mount)
106 {
107 }
108
109 gchar *
110 _win32_get_displayname (const char *drive)
111 {
112   gunichar2 *wdrive = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL);
113   gchar *name = NULL;
114   SHFILEINFOW sfi;
115   if (SHGetFileInfoW(wdrive, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
116     name = g_utf16_to_utf8 (sfi.szDisplayName, -1, NULL, NULL, NULL);
117
118   g_free (wdrive);
119   return name ? name : g_strdup (drive);
120 }
121
122 /*
123  * _g_win32_mount_new:
124  * @volume_monitor: a #GVolumeMonitor.
125  * @path: a win32 path.
126  * @volume: usually NULL
127  * 
128  * Returns: a #GWin32Mount for the given win32 path.
129  **/
130 GWin32Mount *
131 _g_win32_mount_new (GVolumeMonitor  *volume_monitor,
132                     const char      *path,
133                     GWin32Volume    *volume)
134 {
135   GWin32Mount *mount;
136   const gchar *drive = path; //fixme
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 = GetDriveType (drive);
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   return mount;
158 }
159
160 void
161 _g_win32_mount_unmounted (GWin32Mount *mount)
162 {
163   if (mount->volume != NULL)
164     {
165 #if 0
166       _g_win32_volume_unset_mount (mount->volume, mount);
167 #endif
168       mount->volume = NULL;
169       g_signal_emit_by_name (mount, "changed");
170       /* there's really no need to emit mount_changed on the volume monitor 
171        * as we're going to be deleted.. */
172     }
173 }
174
175 void
176 _g_win32_mount_unset_volume (GWin32Mount  *mount,
177                              GWin32Volume *volume)
178 {
179   if (mount->volume == volume)
180     {
181       mount->volume = NULL;
182       /* TODO: Emit changed in idle to avoid locking issues */
183       g_signal_emit_by_name (mount, "changed");
184       if (mount->volume_monitor != NULL)
185         g_signal_emit_by_name (mount->volume_monitor, "mount-changed", mount);
186     }
187 }
188
189 static GFile *
190 g_win32_mount_get_root (GMount *mount)
191 {
192   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
193
194   return g_file_new_for_path (win32_mount->mount_path);
195 }
196
197 const char *
198 _win32_drive_type_to_icon (int type, gboolean use_symbolic)
199 {
200   switch (type)
201   {
202   case DRIVE_REMOVABLE : return use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
203   case DRIVE_FIXED : return use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
204   case DRIVE_REMOTE : return use_symbolic ? "folder-remote-symbolic" : "folder-remote";
205   case DRIVE_CDROM : return use_symbolic ? "drive-optical-symbolic" : "drive-optical";
206   default : return use_symbolic ? "folder-symbolic" : "folder";
207   }
208 }
209
210 static GIcon *
211 g_win32_mount_get_icon (GMount *mount)
212 {
213   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
214
215   g_return_val_if_fail (win32_mount->mount_path != NULL, NULL);
216
217   /* lazy creation */
218   if (!win32_mount->icon)
219     {
220       SHFILEINFOW shfi;
221       wchar_t *wfn = g_utf8_to_utf16 (win32_mount->mount_path, -1, NULL, NULL, NULL);
222
223       if (SHGetFileInfoW (wfn, 0, &shfi, sizeof (shfi), SHGFI_ICONLOCATION))
224         {
225           gchar *name = g_utf16_to_utf8 (shfi.szDisplayName, -1, NULL, NULL, NULL);
226           gchar *id = g_strdup_printf ("%s,%i", name, shfi.iIcon);
227           win32_mount->icon = g_themed_icon_new (id);
228           g_free (name);
229           g_free (id);
230         }
231       else
232         {
233           win32_mount->icon = g_themed_icon_new_with_default_fallbacks (_win32_drive_type_to_icon (win32_mount->drive_type, FALSE);
234         }
235     }
236
237   return g_object_ref (win32_mount->icon);
238 }
239
240 static GIcon *
241 g_win32_mount_get_symbolic_icon (GMount *mount)
242 {
243   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
244
245   g_return_val_if_fail (win32_mount->mount_path != NULL, NULL);
246
247   /* lazy creation */
248   if (!win32_mount->symbolic_icon)
249     {
250       win32_mount->symbolic_icon = g_themed_icon_new_with_default_fallbacks (_win32_drive_type_to_icon (win32_mount->drive_type, TRUE);
251     }
252
253   return g_object_ref (win32_mount->symbolic_icon);
254 }
255
256 static char *
257 g_win32_mount_get_uuid (GMount *mount)
258 {
259   return NULL;
260 }
261
262 static char *
263 g_win32_mount_get_name (GMount *mount)
264 {
265   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
266   
267   return g_strdup (win32_mount->name);
268 }
269
270 static GDrive *
271 g_win32_mount_get_drive (GMount *mount)
272 {
273   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
274
275   if (win32_mount->volume != NULL)
276     return g_volume_get_drive (G_VOLUME (win32_mount->volume));
277
278   return NULL;
279 }
280
281 static GVolume *
282 g_win32_mount_get_volume (GMount *mount)
283 {
284   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
285
286   if (win32_mount->volume)
287     return G_VOLUME (g_object_ref (win32_mount->volume));
288   
289   return NULL;
290 }
291
292 static gboolean
293 g_win32_mount_can_unmount (GMount *mount)
294 {
295   return FALSE;
296 }
297
298 static gboolean
299 g_win32_mount_can_eject (GMount *mount)
300 {
301   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount);
302   return win32_mount->can_eject;
303 }
304
305
306 typedef struct {
307   GWin32Mount *win32_mount;
308   GAsyncReadyCallback callback;
309   gpointer user_data;
310   GCancellable *cancellable;
311   int error_fd;
312   GIOChannel *error_channel;
313   guint error_channel_source_id;
314   GString *error_string;
315 } UnmountEjectOp;
316
317 static void
318 g_win32_mount_unmount (GMount              *mount,
319                        GMountUnmountFlags   flags,
320                        GCancellable        *cancellable,
321                        GAsyncReadyCallback  callback,
322                        gpointer             user_data)
323 {
324 }
325
326 static gboolean
327 g_win32_mount_unmount_finish (GMount        *mount,
328                               GAsyncResult  *result,
329                               GError       **error)
330 {
331   return FALSE;
332 }
333
334 static void
335 g_win32_mount_eject (GMount              *mount,
336                      GMountUnmountFlags   flags,
337                      GCancellable        *cancellable,
338                      GAsyncReadyCallback  callback,
339                      gpointer             user_data)
340 {
341 }
342
343 static gboolean
344 g_win32_mount_eject_finish (GMount        *mount,
345                             GAsyncResult  *result,
346                             GError       **error)
347 {
348   return FALSE;
349 }
350
351 static void
352 g_win32_mount_mount_iface_init (GMountIface *iface)
353 {
354   iface->get_root = g_win32_mount_get_root;
355   iface->get_name = g_win32_mount_get_name;
356   iface->get_icon = g_win32_mount_get_icon;
357   iface->get_symbolic_icon = g_win32_mount_get_symbolic_icon;
358   iface->get_uuid = g_win32_mount_get_uuid;
359   iface->get_drive = g_win32_mount_get_drive;
360   iface->get_volume = g_win32_mount_get_volume;
361   iface->can_unmount = g_win32_mount_can_unmount;
362   iface->can_eject = g_win32_mount_can_eject;
363   iface->unmount = g_win32_mount_unmount;
364   iface->unmount_finish = g_win32_mount_unmount_finish;
365   iface->eject = g_win32_mount_eject;
366   iface->eject_finish = g_win32_mount_eject_finish;
367 }