diff --git a/CMakeLists.txt b/CMakeLists.txt index 830ec5f46..f28620b3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -193,7 +193,6 @@ set(LIBFASTFETCH_SRC src/detection/terminalShell.c src/detection/vulkan.c src/detection/datetime.c - src/detection/temps.c src/detection/title.c src/detection/host/host.c src/detection/os/os.c @@ -243,6 +242,7 @@ set(LIBFASTFETCH_SRC src/modules/colors.c src/modules/opengl.c src/modules/opencl.c + src/modules/users.c ) if(BSD OR APPLE) @@ -262,6 +262,8 @@ if(LINUX OR ANDROID OR BSD) list(APPEND LIBFASTFETCH_SRC src/detection/cpuUsage/cpuUsage_linux.c src/detection/disk/disk_linux.c + src/detection/poweradapter/poweradapter_linux.c + src/detection/temps/temps_linux.c ) endif() @@ -271,7 +273,6 @@ if(LINUX OR BSD) src/detection/os/os_linux.c src/detection/gpu/gpu_linux.c src/detection/battery/battery_linux.c - src/detection/poweradapter/poweradapter_linux.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/wayland.c src/detection/displayserver/linux/xcb.c @@ -280,6 +281,7 @@ if(LINUX OR BSD) src/detection/terminalfont/terminalfont_linux.c src/detection/media/media_linux.c src/detection/wmtheme/wmtheme_linux.c + src/detection/font/font_linux.c ) endif() @@ -300,6 +302,8 @@ if(APPLE) src/detection/media/media_apple.m src/detection/disk/disk_apple.m src/detection/wmtheme/wmtheme_apple.c + src/detection/temps/temps_apple.c + src/detection/font/font_apple.m ) endif() @@ -320,6 +324,7 @@ if(ANDROID) src/detection/terminalfont/terminalfont_android.c src/detection/media/media_android.c src/detection/wmtheme/wmtheme_android.c + src/detection/font/font_android.c ) endif() diff --git a/completions/bash b/completions/bash index 47877db6f..11313cc65 100644 --- a/completions/bash +++ b/completions/bash @@ -177,9 +177,14 @@ __fastfetch_completion() "--allow-slow-operations" "--disable-linewrap" "--hide-cursor" + "--cpu-temp" + "--gpu-temp" + "--battery-temp" + "--font-inline" "--localip-show-ipv4" "--localip-show-ipv6" "--localip-show-loop" + "--localip-name-prefix" "--escape-bedrock" "--pipe" "--title-fqdn" diff --git a/presets/all b/presets/all index 104f28551..6bd7c776d 100644 --- a/presets/all +++ b/presets/all @@ -1 +1 @@ ---structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:OpenGL:OpenCL:Break:Colors +--structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Break:Colors diff --git a/presets/verbose b/presets/verbose index 2f9b41438..6109baa19 100644 --- a/presets/verbose +++ b/presets/verbose @@ -11,7 +11,7 @@ --wm-theme-format Name: {} --theme-format Plasma: {}; Plasma colors: {}; Plasma colors pretty: {}; GTK2: {}; GTK3: {}; GTK4: {}; GTK: {} --icons-format Plasma: {}; GTK2: {}; GTK3: {}; GTK4: {}; GTK: {} ---font-format Plasma raw: {}; Plasma name: {}; Plasma size: {}; Plasma styles: {}; Plasma pretty: {}; GTK2 raw: {}; GTK2 name: {}; GTK2 size: {}; GTK2 styles: {}; GTK2 pretty: {}; GTK3 raw: {}; GTK3 name: {}; GTK3 size: {}; GTK3 styles: {}; GTK3 pretty: {}; GTK4 raw: {}; GTK4 name: {}; GTK4 size: {}; GTK4 styles: {}; GTK4 pretty: {}; GTK: {} +--font-format Type: {}; Font: {} --cursor-format Theme: {}; Size: {} --terminal-format Process: {}; Path: {}; Exe: {} --terminal-font-format Pretty: {}; Name: {}; Size: {}; Styles: {} diff --git a/src/common/init.c b/src/common/init.c index 19771a505..322e661c9 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -220,6 +220,10 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.libplist, 0); ffStrbufInitA(&instance->config.libcJSON, 0); + instance->config.cpuTemp = false; + instance->config.gpuTemp = false; + instance->config.batteryTemp = false; + instance->config.titleFQDN = false; ffStrbufInitA(&instance->config.diskFolders, 0); @@ -229,9 +233,12 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.separatorString, 0); + instance->config.fontInline = true; + instance->config.localIpShowIpV4 = true; instance->config.localIpShowIpV6 = false; instance->config.localIpShowLoop = false; + ffStrbufInit(&instance->config.localIpNamePrefix); instance->config.publicIpTimeout = 0; diff --git a/src/data/help.txt b/src/data/help.txt index eb02e6df5..59bf40e31 100644 --- a/src/data/help.txt +++ b/src/data/help.txt @@ -94,9 +94,14 @@ Module specific options: --disk-folders : A colon separated list of folder paths for the disk output. Default is "/:/home" --disk-removable : Sets if removable volume should be printed. Default is false --battery-dir : The directory where the battery folders are. Standard: /sys/class/power_supply/ + --cpu-temp : Detect and display CPU temperature if supported. Default is false + --gpu-temp : Detect and display GPU temperature if supported. Default is false + --battery-temp : Detect and display Battery temperature if supported. Default is false + --font-inline : Display fonts of different DE in one line --localip-show-ipv4 : Show ipv4 addresses in local ip module. Default is true --localip-show-ipv6 : Show ipv6 addresses in local ip module. Default is false --localip-show-loop : Show loop back addresses (127.0.0.1) in local ip module. Default is false + --localip-name-prefix : Show ips with given name prefix only. Default is empty --public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0) --player-name: The name of the player to use --gl : Sets the opengl context creation library to use. Must be auto, egl, glx or osmesa. Default is auto diff --git a/src/detection/battery/battery.h b/src/detection/battery/battery.h index e7c2a859a..6269f590a 100644 --- a/src/detection/battery/battery.h +++ b/src/detection/battery/battery.h @@ -5,6 +5,8 @@ #include "fastfetch.h" +#define FF_BATTERY_TEMP_UNSET (0/0.0) + typedef struct BatteryResult { FFstrbuf manufacturer; @@ -12,6 +14,7 @@ typedef struct BatteryResult FFstrbuf technology; FFstrbuf capacity; FFstrbuf status; + double temperature; } BatteryResult; const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results); diff --git a/src/detection/battery/battery_apple.c b/src/detection/battery/battery_apple.c index 8fa956c77..0e9667cf7 100644 --- a/src/detection/battery/battery_apple.c +++ b/src/detection/battery/battery_apple.c @@ -1,9 +1,34 @@ #include "fastfetch.h" #include "battery.h" #include "util/apple/cf_helpers.h" +#include "detection/temps/temps_apple.h" #include +static double detectBatteryTemp() +{ + FFlist temps; + ffListInit(&temps, sizeof(FFTempValue)); + + ffDetectCoreTemps(FF_TEMP_BATTERY, &temps); + + if(temps.length == 0) + return FF_BATTERY_TEMP_UNSET; + + double result = 0; + for(uint32_t i = 0; i < temps.length; ++i) + { + FFTempValue* tempValue = (FFTempValue*)ffListGet(&temps, i); + result += tempValue->value; + //TODO: do we really need this? + ffStrbufDestroy(&tempValue->name); + ffStrbufDestroy(&tempValue->deviceClass); + } + result /= temps.length; + ffListDestroy(&temps); + return result; +} + const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) { FF_UNUSED(instance); @@ -69,6 +94,11 @@ const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) else ffStrbufAppendS(&battery->status, ""); + if(instance->config.batteryTemp) + battery->temperature = detectBatteryTemp(); + else + battery->temperature = FF_BATTERY_TEMP_UNSET; + CFRelease(properties); IOObjectRelease(registryEntry); } diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 909ed493f..6a8643521 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -70,6 +70,8 @@ static void parseBattery(FFstrbuf* dir, FFlist* results) ffStrbufAppendS(dir, "/status"); ffReadFileBuffer(dir->chars, &result->status); ffStrbufSubstrBefore(dir, dirLength); + + result->temperature = FF_BATTERY_TEMP_UNSET; } const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) { diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index 90e948a6a..dc0c1a3eb 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -1,5 +1,6 @@ #include "cpu.h" #include "common/sysctl.h" +#include "detection/temps/temps_apple.h" static double getFrequency(const char* propName) { @@ -12,33 +13,64 @@ static double getFrequency(const char* propName) return herz / 1000.0; //to GHz } +static double detectCpuTemp(const FFstrbuf* cpuName) +{ + FFlist temps; + ffListInit(&temps, sizeof(FFTempValue)); + + if(ffStrbufStartsWithS(cpuName, "Apple M1")) + ffDetectCoreTemps(FF_TEMP_CPU_M1X, &temps); + else if(ffStrbufStartsWithS(cpuName, "Apple M2")) + ffDetectCoreTemps(FF_TEMP_CPU_M2X, &temps); + else //TODO: PPC? + ffDetectCoreTemps(FF_TEMP_CPU_X64, &temps); + + if(temps.length == 0) + return FF_CPU_TEMP_UNSET; + + double result = 0; + for(uint32_t i = 0; i < temps.length; ++i) + { + FFTempValue* tempValue = (FFTempValue*)ffListGet(&temps, i); + result += tempValue->value; + //TODO: do we really need this? + ffStrbufDestroy(&tempValue->name); + ffStrbufDestroy(&tempValue->deviceClass); + } + result /= temps.length; + ffListDestroy(&temps); + return result; +} + void ffDetectCPUImpl(const FFinstance* instance, FFCPUResult* cpu, bool cached) { FF_UNUSED(instance); - //TODO find a way to detect this - cpu->temperature = FF_CPU_TEMP_UNSET; + if(!cached) + { + ffSysctlGetString("machdep.cpu.brand_string", &cpu->name); + ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor); - if(cached) - return; + cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu_max", 1); + if(cpu->coresPhysical == 1) + cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu", 1); - ffSysctlGetString("machdep.cpu.brand_string", &cpu->name); - ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor); + cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.logicalcpu_max", 1); + if(cpu->coresLogical == 1) + cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1); - cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu_max", 1); - if(cpu->coresPhysical == 1) - cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.physicalcpu", 1); + cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.logicalcpu", 1); + if(cpu->coresOnline == 1) + cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1); - cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.logicalcpu_max", 1); - if(cpu->coresLogical == 1) - cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1); + cpu->frequencyMin = getFrequency("hw.cpufrequency_min"); + cpu->frequencyMax = getFrequency("hw.cpufrequency_max"); + if(cpu->frequencyMax == 0.0) + cpu->frequencyMax = getFrequency("hw.cpufrequency"); + } - cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.logicalcpu", 1); - if(cpu->coresOnline == 1) - cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1); - - cpu->frequencyMin = getFrequency("hw.cpufrequency_min"); - cpu->frequencyMax = getFrequency("hw.cpufrequency_max"); - if(cpu->frequencyMax == 0.0) - cpu->frequencyMax = getFrequency("hw.cpufrequency"); + if (instance->config.cpuTemp) + cpu->temperature = detectCpuTemp(&cpu->name); + else + cpu->temperature = FF_CPU_TEMP_UNSET; } diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 51da397db..83c0f1140 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -1,7 +1,7 @@ #include "cpu.h" #include "common/io.h" #include "common/properties.h" -#include "detection/temps.h" +#include "detection/temps/temps_linux.h" #include #include @@ -80,7 +80,10 @@ static double detectCPUTemp(const FFinstance* instance) void ffDetectCPUImpl(const FFinstance* instance, FFCPUResult* cpu, bool cached) { - cpu->temperature = detectCPUTemp(instance); + if(instance->config.cpuTemp) + cpu->temperature = detectCPUTemp(instance); + else + cpu->temperature = FF_CPU_TEMP_UNSET; if(cached) return; diff --git a/src/detection/datetime.c b/src/detection/datetime.c index d96431b3d..9c5ebf414 100644 --- a/src/detection/datetime.c +++ b/src/detection/datetime.c @@ -27,21 +27,21 @@ const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance) result.yearShort = (uint8_t) (result.year % 100); result.month = (uint8_t) (tm->tm_mon + 1); - ffStrbufInit(&result.monthPretty); + ffStrbufInitA(&result.monthPretty, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.monthPretty.length = (uint32_t) strftime(result.monthPretty.chars, ffStrbufGetFree(&result.monthPretty), "%m", tm); - ffStrbufInit(&result.monthName); + ffStrbufInitA(&result.monthName, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.monthName.length = (uint32_t) strftime(result.monthName.chars, ffStrbufGetFree(&result.monthName), "%B", tm); - ffStrbufInit(&result.monthNameShort); + ffStrbufInitA(&result.monthNameShort, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.monthNameShort.length = (uint32_t) strftime(result.monthNameShort.chars, ffStrbufGetFree(&result.monthNameShort), "%b", tm); result.week = (uint8_t) (tm->tm_yday / 7 + 1); - ffStrbufInit(&result.weekday); + ffStrbufInitA(&result.weekday, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.weekday.length = (uint32_t) strftime(result.weekday.chars, ffStrbufGetFree(&result.weekday), "%A", tm); - ffStrbufInit(&result.weekdayShort); + ffStrbufInitA(&result.weekdayShort, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.weekdayShort.length = (uint32_t) strftime(result.weekdayShort.chars, ffStrbufGetFree(&result.weekdayShort), "%a", tm); result.dayInYear = (uint8_t) (tm->tm_yday + 1); @@ -50,22 +50,22 @@ const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance) result.hour = (uint8_t) tm->tm_hour; - ffStrbufInit(&result.hourPretty); + ffStrbufInitA(&result.hourPretty, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.hourPretty.length = (uint32_t) strftime(result.hourPretty.chars, ffStrbufGetFree(&result.hourPretty), "%H", tm); result.hour12 = (uint8_t) (result.hour % 12); - ffStrbufInit(&result.hour12Pretty); + ffStrbufInitA(&result.hour12Pretty, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.hour12Pretty.length = (uint32_t) strftime(result.hour12Pretty.chars, ffStrbufGetFree(&result.hour12Pretty), "%I", tm); result.minute = (uint8_t) tm->tm_min; - ffStrbufInit(&result.minutePretty); + ffStrbufInitA(&result.minutePretty, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.minutePretty.length = (uint32_t) strftime(result.minutePretty.chars, ffStrbufGetFree(&result.minutePretty), "%M", tm); result.second = (uint8_t) tm->tm_sec; - ffStrbufInit(&result.secondPretty); + ffStrbufInitA(&result.secondPretty, FASTFETCH_STRBUF_DEFAULT_ALLOC); result.secondPretty.length = (uint32_t) strftime(result.secondPretty.chars, ffStrbufGetFree(&result.secondPretty), "%S", tm); pthread_mutex_unlock(&mutex); diff --git a/src/detection/font/font.h b/src/detection/font/font.h new file mode 100644 index 000000000..f1d36a5b2 --- /dev/null +++ b/src/detection/font/font.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_font_font +#define FF_INCLUDED_detection_font_font + +#include "fastfetch.h" +#include "util/FFstrbuf.h" +#include "util/FFlist.h" + +typedef struct FFFontResult +{ + const char* type; + FFstrbuf fontPretty; +} FFFontResult; + +const char* ffDetectFontImpl(FFinstance* instance, FFlist* result); + +#endif diff --git a/src/detection/font/font_android.c b/src/detection/font/font_android.c new file mode 100644 index 000000000..1719c7511 --- /dev/null +++ b/src/detection/font/font_android.c @@ -0,0 +1,7 @@ +#include "common/font.h" + +const char* ffDetectFontImpl(FFinstance* instance, FFlist* result) +{ + FF_UNUSED(instance, result); + return "Font detection is not supported on Android"; +} diff --git a/src/detection/font/font_apple.m b/src/detection/font/font_apple.m new file mode 100644 index 000000000..974c1c079 --- /dev/null +++ b/src/detection/font/font_apple.m @@ -0,0 +1,41 @@ +#include "common/font.h" +#include "util/apple/cf_helpers.h" +#include "font.h" + +#import + +#define FF_FONT_MODULE_NAME "Font" + +static void detectFontForType(CTFontUIFontType uiType, FFFontResult* result) +{ + CTFontRef ctFont = CTFontCreateUIFontForLanguage(uiType, 12, NULL); + + ffStrbufInit(&result->fontPretty); + ffCfStrGetString(CTFontCopyFullName(ctFont), &result->fontPretty); + + FFstrbuf familyName; + ffStrbufInit(&familyName); + ffCfStrGetString(CTFontCopyFamilyName(ctFont), &familyName); + + if (ffStrbufComp(&familyName, &result->fontPretty) != 0) + { + ffStrbufAppendF(&result->fontPretty, " (%*s)", familyName.length, familyName.chars); + } + + ffStrbufDestroy(&familyName); +} + +const char* ffDetectFontImpl(FFinstance* instance, FFlist* result) +{ + FF_UNUSED(instance); + + FFFontResult* resultSystem = (FFFontResult*)ffListAdd(result); + resultSystem->type = "SYS"; + detectFontForType(kCTFontUIFontSystem, resultSystem); + + FFFontResult* resultUser = (FFFontResult*)ffListAdd(result); + resultUser->type = "USER"; + detectFontForType(kCTFontUIFontUser, resultUser); + + return NULL; +} diff --git a/src/detection/font/font_linux.c b/src/detection/font/font_linux.c new file mode 100644 index 000000000..eb57cdd49 --- /dev/null +++ b/src/detection/font/font_linux.c @@ -0,0 +1,51 @@ +#include "detection/qt.h" +#include "detection/gtk.h" +#include "common/parsing.h" +#include "common/font.h" +#include "font.h" + +const char* ffDetectFontImpl(FFinstance* instance, FFlist* result) +{ + const FFstrbuf* qtRaw = &ffDetectQt(instance)->font; + const FFstrbuf* gtk2Raw = &ffDetectGTK2(instance)->font; + const FFstrbuf* gtk3Raw = &ffDetectGTK3(instance)->font; + const FFstrbuf* gtk4Raw = &ffDetectGTK4(instance)->font; + + if(qtRaw->length > 0) + { + FFfont qt; + ffFontInitQt(&qt, qtRaw->chars); + + FFFontResult* resultQt = (FFFontResult *)ffListAdd(result); + resultQt->type = "QT"; + ffStrbufInitCopy(&resultQt->fontPretty, &qt.pretty); + + ffFontDestroy(&qt); + } + + if(gtk2Raw->length > 0 || gtk3Raw->length > 0 || gtk4Raw->length > 0) + { + FFfont gtk2; + ffFontInitPango(>k2, gtk2Raw->chars); + + FFfont gtk3; + ffFontInitPango(>k3, gtk3Raw->chars); + + FFfont gtk4; + ffFontInitPango(>k4, gtk4Raw->chars); + + FFFontResult* resultGtk = (FFFontResult *)ffListAdd(result); + resultGtk->type = "GTK"; + ffStrbufInit(&resultGtk->fontPretty); + ffParseGTK(&resultGtk->fontPretty, >k2.pretty, >k3.pretty, >k4.pretty); + + ffFontDestroy(>k2); + ffFontDestroy(>k3); + ffFontDestroy(>k4); + } + + if(result->length == 0) + return "No fonts found"; + + return NULL; +} diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index 445df6831..b755d292e 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -1,10 +1,42 @@ #include "gpu.h" #include "common/library.h" #include "detection/cpu/cpu.h" +#include "detection/temps/temps_apple.h" #include "util/apple/cf_helpers.h" #include +static double detectGpuTemp(const FFstrbuf* gpuName) +{ + FFlist temps; + ffListInit(&temps, sizeof(FFTempValue)); + + if(ffStrbufStartsWithS(gpuName, "Apple M1")) + ffDetectCoreTemps(FF_TEMP_GPU_M1X, &temps); + else if(ffStrbufStartsWithS(gpuName, "Apple M2")) + ffDetectCoreTemps(FF_TEMP_GPU_M2X, &temps); + else if(ffStrbufStartsWithS(gpuName, "Radeon") || ffStrbufStartsWithS(gpuName, "AMD")) + ffDetectCoreTemps(FF_TEMP_GPU_AMD, &temps); + else + ffDetectCoreTemps(FF_TEMP_GPU_UNKNOWN, &temps); + + if(temps.length == 0) + return FF_GPU_TEMP_UNSET; + + double result = 0; + for(uint32_t i = 0; i < temps.length; ++i) + { + FFTempValue* tempValue = (FFTempValue*)ffListGet(&temps, i); + result += tempValue->value; + //TODO: do we really need this? + ffStrbufDestroy(&tempValue->name); + ffStrbufDestroy(&tempValue->deviceClass); + } + result /= temps.length; + ffListDestroy(&temps); + return result; +} + const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) { FF_UNUSED(instance); @@ -52,7 +84,10 @@ const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) if(ffCfDictGetInt(properties, CFSTR("gpu-core-count"), &gpu->coreCount)) gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; - gpu->temperature = FF_GPU_TEMP_UNSET; + if(instance->config.gpuTemp) + gpu->temperature = detectGpuTemp(&gpu->name); + else + gpu->temperature = FF_GPU_TEMP_UNSET; CFRelease(properties); IOObjectRelease(registryEntry); diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index 3cceae9b3..8266357ed 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -9,7 +9,7 @@ #include "common/library.h" #include "common/properties.h" #include "common/parsing.h" -#include "detection/temps.h" +#include "detection/temps/temps_linux.h" #include #include #include @@ -200,7 +200,8 @@ static void pciHandleDevice(const FFinstance* instance, FFlist* results, PCIData gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; gpu->temperature = FF_GPU_TEMP_UNSET; - pciDetectTemperatur(instance, gpu, device); + if(instance->config.gpuTemp) + pciDetectTemperatur(instance, gpu, device); } static const char* pciDetectGPUs(const FFinstance* instance, FFlist* gpus) diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index 9ced5df75..f39edf0e0 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -1,11 +1,120 @@ #include "host.h" #include "common/sysctl.h" +static const char* getProductName(const FFstrbuf* hwModel) +{ + //https://github.com/hykilpikonna/hyfetch/blob/master/neofetch#L1386 + if(ffStrbufCompS(hwModel, "Mac14,7") == 0) return "MacBook Pro (13-inch, M2, 2022)"; + if(ffStrbufCompS(hwModel, "MacBookPro18,3") == 0 || + ffStrbufCompS(hwModel, "MacBookPro18,4") == 0) return "MacBook Pro (14-inch, 2021)"; + if(ffStrbufCompS(hwModel, "MacBookPro18,1") == 0 || + ffStrbufCompS(hwModel, "MacBookPro18,2") == 0) return "MacBook Pro (16-inch, 2021)"; + if(ffStrbufCompS(hwModel, "MacBookPro17,1") == 0) return "MacBook Pro (13-inch, M1, 2020)"; + if(ffStrbufCompS(hwModel, "MacBookPro16,4") == 0) return "MacBook Pro (16-inch, 2019)"; + if(ffStrbufCompS(hwModel, "MacBookPro16,3") == 0) return "MacBook Pro (13-inch, 2020, Two Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro16,2") == 0) return "MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro16,1") == 0) return "MacBook Pro (16-inch, 2019)"; + if(ffStrbufCompS(hwModel, "MacBookPro15,4") == 0) return "MacBook Pro (13-inch, 2019, Two Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro15,3") == 0) return "MacBook Pro (15-inch, 2019)"; + if(ffStrbufCompS(hwModel, "MacBookPro15,2") == 0) return "MacBook Pro (13-inch, 2018/2019, Four Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro15,1") == 0) return "MacBook Pro (15-inch, 2018/2019)"; + if(ffStrbufCompS(hwModel, "MacBookPro14,3") == 0) return "MacBook Pro (15-inch, 2017)"; + if(ffStrbufCompS(hwModel, "MacBookPro14,2") == 0) return "MacBook Pro (13-inch, 2017, Four Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro14,1") == 0) return "MacBook Pro (13-inch, 2017, Two Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro13,3") == 0) return "MacBook Pro (15-inch, 2016)"; + if(ffStrbufCompS(hwModel, "MacBookPro13,2") == 0) return "MacBook Pro (13-inch, 2016, Four Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro13,1") == 0) return "MacBook Pro (13-inch, 2016, Two Thunderbolt 3 ports)"; + if(ffStrbufCompS(hwModel, "MacBookPro12,1") == 0) return "MacBook Pro (Retina, 13-inch, Early 2015)"; + if(ffStrbufCompS(hwModel, "MacBookPro11,4") == 0 || + ffStrbufCompS(hwModel, "MacBookPro11,5") == 0) return "MacBook Pro (Retina, 15-inch, Mid 2015)"; + if(ffStrbufCompS(hwModel, "MacBookPro11,2") == 0 || + ffStrbufCompS(hwModel, "MacBookPro11,3") == 0) return "MacBook Pro (Retina, 15-inch, Late 2013/Mid 2014)"; + if(ffStrbufCompS(hwModel, "MacBookPro11,1") == 0) return "MacBook Pro (Retina, 13-inch, Late 2013/Mid 2014)"; + if(ffStrbufCompS(hwModel, "MacBookPro10,2") == 0) return "MacBook Pro (Retina, 13-inch, Late 2012/Early 2013)"; + if(ffStrbufCompS(hwModel, "MacBookPro10,1") == 0) return "MacBook Pro (Retina, 15-inch, Mid 2012/Early 2013)"; + if(ffStrbufCompS(hwModel, "MacBookPro9,2") == 0) return "MacBook Pro (13-inch, Mid 2012)"; + if(ffStrbufCompS(hwModel, "MacBookPro9,1") == 0) return "MacBook Pro (15-inch, Mid 2012)"; + if(ffStrbufCompS(hwModel, "MacBookPro8,3") == 0) return "MacBook Pro (17-inch, 2011)"; + if(ffStrbufCompS(hwModel, "MacBookPro8,2") == 0) return "MacBook Pro (15-inch, 2011)"; + if(ffStrbufCompS(hwModel, "MacBookPro8,1") == 0) return "MacBook Pro (13-inch, 2011)"; + if(ffStrbufCompS(hwModel, "MacBookPro7,1") == 0) return "MacBook Pro (13-inch, Mid 2010)"; + if(ffStrbufCompS(hwModel, "MacBookPro6,2") == 0) return "MacBook Pro (15-inch, Mid 2010)"; + if(ffStrbufCompS(hwModel, "MacBookPro6,1") == 0) return "MacBook Pro (17-inch, Mid 2010)"; + if(ffStrbufCompS(hwModel, "MacBookPro5,5") == 0) return "MacBook Pro (13-inch, Mid 2009)"; + if(ffStrbufCompS(hwModel, "MacBookPro5,3") == 0) return "MacBook Pro (15-inch, Mid 2009)"; + if(ffStrbufCompS(hwModel, "MacBookPro5,2") == 0) return "MacBook Pro (17-inch, Mid/Early 2009)"; + if(ffStrbufCompS(hwModel, "MacBookPro5,1") == 0) return "MacBook Pro (15-inch, Late 2008)"; + if(ffStrbufCompS(hwModel, "MacBookPro4,1") == 0) return "MacBook Pro (17/15-inch, Early 2008)"; + if(ffStrbufCompS(hwModel, "Mac14,2") == 0) return "MacBook Air (M2, 2022)"; + if(ffStrbufCompS(hwModel, "MacBookAir10,1") == 0) return "MacBook Air (M1, 2020)"; + if(ffStrbufCompS(hwModel, "MacBookAir9,1") == 0) return "MacBook Air (Retina, 13-inch, 2020)"; + if(ffStrbufCompS(hwModel, "MacBookAir8,2") == 0) return "MacBook Air (Retina, 13-inch, 2019)"; + if(ffStrbufCompS(hwModel, "MacBookAir8,1") == 0) return "MacBook Air (Retina, 13-inch, 2018)"; + if(ffStrbufCompS(hwModel, "MacBookAir7,2") == 0) return "MacBook Air (13-inch, Early 2015/2017)"; + if(ffStrbufCompS(hwModel, "MacBookAir7,1") == 0) return "MacBook Air (11-inch, Early 2015)"; + if(ffStrbufCompS(hwModel, "MacBookAir6,2") == 0) return "MacBook Air (13-inch, Mid 2013/Early 2014)"; + if(ffStrbufCompS(hwModel, "MacBookAir6,1") == 0) return "MacBook Air (11-inch, Mid 2013/Early 2014)"; + if(ffStrbufCompS(hwModel, "MacBookAir5,2") == 0) return "MacBook Air (13-inch, Mid 2012)"; + if(ffStrbufCompS(hwModel, "MacBookAir5,1") == 0) return "MacBook Air (11-inch, Mid 2012)"; + if(ffStrbufCompS(hwModel, "MacBookAir4,2") == 0) return "MacBook Air (13-inch, Mid 2011)"; + if(ffStrbufCompS(hwModel, "MacBookAir4,1") == 0) return "MacBook Air (11-inch, Mid 2011)"; + if(ffStrbufCompS(hwModel, "MacBookAir3,2") == 0) return "MacBook Air (13-inch, Late 2010)"; + if(ffStrbufCompS(hwModel, "MacBookAir3,1") == 0) return "MacBook Air (11-inch, Late 2010)"; + if(ffStrbufCompS(hwModel, "MacBookAir2,1") == 0) return "MacBook Air (Mid 2009)"; + if(ffStrbufCompS(hwModel, "MacBook10,1") == 0) return "MacBook (Retina, 12-inch, 2017)"; + if(ffStrbufCompS(hwModel, "MacBook9,1") == 0) return "MacBook (Retina, 12-inch, Early 2016)"; + if(ffStrbufCompS(hwModel, "MacBook8,1") == 0) return "MacBook (Retina, 12-inch, Early 2015)"; + if(ffStrbufCompS(hwModel, "MacBook7,1") == 0) return "MacBook (13-inch, Mid 2010)"; + if(ffStrbufCompS(hwModel, "MacBook6,1") == 0) return "MacBook (13-inch, Late 2009)"; + if(ffStrbufCompS(hwModel, "MacBook5,2") == 0) return "MacBook (13-inch, Early/Mid 2009)"; + if(ffStrbufCompS(hwModel, "Mac13,1") == 0) return "Mac Studio (2022, Two USB-C front ports)"; + if(ffStrbufCompS(hwModel, "Mac13,2") == 0) return "Mac Studio (2022, Two Thunderbolt 4 front ports)"; + if(ffStrbufCompS(hwModel, "Macmini9,1") == 0) return "Mac mini (M1, 2020)"; + if(ffStrbufCompS(hwModel, "Macmini8,1") == 0) return "Mac mini (2018)"; + if(ffStrbufCompS(hwModel, "Macmini7,1") == 0) return "Mac mini (Mid 2014)"; + if(ffStrbufCompS(hwModel, "Macmini6,1") == 0 || + ffStrbufCompS(hwModel, "Macmini6,2") == 0) return "Mac mini (Late 2012)"; + if(ffStrbufCompS(hwModel, "Macmini5,1") == 0 || + ffStrbufCompS(hwModel, "Macmini5,2") == 0) return "Mac mini (Mid 2011)"; + if(ffStrbufCompS(hwModel, "Macmini4,1") == 0) return "Mac mini (Mid 2010)"; + if(ffStrbufCompS(hwModel, "Macmini3,1") == 0) return "Mac mini (Early/Late 2009)"; + if(ffStrbufCompS(hwModel, "MacPro7,1") == 0) return "Mac Pro (2019)"; + if(ffStrbufCompS(hwModel, "MacPro6,1") == 0) return "Mac Pro (Late 2013)"; + if(ffStrbufCompS(hwModel, "MacPro5,1") == 0) return "Mac Pro (Mid 2010 - Mid 2012)"; + if(ffStrbufCompS(hwModel, "MacPro4,1") == 0) return "Mac Pro (Early 2009)"; + if(ffStrbufCompS(hwModel, "iMac21,1") == 0 || + ffStrbufCompS(hwModel, "iMac21,2") == 0) return "iMac (24-inch, M1, 2021)"; + if(ffStrbufCompS(hwModel, "iMac20,1") == 0 || + ffStrbufCompS(hwModel, "iMac20,2") == 0) return "iMac (Retina 5K, 27-inch, 2020)"; + if(ffStrbufCompS(hwModel, "iMac19,1") == 0 || + ffStrbufCompS(hwModel, "iMac19,2") == 0) return "iMac (Retina 4K, 21.5-inch, 2019)"; + if(ffStrbufCompS(hwModel, "iMacPro1,1") == 0) return "iMac Pro (2017)"; + if(ffStrbufCompS(hwModel, "iMac18,3") == 0) return "iMac (Retina 5K, 27-inch, 2017)"; + if(ffStrbufCompS(hwModel, "iMac18,2") == 0) return "iMac (Retina 4K, 21.5-inch, 2017)"; + if(ffStrbufCompS(hwModel, "iMac18,1") == 0) return "iMac (21.5-inch, 2017)"; + if(ffStrbufCompS(hwModel, "iMac17,1") == 0) return "iMac (Retina 5K, 27-inch, Late 2015)"; + if(ffStrbufCompS(hwModel, "iMac16,2") == 0) return "iMac (Retina 4K, 21.5-inch, Late 2015)"; + if(ffStrbufCompS(hwModel, "iMac16,1") == 0) return "iMac (21.5-inch, Late 2015)"; + if(ffStrbufCompS(hwModel, "iMac15,1") == 0) return "iMac (Retina 5K, 27-inch, Late 2014 - Mid 2015)"; + if(ffStrbufCompS(hwModel, "iMac14,4") == 0) return "iMac (21.5-inch, Mid 2014)"; + if(ffStrbufCompS(hwModel, "iMac14,2") == 0) return "iMac (27-inch, Late 2013)"; + if(ffStrbufCompS(hwModel, "iMac14,1") == 0) return "iMac (21.5-inch, Late 2013)"; + if(ffStrbufCompS(hwModel, "iMac13,2") == 0) return "iMac (27-inch, Late 2012)"; + if(ffStrbufCompS(hwModel, "iMac13,1") == 0) return "iMac (21.5-inch, Late 2012)"; + if(ffStrbufCompS(hwModel, "iMac12,2") == 0) return "iMac (27-inch, Mid 2011)"; + if(ffStrbufCompS(hwModel, "iMac12,1") == 0) return "iMac (21.5-inch, Mid 2011)"; + if(ffStrbufCompS(hwModel, "iMac11,3") == 0) return "iMac (27-inch, Mid 2010)"; + if(ffStrbufCompS(hwModel, "iMac11,2") == 0) return "iMac (21.5-inch, Mid 2010)"; + if(ffStrbufCompS(hwModel, "iMac10,1") == 0) return "iMac (27/21.5-inch, Late 2009)"; + if(ffStrbufCompS(hwModel, "iMac9,1") == 0) return "iMac (24/20-inch, Early 2009)"; + return hwModel->chars; +} + void ffDetectHostImpl(FFHostResult* host) { ffStrbufInit(&host->productName); + ffStrbufInit(&host->productFamily); - ffStrbufInitA(&host->productFamily, 0); ffStrbufInitA(&host->sysVendor, 0); ffStrbufInitA(&host->productVersion, 0); ffStrbufInitA(&host->productSku, 0); @@ -20,5 +129,6 @@ void ffDetectHostImpl(FFHostResult* host) ffStrbufInitA(&host->chassisVendor, 0); ffStrbufInitA(&host->chassisVersion, 0); - ffSysctlGetString("hw.model", &host->productName); + ffSysctlGetString("hw.model", &host->productFamily); + ffStrbufAppendS(&host->productName, getProductName(&host->productFamily)); } diff --git a/src/detection/temps/temps_apple.c b/src/detection/temps/temps_apple.c new file mode 100644 index 000000000..ef21131b8 --- /dev/null +++ b/src/detection/temps/temps_apple.c @@ -0,0 +1,405 @@ +#include "fastfetch.h" +#include "temps_apple.h" + +#include +#include +#include + +static const char kDataTypeFlt[] = "flt "; +static const char kDataTypeFp1f[] = "fp1f"; +static const char kDataTypeFp4c[] = "fp4c"; +static const char kDataTypeFp5b[] = "fp5b"; +static const char kDataTypeFp6a[] = "fp6a"; +static const char kDataTypeFp79[] = "fp79"; +static const char kDataTypeFp88[] = "fp88"; +static const char kDataTypeFpa6[] = "fpa6"; +static const char kDataTypeFpc4[] = "fpc4"; +static const char kDataTypeFpe2[] = "fpe2"; +static const char kDataTypeSp1e[] = "sp1e"; +static const char kDataTypeSp3c[] = "sp3c"; +static const char kDataTypeSp4b[] = "sp4b"; +static const char kDataTypeSp5a[] = "sp5a"; +static const char kDataTypeSp69[] = "sp69"; +static const char kDataTypeSp78[] = "sp78"; +static const char kDataTypeSp87[] = "sp87"; +static const char kDataTypeSp96[] = "sp96"; +static const char kDataTypeSpb4[] = "spb4"; +static const char kDataTypeSpf0[] = "spf0"; +static const char kDataTypeUi8[] = "ui8 "; +static const char kDataTypeUi16[] = "ui16"; +static const char kDataTypeUi32[] = "ui32"; +static const char kDataTypeUi64[] = "ui64"; +static const char kDataTypeSi8[] = "si8 "; +static const char kDataTypeSi16[] = "si16"; +static const char kDataTypePwm[] = "{pwm"; + +static const char *kIOAppleSmcHiddenClassName = "AppleSMC"; +static const char kSmcCmdReadBytes = 5; +static const char kSmcCmdReadKeyInfo = 9; +static const uint32_t kKernelIndexSmc = 2; + +typedef struct +{ + char major; + char minor; + char build; + char reserved[1]; + uint16_t release; +} SmcKeyData_vers_t; + +typedef struct +{ + uint16_t version; + uint16_t length; + uint32_t cpuPLimit; + uint32_t gpuPLimit; + uint32_t memPLimit; +} SmcKeyData_pLimitData_t; + +typedef struct +{ + uint32_t dataSize; + uint32_t dataType; + char dataAttributes; +} SmcKeyData_keyInfo_t; + +typedef unsigned char SmcBytes_t[32]; + +typedef struct +{ + uint32_t key; + SmcKeyData_vers_t vers; + SmcKeyData_pLimitData_t pLimitData; + SmcKeyData_keyInfo_t keyInfo; + char result; + char status; + char data8; + uint32_t data32; + SmcBytes_t bytes; +} SmcKeyData_t; + +typedef char UInt32Char_t[5]; + +typedef struct +{ + UInt32Char_t key; + uint32_t dataSize; + UInt32Char_t dataType; + SmcBytes_t bytes; +} SmcVal_t; + +static uint32_t smcStrtoul(const char *str, int size, int base) +{ + uint32_t total = 0; + + for (int i = 0; i < size; i++) + { + if (base == 16) + total += (uint32_t)(str[i] << (size - 1 - i) * 8); + else + total += (uint32_t)((unsigned char)(str[i]) << (size - 1 - i) * 8); + } + return total; +} + +static void smcUltostr(char *str, uint32_t val) +{ + str[0] = '\0'; + sprintf(str, "%c%c%c%c", + (unsigned int)val >> 24, + (unsigned int)val >> 16, + (unsigned int)val >> 8, + (unsigned int)val); +} + +static const char *smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t *inputStructure, SmcKeyData_t *outputStructure) +{ + size_t structureInputSize; + size_t structureOutputSize; + structureInputSize = sizeof(SmcKeyData_t); + structureOutputSize = sizeof(SmcKeyData_t); + + if (IOConnectCallStructMethod(conn, selector, inputStructure, structureInputSize, outputStructure, &structureOutputSize) != kIOReturnSuccess) + return "IOConnectCallStructMethod(conn) failed"; + return NULL; +} + +// Provides key info, using a cache to dramatically improve the energy impact of smcFanControl +static const char *smcGetKeyInfo(io_connect_t conn, const uint32_t key, SmcKeyData_keyInfo_t *key_info) +{ + SmcKeyData_t inputStructure = {0}; + SmcKeyData_t outputStructure = {0}; + + inputStructure.key = key; + inputStructure.data8 = kSmcCmdReadKeyInfo; + + const char *error = smcCall(conn, kKernelIndexSmc, &inputStructure, &outputStructure); + if (error) + return error; + + *key_info = outputStructure.keyInfo; + return NULL; +} + +static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcVal_t *val) +{ + SmcKeyData_t inputStructure = {0}; + SmcKeyData_t outputStructure = {0}; + + inputStructure.key = smcStrtoul(key, 4, 16); + strcpy(val->key, key); + + const char *error = smcGetKeyInfo(conn, inputStructure.key, &outputStructure.keyInfo); + if (error) + return error; + + val->dataSize = outputStructure.keyInfo.dataSize; + smcUltostr(val->dataType, outputStructure.keyInfo.dataType); + inputStructure.keyInfo.dataSize = val->dataSize; + inputStructure.data8 = kSmcCmdReadBytes; + + error = smcCall(conn, kKernelIndexSmc, &inputStructure, &outputStructure); + if (error) + return error; + + memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes)); + + return NULL; +} + +static const char *smcOpen(io_connect_t *conn) +{ + CFMutableDictionaryRef matchDict = IOServiceMatching(kIOAppleSmcHiddenClassName); + if (matchDict == NULL) + return "IOServiceMatching(\"AppleSmartBattery\") failed"; + + io_iterator_t iterator; + if (IOServiceGetMatchingServices(MACH_PORT_NULL, matchDict, &iterator) != kIOReturnSuccess) + return "IOServiceGetMatchingServices() failed"; + + io_object_t device = IOIteratorNext(iterator); + IOObjectRelease(iterator); + if (device == 0) + return "No SMC device found"; + + kern_return_t result = IOServiceOpen(device, mach_task_self(), 0, conn); + IOObjectRelease(device); + if (result != kIOReturnSuccess) + return "IOServiceOpen() failed"; + + return NULL; +} + +static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, double *value) +{ + SmcVal_t val = {0}; + const char* error = smcReadSmcVal(conn, key, &val); + if (error != NULL) + return error; + + if (strcmp(val.dataType, kDataTypeUi8) == 0 || + strcmp(val.dataType, kDataTypeUi16) == 0 || + strcmp(val.dataType, kDataTypeUi32) == 0 || + strcmp(val.dataType, kDataTypeUi64) == 0) + { + uint64_t tmp = 0; + for (uint32_t i = 0; i < val.dataSize; i++) + tmp += (uint64_t)((uint8_t)(val.bytes[i]) * pow(256, val.dataSize - 1 - i)); + *value = tmp; + } + else if (strcmp(val.dataType, kDataTypeFlt) == 0) + { + *value = *(float *)(val.bytes); + } + else if (strcmp(val.dataType, kDataTypeFp1f) && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 32768.0; + } + else if (strcmp(val.dataType, kDataTypeFp4c) && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0; + } + else if (strcmp(val.dataType, kDataTypeFp5b) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0; + } + else if (strcmp(val.dataType, kDataTypeFp6a) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0; + } + else if (strcmp(val.dataType, kDataTypeFp79) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 512.0; + } + else if (strcmp(val.dataType, kDataTypeFp88) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 256.0; + } + else if (strcmp(val.dataType, kDataTypeFpa6) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 64.0; + } + else if (strcmp(val.dataType, kDataTypeFpc4) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 16.0; + } + else if (strcmp(val.dataType, kDataTypeFpe2) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 4.0; + } + else if (strcmp(val.dataType, kDataTypeSp1e) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 16384.0; + } + else if (strcmp(val.dataType, kDataTypeSp3c) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0; + } + else if (strcmp(val.dataType, kDataTypeSp4b) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0; + } + else if (strcmp(val.dataType, kDataTypeSp5a) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0; + } + else if (strcmp(val.dataType, kDataTypeSp69) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 512.0; + } + else if (strcmp(val.dataType, kDataTypeSp78) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 256.0; + } + else if (strcmp(val.dataType, kDataTypeSp87) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 128.0; + } + else if (strcmp(val.dataType, kDataTypeSp96) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 64.0; + } + else if (strcmp(val.dataType, kDataTypeSpb4) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 16.0; + } + else if (strcmp(val.dataType, kDataTypeSpf0) == 0 && val.dataSize == 2) + { + *value = ntohs(*(uint16_t *)(val.bytes)) / 1.0; + } + else if (strcmp(val.dataType, kDataTypeSi8) == 0 && val.dataSize == 1) + { + signed char *bytes = (signed char *)val.bytes; + int16_t temp = 0; + temp += (int8_t)(bytes[0]); + *value = temp; + } + else if (strcmp(val.dataType, kDataTypeSi16) == 0 && val.dataSize == 2) + { + *value = ntohs(*(int16_t *)(val.bytes)); + } + else if (strcmp(val.dataType, kDataTypePwm) == 0 && val.dataSize == 2) + { + *value = (double)ntohs(*(uint16_t *)(val.bytes)) * 100 / 65536.0; + } + else + return "Unknown SMC data type"; + return NULL; +} + +static void detectTemp(io_connect_t conn, const char *sensor, const char *name, FFlist *list) +{ + double temp = 0; + const char* error = smcReadValue(conn, sensor, &temp); + if (error) + return; + + FFTempValue* tempValue= (FFTempValue*)ffListAdd(list); + tempValue->value = temp; + + assert(strlen(sensor) == 4); + ffStrbufInitNS(&tempValue->deviceClass, 4, sensor); + + ffStrbufInitS(&tempValue->name, name); +} + +const char *ffDetectCoreTemps(enum FFTempType type, FFlist *result) +{ + static io_connect_t conn; + static dispatch_once_t once_control; + dispatch_once_f(&once_control, &conn, (dispatch_function_t) smcOpen); + if(!conn) + return "smcOpen() failed"; + + // https://github.com/exelban/stats/blob/master/Modules/Sensors/values.swift + switch (type) + { + case FF_TEMP_CPU_X64: + detectTemp(conn, "TC0D", "CPU diode", result); + detectTemp(conn, "TC0E", "CPU diode virtual", result); + detectTemp(conn, "TC0E", "CPU diode filtered", result); + detectTemp(conn, "TC0P", "CPU proximity", result); + break; + + case FF_TEMP_CPU_M1X: + detectTemp(conn, "Tp09", "CPU efficient core 1", result); + detectTemp(conn, "Tp0T", "CPU efficient core 2", result); + + detectTemp(conn, "Tp01", "CPU performance core 1", result); + detectTemp(conn, "Tp05", "CPU performance core 2", result); + detectTemp(conn, "Tp0D", "CPU performance core 3", result); + detectTemp(conn, "Tp0H", "CPU performance core 4", result); + detectTemp(conn, "Tp0L", "CPU performance core 5", result); + detectTemp(conn, "Tp0P", "CPU performance core 6", result); + detectTemp(conn, "Tp0X", "CPU performance core 7", result); + detectTemp(conn, "Tp0b", "CPU performance core 8", result); + break; + + case FF_TEMP_CPU_M2X: + detectTemp(conn, "Tp05", "CPU efficient core 1", result); + detectTemp(conn, "Tp0D", "CPU efficient core 2", result); + detectTemp(conn, "Tp0j", "CPU efficient core 3", result); + detectTemp(conn, "Tp0r", "CPU efficient core 4", result); + + detectTemp(conn, "Tp01", "CPU performance core 1", result); + detectTemp(conn, "Tp09", "CPU performance core 2", result); + detectTemp(conn, "Tp0f", "CPU performance core 3", result); + detectTemp(conn, "Tp0n", "CPU performance core 4", result); + break; + + case FF_TEMP_GPU_INTEL: + detectTemp(conn, "TCGC", "GPU Intel Graphics", result); + detectTemp(conn, "TG0D", "GPU diode", result); + detectTemp(conn, "TG0P", "GPU proximity", result); + break; + + case FF_TEMP_GPU_AMD: + detectTemp(conn, "TGDD", "GPU AMD Radeon", result); + detectTemp(conn, "TG0D", "GPU diode", result); + detectTemp(conn, "TG0P", "GPU proximity", result); + break; + + case FF_TEMP_GPU_UNKNOWN: // Nvidia? + detectTemp(conn, "TG0D", "GPU diode", result); + detectTemp(conn, "TG0P", "GPU proximity", result); + break; + + case FF_TEMP_GPU_M1X: + detectTemp(conn, "Tg05", "GPU 1", result); + detectTemp(conn, "Tg0D", "GPU 2", result); + detectTemp(conn, "Tg0L", "GPU 3", result); + detectTemp(conn, "Tg0T", "GPU 4", result); + break; + + case FF_TEMP_GPU_M2X: + detectTemp(conn, "Tg0f", "GPU 1", result); + detectTemp(conn, "Tg0n", "GPU 2", result); + break; + + case FF_TEMP_BATTERY: + detectTemp(conn, "TB1T", "Battery", result); + break; + } + + return NULL; +} diff --git a/src/detection/temps/temps_apple.h b/src/detection/temps/temps_apple.h new file mode 100644 index 000000000..8ac83e22d --- /dev/null +++ b/src/detection/temps/temps_apple.h @@ -0,0 +1,33 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_temps_apple +#define FF_INCLUDED_detection_temps_apple + +#include "fastfetch.h" +#include "util/FFlist.h" + +typedef struct FFTempValue +{ + FFstrbuf name; + FFstrbuf deviceClass; + double value; +} FFTempValue; + +enum FFTempType +{ + FF_TEMP_CPU_X64, + FF_TEMP_CPU_M1X, + FF_TEMP_CPU_M2X, + + FF_TEMP_GPU_INTEL, + FF_TEMP_GPU_AMD, + FF_TEMP_GPU_UNKNOWN, + FF_TEMP_GPU_M1X, + FF_TEMP_GPU_M2X, + + FF_TEMP_BATTERY, +}; + +const char *ffDetectCoreTemps(enum FFTempType type, FFlist *result); + +#endif diff --git a/src/detection/temps.c b/src/detection/temps/temps_linux.c similarity index 98% rename from src/detection/temps.c rename to src/detection/temps/temps_linux.c index 391a05954..5fad783d5 100644 --- a/src/detection/temps.c +++ b/src/detection/temps/temps_linux.c @@ -1,6 +1,6 @@ #include "fastfetch.h" -#include "detection/temps.h" #include "common/io.h" +#include "temps_linux.h" #include #include diff --git a/src/detection/temps.h b/src/detection/temps/temps_linux.h similarity index 78% rename from src/detection/temps.h rename to src/detection/temps/temps_linux.h index 3f923b0ff..6bece23ed 100644 --- a/src/detection/temps.h +++ b/src/detection/temps/temps_linux.h @@ -1,7 +1,7 @@ #pragma once -#ifndef FF_INCLUDED_detection_temps -#define FF_INCLUDED_detection_temps +#ifndef FF_INCLUDED_detection_temps_linux +#define FF_INCLUDED_detection_temps_linux #include "fastfetch.h" diff --git a/src/fastfetch.c b/src/fastfetch.c index 090e84936..cbf56a96e 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -1253,6 +1253,12 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con //Module options// ////////////////// + else if(strcasecmp(key, "--cpu-temp") == 0) + instance->config.cpuTemp = optionParseBoolean(value); + else if(strcasecmp(key, "--gpu-temp") == 0) + instance->config.gpuTemp = optionParseBoolean(value); + else if(strcasecmp(key, "--battery-temp") == 0) + instance->config.batteryTemp = optionParseBoolean(value); else if(strcasecmp(key, "--title-fqdn") == 0) instance->config.titleFQDN = optionParseBoolean(value); else if(strcasecmp(key, "--disk-folders") == 0) @@ -1263,12 +1269,16 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.batteryDir); else if(strcasecmp(key, "--separator-string") == 0) optionParseString(key, value, &instance->config.separatorString); + else if(strcasecmp(key, "--font-inline") == 0) + instance->config.fontInline = optionParseBoolean(value); else if(strcasecmp(key, "--localip-show-ipv4") == 0) instance->config.localIpShowIpV4 = optionParseBoolean(value); else if(strcasecmp(key, "--localip-show-ipv6") == 0) instance->config.localIpShowIpV6 = optionParseBoolean(value); else if(strcasecmp(key, "--localip-show-loop") == 0) instance->config.localIpShowLoop = optionParseBoolean(value); + else if(strcasecmp(key, "--localip-name-prefix") == 0) + optionParseString(key, value, &instance->config.localIpNamePrefix); else if(strcasecmp(key, "--os-file") == 0) optionParseString(key, value, &instance->config.osFile); else if(strcasecmp(key, "--player-name") == 0) @@ -1428,6 +1438,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char ffPrintOpenGL(instance); else if(strcasecmp(line, "opencl") == 0) ffPrintOpenCL(instance); + else if(strcasecmp(line, "users") == 0) + ffPrintUsers(instance); else ffPrintErrorString(instance, line, 0, NULL, NULL, ""); } diff --git a/src/fastfetch.h b/src/fastfetch.h index 0eb435ec2..a8178453d 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -152,6 +152,10 @@ typedef struct FFconfig FFstrbuf libplist; FFstrbuf libcJSON; + bool cpuTemp; + bool gpuTemp; + bool batteryTemp; + bool titleFQDN; FFstrbuf diskFolders; @@ -161,9 +165,12 @@ typedef struct FFconfig FFstrbuf separatorString; + bool fontInline; + bool localIpShowLoop; bool localIpShowIpV4; bool localIpShowIpV6; + FFstrbuf localIpNamePrefix; uint32_t publicIpTimeout; @@ -270,5 +277,6 @@ void ffPrintColors(FFinstance* instance); void ffPrintVulkan(FFinstance* instance); void ffPrintOpenGL(FFinstance* instance); void ffPrintOpenCL(FFinstance* instance); +void ffPrintUsers(FFinstance* instance); #endif diff --git a/src/flashfetch.c b/src/flashfetch.c index 8688b918c..296d589f0 100644 --- a/src/flashfetch.c +++ b/src/flashfetch.c @@ -52,6 +52,7 @@ int main(int argc, char** argv) //ffPrintVulkan(&instance); //ffPrintOpenGL(&instance); //ffPrintOpenCL(&instance); + //ffPrintUsers(&instance); ffPrintBreak(&instance); ffPrintColors(&instance); diff --git a/src/modules/battery.c b/src/modules/battery.c index 8900ef2ec..58773bf0a 100644 --- a/src/modules/battery.c +++ b/src/modules/battery.c @@ -5,7 +5,7 @@ #define FF_BATTERY_MODULE_NAME "Battery" #define FF_BATTERY_NUM_FORMAT_ARGS 5 -static void printBattery(FFinstance* instance, const BatteryResult* result, uint8_t index) +static void printBattery(FFinstance* instance, BatteryResult* result, uint8_t index) { if(instance->config.battery.outputFormat.length == 0) { @@ -32,6 +32,9 @@ static void printBattery(FFinstance* instance, const BatteryResult* result, uint putchar(']'); } + if(result->temperature == result->temperature) //FF_BATTERY_TEMP_UNSET + printf(" - %.1f°C", result->temperature); + putchar('\n'); } else @@ -41,7 +44,8 @@ static void printBattery(FFinstance* instance, const BatteryResult* result, uint {FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->technology}, {FF_FORMAT_ARG_TYPE_STRBUF, &result->capacity}, - {FF_FORMAT_ARG_TYPE_STRBUF, &result->status} + {FF_FORMAT_ARG_TYPE_STRBUF, &result->status}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &result->temperature}, }); } } diff --git a/src/modules/cpu.c b/src/modules/cpu.c index b30db7fc7..89c40fb99 100644 --- a/src/modules/cpu.c +++ b/src/modules/cpu.c @@ -36,6 +36,9 @@ void ffPrintCPU(FFinstance* instance) if(cpu->frequencyMax > 0.0) printf(" @ %.9g GHz", cpu->frequencyMax); + if(cpu->temperature == cpu->temperature) //FF_CPU_TEMP_UNSET + printf(" - %.1f°C", cpu->temperature); + putchar('\n'); } else diff --git a/src/modules/cursor.c b/src/modules/cursor.c index 5d6aa4d59..c0f572823 100644 --- a/src/modules/cursor.c +++ b/src/modules/cursor.c @@ -11,6 +11,8 @@ #define FF_CURSOR_MODULE_NAME "Cursor" #define FF_CURSOR_NUM_FORMAT_ARGS 2 +#if !(defined(__ANDROID__) || defined(__APPLE__)) + static void printCursor(FFinstance* instance, FFstrbuf* cursorTheme, const FFstrbuf* cursorSize) { ffStrbufRemoveIgnCaseEndS(cursorTheme, "cursors"); @@ -190,12 +192,17 @@ static bool printCursorFromEnv(FFinstance* instance) return true; } +#endif + void ffPrintCursor(FFinstance* instance) { - #ifdef __ANDROID__ - ffPrintError(instance, FF_CURSOR_MODULE_NAME, 0, &instance->config.cursor, "Cursor detection is not supported on Android"); - return; - #endif + #if defined(__ANDROID__) || defined(__APPLE__) + + FF_UNUSED(instance); + ffPrintError(instance, FF_CURSOR_MODULE_NAME, 0, &instance->config.cursor, "Cursor detection is not supported"); + return; + + #else const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); @@ -243,4 +250,6 @@ void ffPrintCursor(FFinstance* instance) ) return; printCursorGTK(instance); + + #endif } diff --git a/src/modules/font.c b/src/modules/font.c index 7abc84d22..fff39939d 100644 --- a/src/modules/font.c +++ b/src/modules/font.c @@ -1,21 +1,13 @@ #include "fastfetch.h" -#include "common/font.h" #include "common/printing.h" -#include "common/parsing.h" -#include "detection/qt.h" -#include "detection/gtk.h" +#include "detection/font/font.h" #include "detection/displayserver/displayserver.h" #define FF_FONT_MODULE_NAME "Font" -#define FF_FONT_NUM_FORMAT_ARGS 21 +#define FF_FONT_NUM_FORMAT_ARGS 2 void ffPrintFont(FFinstance* instance) { - #ifdef __ANDROID__ - ffPrintError(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font, "Font detection is not supported on Android"); - return; - #endif - const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0) @@ -24,76 +16,47 @@ void ffPrintFont(FFinstance* instance) return; } - const FFstrbuf* plasmaRaw = &ffDetectQt(instance)->font; - const FFstrbuf* gtk2Raw = &ffDetectGTK2(instance)->font; - const FFstrbuf* gtk3Raw = &ffDetectGTK3(instance)->font; - const FFstrbuf* gtk4Raw = &ffDetectGTK4(instance)->font; - - if(plasmaRaw->length == 0 && gtk2Raw->length == 0 && gtk3Raw->length == 0 && gtk4Raw->length == 0) + FFlist list; + ffListInit(&list, sizeof(FFFontResult)); + const char* error = ffDetectFontImpl(instance, &list); + if(error) { - ffPrintError(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font, "No fonts found"); + ffPrintError(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font, "%s", error); return; } - FFfont plasma; - ffFontInitQt(&plasma, plasmaRaw->chars); - - FFfont gtk2; - ffFontInitPango(>k2, gtk2Raw->chars); - - FFfont gtk3; - ffFontInitPango(>k3, gtk3Raw->chars); - - FFfont gtk4; - ffFontInitPango(>k4, gtk4Raw->chars); - - FFstrbuf gtk; - ffStrbufInitA(>k, 64); - ffParseGTK(>k, >k2.pretty, >k3.pretty, >k4.pretty); - - if(instance->config.font.outputFormat.length == 0) + if (instance->config.font.outputFormat.length == 0 && instance->config.fontInline) { ffPrintLogoAndKey(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font.key); - if(plasma.pretty.length > 0) + for(uint32_t i = 0; i < list.length; ++i) { - ffStrbufWriteTo(&plasma.pretty, stdout); - fputs(" [QT]", stdout); - - if(gtk.length > 0) - fputs(", ", stdout); + FFFontResult* font = (FFFontResult*)ffListGet(&list, i); + printf("[%s] %*s%s", font->type, font->fontPretty.length, font->fontPretty.chars, i < list.length - 1 ? ", " : ""); + ffStrbufDestroy(&font->fontPretty); } - ffStrbufPutTo(>k, stdout); + putchar('\n'); } else { - ffPrintFormat(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font, FF_FONT_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRBUF, plasmaRaw}, - {FF_FORMAT_ARG_TYPE_STRBUF, &plasma.name}, - {FF_FORMAT_ARG_TYPE_STRBUF, &plasma.size}, - {FF_FORMAT_ARG_TYPE_LIST, &plasma.styles}, - {FF_FORMAT_ARG_TYPE_STRBUF, &plasma.pretty}, - {FF_FORMAT_ARG_TYPE_STRBUF, gtk2Raw}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k2.name}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k2.size}, - {FF_FORMAT_ARG_TYPE_LIST, >k2.styles}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k2.pretty}, - {FF_FORMAT_ARG_TYPE_STRBUF, gtk3Raw}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k3.name}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k3.size}, - {FF_FORMAT_ARG_TYPE_LIST, >k3.styles}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k3.pretty}, - {FF_FORMAT_ARG_TYPE_STRBUF, gtk4Raw}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k4.name}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k4.size}, - {FF_FORMAT_ARG_TYPE_LIST, >k4.styles}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k4.pretty}, - {FF_FORMAT_ARG_TYPE_STRBUF, >k} - }); + for(uint32_t i = 0; i < list.length; ++i) + { + FFFontResult* font = (FFFontResult*)ffListGet(&list, i); + if(instance->config.font.outputFormat.length == 0) + { + char keyChars[32]; + snprintf(keyChars, sizeof(keyChars), "%s (%s)", FF_FONT_MODULE_NAME, font->type); + ffPrintLogoAndKey(instance, keyChars, 0, &instance->config.font.key); + puts(font->fontPretty.chars); + } + else + { + ffPrintFormat(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font, FF_FONT_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRING, font->type}, + {FF_FORMAT_ARG_TYPE_STRBUF, &font->fontPretty} + }); + } + ffStrbufDestroy(&font->fontPretty); + } } - - ffFontDestroy(&plasma); - ffFontDestroy(>k2); - ffFontDestroy(>k3); - ffFontDestroy(>k4); - ffStrbufDestroy(>k); + ffListDestroy(&list); } diff --git a/src/modules/gpu.c b/src/modules/gpu.c index 93aaa6940..c98ca3af8 100644 --- a/src/modules/gpu.c +++ b/src/modules/gpu.c @@ -25,11 +25,14 @@ static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, if(gpu->coreCount != FF_GPU_CORE_COUNT_UNSET) ffStrbufAppendF(&output, " (%d)", gpu->coreCount); + if(gpu->temperature == gpu->temperature) //FF_GPU_TEMP_UNSET + ffStrbufAppendF(&output, " - %.1f°C", gpu->temperature); + ffPrintAndAppendToCache(instance, FF_GPU_MODULE_NAME, index, &instance->config.gpu, cache, &output, FF_GPU_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->vendor}, {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->name}, {FF_FORMAT_ARG_TYPE_STRBUF, &gpu->driver}, - {FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->temperature}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->temperature}, //FIXME: temperature shouldn't be cached {FF_FORMAT_ARG_TYPE_INT, &gpu->coreCount}, }); diff --git a/src/modules/icons.c b/src/modules/icons.c index 36e12230c..38d0823fb 100644 --- a/src/modules/icons.c +++ b/src/modules/icons.c @@ -10,10 +10,13 @@ void ffPrintIcons(FFinstance* instance) { - #ifdef __ANDROID__ - ffPrintError(instance, FF_ICONS_MODULE_NAME, 0, &instance->config.icons, "Icons detection is not supported on Android"); - return; - #endif + #if defined(__ANDROID__) || defined(__APPLE__) + + FF_UNUSED(instance); + ffPrintError(instance, FF_ICONS_MODULE_NAME, 0, &instance->config.icons, "Icons detection is not supported"); + return; + + #else const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); @@ -64,4 +67,6 @@ void ffPrintIcons(FFinstance* instance) } ffStrbufDestroy(>kPretty); + + #endif } diff --git a/src/modules/localip.c b/src/modules/localip.c index 0976579a1..9308d246a 100644 --- a/src/modules/localip.c +++ b/src/modules/localip.c @@ -62,6 +62,9 @@ void ffPrintLocalIp(FFinstance* instance) if (strncmp(ifa->ifa_name, "lo", 2) == 0 && (ifa->ifa_name[2] == '\0' || isdigit(ifa->ifa_name[2])) && !instance->config.localIpShowLoop) continue; + if (instance->config.localIpNamePrefix.length && strncmp(ifa->ifa_name, instance->config.localIpNamePrefix.chars, instance->config.localIpNamePrefix.length) != 0) + continue; + if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4 // is a valid IP4 Address if (!instance->config.localIpShowIpV4) diff --git a/src/modules/theme.c b/src/modules/theme.c index e3b2387b2..612bb6b96 100644 --- a/src/modules/theme.c +++ b/src/modules/theme.c @@ -10,10 +10,13 @@ void ffPrintTheme(FFinstance* instance) { - #ifdef __ANDROID__ - ffPrintError(instance, FF_THEME_MODULE_NAME, 0, &instance->config.theme, "Theme detection is not supported on Android"); - return; - #endif + #if defined(__ANDROID__) || defined(__APPLE__) + + FF_UNUSED(instance); + ffPrintError(instance, FF_THEME_MODULE_NAME, 0, &instance->config.theme, "Theme detection is not supported"); + return; + + #else const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); @@ -98,4 +101,6 @@ void ffPrintTheme(FFinstance* instance) ffStrbufDestroy(&plasmaColorPretty); ffStrbufDestroy(>kPretty); + + #endif } diff --git a/src/modules/users.c b/src/modules/users.c new file mode 100644 index 000000000..880b14c35 --- /dev/null +++ b/src/modules/users.c @@ -0,0 +1,54 @@ +#include "fastfetch.h" +#include "common/printing.h" + +#include + +#define FF_USERS_MODULE_NAME "Users" +#define FF_USERS_NUM_FORMAT_ARGS 1 + +void ffPrintUsers(FFinstance* instance) +{ + struct utmpx* n = NULL; + setutxent(); + + FFlist users; + ffListInit(&users, sizeof(n->ut_user)); + +next: + while((n = getutxent())) + { + if(n->ut_type == USER_PROCESS) + { + for(uint32_t i = 0; i < users.length; ++i) + { + if(strcmp((const char*)ffListGet(&users, i), n->ut_user) == 0) + goto next; + } + strcpy((char*)ffListAdd(&users), n->ut_user); + } + } + + FFstrbuf result; + ffStrbufInit(&result); + for(uint32_t i = 0; i < users.length; ++i) + { + if(i > 0) + ffStrbufAppendS(&result, ", "); + ffStrbufAppendS(&result, (const char*)ffListGet(&users, i)); + } + ffListDestroy(&users); + + if(instance->config.uptime.outputFormat.length == 0) + { + ffPrintLogoAndKey(instance, FF_USERS_MODULE_NAME, 0, &instance->config.uptime.key); + puts(result.chars); + } + else + { + ffPrintFormat(instance, FF_USERS_MODULE_NAME, 0, &instance->config.uptime, FF_USERS_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRBUF, &result}, + }); + } + + ffStrbufDestroy(&result); +} diff --git a/src/util/FFlist.h b/src/util/FFlist.h index 0ec1f2899..d1eee05ad 100644 --- a/src/util/FFlist.h +++ b/src/util/FFlist.h @@ -29,12 +29,13 @@ void ffListDestroy(FFlist* list); static inline void ffListInit(FFlist* list, uint32_t elementSize) { + assert(elementSize > 0); ffListInitA(list, elementSize, 0); } static inline void* ffListGet(const FFlist* list, uint32_t index) { - assert(list->capacity > 0); + assert(list->capacity > index); return list->data + (index * list->elementSize); } diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 1b152ae44..b302bce0a 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -363,42 +363,6 @@ void ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c) ffStrbufSubstrAfter(strbuf, index); } -bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) -{ - for(uint32_t i = 0; start[i] != '\0'; i++) - { - if(i >= strbuf->length) - return false; - - if(tolower(strbuf->chars[i]) != tolower(start[i])) - return false; - } - return true; -} - -bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) -{ - if (start->length > strbuf->length) - return false; - return ffStrbufStartsWithIgnCaseS(strbuf, start->chars); -} - -bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) -{ - return strbuf->length == 0 ? false : - strbuf->chars[strbuf->length - 1] == c; -} - -bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) -{ - uint32_t endLength = (uint32_t) strlen(end); - - if(endLength > strbuf->length) - return false; - - return memcmp(strbuf->chars + strbuf->length - endLength, end, endLength) == 0; -} - uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c) { uint32_t result = 0; @@ -411,26 +375,11 @@ uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c) return result; } -static bool testEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end, uint32_t* endLength) -{ - *endLength = (uint32_t) strlen(end); - - if(*endLength > strbuf->length) - return false; - - for(uint32_t i = 0; i < *endLength; ++i) - { - if(tolower(strbuf->chars[strbuf->length - *endLength + i]) != tolower(end[i])) - return false; - } - - return true; -} bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end) { - uint32_t endLength; - if(testEndsWithIgnCaseS(strbuf, end, &endLength)) + uint32_t endLength = (uint32_t) strlen(end); + if(ffStrbufEndsWithIgnCaseNS(strbuf, endLength, end)) { ffStrbufSubstrBefore(strbuf, strbuf->length - endLength); return true; diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 84db2f060..23f2e48f1 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -70,12 +70,6 @@ void ffStrbufSubstrAfterFirstC(FFstrbuf* strbuf, char c); void ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str); void ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c); -bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start); -bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start); - -bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c); -bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end); - FF_C_NODISCARD uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c); bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end); @@ -110,9 +104,20 @@ static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value) ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value); } -static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) +static inline void ffStrbufInit(FFstrbuf* strbuf) { ffStrbufInitA(strbuf, 0); +} + +static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str) +{ + ffStrbufInit(strbuf); + ffStrbufAppendNS(strbuf, length, str); +} + +static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) +{ + ffStrbufInit(strbuf); ffStrbufAppendS(strbuf, str); } @@ -124,11 +129,6 @@ static inline void ffStrbufAppend(FFstrbuf* strbuf, const FFstrbuf* value) ffStrbufAppendNS(strbuf, value->length, value->chars); } -static inline void ffStrbufInit(FFstrbuf* strbuf) -{ - ffStrbufInitA(strbuf, 0); -} - static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) { if(value == NULL) @@ -199,4 +199,62 @@ static inline FF_C_NODISCARD bool ffStrbufStartsWith(const FFstrbuf* strbuf, con { return ffStrbufStartsWithSN(strbuf, start->chars, start->length); } + +static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start) +{ + if(length > strbuf->length) + return false; + return strncasecmp(strbuf->chars, start, length) == 0; +} + +static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) +{ + return ffStrbufStartsWithIgnCaseNS(strbuf, (uint32_t) strlen(start), start); +} + +static inline FF_C_NODISCARD bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) +{ + return ffStrbufStartsWithIgnCaseNS(strbuf, start->length, start->chars); +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) +{ + return strbuf->length == 0 ? false : + strbuf->chars[strbuf->length - 1] == c; +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) +{ + if(endLength > strbuf->length) + return false; + + return memcmp(strbuf->chars + strbuf->length - endLength, end, endLength) == 0; +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) +{ + return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end); +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end) +{ + return ffStrbufEndsWithNS(strbuf, end->length, end->chars); +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) +{ + if(endLength > strbuf->length) + return false; + return strcasecmp(strbuf->chars + strbuf->length - endLength, end) == 0; +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end) +{ + return ffStrbufEndsWithIgnCaseNS(strbuf, (uint32_t) strlen(end), end); +} + +static inline FF_C_NODISCARD bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end) +{ + return ffStrbufEndsWithIgnCaseNS(strbuf, end->length, end->chars); +} #endif diff --git a/tests/strbuf.c b/tests/strbuf.c index da26e50e7..403da59d5 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -156,6 +156,21 @@ int main(int argc, char** argv) VERIFY(ffStrbufNextIndexS(&strbuf, 1, "1") == 3); VERIFY(ffStrbufNextIndexS(&strbuf, 4, "1") == 5); + //ignCase + ffStrbufSetS(&strbuf, "AbCdEfG"); + + VERIFY(ffStrbufIgnCaseCompS(&strbuf, "aBcDeFg") == 0); + VERIFY(ffStrbufStartsWithIgnCaseS(&strbuf, "ABCD")); + VERIFY(ffStrbufEndsWithIgnCaseS(&strbuf, "defg")); + VERIFY(!ffStrbufStartsWithIgnCaseS(&strbuf, "aBcDeFgH")); + VERIFY(!ffStrbufEndsWithIgnCaseS(&strbuf, "0aBcDeFg")); + + //ensure + ffStrbufEnsureEndsWithC(&strbuf, '^'); + VERIFY(ffStrbufCompS(&strbuf, "^aBcDeFg")); + ffStrbufEnsureEndsWithC(&strbuf, '$'); + VERIFY(ffStrbufCompS(&strbuf, "^aBcDeFg$")); + //Destroy ffStrbufDestroy(&strbuf);