From ce61783c4baeaecbb6989fae7cbeb47240849dc2 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 3 Sep 2026 09:43:07 +0800 Subject: [PATCH] Wallpaper (macOS): extracts image path from NSData `Configuration` field Also moves NSWorkspace method to the last method to try Fixes #2559 --- src/detection/wallpaper/wallpaper_apple.m | 162 ++++++++++++++-------- 1 file changed, 104 insertions(+), 58 deletions(-) diff --git a/src/detection/wallpaper/wallpaper_apple.m b/src/detection/wallpaper/wallpaper_apple.m index 63acae325..1b4f6e3d5 100644 --- a/src/detection/wallpaper/wallpaper_apple.m +++ b/src/detection/wallpaper/wallpaper_apple.m @@ -5,79 +5,125 @@ #import #import -const char* ffDetectWallpaper(FFstrbuf* result) -{ - { - // Reliable for user-picked static images. - NSURL* url = [NSWorkspace.sharedWorkspace desktopImageURLForScreen:NSScreen.mainScreen]; - if (url.fileURL && ![url.path isEqualToString:@"/System/Library/CoreServices/DefaultDesktop.heic"] /* dynamic wallpapers */) - { - ffStrbufSetS(result, url.path.UTF8String); - return nullptr; - } +const char* detectFromPlist(FFstrbuf* result) { + // For Sonoma and later (macOS 14.0+) + // https://github.com/JohnCoates/Aerial/issues/1332 + NSError* error; + NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Application Support/com.apple.wallpaper/Store/Index.plist", instance.state.platform.homeDir.chars]; + NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName] + error:&error]; + + if (error) { + return "Failed to read wallpaper plist file"; } - { - // For Sonoma - // https://github.com/JohnCoates/Aerial/issues/1332 - NSError* error; - NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Application Support/com.apple.wallpaper/Store/Index.plist", instance.state.platform.homeDir.chars]; - NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName] - error:&error]; - if (!error) - { - NSArray* choices = [dict valueForKeyPath:@"SystemDefault.Desktop.Content.Choices"]; - if (choices.count > 0) - { - NSDictionary* choice = choices[0]; - NSArray* files = choice[@"Files"]; - if (files.count > 0) - { - NSString* file = files[0][@"relative"]; - ffStrbufAppendS(result, [NSURL URLWithString:file].path.UTF8String); - } - else - { - NSString* provider = choice[@"Provider"]; - NSString* builtinPrefix = @"com.apple.wallpaper.choice."; - if ([provider hasPrefix:builtinPrefix]) - provider = [provider substringFromIndex:builtinPrefix.length]; - if ([provider isEqualToString:@"sonoma"]) - ffStrbufSetStatic(result, "macOS Sonoma"); - else if ([provider isEqualToString:@"aerials"]) // Most builtin aerial wallpapers are private - ffStrbufSetStatic(result, "Built-in aerial photography"); - else - ffStrbufAppendF(result, "Built-in %s wallpaper", provider.UTF8String); + NSArray* choices = [dict valueForKeyPath:@"SystemDefault.Desktop.Content.Choices"]; + if (choices.count > 0) { + NSDictionary* choice = choices[0]; + + NSArray* files = choice[@"Files"]; + if (files.count > 0) { + NSString* file = files[0][@"relative"]; + ffStrbufSetS(result, [NSURL URLWithString:file].path.UTF8String); + } + + if (result->length == 0) { + NSData* configData = choice[@"Configuration"]; + if (configData && configData.length > 0) { + NSError* plistError = nil; + NSDictionary* configPlist = [NSPropertyListSerialization propertyListWithData:configData + options:NSPropertyListImmutable + format:NULL + error:&plistError]; + + if (!plistError && [configPlist isKindOfClass:NSDictionary.class]) { + NSDictionary* urlDict = configPlist[@"url"]; + if ([urlDict isKindOfClass:NSDictionary.class]) { + NSString* relativeUrlString = urlDict[@"relative"]; + if ([relativeUrlString isKindOfClass:[NSString class]]) { + NSURL* fileUrl = [NSURL URLWithString:relativeUrlString]; + if (fileUrl.fileURL) { + ffStrbufSetS(result, fileUrl.path.UTF8String); + } + } + } + } + } + } + + if (result->length == 0) { + NSString* provider = choice[@"Provider"]; + if ([provider isKindOfClass:NSString.class]) { + NSString* builtinPrefix = @"com.apple.wallpaper.choice."; + if ([provider hasPrefix:builtinPrefix]) { + provider = [provider substringFromIndex:builtinPrefix.length]; + } + + // macOS internal wallpapers + if ([provider isEqualToString:@"aerials"]) { // Most builtin aerial wallpapers are private + ffStrbufSetStatic(result, "Built-in aerial photography"); + } else if ([provider isEqualToString:@"default"]) { + ffStrbufSetStatic(result, "macOS Default Wallpaper"); + } else { + ffStrbufSetF(result, "Built-in %s wallpaper", provider.UTF8String); } } - if (result->length > 0) - return nullptr; } } + if (result->length == 0) { + return "Failed to detect wallpaper from plist"; + } + return nullptr; +} - #ifdef FF_HAVE_SQLITE3 - - { - // For Ventura - // https://stackoverflow.com/questions/301215/getting-desktop-background-on-mac - FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir); - ffStrbufAppendS(&path, "Library/Application Support/Dock/desktoppicture.db"); - if (ffSettingsGetSQLite3String(path.chars, +#ifdef FF_HAVE_SQLITE3 +const char* detectFromSQLite(FFstrbuf* result) { + // For Ventura + // https://stackoverflow.com/questions/301215/getting-desktop-background-on-mac + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir); + ffStrbufAppendS(&path, "Library/Application Support/Dock/desktoppicture.db"); + if (ffSettingsGetSQLite3String(path.chars, "SELECT value\n" "FROM preferences\n" "JOIN data ON preferences.data_id=data.ROWID\n" "JOIN pictures ON preferences.picture_id=pictures.ROWID\n" "JOIN displays ON pictures.display_id=displays.ROWID\n" "JOIN spaces ON pictures.space_id=spaces.ROWID\n" - "WHERE display_id=1 AND space_id=1 AND key=1", result) - ) - return nullptr; + "WHERE display_id=1 AND space_id=1 AND key=1", + result)) { + return nullptr; + } + return "Failed to detect wallpaper from SQLite database"; +} +#endif + +const char* detectFromNSWorkspace(FFstrbuf* result) { + // Reliable for user-picked static images. + NSScreen* mainScreen = NSScreen.mainScreen; + if (!mainScreen) { + return "Failed to detect wallpaper from NSWorkspace: No main screen found"; } - #endif - - if (ffOsascript("tell application \"Finder\" to get POSIX path of (get desktop picture as alias)", result)) + NSURL* url = [NSWorkspace.sharedWorkspace desktopImageURLForScreen:mainScreen]; + if (url.fileURL) { + ffStrbufSetS(result, url.path.UTF8String); return nullptr; + } - return "All detection methods failed"; + return "Failed to detect wallpaper from NSWorkspace"; +} + +const char* ffDetectWallpaper(FFstrbuf* result) { + const char* error; + + if (@available(macOS 14.0, *)) { + error = detectFromPlist(result); + } else { +#ifdef FF_HAVE_SQLITE3 + error = detectFromSQLite(result); +#else + error = detectFromNSWorkspace(result); +#endif + } + return error; }