简体   繁体   English

是否可以以编程方式更改Mac OS X上已安装驱动器上的音量图标?

[英]Is it possible to programmatically change the volume icon on a mounted drive on Mac OS X?

I want to programmatically change the volume icon for a stacked file system implemented using OSXFUSE (formerly MacFUSE). 我想以编程方式更改使用OSXFUSE (以前称为MacFUSE)实现的堆叠文件系统的卷图标。 The icon needs to reflect the state of a mounted file system. 该图标需要反映已安装文件系统的状态。

The approach that I have been trying to get working is to map requests for /.VolumeIcon.icns to the appropriate icon in the application bundle. 我一直在尝试的方法是将/.VolumeIcon.icns的请求映射到应用程序包中的相应图标。 Then sending change notifications to the file system for the actual path (path) and the mount path (mountPath). 然后将更改通知发送到文件系统,以获取实际路径(路径)和装载路径(mountPath)。

    [[NSWorkspace sharedWorkspace] noteFileSystemChanged: @"/Volumes"]; 
    [[NSWorkspace sharedWorkspace] noteFileSystemChanged: [mountPath stringByDeletingLastPathComponent]];
    [[NSWorkspace sharedWorkspace] noteFileSystemChanged: mountPath];
    [[NSWorkspace sharedWorkspace] noteFileSystemChanged: [path stringByDeletingLastPathComponent]];
    [[NSWorkspace sharedWorkspace] noteFileSystemChanged: path];

    FNNotifyByPath([[[mountPath stringByDeletingLastPathComponent] dataUsingEncoding:NSUTF8StringEncoding] bytes], kFNDirectoryModifiedMessage, kNilOptions);
    FNNotifyByPath([[[path stringByDeletingLastPathComponent] dataUsingEncoding:NSUTF8StringEncoding] bytes], kFNDirectoryModifiedMessage, kNilOptions);
    FNNotifyByPath([[@"/Volumes" dataUsingEncoding:NSUTF8StringEncoding] bytes], kFNDirectoryModifiedMessage, kNilOptions);

Stepping through the debugger I can see this code being hit but the code to map the /.VolumeIcon.icns gets called infrequently and never in response to these notifications. 单步执行调试器,我可以看到此代码被命中,但映射/.VolumeIcon.icns的代码很少被调用,并且从不响应这些通知。

I think the short answer is, you're out of luck. 我认为简短的回答是,你运气不好。 The long answer is while the OSXFUSE project is different than the Fuse4X project, they're both derived from the same source, and Fuse4X has this to say about volume icons in their FAQ: 答案很长,虽然OSXFUSE项目与Fuse4X项目不同,但它们都来自同一个来源,而Fuse4X在其常见问题解答中有关于音量图标的说法:

Q 4.1. 问4.1。 Why do Fuse4X volumes show up with "server" (or "network volume") icons? 为什么Fuse4X卷显示“服务器”(或“网络卷”)图标?

A: To be precise, by default Fuse4X volumes show up as nonlocal volumes, which the Finder unfortunately treats the same as "servers". 答:确切地说,默认情况下,Fuse4X卷显示为非本地卷,但Finder不幸地将其视为“服务器”。 It's a good question as to why Fuse4X normally tags its volumes as nonlocal. 这是一个很好的问题,为什么Fuse4X通常将其卷标记为非本地。 Some people think that in the case of disk-based file systems, Fuse4X must tag the volume as local. 有些人认为,对于基于磁盘的文件系统,Fuse4X必须将卷标记为本地。 Well, let us see. 好吧,让我们看看。

For a vfs to be local on Mac OS X, you need a "real" disk device – a /dev/disk* style node. 要使vfs在Mac OS X上是本地的,您需要一个“真正的”磁盘设备 - / dev / disk *样式节点。 Such a real disk device node in Fuse4X's case is problematic: at mount time, for a local volume, the kernel would itself open the device node and pass it to Fuse4X. Fuse4X案例中的这种真实磁盘设备节点存在问题:在安装时,对于本地卷,内核本身会打开设备节点并将其传递给Fuse4X。 In doing so, the kernel would make sure that the device is not currently in use (for one, to disallow multiple mounts of the same device). 在这样做时,内核将确保当前没有使用该设备(例如,不允许同一设备的多个安装)。 This happens before control passes to Fuse4X and mounting can proceed. 这在控制传递到Fuse4X并且可以继续安装之前发生。 This would have been fine if the entire file system lived in the kernel, but in Fuse4X's case, the user-space file system program would also want to (exclusively) open the disk device. 如果整个文件系统都在内核中,那就没问题,但在Fuse4X的情况下,用户空间文件系统程序也希望(独占)打开磁盘设备。

Take a look at path finder source code . 看一下路径查找器源代码

- (BOOL)setAsCustomIconForVolume:(NString *)path;
{
    FSref FSRefpath = convertoFsref(path);
    // filename for custom icon is ".VolumeIcon.icns"
    NSString *iconPath = [path stringByAppendingPathComponent:@".VolumeIcon.icns"];

    // remove any existing file first.

    [self writeToFile:iconPath];
    FSSetHasCustomIcon(FSRefpath);

    // rebuild volumeList


    return YES;
}
OSErr FSSetHasCustomIcon(
                   const FSRef *ref)
{
    return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
}
OSErr FSChangeFinderFlags(
                    const FSRef *ref,
                    Boolean setBits,
                    UInt16 flagBits)
{
    OSErr           result;
    FSCatalogInfo   catalogInfo;
    FSRef           parentRef;

    /* get the current finderInfo */
    result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
    require_noerr(result, FSGetCatalogInfo);

    /* set or clear the appropriate bits in the finderInfo.finderFlags */
    if ( setBits )
    {
        /* OR in the bits */
        ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
    }
    else
    {
        /* AND out the bits */
        ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
    }

    /* save the modified finderInfo */
    result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
    require_noerr(result, FSSetCatalogInfo);

FSSetCatalogInfo:
FSGetCatalogInfo:

        return ( result );
}  

NTVolumeNotificationMgr NTVolumeNotificationMgr
NTIconFamily NTIconFamily

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM