diff --git a/CMakeLists.txt b/CMakeLists.txt index f28620b3c6..533340744e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR BSD" OFF) cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD" OFF) cmake_dependent_option(ENABLE_LIBPLIST "Enable libplist" ON "APPLE" OFF) cmake_dependent_option(ENABLE_LIBCJSON "Enable libcjson" ON "LINUX" OFF) +cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds @@ -338,6 +339,11 @@ if(HAVE_SYSINFO_H) target_compile_definitions(libfastfetch PUBLIC FF_HAVE_SYSINFO_H) endif() +CHECK_INCLUDE_FILE("utmpx.h" HAVE_UTMPX_H) +if(HAVE_UTMPX_H) + target_compile_definitions(libfastfetch PRIVATE FF_HAVE_UTMPX_H) +endif() + function(ff_lib_enable VARNAME) if(NOT ENABLE_${VARNAME}) return() @@ -384,6 +390,7 @@ ff_lib_enable(OSMESA osmesa) ff_lib_enable(OPENCL OpenCL) ff_lib_enable(LIBPLIST libplist-2.0) ff_lib_enable(LIBCJSON libcjson) +ff_lib_enable(FREETYPE freetype2) if(APPLE) target_link_libraries(libfastfetch diff --git a/README.md b/README.md index 41ad3fbada..7542ada8f4 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ The following libraries are used if present at runtime: * [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE. * [`libplist`](https://github.com/libimobiledevice/libplist): Binary `plist` file parser ( macOS ). Needed for iTerm2 Terminal font and WM Theme. * [`libcJSON`](https://github.com/DaveGamble/cJSON): Needed for Windows Terminal font ( WSL ). +* [`freetype`](https://www.freetype.org/): Needed for Termux font detection ( Android ). ## Support status All categories not listed here should work without needing a specific implementation. @@ -82,7 +83,7 @@ KDE Plasma, Gnome, Cinnamon, Mate, XFCE4, LXQt ##### Terminal fonts ``` -Konsole, Gnome Terminal, Tilix, XFCE4 Terminal, Alacritty, LXTerminal, iTerm2, Apple Terminal, TTY, Windows Terminal +Konsole, Gnome Terminal, Tilix, XFCE4 Terminal, Alacritty, LXTerminal, iTerm2, Apple Terminal, TTY, Windows Terminal, Termux ``` ## Building diff --git a/completions/bash b/completions/bash index 11313cc65a..5c645d898c 100644 --- a/completions/bash +++ b/completions/bash @@ -326,6 +326,9 @@ __fastfetch_completion() "--opencl-key" "--opencl-format" "--opencl-error" + "--users-key" + "--users-format" + "--users-error" ) local FF_OPTIONS_PATH=( diff --git a/src/common/init.c b/src/common/init.c index 322e661c9a..53fe6467a3 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -196,6 +196,7 @@ static void defaultConfig(FFinstance* instance) initModuleArg(&instance->config.vulkan); initModuleArg(&instance->config.openGL); initModuleArg(&instance->config.openCL); + initModuleArg(&instance->config.users); ffStrbufInitA(&instance->config.libPCI, 0); ffStrbufInitA(&instance->config.libVulkan, 0); @@ -219,6 +220,7 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.libOpenCL, 0); ffStrbufInitA(&instance->config.libplist, 0); ffStrbufInitA(&instance->config.libcJSON, 0); + ffStrbufInitA(&instance->config.libfreetype, 0); instance->config.cpuTemp = false; instance->config.gpuTemp = false; @@ -356,6 +358,8 @@ static void exitSignalHandler(int signal) void ffStart(FFinstance* instance) { + ffPrepareCPUUsage(); + if(instance->config.multithreading) startDetectionThreads(instance); @@ -477,6 +481,15 @@ void ffListFeatures() #ifdef FF_HAVE_OPENCL "opencl\n" #endif + #ifdef FF_HAVE_LIBPLIST + "libplist\n" + #endif + #ifdef FF_HAVE_LIBCJSON + "libcjson\n" + #endif + #ifdef FF_HAVE_FREETYPE + "freetype" + #endif "" , stdout); } diff --git a/src/data/config_user.txt b/src/data/config_user.txt index 1ded95bfcb..d745e0ba6f 100644 --- a/src/data/config_user.txt +++ b/src/data/config_user.txt @@ -219,6 +219,7 @@ #--vulkan-key Vulkan #--opengl-key OpenGL #--opencl-key OpenCL +#--users-key Users # Format options: # Sets the format string for module values. @@ -259,6 +260,7 @@ #--vulkan-format #--opengl-format #--opencl-format +#--users-format # Error options: # Sets the format string to use if an error occured @@ -299,6 +301,7 @@ #--vulkan-error #--opengl-error #--opencl-error +#--users-error # Library options: # Sets an user specific path to a library to load. @@ -325,3 +328,4 @@ #--lib-opencl /usr/lib/libOpenCL.so #--lib-plist /usr/local/bin/libplist-2.0.dylib #--lib-cjson /usr/lib/libcjson.so +#--lib-freetype /data/data/com.termux/files/usr/lib diff --git a/src/detection/cpuUsage/cpuUsage.h b/src/detection/cpuUsage/cpuUsage.h index 577d2a3746..cddd1866bc 100644 --- a/src/detection/cpuUsage/cpuUsage.h +++ b/src/detection/cpuUsage/cpuUsage.h @@ -3,6 +3,6 @@ #ifndef FF_INCLUDED_detection_cpu_cpuUsage #define FF_INCLUDED_detection_cpu_cpuUsage -const char* ffGetCpuUsagePercent(double* result); +const char* ffGetCpuUsageInfo(long* inUseAll, long* totalAll); #endif diff --git a/src/detection/cpuUsage/cpuUsage_apple.c b/src/detection/cpuUsage/cpuUsage_apple.c index 49f1d34c88..e170a7cebc 100644 --- a/src/detection/cpuUsage/cpuUsage_apple.c +++ b/src/detection/cpuUsage/cpuUsage_apple.c @@ -3,13 +3,13 @@ #include #include -#include -static const char* getCpuUsageInfo(long* inUseAll, long* totalAll) +const char* ffGetCpuUsageInfo(long* inUseAll, long* totalAll) { natural_t numCPUs = 0U; processor_info_array_t cpuInfo; mach_msg_type_number_t numCpuInfo; + *inUseAll = *totalAll = 0; if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUs, &cpuInfo, &numCpuInfo) != KERN_SUCCESS) return "host_processor_info() failed"; @@ -26,21 +26,3 @@ static const char* getCpuUsageInfo(long* inUseAll, long* totalAll) } return NULL; } - -const char* ffGetCpuUsagePercent(double* result) -{ - long inUseAll1 = 0, totalAll1 = 0; - const char* error = getCpuUsageInfo(&inUseAll1, &totalAll1); - if(error) - return error; - - sleep(1); - - long inUseAll2 = 0, totalAll2 = 0; - error = getCpuUsageInfo(&inUseAll2, &totalAll2); - if(error) - return error; - - *result = (double)(inUseAll2 - inUseAll1) / (double)(totalAll2 - totalAll1) * 100; - return NULL; -} diff --git a/src/detection/cpuUsage/cpuUsage_linux.c b/src/detection/cpuUsage/cpuUsage_linux.c index 499759a822..3696a8d77b 100644 --- a/src/detection/cpuUsage/cpuUsage_linux.c +++ b/src/detection/cpuUsage/cpuUsage_linux.c @@ -1,13 +1,16 @@ #include "fastfetch.h" #include "cpuUsage.h" -#include #include -static const char* getCpuUsageInfo(FILE* procStat, long* inUseAll, long* totalAll) +const char* ffGetCpuUsageInfo(long* inUseAll, long* totalAll) { long user, nice, system, idle, iowait, irq, softirq; + FILE* procStat = fopen("/proc/stat", "r"); + if(procStat == NULL) + return "fopen(\"""/proc/stat\", \"r\") == NULL"; + if (fscanf(procStat, "cpu%ld%ld%ld%ld%ld%ld%ld", &user, &nice, &system, &idle, &iowait, &irq, &softirq) < 0) { fclose(procStat); @@ -15,32 +18,8 @@ static const char* getCpuUsageInfo(FILE* procStat, long* inUseAll, long* totalAl } *inUseAll = user + nice + system; *totalAll = *inUseAll + idle + iowait + irq + softirq; - return NULL; -} -const char* ffGetCpuUsagePercent(double* result) -{ - FILE* procStat = fopen("/proc/stat", "r"); - if(procStat == NULL) - return "fopen(\"""/proc/stat\", \"r\") == NULL"; - - const char* error = NULL; - long inUseAll1 = 0, totalAll1 = 0; - error = getCpuUsageInfo(procStat, &inUseAll1, &totalAll1); - if(error) - goto exit; - - sleep(1); - rewind(procStat); - - long inUseAll2 = 0, totalAll2 = 0; - error = getCpuUsageInfo(procStat, &inUseAll2, &totalAll2); - if(error) - goto exit; - - *result = (double)(inUseAll2 - inUseAll1) / (double)(totalAll2 - totalAll1) * 100; - -exit: fclose(procStat); - return error; + + return NULL; } diff --git a/src/detection/font/font_android.c b/src/detection/font/font_android.c index 1719c7511b..3f8578b81e 100644 --- a/src/detection/font/font_android.c +++ b/src/detection/font/font_android.c @@ -1,3 +1,4 @@ +#include "fastfetch.h" #include "common/font.h" const char* ffDetectFontImpl(FFinstance* instance, FFlist* result) diff --git a/src/detection/terminalfont/terminalfont_android.c b/src/detection/terminalfont/terminalfont_android.c index 06eab584ab..8211ab1d27 100644 --- a/src/detection/terminalfont/terminalfont_android.c +++ b/src/detection/terminalfont/terminalfont_android.c @@ -1,7 +1,74 @@ +#include "fastfetch.h" #include "terminalfont.h" #include "detection/terminalshell.h" +#include "common/io.h" + +#include + +#ifdef FF_HAVE_FREETYPE + #include "common/library.h" + #include + #include FT_FREETYPE_H +#endif + +#define FF_TERMUX_FONT_PATH FASTFETCH_TARGET_DIR_HOME "/.termux/font.ttf" + +const char* detectTermux(const FFinstance* instance, FFTerminalFontResult* terminalFont) +{ + #ifdef FF_HAVE_FREETYPE + + FF_LIBRARY_LOAD(freetype, &instance->config.libfreetype, "dlopen libfreetype"FF_LIBRARY_EXTENSION " failed", "libfreetype"FF_LIBRARY_EXTENSION, 2) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(freetype, FT_Init_FreeType); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(freetype, FT_New_Face); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(freetype, FT_Done_Face); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(freetype, FT_Done_FreeType); + + FT_Library library = NULL; + FT_Face face = NULL; + const char* error = NULL; + + if(ffFT_Init_FreeType(&library)) + { + error = "FT_Init_FreeType() failed"; + goto exit; + } + + if(ffFT_New_Face(library, FF_TERMUX_FONT_PATH, 0, &face )) + { + error = "FT_NEW_Face(" FF_TERMUX_FONT_PATH ") failed"; + goto exit; + } + + ffFontInitCopy(&terminalFont->font, face->family_name); + +exit: + if(face) ffFT_Done_Face(face); + if(library) ffFT_Done_FreeType(library); + dlclose(freetype); + + return error; + + #else + + FF_UNUSED(terminalFont); + ffStrbufSetS(&terminalFont->error, "fastfetch is built without freetype2 support"); + + #endif +} void ffDetectTerminalFontPlatform(const FFinstance* instance, const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont) { - FF_UNUSED(instance, terminalShell, terminalFont); + if(ffStrbufCompS(&terminalShell->terminalProcessName, "Termux") != 0) + { + ffStrbufSetS(&terminalFont->error, "Unsupported terminal"); + return; + } + + if(!ffFileExists(FF_TERMUX_FONT_PATH, S_IFREG)) + { + ffFontInitCopy(&terminalFont->font, "monospace"); + return; + } + + ffStrbufSetS(&terminalFont->error, detectTermux(instance, terminalFont)); } diff --git a/src/fastfetch.c b/src/fastfetch.c index cbf56a96ec..9dc7cdef05 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -1199,6 +1199,12 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.openCL.outputFormat); else if(strcasecmp(key, "--opencl-error") == 0) optionParseString(key, value, &instance->config.openCL.errorFormat); + else if(strcasecmp(key, "--users-key") == 0) + optionParseString(key, value, &instance->config.users.key); + else if(strcasecmp(key, "--users-format") == 0) + optionParseString(key, value, &instance->config.users.outputFormat); + else if(strcasecmp(key, "--users-error") == 0) + optionParseString(key, value, &instance->config.users.errorFormat); /////////////////// //Library options// @@ -1208,6 +1214,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.libPCI); else if(strcasecmp(key, "--lib-vulkan") == 0) optionParseString(key, value, &instance->config.libVulkan); + else if(strcasecmp(key, "--lib-freetype") == 0) + optionParseString(key, value, &instance->config.libfreetype); else if(strcasecmp(key, "--lib-wayland") == 0) optionParseString(key, value, &instance->config.libWayland); else if(strcasecmp(key, "--lib-xcb-randr") == 0) diff --git a/src/fastfetch.h b/src/fastfetch.h index a8178453db..b4ea8b0552 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -128,6 +128,7 @@ typedef struct FFconfig FFModuleArgs vulkan; FFModuleArgs openGL; FFModuleArgs openCL; + FFModuleArgs users; FFstrbuf libPCI; FFstrbuf libVulkan; @@ -151,6 +152,7 @@ typedef struct FFconfig FFstrbuf libOpenCL; FFstrbuf libplist; FFstrbuf libcJSON; + FFstrbuf libfreetype; bool cpuTemp; bool gpuTemp; @@ -233,6 +235,7 @@ void ffLogoBuiltinListAutocompletion(); //Common void ffPrintDateTimeFormat(FFinstance* instance, const char* moduleName, const FFModuleArgs* moduleArgs); +void ffPrepareCPUUsage(); //Printing diff --git a/src/flashfetch.c b/src/flashfetch.c index 296d589f0e..15609669c6 100644 --- a/src/flashfetch.c +++ b/src/flashfetch.c @@ -34,7 +34,6 @@ int main(int argc, char** argv) ffPrintTerminal(&instance); ffPrintTerminalFont(&instance); ffPrintCPU(&instance); - //ffPrintCPUUsage(&instance); ffPrintGPU(&instance); ffPrintMemory(&instance); //ffPrintSwap(&instance); @@ -45,6 +44,7 @@ int main(int argc, char** argv) //ffPrintSong(&instance); //ffPrintLocalIp(&instance); //ffPrintPublicIp(&instance); + //ffPrintCPUUsage(&instance); ffPrintLocale(&instance); //ffPrintDateTime(&instance); //ffPrintDate(&instance); diff --git a/src/modules/cpuUsage.c b/src/modules/cpuUsage.c index fe655af990..8ad2cf1dd4 100644 --- a/src/modules/cpuUsage.c +++ b/src/modules/cpuUsage.c @@ -1,21 +1,55 @@ #include "fastfetch.h" #include "common/printing.h" #include "detection/cpuUsage/cpuUsage.h" +#include "sys/time.h" #define FF_CPU_USAGE_MODULE_NAME "CPU Usage" #define FF_CPU_USAGE_NUM_FORMAT_ARGS 1 +time_t getTimeInMs() +{ + struct timeval timeNow; + gettimeofday(&timeNow, NULL); + return (timeNow.tv_sec * 1000) + (timeNow.tv_usec / 1000); +} + +static long inUseAll1, totalAll1, startTime; + +void ffPrepareCPUUsage() +{ + startTime = getTimeInMs(); + ffGetCpuUsageInfo(&inUseAll1, &totalAll1); +} + void ffPrintCPUUsage(FFinstance* instance) { - double cpuPercent = 0; - const char* error = ffGetCpuUsagePercent(&cpuPercent); + const char* error = NULL; + if(startTime == 0) + { + error = ffGetCpuUsageInfo(&inUseAll1, &totalAll1); + if(error) + goto error; + nanosleep(&(struct timespec){ 1, 0 }, NULL); + } + else + { + time_t duration = getTimeInMs() - startTime; + if(duration < 1000) + nanosleep(&(struct timespec){ 0, (1000 - duration) * 1000000L }, NULL); + } + + long inUseAll2, totalAll2; + error = ffGetCpuUsageInfo(&inUseAll2, &totalAll2); if(error) { + error: ffPrintError(instance, FF_CPU_USAGE_MODULE_NAME, 0, &instance->config.cpu, "%s", error); return; } + double cpuPercent = (double)(inUseAll2 - inUseAll1) / (double)(totalAll2 - totalAll1) * 100; + if(instance->config.cpuUsage.outputFormat.length == 0) { ffPrintLogoAndKey(instance, FF_CPU_USAGE_MODULE_NAME, 0, &instance->config.cpuUsage.key); diff --git a/src/modules/users.c b/src/modules/users.c index 880b14c35c..c49c2570a1 100644 --- a/src/modules/users.c +++ b/src/modules/users.c @@ -1,7 +1,15 @@ #include "fastfetch.h" #include "common/printing.h" -#include +#if FF_HAVE_UTMPX_H + #include +#else + //for Android compatibility + #include + #define utmpx utmp + #define setutxent setutent + #define getutxent getutent +#endif #define FF_USERS_MODULE_NAME "Users" #define FF_USERS_NUM_FORMAT_ARGS 1 @@ -28,6 +36,13 @@ void ffPrintUsers(FFinstance* instance) } } + if(users.length == 0) + { + ffListDestroy(&users); + ffPrintError(instance, FF_USERS_MODULE_NAME, 0, &instance->config.users, "Unable to detect users"); + return; + } + FFstrbuf result; ffStrbufInit(&result); for(uint32_t i = 0; i < users.length; ++i) @@ -38,14 +53,14 @@ void ffPrintUsers(FFinstance* instance) } ffListDestroy(&users); - if(instance->config.uptime.outputFormat.length == 0) + if(instance->config.users.outputFormat.length == 0) { - ffPrintLogoAndKey(instance, FF_USERS_MODULE_NAME, 0, &instance->config.uptime.key); + ffPrintLogoAndKey(instance, FF_USERS_MODULE_NAME, 0, &instance->config.users.key); puts(result.chars); } else { - ffPrintFormat(instance, FF_USERS_MODULE_NAME, 0, &instance->config.uptime, FF_USERS_NUM_FORMAT_ARGS, (FFformatarg[]){ + ffPrintFormat(instance, FF_USERS_MODULE_NAME, 0, &instance->config.users, FF_USERS_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &result}, }); } diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 23f2e48f17..ec985b84fa 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -157,6 +157,16 @@ static inline FF_C_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, con return ffStrbufIgnCaseCompS(strbuf, comp->chars); } +static inline FF_C_NODISCARD bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str) +{ + return strnstr(strbuf->chars, str, strbuf->length) != NULL; +} + +static inline FF_C_NODISCARD bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str) +{ + return strcasestr(strbuf->chars, str) != NULL; +} + static inline FF_C_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) { return ffStrbufNextIndexC(strbuf, 0, c);