| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | /* GIO - GLib Input, Output and Streaming Library
 | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  * Copyright (C) 2006-2007 Red Hat, Inc. | 
					
						
							|  |  |  |  * Copyright (C) 2008 Hans Breuer | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2022-05-18 09:12:45 +01:00
										 |  |  |  * SPDX-License-Identifier: LGPL-2.1-or-later | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2017-05-27 18:21:30 +02:00
										 |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Lesser General | 
					
						
							| 
									
										
										
										
											2014-01-23 12:58:29 +01:00
										 |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Author: Alexander Larsson <alexl@redhat.com> | 
					
						
							|  |  |  |  *         David Zeuthen <davidz@redhat.com> | 
					
						
							|  |  |  |  *         Hans Breuer <hans@breuer.org> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-22 15:10:51 +00:00
										 |  |  | #include "config.h"
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #define WIN32_MEAN_AND_LEAN
 | 
					
						
							| 
									
										
										
										
											2021-03-30 19:39:20 +00:00
										 |  |  | #define COBJMACROS
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | #include <windows.h>
 | 
					
						
							| 
									
										
										
										
											2021-03-30 19:39:20 +00:00
										 |  |  | #include <shlobj.h>
 | 
					
						
							|  |  |  | #include <shlwapi.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* At the moment of writing IExtractIconW interface in Mingw-w64
 | 
					
						
							|  |  |  |  * is missing IUnknown members in its vtable. Use our own | 
					
						
							|  |  |  |  * fixed declaration for now. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #undef INTERFACE
 | 
					
						
							|  |  |  | #define INTERFACE IMyExtractIconW
 | 
					
						
							|  |  |  | DECLARE_INTERFACE_(IMyExtractIconW,IUnknown) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*** IUnknown methods ***/ | 
					
						
							|  |  |  |     STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; | 
					
						
							|  |  |  |     STDMETHOD_(ULONG,AddRef)(THIS) PURE; | 
					
						
							|  |  |  |     STDMETHOD_(ULONG,Release)(THIS) PURE; | 
					
						
							|  |  |  |     /*** IMyExtractIconW methods ***/ | 
					
						
							|  |  |  |     STDMETHOD(GetIconLocation)(THIS_ UINT uFlags, LPWSTR pszIconFile, UINT cchMax, int *piIndex, PUINT pwFlags) PURE; | 
					
						
							|  |  |  |     STDMETHOD(Extract)(THIS_ LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) PURE; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | #undef INTERFACE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined(__cplusplus) || defined(CINTERFACE)
 | 
					
						
							|  |  |  | /*** IUnknown methods ***/ | 
					
						
							|  |  |  | #define IMyExtractIconW_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
 | 
					
						
							|  |  |  | #define IMyExtractIconW_AddRef(p)             (p)->lpVtbl->AddRef(p)
 | 
					
						
							|  |  |  | #define IMyExtractIconW_Release(p)            (p)->lpVtbl->Release(p)
 | 
					
						
							|  |  |  | /*** IMyExtractIconW methods ***/ | 
					
						
							|  |  |  | #define IMyExtractIconW_GetIconLocation(p,a,b,c,d,e) (p)->lpVtbl->GetIconLocation(p,a,b,c,d,e)
 | 
					
						
							|  |  |  | #define IMyExtractIconW_Extract(p,a,b,c,d,e)         (p)->lpVtbl->Extract(p,a,b,c,d,e)
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | /*** IUnknown methods ***/ | 
					
						
							|  |  |  | #define IMyExtractIconW_QueryInterface(p,a,b) (p)->QueryInterface(a,b)
 | 
					
						
							|  |  |  | #define IMyExtractIconW_AddRef(p)             (p)->AddRef()
 | 
					
						
							|  |  |  | #define IMyExtractIconW_Release(p)            (p)->Release()
 | 
					
						
							|  |  |  | /*** IMyExtractIconW methods ***/ | 
					
						
							|  |  |  | #define IMyExtractIconW_GetIconLocation(p,a,b,c,d,e) (p)->GetIconLocation(p,a,b,c,d,e)
 | 
					
						
							|  |  |  | #define IMyExtractIconW_Extract(p,a,b,c,d,e)         (p)->Extract(p,a,b,c,d,e)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <glib.h>
 | 
					
						
							|  |  |  | #include "gwin32volumemonitor.h"
 | 
					
						
							|  |  |  | #include "gwin32mount.h"
 | 
					
						
							| 
									
										
										
										
											2008-07-02 01:52:37 +00:00
										 |  |  | #include "gmount.h"
 | 
					
						
							|  |  |  | #include "gfile.h"
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | #include "gmountprivate.h"
 | 
					
						
							|  |  |  | #include "gvolumemonitor.h"
 | 
					
						
							|  |  |  | #include "gthemedicon.h"
 | 
					
						
							|  |  |  | #include "glibintl.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct _GWin32Mount { | 
					
						
							|  |  |  |   GObject parent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GVolumeMonitor   *volume_monitor; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GWin32Volume      *volume; /* owned by volume monitor */ | 
					
						
							|  |  |  |   int   drive_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* why does all this stuff need to be duplicated? It is in volume already! */ | 
					
						
							|  |  |  |   char *name; | 
					
						
							|  |  |  |   GIcon *icon; | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  |   GIcon *symbolic_icon; | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |   char *mount_path; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   gboolean can_eject; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void g_win32_mount_mount_iface_init (GMountIface *iface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #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)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_win32_mount_finalize (GObject *object) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *mount; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   mount = G_WIN32_MOUNT (object); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (mount->volume_monitor != NULL) | 
					
						
							|  |  |  |     g_object_unref (mount->volume_monitor); | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  |   if (mount->volume) | 
					
						
							|  |  |  |     _g_win32_volume_unset_mount (mount->volume, mount); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |   /* TODO: g_warn_if_fail (volume->volume == NULL); */ | 
					
						
							| 
									
										
										
										
											2008-09-04 20:41:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (mount->icon != NULL) | 
					
						
							|  |  |  |     g_object_unref (mount->icon); | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  |   if (mount->symbolic_icon != NULL) | 
					
						
							|  |  |  |     g_object_unref (mount->symbolic_icon); | 
					
						
							| 
									
										
										
										
											2008-09-04 20:41:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |   g_free (mount->name); | 
					
						
							|  |  |  |   g_free (mount->mount_path); | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if (G_OBJECT_CLASS (g_win32_mount_parent_class)->finalize) | 
					
						
							|  |  |  |     (*G_OBJECT_CLASS (g_win32_mount_parent_class)->finalize) (object); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_win32_mount_class_init (GWin32MountClass *klass) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   gobject_class->finalize = g_win32_mount_finalize; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_win32_mount_init (GWin32Mount *win32_mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-30 20:27:25 +00:00
										 |  |  | /* wdrive doesn't need to end with a path separator.
 | 
					
						
							|  |  |  |    wdrive must use backslashes as path separators, not slashes. | 
					
						
							|  |  |  |    IShellFolder::ParseDisplayName() takes non-const string as input, | 
					
						
							|  |  |  |    so wdrive can't be a const string. | 
					
						
							|  |  |  |    Returns the name on success (free with g_free), | 
					
						
							|  |  |  |    NULL otherwise. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static gchar * | 
					
						
							|  |  |  | get_mount_display_name (gunichar2 *wdrive) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   IShellFolder *desktop; | 
					
						
							|  |  |  |   PIDLIST_RELATIVE volume; | 
					
						
							|  |  |  |   STRRET volume_name; | 
					
						
							|  |  |  |   gchar *result = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Get the desktop folder object reference */ | 
					
						
							|  |  |  |   if (!SUCCEEDED (SHGetDesktopFolder (&desktop))) | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (SUCCEEDED (IShellFolder_ParseDisplayName (desktop, NULL, NULL, wdrive, NULL, &volume, NULL))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       volume_name.uType = STRRET_WSTR; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (SUCCEEDED (IShellFolder_GetDisplayNameOf (desktop, volume, SHGDN_FORADDRESSBAR, &volume_name))) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           wchar_t *volume_name_wchar; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (SUCCEEDED (StrRetToStrW (&volume_name, volume, &volume_name_wchar))) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               result = g_utf16_to_utf8 (volume_name_wchar, -1, NULL, NULL, NULL); | 
					
						
							|  |  |  |               CoTaskMemFree (volume_name_wchar); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       CoTaskMemFree (volume); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   IShellFolder_Release (desktop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-10 10:58:19 -05:00
										 |  |  | static gchar * | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | _win32_get_displayname (const char *drive) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   gunichar2 *wdrive = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2021-03-30 20:27:25 +00:00
										 |  |  |   gchar *name = get_mount_display_name (wdrive); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   g_free (wdrive); | 
					
						
							|  |  |  |   return name ? name : g_strdup (drive); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 16:20:43 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |  * _g_win32_mount_new: | 
					
						
							|  |  |  |  * @volume_monitor: a #GVolumeMonitor. | 
					
						
							|  |  |  |  * @path: a win32 path. | 
					
						
							| 
									
										
										
										
											2011-08-29 14:49:32 -04:00
										 |  |  |  * @volume: usually NULL | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |  *  | 
					
						
							|  |  |  |  * Returns: a #GWin32Mount for the given win32 path. | 
					
						
							|  |  |  |  **/ | 
					
						
							|  |  |  | GWin32Mount * | 
					
						
							|  |  |  | _g_win32_mount_new (GVolumeMonitor  *volume_monitor, | 
					
						
							| 
									
										
										
										
											2008-08-08 06:38:05 +00:00
										 |  |  |                     const char      *path, | 
					
						
							|  |  |  |                     GWin32Volume    *volume) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *mount; | 
					
						
							|  |  |  |   const gchar *drive = path; //fixme
 | 
					
						
							| 
									
										
										
										
											2018-08-15 22:25:08 +02:00
										 |  |  |   WCHAR *drive_utf16; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   drive_utf16 = g_utf8_to_utf16 (drive, -1, NULL, NULL, NULL); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if 0  
 | 
					
						
							|  |  |  |   /* No volume for mount: Ignore internal things */ | 
					
						
							|  |  |  |   if (volume == NULL && !g_win32_mount_guess_should_display (mount_entry)) | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   mount = g_object_new (G_TYPE_WIN32_MOUNT, NULL); | 
					
						
							|  |  |  |   mount->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL; | 
					
						
							|  |  |  |   mount->mount_path = g_strdup (path); | 
					
						
							| 
									
										
										
										
											2018-08-15 22:25:08 +02:00
										 |  |  |   mount->drive_type = GetDriveTypeW (drive_utf16); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |   mount->can_eject = FALSE; /* TODO */ | 
					
						
							|  |  |  |   mount->name = _win32_get_displayname (drive); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* need to do this last */ | 
					
						
							|  |  |  |   mount->volume = volume; | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  |   if (volume != NULL) | 
					
						
							|  |  |  |     _g_win32_volume_set_mount (volume, mount); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-08-15 22:25:08 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   g_free (drive_utf16); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |   return mount; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _g_win32_mount_unmounted (GWin32Mount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (mount->volume != NULL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  |       _g_win32_volume_unset_mount (mount->volume, mount); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |       mount->volume = NULL; | 
					
						
							|  |  |  |       g_signal_emit_by_name (mount, "changed"); | 
					
						
							|  |  |  |       /* there's really no need to emit mount_changed on the volume monitor 
 | 
					
						
							|  |  |  |        * as we're going to be deleted.. */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							| 
									
										
										
										
											2008-08-08 06:38:05 +00:00
										 |  |  | _g_win32_mount_unset_volume (GWin32Mount  *mount, | 
					
						
							|  |  |  | 			     GWin32Volume *volume) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   if (mount->volume == volume) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       mount->volume = NULL; | 
					
						
							|  |  |  |       /* TODO: Emit changed in idle to avoid locking issues */ | 
					
						
							|  |  |  |       g_signal_emit_by_name (mount, "changed"); | 
					
						
							|  |  |  |       if (mount->volume_monitor != NULL) | 
					
						
							| 
									
										
										
										
											2008-08-11 19:45:08 +00:00
										 |  |  |         g_signal_emit_by_name (mount->volume_monitor, "mount-changed", mount); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GFile * | 
					
						
							|  |  |  | g_win32_mount_get_root (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return g_file_new_for_path (win32_mount->mount_path); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-10 10:58:19 -05:00
										 |  |  | static const char * | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  | _win32_drive_type_to_icon (int type, gboolean use_symbolic) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   switch (type) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  |   case DRIVE_REMOVABLE : return use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media"; | 
					
						
							|  |  |  |   case DRIVE_FIXED : return use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk"; | 
					
						
							|  |  |  |   case DRIVE_REMOTE : return use_symbolic ? "folder-remote-symbolic" : "folder-remote"; | 
					
						
							|  |  |  |   case DRIVE_CDROM : return use_symbolic ? "drive-optical-symbolic" : "drive-optical"; | 
					
						
							|  |  |  |   default : return use_symbolic ? "folder-symbolic" : "folder"; | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-30 19:39:20 +00:00
										 |  |  | /* mount_path doesn't need to end with a path separator.
 | 
					
						
							|  |  |  |    mount_path must use backslashes as path separators, not slashes. | 
					
						
							|  |  |  |    IShellFolder::ParseDisplayName() takes non-const string as input, | 
					
						
							|  |  |  |    so mount_path can't be a const string. | 
					
						
							|  |  |  |    result_name and result_index must not be NULL. | 
					
						
							|  |  |  |    Returns TRUE when result_name is set (free with g_free), | 
					
						
							|  |  |  |    FALSE otherwise. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | get_icon_name_index (wchar_t  *mount_path, | 
					
						
							|  |  |  |                      wchar_t **result_name, | 
					
						
							|  |  |  |                      int      *result_index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   IShellFolder *desktop; | 
					
						
							|  |  |  |   PIDLIST_RELATIVE volume; | 
					
						
							|  |  |  |   IShellFolder *volume_parent; | 
					
						
							|  |  |  |   PCUITEMID_CHILD volume_relative; | 
					
						
							|  |  |  |   IMyExtractIconW *eicon; | 
					
						
							|  |  |  |   int icon_index; | 
					
						
							|  |  |  |   UINT icon_flags; | 
					
						
							|  |  |  |   wchar_t *name_buffer; | 
					
						
							|  |  |  |   gsize name_buffer_size; | 
					
						
							|  |  |  |   gsize arbitrary_reasonable_limit = 5000; | 
					
						
							|  |  |  |   gboolean result = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *result_name = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Get the desktop folder object reference */ | 
					
						
							|  |  |  |   if (!SUCCEEDED (SHGetDesktopFolder (&desktop))) | 
					
						
							|  |  |  |     return FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Construct the volume IDList relative to desktop */ | 
					
						
							|  |  |  |   if (SUCCEEDED (IShellFolder_ParseDisplayName (desktop, NULL, NULL, mount_path, NULL, &volume, NULL))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* Get the parent of the volume (transfer-full) and the IDList relative to parent (transfer-none) */ | 
					
						
							|  |  |  |       if (SUCCEEDED (SHBindToParent (volume, &IID_IShellFolder, (void **) &volume_parent, &volume_relative))) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           /* Get a reference to IExtractIcon object for the volume */ | 
					
						
							|  |  |  |           if (SUCCEEDED (IShellFolder_GetUIObjectOf (volume_parent, NULL, 1, (LPCITEMIDLIST *) &volume_relative, &IID_IExtractIconW, NULL, (void **) &eicon))) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |               gboolean keep_going = TRUE; | 
					
						
							|  |  |  |               name_buffer = NULL; | 
					
						
							|  |  |  |               name_buffer_size = MAX_PATH / 2; | 
					
						
							|  |  |  |               while (keep_going) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                   name_buffer_size *= 2; | 
					
						
							|  |  |  |                   name_buffer = g_renew (wchar_t, name_buffer, name_buffer_size); | 
					
						
							|  |  |  |                   name_buffer[name_buffer_size - 1] = 0x1; /* sentinel */ | 
					
						
							|  |  |  |                   keep_going = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                   /* Try to get the icon location */ | 
					
						
							|  |  |  |                   if (SUCCEEDED (IMyExtractIconW_GetIconLocation (eicon, GIL_FORSHELL, name_buffer, name_buffer_size, &icon_index, &icon_flags))) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                       if (name_buffer[name_buffer_size - 1] != 0x1) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                           if (name_buffer_size < arbitrary_reasonable_limit) | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                               /* Buffer was too small, keep going */ | 
					
						
							|  |  |  |                               keep_going = TRUE; | 
					
						
							|  |  |  |                               continue; | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                           /* Else stop trying */ | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                       /* name_buffer might not contain a name */ | 
					
						
							|  |  |  |                       else if ((icon_flags & GIL_NOTFILENAME) != GIL_NOTFILENAME) | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                           *result_name = g_steal_pointer (&name_buffer); | 
					
						
							|  |  |  |                           *result_index = icon_index; | 
					
						
							|  |  |  |                           result = TRUE; | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               g_free (name_buffer); | 
					
						
							|  |  |  |               IMyExtractIconW_Release (eicon); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           IShellFolder_Release (volume_parent); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       CoTaskMemFree (volume); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   IShellFolder_Release (desktop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | static GIcon * | 
					
						
							|  |  |  | g_win32_mount_get_icon (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (win32_mount->mount_path != NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* lazy creation */ | 
					
						
							|  |  |  |   if (!win32_mount->icon) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-03-30 19:39:20 +00:00
										 |  |  |       wchar_t *icon_path; | 
					
						
							|  |  |  |       int icon_index; | 
					
						
							|  |  |  |       wchar_t *p; | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |       wchar_t *wfn = g_utf8_to_utf16 (win32_mount->mount_path, -1, NULL, NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-30 19:39:20 +00:00
										 |  |  |       for (p = wfn; p != NULL && *p != 0; p++) | 
					
						
							|  |  |  |         if (*p == L'/') | 
					
						
							|  |  |  |           *p = L'\\'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (get_icon_name_index (wfn, &icon_path, &icon_index)) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-03-30 19:39:20 +00:00
										 |  |  | 	  gchar *id = g_strdup_printf ("%S,%i", icon_path, icon_index); | 
					
						
							|  |  |  | 	  g_free (icon_path); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | 	  win32_mount->icon = g_themed_icon_new (id); | 
					
						
							|  |  |  | 	  g_free (id); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2012-09-09 10:49:06 -04:00
										 |  |  |           win32_mount->icon = g_themed_icon_new_with_default_fallbacks (_win32_drive_type_to_icon (win32_mount->drive_type, FALSE)); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-01-23 11:50:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       g_free (wfn); | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return g_object_ref (win32_mount->icon); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  | static GIcon * | 
					
						
							|  |  |  | g_win32_mount_get_symbolic_icon (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   g_return_val_if_fail (win32_mount->mount_path != NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* lazy creation */ | 
					
						
							|  |  |  |   if (!win32_mount->symbolic_icon) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2012-09-09 10:49:06 -04:00
										 |  |  |       win32_mount->symbolic_icon = g_themed_icon_new_with_default_fallbacks (_win32_drive_type_to_icon (win32_mount->drive_type, TRUE)); | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return g_object_ref (win32_mount->symbolic_icon); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | static char * | 
					
						
							|  |  |  | g_win32_mount_get_uuid (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char * | 
					
						
							|  |  |  | g_win32_mount_get_name (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   return g_strdup (win32_mount->name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GDrive * | 
					
						
							|  |  |  | g_win32_mount_get_drive (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (win32_mount->volume != NULL) | 
					
						
							|  |  |  |     return g_volume_get_drive (G_VOLUME (win32_mount->volume)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static GVolume * | 
					
						
							|  |  |  | g_win32_mount_get_volume (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (win32_mount->volume) | 
					
						
							|  |  |  |     return G_VOLUME (g_object_ref (win32_mount->volume)); | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | g_win32_mount_can_unmount (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | g_win32_mount_can_eject (GMount *mount) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount = G_WIN32_MOUNT (mount); | 
					
						
							|  |  |  |   return win32_mount->can_eject; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct { | 
					
						
							|  |  |  |   GWin32Mount *win32_mount; | 
					
						
							|  |  |  |   GAsyncReadyCallback callback; | 
					
						
							|  |  |  |   gpointer user_data; | 
					
						
							|  |  |  |   GCancellable *cancellable; | 
					
						
							|  |  |  |   int error_fd; | 
					
						
							|  |  |  |   GIOChannel *error_channel; | 
					
						
							|  |  |  |   guint error_channel_source_id; | 
					
						
							|  |  |  |   GString *error_string; | 
					
						
							|  |  |  | } UnmountEjectOp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2008-08-08 06:38:05 +00:00
										 |  |  | g_win32_mount_unmount (GMount              *mount, | 
					
						
							|  |  |  | 		       GMountUnmountFlags   flags, | 
					
						
							|  |  |  | 		       GCancellable        *cancellable, | 
					
						
							|  |  |  | 		       GAsyncReadyCallback  callback, | 
					
						
							|  |  |  | 		       gpointer             user_data) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							| 
									
										
										
										
											2008-08-08 06:38:05 +00:00
										 |  |  | g_win32_mount_unmount_finish (GMount        *mount, | 
					
						
							|  |  |  | 			      GAsyncResult  *result, | 
					
						
							|  |  |  | 			      GError       **error) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2008-08-08 06:38:05 +00:00
										 |  |  | g_win32_mount_eject (GMount              *mount, | 
					
						
							|  |  |  | 		     GMountUnmountFlags   flags, | 
					
						
							|  |  |  | 		     GCancellable        *cancellable, | 
					
						
							|  |  |  | 		     GAsyncReadyCallback  callback, | 
					
						
							|  |  |  | 		     gpointer             user_data) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							| 
									
										
										
										
											2008-08-08 06:38:05 +00:00
										 |  |  | g_win32_mount_eject_finish (GMount        *mount, | 
					
						
							|  |  |  | 			    GAsyncResult  *result, | 
					
						
							|  |  |  | 			    GError       **error) | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  | { | 
					
						
							|  |  |  |   return FALSE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | g_win32_mount_mount_iface_init (GMountIface *iface) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   iface->get_root = g_win32_mount_get_root; | 
					
						
							|  |  |  |   iface->get_name = g_win32_mount_get_name; | 
					
						
							|  |  |  |   iface->get_icon = g_win32_mount_get_icon; | 
					
						
							| 
									
										
										
										
											2012-08-28 15:37:43 -04:00
										 |  |  |   iface->get_symbolic_icon = g_win32_mount_get_symbolic_icon; | 
					
						
							| 
									
										
										
										
											2008-06-17 21:40:04 +00:00
										 |  |  |   iface->get_uuid = g_win32_mount_get_uuid; | 
					
						
							|  |  |  |   iface->get_drive = g_win32_mount_get_drive; | 
					
						
							|  |  |  |   iface->get_volume = g_win32_mount_get_volume; | 
					
						
							|  |  |  |   iface->can_unmount = g_win32_mount_can_unmount; | 
					
						
							|  |  |  |   iface->can_eject = g_win32_mount_can_eject; | 
					
						
							|  |  |  |   iface->unmount = g_win32_mount_unmount; | 
					
						
							|  |  |  |   iface->unmount_finish = g_win32_mount_unmount_finish; | 
					
						
							|  |  |  |   iface->eject = g_win32_mount_eject; | 
					
						
							|  |  |  |   iface->eject_finish = g_win32_mount_eject_finish; | 
					
						
							|  |  |  | } |