Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ endif()

if(APPLE)
list(APPEND LIBFASTFETCH_SRC
src/util/apple/cfdict_helpers.c
src/util/apple/cf_helpers.c
src/util/apple/osascript.m
src/detection/host/host_apple.c
src/detection/os/os_apple.c
Expand Down Expand Up @@ -369,6 +369,7 @@ if(APPLE)
PRIVATE "-framework OpenGL"
PRIVATE "-framework OpenCL"
PRIVATE "-framework Cocoa"
PRIVATE "-weak_framework MediaRemote -F /System/Library/PrivateFrameworks"
)
endif()

Expand Down
24 changes: 17 additions & 7 deletions src/detection/battery/battery_apple.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "fastfetch.h"
#include "battery.h"
#include "util/apple/cfdict_helpers.h"
#include "util/apple/cf_helpers.h"

#include <IOKit/IOKitLib.h>

Expand All @@ -27,18 +27,28 @@ const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results)
}

bool boolValue;
const char* error;

BatteryResult* battery = ffListAdd(results);
ffStrbufInit(&battery->capacity);
int currentCapacity, maxCapacity;
if(ffCfDictGetInt(properties, CFSTR("CurrentCapacity"), &currentCapacity) &&
ffCfDictGetInt(properties, CFSTR("MaxCapacity"), &maxCapacity))
ffStrbufAppendF(&battery->capacity, "%.0f", currentCapacity * 100.0 / maxCapacity);

if ((error = ffCfDictGetInt(properties, CFSTR("MaxCapacity"), &maxCapacity)))
return error;
if (maxCapacity <= 0)
return "Querying MaxCapacity failed";

if ((error = ffCfDictGetInt(properties, CFSTR("CurrentCapacity"), &currentCapacity)))
return error;
if(currentCapacity <= 0)
return "Querying CurrentCapacity failed";

ffStrbufAppendF(&battery->capacity, "%.0f", currentCapacity * 100.0 / maxCapacity);

ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->technology);
if (ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue)
if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue)
{
ffStrbufAppendS(&battery->manufacturer, "Apple Inc.");
ffStrbufAppendS(&battery->modelName, "Builtin");
Expand All @@ -52,9 +62,9 @@ const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results)
}

ffStrbufInit(&battery->status);
if (ffCfDictGetBool(properties, CFSTR("FullyCharged"), &boolValue) && boolValue)
if (!ffCfDictGetBool(properties, CFSTR("FullyCharged"), &boolValue) && boolValue)
ffStrbufAppendS(&battery->status, "Fully charged");
else if (ffCfDictGetBool(properties, CFSTR("IsCharging"), &boolValue) && boolValue)
else if (!ffCfDictGetBool(properties, CFSTR("IsCharging"), &boolValue) && boolValue)
ffStrbufAppendS(&battery->status, "Charging");
else
ffStrbufAppendS(&battery->status, "");
Expand Down
6 changes: 3 additions & 3 deletions src/detection/gpu/gpu_apple.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "gpu.h"
#include "common/library.h"
#include "detection/cpu/cpu.h"
#include "util/apple/cfdict_helpers.h"
#include "util/apple/cf_helpers.h"

#include <IOKit/graphics/IOGraphicsLib.h>

Expand Down Expand Up @@ -34,7 +34,7 @@ const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance)
ffStrbufInit(&gpu->name);
//IOAccelerator returns model property for Apple Silicon, but not for Intel Iris GPUs.
//Still needs testing for AMD's
if(!ffCfDictGetString(properties, CFSTR("model"), &gpu->name))
if(ffCfDictGetString(properties, CFSTR("model"), &gpu->name))
{
CFRelease(properties);

Expand All @@ -49,7 +49,7 @@ const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance)
ffCfDictGetString(properties, CFSTR("model"), &gpu->name);
}

if(!ffCfDictGetInt(properties, CFSTR("gpu-core-count"), &gpu->coreCount))
if(ffCfDictGetInt(properties, CFSTR("gpu-core-count"), &gpu->coreCount))
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;

gpu->temperature = FF_GPU_TEMP_UNSET;
Expand Down
1 change: 1 addition & 0 deletions src/detection/media/media.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const FFMediaResult* ffDetectMedia(const FFinstance* instance)
ffStrbufInit(&result.artist);
ffStrbufInit(&result.album);
ffStrbufInit(&result.url);
ffStrbufInit(&result.status);

ffDetectMediaImpl(instance, &result);

Expand Down
1 change: 1 addition & 0 deletions src/detection/media/media.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef struct FFMediaResult
FFstrbuf artist;
FFstrbuf album;
FFstrbuf url;
FFstrbuf status;
} FFMediaResult;

const FFMediaResult* ffDetectMedia(const FFinstance* instance);
Expand Down
59 changes: 46 additions & 13 deletions src/detection/media/media_apple.m
Original file line number Diff line number Diff line change
@@ -1,28 +1,66 @@
#include "fastfetch.h"
#include "detection/media/media.h"
#include "common/library.h"
#include "util/apple/cfdict_helpers.h"
#include "util/apple/cf_helpers.h"
#include "util/apple/osascript.h"

#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>

void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info));
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import));
extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribute__((weak_import));
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing));

static const char* getMedia(FFMediaResult* result)
{
FF_LIBRARY_LOAD(MediaRemote, NULL, "dlopen MediaRemote failed", "/System/Library/PrivateFrameworks/MediaRemote.framework/MediaRemote", -1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(MediaRemote, MRMediaRemoteGetNowPlayingInfo);
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingClient);
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetBundleIdentifier);
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetParentAppBundleIdentifier);
#undef FF_TEST_FN_EXISTANCE

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
ffMRMediaRemoteGetNowPlayingInfo(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(_Nullable CFDictionaryRef info) {
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
ffStrbufAppendS(&result->status, playing ? "Playing" : "Paused");
dispatch_group_leave(group);
});

dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) {
if(info != nil) {
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
}
dispatch_semaphore_signal(semaphore);
dispatch_group_leave(group);
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

dispatch_group_enter(group);
MRMediaRemoteGetNowPlayingClient(queue, ^(_Nullable id clientObj) {
if (clientObj != nil) {
CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier(clientObj);
if (identifier == nil)
identifier = MRNowPlayingClientGetParentAppBundleIdentifier(clientObj);
if (identifier != nil)
ffCfStrGetString(identifier, &result->busNameShort);
}
dispatch_group_leave(group);
});

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

if(result->busNameShort.length > 0)
{
char buf[128];
snprintf(buf, sizeof(buf), "name of app id \"%s\"", result->busNameShort.chars);
ffOsascript(buf, &result->player);
}

if(result->song.length > 0)
return NULL;
Expand All @@ -35,9 +73,4 @@ void ffDetectMediaImpl(const FFinstance* instance, FFMediaResult* media)
FF_UNUSED(instance)
const char* error = getMedia(media);
ffStrbufAppendS(&media->error, error);

//TODO: proper detection
//I already set it here, because the player module expects it to be set if the error is not set
if(error == NULL)
ffStrbufAppendS(&media->player, "Media Player");
}
8 changes: 6 additions & 2 deletions src/modules/song.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <ctype.h>

#define FF_SONG_MODULE_NAME "Media"
#define FF_SONG_NUM_FORMAT_ARGS 4
#define FF_SONG_NUM_FORMAT_ARGS 5

static bool shouldIgoreChar(char c)
{
Expand Down Expand Up @@ -89,6 +89,9 @@ void ffPrintSong(FFinstance* instance)
fputs(" - ", stdout);
}

if (media->status.length > 0)
ffStrbufAppendF(&songPretty, " (%s)", media->status.chars);

ffStrbufPutTo(&songPretty, stdout);
}
else
Expand All @@ -97,7 +100,8 @@ void ffPrintSong(FFinstance* instance)
{FF_FORMAT_ARG_TYPE_STRBUF, &songPretty},
{FF_FORMAT_ARG_TYPE_STRBUF, &media->song},
{FF_FORMAT_ARG_TYPE_STRBUF, &media->artist},
{FF_FORMAT_ARG_TYPE_STRBUF, &media->album}
{FF_FORMAT_ARG_TYPE_STRBUF, &media->album},
{FF_FORMAT_ARG_TYPE_STRBUF, &media->status}
});
}

Expand Down
59 changes: 59 additions & 0 deletions src/util/apple/cf_helpers.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include "cf_helpers.h"

const char* ffCfStrGetString(CFStringRef str, FFstrbuf* result)
{
uint32_t length = (uint32_t)CFStringGetLength(str);
//CFString stores UTF16 characters, therefore may require larger buffer to convert to UTF8 string
ffStrbufEnsureFree(result, length * 2);
if(!CFStringGetCString(str, result->chars, result->allocated, kCFStringEncodingUTF8))
return "CFStringGetCString() failed";
// CFStringGetCString ensures the buffer is NUL terminated
// https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring
result->length = (uint32_t) strnlen(result->chars, (uint32_t)result->allocated);
return NULL;
}

const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
{
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
if(cf == NULL)
return "CFDictionaryGetValue() failed";

if(CFGetTypeID(cf) == CFStringGetTypeID())
{
return ffCfStrGetString((CFStringRef)cf, result);
}
else if(CFGetTypeID(cf) == CFDataGetTypeID())
{
CFDataRef cfData = (CFDataRef)cf;
uint32_t length = (uint32_t)CFDataGetLength(cfData);
ffStrbufEnsureFree(result, length + 1);
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
result->length = (uint32_t)strnlen(result->chars, length);
result->chars[result->length] = '\0';
return NULL;
}

return "TypeID is neither 'CFString' nor 'CFData'";
}

const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result)
{
CFBooleanRef cf = (CFBooleanRef)CFDictionaryGetValue(dict, key);
if(cf == NULL || CFGetTypeID(cf) != CFBooleanGetTypeID())
return "TypeID is not 'CFBoolean'";

*result = CFBooleanGetValue(cf);
return NULL;
}

const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result)
{
CFNumberRef cf = (CFNumberRef)CFDictionaryGetValue(dict, key);
if (cf == NULL || CFGetTypeID(cf) != CFNumberGetTypeID())
return "TypeID is not 'CFNumber'";

if(!CFNumberGetValue(cf, kCFNumberSInt32Type, result))
return "Number type is not SInt32";
return NULL;
}
15 changes: 15 additions & 0 deletions src/util/apple/cf_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#ifndef FASTFETCH_INCLUDED_cf_helpers
#define FASTFETCH_INCLUDED_cf_helpers

#include "fastfetch.h"
#include <CoreFoundation/CoreFoundation.h>

//Return error info if failed, NULL otherwise
const char* ffCfStrGetString(CFStringRef str, FFstrbuf* result);
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result);
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result);

#endif
57 changes: 0 additions & 57 deletions src/util/apple/cfdict_helpers.c

This file was deleted.

13 changes: 0 additions & 13 deletions src/util/apple/cfdict_helpers.h

This file was deleted.