mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-27 23:30:47 +01:00
148 lines
6.2 KiB
Objective-C
148 lines
6.2 KiB
Objective-C
#include "wallpaper.h"
|
|
#include "common/settings.h"
|
|
|
|
#import <Foundation/Foundation.h>
|
|
#import <AppKit/AppKit.h>
|
|
|
|
const char* detectFromPlist(FFstrbuf* result) {
|
|
// For Sonoma and later (macOS 14.0+)
|
|
// https://github.com/JohnCoates/Aerial/issues/1332
|
|
// Initialised because the check below reads it: the method is documented to assign it, but an
|
|
// uninitialised read decides between two sources of the wallpaper, so it is not worth relying on.
|
|
NSError* error = nil;
|
|
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";
|
|
}
|
|
|
|
NSArray* choices = [dict valueForKeyPath:@"SystemDefault.Desktop.Content.Choices"];
|
|
if (choices.count > 0) {
|
|
NSDictionary* choice = choices[0];
|
|
|
|
NSArray* files = choice[@"Files"];
|
|
if ([files isKindOfClass:NSArray.class] && files.count > 0) {
|
|
NSDictionary* fileEntry = files[0];
|
|
// `relative` is read through a dictionary, which raises an unrecognized selector rather
|
|
// than returning nil when the entry is not one.
|
|
if ([fileEntry isKindOfClass:NSDictionary.class]) {
|
|
NSString* relative = fileEntry[@"relative"];
|
|
if ([relative isKindOfClass:NSString.class]) {
|
|
ffStrbufSetS(result, [NSURL URLWithString:relative].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 "Failed to detect wallpaper from plist";
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
#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;
|
|
}
|
|
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";
|
|
}
|
|
|
|
NSURL* url = [NSWorkspace.sharedWorkspace desktopImageURLForScreen:mainScreen];
|
|
if (url.fileURL) {
|
|
ffStrbufSetS(result, url.path.UTF8String);
|
|
return nullptr;
|
|
}
|
|
|
|
return "Failed to detect wallpaper from NSWorkspace";
|
|
}
|
|
|
|
const char* ffDetectWallpaper(FFstrbuf* result) {
|
|
const char* error;
|
|
|
|
if (@available(macOS 14.0, *)) {
|
|
error = detectFromPlist(result);
|
|
if (error) {
|
|
// The plist is the authoritative source on Sonoma and later, but when it can not be read
|
|
// at all, NSWorkspace can still resolve a user-picked static image.
|
|
error = detectFromNSWorkspace(result);
|
|
}
|
|
} else {
|
|
#ifdef FF_HAVE_SQLITE3
|
|
error = detectFromSQLite(result);
|
|
if (error) {
|
|
// The database only holds the user-picked picture, so it goes missing on a machine that
|
|
// never changed its wallpaper. NSWorkspace answers for the system default there.
|
|
error = detectFromNSWorkspace(result);
|
|
}
|
|
#else
|
|
error = detectFromNSWorkspace(result);
|
|
#endif
|
|
}
|
|
return error;
|
|
}
|