Можно ли программно изменить значок громкости на подключенном диске в Mac OS X?
Я хочу программно изменить значок громкости для стековой файловой системы, реализованной с использованием OSXFUSE (ранее MacFUSE). Значок должен отражать состояние смонтированной файловой системы.
Подход, который я пытался заставить работать, заключается в том, чтобы сопоставить запросы для /.VolumeIcon.icns с соответствующим значком в комплекте приложений. Затем отправка уведомлений об изменениях в файловую систему для фактического пути (путь) и пути монтирования (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);
Проходя через отладчик, я вижу, что этот код ударился, но код для сопоставления /.VolumeIcon.icns вызывается нечасто и никогда в ответ на эти уведомления.
2 ответа
Я думаю, что короткий ответ, вам не повезло. Длинный ответ таков: хотя проект OSXFUSE отличается от проекта Fuse4X, они оба получены из одного и того же источника, и Fuse4X может сказать о значках громкости в своих часто задаваемых вопросах:
Q 4.1. Почему тома Fuse4X отображаются с иконками "сервер" (или "том сети")?
A: Если быть точным, то по умолчанию тома Fuse4X отображаются как нелокальные тома, которые, к сожалению, Finder трактует так же, как "серверы". Это хороший вопрос, почему Fuse4X обычно отмечает свои объемы как нелокальные. Некоторые люди считают, что в случае дисковых файловых систем Fuse4X должен помечать том как локальный. Ну что ж, посмотрим.
Для того, чтобы vfs был локальным в Mac OS X, вам нужно "реальное" дисковое устройство - узел в стиле / dev / disk *. Такой реальный узел устройства диска в случае Fuse4X проблематичен: во время монтирования для локального тома ядро само откроет узел устройства и передаст его Fuse4X. При этом ядро должно убедиться, что устройство в данный момент не используется (например, чтобы запретить несколько монтирований одного устройства). Это происходит до того, как управление переходит к Fuse4X и установка может продолжаться. Это было бы хорошо, если бы в ядре находилась вся файловая система, но в случае Fuse4X программа файловой системы пользовательского пространства также хотела бы (исключительно) открыть дисковое устройство.
Взгляните на исходный код поиска пути.
- (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 );
}