From 01bb73b9e80fc2d0e73bea3c8ce98ea79445f5d7 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 6 Aug 2026 16:40:33 +0800 Subject: [PATCH 01/26] Packaging: updates debian stuff [ci skip] --- debian/changelog.tpl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog.tpl b/debian/changelog.tpl index 5907db1c60..84e5dda3fe 100644 --- a/debian/changelog.tpl +++ b/debian/changelog.tpl @@ -1,3 +1,9 @@ +fastfetch (2.67.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium + + * Update to 2.67.0 + + -- Carter Li Thu, 06 Aug 2026 16:22:22 +0800 + fastfetch (2.66.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium * Update to 2.66.0 From 51a4f34bb518a8262a3e5a65a1f29e68d8c548c2 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 7 Aug 2026 09:37:11 +0800 Subject: [PATCH 02/26] Codec (macOS): fixes a symbol not found error when running on 10.15 --- src/detection/codec/codec_apple.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/detection/codec/codec_apple.c b/src/detection/codec/codec_apple.c index 2cf2a48b2f..e6cb3d3829 100644 --- a/src/detection/codec/codec_apple.c +++ b/src/detection/codec/codec_apple.c @@ -3,6 +3,10 @@ #include #include "common/apple/cf_helpers.h" +#ifdef MAC_OS_VERSION_11_0 +[[clang::weak_import]] VT_EXPORT void VTRegisterSupplementalVideoDecoderIfAvailable(CMVideoCodecType codecType); +#endif + static const struct { CMVideoCodecType codec; FFCodecType type; @@ -70,9 +74,11 @@ static FFCodecType ffCodecDetectDecoders() { continue; } - if (__builtin_available(macOS 11.0, *)) { +#ifdef MAC_OS_VERSION_11_0 + if (VTRegisterSupplementalVideoDecoderIfAvailable) { VTRegisterSupplementalVideoDecoderIfAvailable(codec.codec); } +#endif bool supported = VTIsHardwareDecodeSupported(codec.codec); if (!supported) { continue; From ba60d7975c5e74477d4e9a9f443cb66543af6c34 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 7 Aug 2026 09:37:31 +0800 Subject: [PATCH 03/26] Camera (macOS): simplifies code --- src/detection/camera/camera_apple.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/detection/camera/camera_apple.m b/src/detection/camera/camera_apple.m index da6884486c..ba1509e0dd 100644 --- a/src/detection/camera/camera_apple.m +++ b/src/detection/camera/camera_apple.m @@ -19,12 +19,8 @@ AVCaptureDeviceType deviceType = nullptr; #ifdef MAC_OS_VERSION_14_0 - // Strangely `@available(macOS 14.0, *)` doesn't work here (#1594) - if (@available(macOS 14.0, *)) - { - if (&AVCaptureDeviceTypeExternal) - deviceType = AVCaptureDeviceTypeExternal; - } + if (&AVCaptureDeviceTypeExternal) + deviceType = AVCaptureDeviceTypeExternal; #endif if (deviceType == nullptr) deviceType = AVCaptureDeviceTypeExternalUnknown; From 39b3dc001ae717a8333232fe9e97494d9f6d6769 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 7 Aug 2026 10:34:23 +0800 Subject: [PATCH 04/26] CMake: adds C23 feature detection and compatibility workarounds for Apple clang 17 --- CMakeLists.txt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cd0df0d18..61582f4e17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1469,10 +1469,24 @@ endforeach() include(CheckCSourceCompiles) check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF) if(COMPILER_SUPPORTS_COUNT_OF) - message(STATUS "_Countof is supported by the compiler") + message(STATUS "C2Y _Countof is supported by the compiler") target_compile_definitions(libfastfetch PUBLIC FF_SUPPORTS_COUNT_OF=1) else() - message(STATUS "_Countof is NOT supported by the compiler") + message(STATUS "C2Y _Countof is NOT supported by the compiler") +endif() + +# Test C23 compiler support +check_c_source_compiles("enum my_enum: long{MY_ENUM_ZERO}; void test(void*p){} int main(int,const char**){[[gnu::cleanup(test)]] void* x=nullptr; return (int)MY_ENUM_ZERO;}" COMPILER_SUPPORTS_C23) +if(NOT COMPILER_SUPPORTS_C23) + message(FATAL_ERROR "Compiler does not support C23. Please use a newer compiler.") +endif() + +# A hack for AppleClang 17, which supports most C23 features we use except for the `auto` keyword. +# See https://github.com/Homebrew/homebrew-core/pull/297403 +check_c_source_compiles("int main(void){auto v = 12.34; return (int)v;}" COMPILER_SUPPORTS_AUTO) +if(NOT COMPILER_SUPPORTS_AUTO) + message(WARNING "Compiler does not support C23 'auto' keyword. A workaround will be applied.") + target_compile_definitions(libfastfetch PUBLIC $<$:auto=__auto_type>) endif() if(yyjson_FOUND) From 8686820c1a0b19e2433f5f545a9a1201384e9f3b Mon Sep 17 00:00:00 2001 From: Yelninei Date: Thu, 6 Aug 2026 14:10:33 +0000 Subject: [PATCH 05/26] CMake (Hurd): Define O_PATH to O_NORW. This is a noop because O_RW is 0 but O_NORW is the correct constant to open a file without read/write permissions. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 61582f4e17..5ff5365387 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1569,7 +1569,7 @@ elseif(Haiku) target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE) elseif(GNU) # On Hurd PATH_MAX is not defined. Set an arbitrary limit as workaround. - target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=0) + target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=O_NORW) endif() if(APPLE) From ac8fc63c288b746ea950e62e288b100ab6848019 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 7 Aug 2026 16:38:40 +0800 Subject: [PATCH 06/26] Doc: updates changelog [ci skip] --- CHANGELOG.md | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ab97abc36..1088ace296 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 2.67.1 + +Bugfixes: +* Fixed `Symbol not found` error when running on macOS 10.15 (macOS) +* Fixed building on Apple clang 16 (the default compiler of macOS 14) +* Added a C23 compiler check so the build process exits during CMake configuration + # 2.67.0 Changes: @@ -31,12 +38,12 @@ Bugfixes: * Fixed invalid URL parsing in the PublicIP module. (PublicIP) * Correctly reported virtual GPUs on Windows. (#2461, GPU, Windows) * Added a size limit for network responses to prevent excessive memory usage and mitigate potential attacks. (PublicIP / Weather) -* Fixed Ubuntu Studio Core detection (OS, Linux) +* Fixed Ubuntu Studio Core detection. (OS, Linux) * Relaxed the HTTP response check so that both `HTTP/1.0` and `HTTP/1.1` responses are accepted when fetching data over the network. (PublicIP / Weather) * Various internal cleanups and optimizations: - * Fixed multiple memory leaks (Separator, Camera, Codec, Display) - * Added integer overflow checks to the string buffer implementation - * Various code cleanups and compiler warning fixes + * Fixed multiple memory leaks (Separator, Camera, Codec, Display). + * Added integer overflow checks to the string buffer implementation. + * Various code cleanups and compiler warning fixes. Logos: * Removed Hypros, MagpieOS, Furreto, EmperorOS and Magix @@ -49,9 +56,9 @@ Changes: Bugfixes: * Fixed compatibility with WSL 2.9.3 (#2433, WM, Linux) -* Fixed accurate AMD GPU names are not queried in `driverSpecific` mode (GPU, Linux) +* Fixed AMD GPU names not being queried accurately in `driverSpecific` mode (GPU, Linux) * Fixed GPU core counting for Apple Silicon GPU on Asahi Linux (GPU, Linux) -* Some internal cleanups and optimizations +* Some internal cleanups and optimizations. Features: * Added Astra Linux version detection (OS, Linux) @@ -784,7 +791,7 @@ Features: * Added support for interface speed detection on SunOS (LocalIP, SunOS) * Added detection support for Xlibre (#1888, WM, Linux) * Improved the accuracy of color detection (Cursor, macOS) -* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS) +* Improved the performance of `Nix` package manager detection on macOS by porting optimizations from the Linux port (#1893, Packages, macOS) Bugfixes: * Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477) @@ -1295,7 +1302,7 @@ Features: * Change package manager name of NetBSD from `pkg` to `pkgsrc` (#1515, Packages, NetBSD) * Detect SOC name on RISCV (#1519, CPU, Linux) * Report marketing name of new QS8Es (CPU, Android) -* Acquire acquire more os info from lsb-release if missing from os-release (#1521) +* Acquire more OS info from lsb-release if missing from os-release (#1521) * CMake: add option `-DCUSTOM_LSB_RELEASE_PATH` to specify the path of `lsb-release` file * `-DCUSTOM_OS_RELEASE_PATH` has been supported since `v2.11.4` * Report more SOC names on Android (CPU, Android) @@ -1763,7 +1770,7 @@ Logos: Bugfixes: * Fix bad Intel Arc GPU name detection, which was supposed to be fixed in the last version but the change was reverted accidentally (#1177, GPU, Linux) -* Fix arm32 CPU name detection no longer work. Regression of 2.21.2 (CPU, Linux) +* Fix arm32 CPU name detection no longer working. Regression of 2.21.2 (CPU, Linux) # 2.21.2 From 881730d0bd778195ae4a4ed2ccc9c473efec4171 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 8 Aug 2026 22:38:53 +0800 Subject: [PATCH 07/26] TerminalFont: improves Ghostty config loading with fallback support Fixes: #2500 --- src/detection/terminalfont/terminalfont.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index b7c2d0a5a4..68aadea2cb 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -69,7 +69,7 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont) { ffFontInitMoveValues(&terminalFont->font, &fontFamily, &fontSize, &fontStyle); } -static void parseGhosttyConfig(const FFstrbuf* path, FFstrbuf* fontName, FFstrbuf* fontNameFallback, FFstrbuf* fontSize, FFlist* configFiles /* list of FFstrbuf */) { +static void parseGhosttyConfig(FFstrbuf* path, FFstrbuf* fontName, FFstrbuf* fontNameFallback, FFstrbuf* fontSize, FFlist* configFiles /* list of FFstrbuf */) { // Maximum number of `config-file` directives to follow, guarding against runaway includes enum { FF_GHOSTTY_MAX_CONFIG_FILES = 16 }; @@ -79,7 +79,18 @@ static void parseGhosttyConfig(const FFstrbuf* path, FFstrbuf* fontName, FFstrbu FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate(); if (!ffAppendFileBuffer(path->chars, &buffer)) { FF_DEBUG("cannot read config: %s", path->chars); - return; + if (ffStrbufEndsWithS(path, ".ghostty")) { + FF_DEBUG("Trying to load config without .ghostty extension"); + path->chars[path->length - strlen(".ghostty")] = '\0'; + bool ok = ffAppendFileBuffer(path->chars, &buffer); + path->chars[path->length - strlen(".ghostty")] = '.'; + if (!ok) { + FF_DEBUG("cannot read config: %s", path->chars); + return; + } + } else { + return; + } } char* line = nullptr; @@ -394,7 +405,7 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour")) { detectContour(&terminal->exe, terminalFont); } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty")) { - detectGhostty(terminalFont, "com.mitchellh.ghostty/config", "ghostty/config"); + detectGhostty(terminalFont, "com.mitchellh.ghostty/config.ghostty", "ghostty/config.ghostty"); } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "Muxy")) { detectGhostty(terminalFont, "Muxy/ghostty.conf", "muxy/ghostty.conf"); } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "rio")) { From 558a90d4e054a023453383e64f2260ac6fe2fff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 9 Aug 2026 00:56:04 +0800 Subject: [PATCH 08/26] Loadavg (Haiku): adds support on R1B6 --- CMakeLists.txt | 11 +++++++++-- src/detection/loadavg/loadavg_sunos.c | 6 +++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ff5365387..536979b1de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ if(NOT PKG_CONFIG_FOUND) endif() include(CheckIncludeFile) +include(CheckFunctionExists) if(LINUX) CHECK_INCLUDE_FILE("linux/version.h" HAVE_LINUX_VERSION_H) @@ -1281,7 +1282,6 @@ elseif(Haiku) src/detection/keyboard/keyboard_haiku.cpp src/detection/libc/libc_nosupport.c src/detection/lm/lm_nosupport.c - src/detection/loadavg/loadavg_nosupport.c src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_haiku.cpp @@ -1311,6 +1311,13 @@ elseif(Haiku) src/detection/wmtheme/wmtheme_haiku.cpp src/detection/camera/camera_nosupport.c ) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} bsd) + check_function_exists(getloadavg HAVE_GETLOADAVG) + if(HAVE_GETLOADAVG) + list(APPEND LIBFASTFETCH_SRC src/detection/loadavg/loadavg_sunos.c) + else() + list(APPEND LIBFASTFETCH_SRC src/detection/loadavg/loadavg_nosupport.c) + endif() elseif(GNU) list(APPEND LIBFASTFETCH_SRC src/common/impl/dbus.c @@ -1428,7 +1435,6 @@ if(WIN32) endif() endif() endif() -include(CheckFunctionExists) if(NOT WIN32) check_function_exists(pipe2 HAVE_PIPE2) endif() @@ -2020,6 +2026,7 @@ elseif(Haiku) PRIVATE "GL" PRIVATE "be" PRIVATE "gnu" + PRIVATE "bsd" ) endif() diff --git a/src/detection/loadavg/loadavg_sunos.c b/src/detection/loadavg/loadavg_sunos.c index 7cf63eec67..7deedb10be 100644 --- a/src/detection/loadavg/loadavg_sunos.c +++ b/src/detection/loadavg/loadavg_sunos.c @@ -1,6 +1,10 @@ #include "detection/loadavg/loadavg.h" -#include +#if __has_include() + #include +#else + #include +#endif const char* ffDetectLoadavg(double result[3]) { return getloadavg(result, 3) == 3 ? nullptr : "getloadavg() failed"; From 4361c5e7876b3beaf6ad2cbd4741050c427748e8 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 8 Aug 2026 22:18:27 +0800 Subject: [PATCH 09/26] Library: adds function `ffLibraryIterateDynamicLibs` --- src/common/impl/library.c | 75 +++++++++++++++++++++++++++++++++++++++ src/common/library.h | 6 +++- src/common/windows/nt.h | 16 +++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/common/impl/library.c b/src/common/impl/library.c index 440ea1336a..f4cfd1421b 100644 --- a/src/common/impl/library.c +++ b/src/common/impl/library.c @@ -178,3 +178,78 @@ void* ffLibraryGetModule(const wchar_t* libraryFileName) { return module; } #endif + +struct LibraryIterateDynamicLibsBundle { + FFLibraryIterateCallback callback; + void* userData; +}; + +#if _WIN32 + +static void ffLibraryIterateDynamicLibsCallback(PLDR_DATA_TABLE_ENTRY DataTableEntry, PVOID Context, BOOLEAN* StopEnumeration) { + if (DataTableEntry->FullDllName.Buffer == nullptr || DataTableEntry->FullDllName.Buffer[0] == L'\0') { + return; + } + + char path[PATH_MAX * 3]; + ULONG outBytes; + if (NT_SUCCESS(RtlUnicodeToUTF8N(path, sizeof(path), &outBytes, DataTableEntry->FullDllName.Buffer, (uint32_t) (DataTableEntry->FullDllName.Length + sizeof(wchar_t))))) { + struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) Context; + *StopEnumeration = !bundle->callback(path, bundle->userData); + } +} + +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { + struct LibraryIterateDynamicLibsBundle bundle = { + .callback = callback, + .userData = userData, + }; + LdrEnumerateLoadedModules(FALSE, ffLibraryIterateDynamicLibsCallback, &bundle); +} + +#elif defined(__APPLE__) + +#include + +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { + uint32_t imageCount = _dyld_image_count(); + for (uint32_t i = 0; i < imageCount; ++i) { + const char* name = _dyld_get_image_name(i); + if (name == nullptr || name[0] == '\0') { + continue; + } + + if (!callback(name, userData)) { + break; + } + } +} + +#elif __has_include() + #include + +static int ffLibraryIterateDynamicLibsCallback(struct dl_phdr_info* info, size_t, void* data) { + if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') { + return 0; + } + + struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) data; + return !bundle->callback(info->dlpi_name, bundle->userData); +} + +void ffLibraryIterateDynamicLibs(bool (*callback)(const char* name, void* userData), void* userData) { + dl_iterate_phdr( + ffLibraryIterateDynamicLibsCallback, + &(struct LibraryIterateDynamicLibsBundle) { + .callback = callback, + .userData = userData, + }); +} + +#else + +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback, void*) { + // Not implemented for this platform +} + +#endif diff --git a/src/common/library.h b/src/common/library.h index 06003cc938..f2b2cca335 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -1,6 +1,6 @@ #pragma once -#include "fastfetch.h" +#include "fastfetch.h" // IWYU pragma: keep #ifndef FF_DISABLE_DLOPEN @@ -111,3 +111,7 @@ void* ffLibraryLoadMulti(const char* path, int maxVersion, ...); #if _WIN32 void* ffLibraryGetModule(const wchar_t* libraryFileName); #endif + +// Return false to stop iterating, true to continue +typedef bool (*FFLibraryIterateCallback)(const char* name, void* userData); +void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData); diff --git a/src/common/windows/nt.h b/src/common/windows/nt.h index 77e0a00c18..f003849845 100644 --- a/src/common/windows/nt.h +++ b/src/common/windows/nt.h @@ -1279,6 +1279,22 @@ NTSYSAPI NTSTATUS NTAPI LdrGetProcedureAddress( _In_opt_ ULONG ProcedureNumber, _Out_ PVOID* ProcedureAddress); +typedef _Function_class_(LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION) +VOID NTAPI LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION( + _In_ PLDR_DATA_TABLE_ENTRY DataTableEntry, + _In_opt_ PVOID Context, + _Inout_ BOOLEAN* StopEnumeration +); + +NTSYSAPI +NTSTATUS +NTAPI +LdrEnumerateLoadedModules( + _In_ BOOLEAN ReservedFlag, + _In_ LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION* EnumProc, + _In_opt_ PVOID Context +); + typedef enum _SECTION_INHERIT { ViewShare = 1, ViewUnmap = 2 From 8bc4464b64c96c0f6c781e494a121939b8bc74fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 9 Aug 2026 10:11:25 +0800 Subject: [PATCH 10/26] Library: makes `ffLibraryIterateDynamicLibs` return false on failure --- src/common/impl/library.c | 14 +++++++++----- src/common/library.h | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/common/impl/library.c b/src/common/impl/library.c index f4cfd1421b..3c34c79f8b 100644 --- a/src/common/impl/library.c +++ b/src/common/impl/library.c @@ -199,19 +199,19 @@ static void ffLibraryIterateDynamicLibsCallback(PLDR_DATA_TABLE_ENTRY DataTableE } } -void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { +bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { struct LibraryIterateDynamicLibsBundle bundle = { .callback = callback, .userData = userData, }; - LdrEnumerateLoadedModules(FALSE, ffLibraryIterateDynamicLibsCallback, &bundle); + return NT_SUCCESS(LdrEnumerateLoadedModules(FALSE, ffLibraryIterateDynamicLibsCallback, &bundle)); } #elif defined(__APPLE__) #include -void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { +bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) { uint32_t imageCount = _dyld_image_count(); for (uint32_t i = 0; i < imageCount; ++i) { const char* name = _dyld_get_image_name(i); @@ -223,6 +223,8 @@ void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userDa break; } } + + return true; } #elif __has_include() @@ -237,19 +239,21 @@ static int ffLibraryIterateDynamicLibsCallback(struct dl_phdr_info* info, size_t return !bundle->callback(info->dlpi_name, bundle->userData); } -void ffLibraryIterateDynamicLibs(bool (*callback)(const char* name, void* userData), void* userData) { +bool ffLibraryIterateDynamicLibs(bool (*callback)(const char* name, void* userData), void* userData) { dl_iterate_phdr( ffLibraryIterateDynamicLibsCallback, &(struct LibraryIterateDynamicLibsBundle) { .callback = callback, .userData = userData, }); + return true; } #else -void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback, void*) { +bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback, void*) { // Not implemented for this platform + return false; } #endif diff --git a/src/common/library.h b/src/common/library.h index f2b2cca335..fc5ddbe956 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -114,4 +114,5 @@ void* ffLibraryGetModule(const wchar_t* libraryFileName); // Return false to stop iterating, true to continue typedef bool (*FFLibraryIterateCallback)(const char* name, void* userData); -void ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData); +// Iterate over all loaded dynamic libraries. Returns true on success, false on failure. +bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData); From 8b8efcdcce100594fc81f10b79df5b13632754c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 9 Aug 2026 10:12:37 +0800 Subject: [PATCH 11/26] Locale (macOS): queries system-wide locale preference --- CMakeLists.txt | 2 +- src/detection/locale/locale_apple.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/detection/locale/locale_apple.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 536979b1de..238537f9fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1038,7 +1038,7 @@ elseif(APPLE) src/detection/lm/lm_nosupport.c src/detection/loadavg/loadavg_bsd.c src/detection/libc/libc_apple.c - src/detection/locale/locale_linux.c + src/detection/locale/locale_apple.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_apple.c src/detection/media/media_apple.m diff --git a/src/detection/locale/locale_apple.c b/src/detection/locale/locale_apple.c new file mode 100644 index 0000000000..c5a5e8e1a3 --- /dev/null +++ b/src/detection/locale/locale_apple.c @@ -0,0 +1,13 @@ +#include "detection/locale/locale.h" +#include "common/apple/cf_helpers.h" + +const char* ffDetectLocale(FFstrbuf* result) { + // Read the system-wide locale preference (equivalent to `defaults read -g AppleLocale`), + // which is NOT affected by user environment variables (LANG, LC_ALL, etc.) + FF_CFTYPE_AUTO_RELEASE CFStringRef appleLocale = CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesAnyApplication); + if (!appleLocale) { + return "Failed to read AppleLocale"; + } + + return ffCfStrGetString(appleLocale, result); +} From da42108732b4411da2afd7bdc4d85038da174d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 9 Aug 2026 10:22:21 +0800 Subject: [PATCH 12/26] Cursor (macOS): migrates impl to pure C using CoreFoundation --- CMakeLists.txt | 2 +- src/detection/cursor/cursor_apple.c | 70 +++++++++++++++++++++++++++++ src/detection/cursor/cursor_apple.m | 63 -------------------------- 3 files changed, 71 insertions(+), 64 deletions(-) create mode 100644 src/detection/cursor/cursor_apple.c delete mode 100644 src/detection/cursor/cursor_apple.m diff --git a/CMakeLists.txt b/CMakeLists.txt index 238537f9fe..49a8f2f8d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1023,7 +1023,7 @@ elseif(APPLE) src/detection/cpu/cpu_apple.c src/detection/cpucache/cpucache_apple.c src/detection/cpuusage/cpuusage_apple.c - src/detection/cursor/cursor_apple.m + src/detection/cursor/cursor_apple.c src/detection/disk/disk_bsd.c src/detection/dns/dns_apple.c src/detection/physicaldisk/physicaldisk_apple.c diff --git a/src/detection/cursor/cursor_apple.c b/src/detection/cursor/cursor_apple.c new file mode 100644 index 0000000000..957d08935c --- /dev/null +++ b/src/detection/cursor/cursor_apple.c @@ -0,0 +1,70 @@ +#include "cursor.h" +#include "common/apple/cf_helpers.h" + +static bool appendColor(FFstrbuf* str, CFDictionaryRef dict) { + double r, g, b, a; + if ( + ffCfDictGetDouble(dict, CFSTR("red"), &r) || + ffCfDictGetDouble(dict, CFSTR("green"), &g) || + ffCfDictGetDouble(dict, CFSTR("blue"), &b) || + ffCfDictGetDouble(dict, CFSTR("alpha"), &a)) { + return false; + } + + r = r * 255 + .5; + g = g * 255 + .5; + b = b * 255 + .5; + a = a * 255 + .5; + + uint32_t color = ((uint32_t) r << 24) | ((uint32_t) g << 16) | ((uint32_t) b << 8) | ((uint32_t) a); + + // clang-format off + switch (color) + { + case 0x000000FF: ffStrbufAppendS(str, "Black"); break; + case 0x0433FFFF: ffStrbufAppendS(str, "Blue"); break; + case 0xAA7942FF: ffStrbufAppendS(str, "Brown"); break; + case 0x00FDFFFF: ffStrbufAppendS(str, "Cyan"); break; + case 0x00F900FF: ffStrbufAppendS(str, "Green"); break; + case 0xFF40FFFF: ffStrbufAppendS(str, "Magenta"); break; + case 0xFF9300FF: ffStrbufAppendS(str, "Orange"); break; + case 0x942192FF: ffStrbufAppendS(str, "Purple"); break; + case 0xFF2600FF: ffStrbufAppendS(str, "Red"); break; + case 0xFFFB00FF: ffStrbufAppendS(str, "Yellow"); break; + case 0xFFFFFFFF: ffStrbufAppendS(str, "White"); break; + case 0x00000000: ffStrbufAppendS(str, "Transparent"); break; + default: ffStrbufAppendF(str, "#%08X", color); break; + } + // clang-format on + + return true; +} + +void ffDetectCursor(FFCursorResult* result) { + // Read via cfprefsd (equivalent to `defaults read com.apple.universalaccess `) + ffStrbufAppendS(&result->theme, "Fill - "); + { + FF_CFTYPE_AUTO_RELEASE CFTypeRef color = CFPreferencesCopyAppValue(CFSTR("cursorFill"), CFSTR("com.apple.universalaccess")); + if (!color || CFGetTypeID(color) != CFDictionaryGetTypeID() || !appendColor(&result->theme, (CFDictionaryRef) color)) { + ffStrbufAppendS(&result->theme, "Black"); + } + } + + ffStrbufAppendS(&result->theme, ", Outline - "); + { + FF_CFTYPE_AUTO_RELEASE CFTypeRef color = CFPreferencesCopyAppValue(CFSTR("cursorOutline"), CFSTR("com.apple.universalaccess")); + if (!color || CFGetTypeID(color) != CFDictionaryGetTypeID() || !appendColor(&result->theme, (CFDictionaryRef) color)) { + ffStrbufAppendS(&result->theme, "White"); + } + } + + { + FF_CFTYPE_AUTO_RELEASE CFTypeRef mouseDriverCursorSize = CFPreferencesCopyAppValue(CFSTR("mouseDriverCursorSize"), CFSTR("com.apple.universalaccess")); + double size = 32; + if (mouseDriverCursorSize && ffCfNumGetDouble(mouseDriverCursorSize, &size) == nullptr) { + ffStrbufAppendUInt(&result->size, (uint32_t) (size * 32 + 0.5)); + } else { + ffStrbufAppendS(&result->size, "32"); + } + } +} diff --git a/src/detection/cursor/cursor_apple.m b/src/detection/cursor/cursor_apple.m deleted file mode 100644 index 610bd1ed8a..0000000000 --- a/src/detection/cursor/cursor_apple.m +++ /dev/null @@ -1,63 +0,0 @@ -#include "cursor.h" - -#import - -static void appendColor(FFstrbuf* str, NSDictionary* dict) -{ - uint32_t r = (uint32_t) (((NSNumber*) dict[@"red"]).doubleValue * 255 + .5); - uint32_t g = (uint32_t) (((NSNumber*) dict[@"green"]).doubleValue * 255 + .5); - uint32_t b = (uint32_t) (((NSNumber*) dict[@"blue"]).doubleValue * 255 + .5); - uint32_t a = (uint32_t) (((NSNumber*) dict[@"alpha"]).doubleValue * 255 + .5); - uint32_t color = (r << 24) | (g << 16) | (b << 8) | a; - - switch (color) - { - case 0x000000FF: ffStrbufAppendS(str, "Black"); return; - case 0x0433FFFF: ffStrbufAppendS(str, "Blue"); return; - case 0xAA7942FF: ffStrbufAppendS(str, "Brown"); return; - case 0x00FDFFFF: ffStrbufAppendS(str, "Cyan"); return; - case 0x00F900FF: ffStrbufAppendS(str, "Green"); return; - case 0xFF40FFFF: ffStrbufAppendS(str, "Magenta"); return; - case 0xFF9300FF: ffStrbufAppendS(str, "Orange"); return; - case 0x942192FF: ffStrbufAppendS(str, "Purple"); return; - case 0xFF2600FF: ffStrbufAppendS(str, "Red"); return; - case 0xFFFB00FF: ffStrbufAppendS(str, "Yellow"); return; - case 0xFFFFFFFF: ffStrbufAppendS(str, "White"); return; - case 0x00000000: ffStrbufAppendS(str, "Transparent"); return; - default: ffStrbufAppendF(str, "#%08X", color); return; - } -} - -void ffDetectCursor(FFCursorResult* result) -{ - NSError* error; - NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/com.apple.universalaccess.plist", instance.state.platform.homeDir.chars]; - NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName] - error:&error]; - if(error) - { - ffStrbufAppendS(&result->error, error.localizedDescription.UTF8String); - return; - } - - NSDictionary* color; - - ffStrbufAppendS(&result->theme, "Fill - "); - if ((color = dict[@"cursorFill"])) - appendColor(&result->theme, color); - else - ffStrbufAppendS(&result->theme, "Black"); - - ffStrbufAppendS(&result->theme, ", Outline - "); - - if ((color = dict[@"cursorOutline"])) - appendColor(&result->theme, color); - else - ffStrbufAppendS(&result->theme, "White"); - - NSNumber* mouseDriverCursorSize = dict[@"mouseDriverCursorSize"]; - if (mouseDriverCursorSize) - ffStrbufAppendF(&result->size, "%d", (int) (mouseDriverCursorSize.doubleValue * 32 + 0.5)); - else - ffStrbufAppendS(&result->size, "32"); -} From 1d4b0236ac2be3dd61833b912700540b122871ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 9 Aug 2026 10:25:13 +0800 Subject: [PATCH 13/26] WMTheme (macOS): migrates impl to pure C using CoreFoundation --- CMakeLists.txt | 2 +- src/detection/wmtheme/wmtheme_apple.c | 52 +++++++++++++++++++++++++++ src/detection/wmtheme/wmtheme_apple.m | 40 --------------------- 3 files changed, 53 insertions(+), 41 deletions(-) create mode 100644 src/detection/wmtheme/wmtheme_apple.c delete mode 100644 src/detection/wmtheme/wmtheme_apple.m diff --git a/CMakeLists.txt b/CMakeLists.txt index 49a8f2f8d5..9e86d3d400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1064,7 +1064,7 @@ elseif(APPLE) src/detection/wifi/wifi_apple.m src/detection/wm/wm_apple.m src/detection/de/de_nosupport.c - src/detection/wmtheme/wmtheme_apple.m + src/detection/wmtheme/wmtheme_apple.c src/detection/camera/camera_apple.m ) # CMAKE_SYSTEM_PROCESSOR has been normalized before diff --git a/src/detection/wmtheme/wmtheme_apple.c b/src/detection/wmtheme/wmtheme_apple.c new file mode 100644 index 0000000000..ef30757c5f --- /dev/null +++ b/src/detection/wmtheme/wmtheme_apple.c @@ -0,0 +1,52 @@ +#include "fastfetch.h" +#include "wmtheme.h" +#include "common/apple/cf_helpers.h" + +bool ffDetectWmTheme(FFstrbuf* themeOrError) { + // Read via cfprefsd instead of the raw plist file to keep cache consistency with the system + FF_CFTYPE_AUTO_RELEASE CFTypeRef wmThemeColor = CFPreferencesCopyAppValue(CFSTR("AppleAccentColor"), kCFPreferencesAnyApplication); + int32_t accentColor = -2; // -2: not set; -1 is Graphite + if (wmThemeColor && ffCfNumGetInt(wmThemeColor, &accentColor) == nullptr) { + switch (accentColor) { + case -1: + ffStrbufAppendS(themeOrError, "Graphite"); + break; + case 0: + ffStrbufAppendS(themeOrError, "Red"); + break; + case 1: + ffStrbufAppendS(themeOrError, "Orange"); + break; + case 2: + ffStrbufAppendS(themeOrError, "Yellow"); + break; + case 3: + ffStrbufAppendS(themeOrError, "Green"); + break; + case 4: + ffStrbufAppendS(themeOrError, "Blue"); + break; + case 5: + ffStrbufAppendS(themeOrError, "Purple"); + break; + case 6: + ffStrbufAppendS(themeOrError, "Pink"); + break; + default: + ffStrbufAppendS(themeOrError, "Unknown"); + break; + } + } else { + ffStrbufAppendS(themeOrError, "Multicolor"); + } + + FF_STRBUF_AUTO_DESTROY style = ffStrbufCreate(); + FF_CFTYPE_AUTO_RELEASE CFTypeRef wmTheme = CFPreferencesCopyAppValue(CFSTR("AppleInterfaceStyle"), kCFPreferencesAnyApplication); + if (wmTheme && ffCfStrGetString(wmTheme, &style) == nullptr) { + ffStrbufAppendF(themeOrError, " (%s)", style.chars); + } else { + ffStrbufAppendS(themeOrError, " (Light)"); + } + + return true; +} diff --git a/src/detection/wmtheme/wmtheme_apple.m b/src/detection/wmtheme/wmtheme_apple.m deleted file mode 100644 index 8c43877b12..0000000000 --- a/src/detection/wmtheme/wmtheme_apple.m +++ /dev/null @@ -1,40 +0,0 @@ -#include "fastfetch.h" -#include "wmtheme.h" - -#import - -bool ffDetectWmTheme(FFstrbuf* themeOrError) -{ - NSError* error; - NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/.GlobalPreferences.plist", instance.state.platform.homeDir.chars]; - NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName] - error:&error]; - if(error) - { - ffStrbufAppendS(themeOrError, error.localizedDescription.UTF8String); - return false; - } - - NSNumber* wmThemeColor = dict[@"AppleAccentColor"]; - if(!wmThemeColor) - ffStrbufAppendS(themeOrError, "Multicolor"); - else - { - switch(wmThemeColor.intValue) - { - case -1: ffStrbufAppendS(themeOrError, "Graphite"); break; - case 0: ffStrbufAppendS(themeOrError, "Red"); break; - case 1: ffStrbufAppendS(themeOrError, "Orange"); break; - case 2: ffStrbufAppendS(themeOrError, "Yellow"); break; - case 3: ffStrbufAppendS(themeOrError, "Green"); break; - case 4: ffStrbufAppendS(themeOrError, "Blue"); break; - case 5: ffStrbufAppendS(themeOrError, "Purple"); break; - case 6: ffStrbufAppendS(themeOrError, "Pink"); break; - default: ffStrbufAppendS(themeOrError, "Unknown"); break; - } - } - - NSString* wmTheme = dict[@"AppleInterfaceStyle"]; - ffStrbufAppendF(themeOrError, " (%s)", wmTheme ? wmTheme.UTF8String : "Light"); - return true; -} From e3b8e94055154a884b3e3b342d46dec22294e1fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 9 Aug 2026 10:27:19 +0800 Subject: [PATCH 14/26] Wallpaper (macOS): uses the official API if possible --- .gitignore | 1 + src/detection/wallpaper/wallpaper_apple.m | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/.gitignore b/.gitignore index db85643822..1394fe9317 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ fastfetch.kdev4 *.user *.user.* *.swp +*.log diff --git a/src/detection/wallpaper/wallpaper_apple.m b/src/detection/wallpaper/wallpaper_apple.m index f4ba8a6823..63acae325c 100644 --- a/src/detection/wallpaper/wallpaper_apple.m +++ b/src/detection/wallpaper/wallpaper_apple.m @@ -3,9 +3,20 @@ #include "common/apple/osascript.h" #import +#import const char* ffDetectWallpaper(FFstrbuf* result) { + { + // Reliable for user-picked static images. + NSURL* url = [NSWorkspace.sharedWorkspace desktopImageURLForScreen:NSScreen.mainScreen]; + if (url.fileURL && ![url.path isEqualToString:@"/System/Library/CoreServices/DefaultDesktop.heic"] /* dynamic wallpapers */) + { + ffStrbufSetS(result, url.path.UTF8String); + return nullptr; + } + } + { // For Sonoma // https://github.com/JohnCoates/Aerial/issues/1332 From 4c2af4071c0bbcf1edafdc2e44d605b4fe5d4e7c Mon Sep 17 00:00:00 2001 From: HashimAbdulaziz Date: Sun, 9 Aug 2026 09:27:11 +0300 Subject: [PATCH 15/26] TerminalFont (Alacritty): fix font size never being parsed from config The query array gained a third entry in dd30c82b83667ce45d71fb4d32b5b0c2cb727e19 but numQueries stayed at 2, so `size =` was never queried and every Alacritty user silently got the hardcoded 11.25 fallback. --- src/detection/terminalfont/terminalfont.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index 68aadea2cb..8c54a85009 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -23,13 +23,13 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont) { }; // alacritty parses config files in this order - if (ffParsePropFileConfigValues("alacritty/alacritty.toml", 2, fontQueryToml)) { + if (ffParsePropFileConfigValues("alacritty/alacritty.toml", 3, fontQueryToml)) { break; } - if (ffParsePropFileConfigValues("alacritty.toml", 2, fontQueryToml)) { + if (ffParsePropFileConfigValues("alacritty.toml", 3, fontQueryToml)) { break; } - if (ffParsePropFileConfigValues(".alacritty.toml", 2, fontQueryToml)) { + if (ffParsePropFileConfigValues(".alacritty.toml", 3, fontQueryToml)) { break; } } while (false); From ebf38e829da1982ef52e7d52356de8fac68ac5b2 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 11 Aug 2026 11:00:17 +0800 Subject: [PATCH 16/26] OS (Android): reports real code names --- src/detection/os/os_android.c | 50 ++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/detection/os/os_android.c b/src/detection/os/os_android.c index 47ea40b469..0e8a7c1b2e 100644 --- a/src/detection/os/os_android.c +++ b/src/detection/os/os_android.c @@ -1,6 +1,43 @@ #include "os.h" #include "common/settings.h" +// https://en.wikipedia.org/wiki/Android_version_history +static const struct { + const char* version; + const char* codename; +} androidCodenames[] = { + { "17", "Cinnamon Bun" }, + { "16", "Baklava" }, + { "15", "Vanilla Ice Cream" }, + { "14", "Upside Down Cake" }, + { "13", "Tiramisu" }, + { "12", "Snow Cone" }, + { "11", "Red Velvet Cake" }, + { "10", "Quince Tart" }, + { "9", "Pie" }, + { "8.1", "Oreo" }, + { "8.0", "Oreo" }, + { "7.1", "Nougat" }, + { "7.0", "Nougat" }, + { "6.0", "Marshmallow" }, + { "5.1", "Lollipop" }, + { "5.0", "Lollipop" }, + { "4.4", "KitKat" }, + { "4.3", "Jelly Bean" }, + { "4.2", "Jelly Bean" }, + { "4.1", "Jelly Bean" }, + { "4.0", "Ice Cream Sandwich" }, + { "3.2", "Honeycomb" }, + { "3.1", "Honeycomb" }, + { "3.0", "Honeycomb" }, + { "2.3", "Gingerbread" }, + { "2.2", "Froyo" }, + { "2.1", "Eclair" }, + { "2.0", "Eclair" }, + { "1.6", "Donut" }, + { "1.5", "Cupcake" }, +}; + void ffDetectOSImpl(FFOSResult* os) { ffStrbufSetStatic(&os->name, "Android"); @@ -8,9 +45,20 @@ void ffDetectOSImpl(FFOSResult* os) { ffSettingsGetAndroidProperty("ro.build.version.release", &os->version); - ffSettingsGetAndroidProperty("ro.build.version.release", &os->versionID); + ffStrbufSet(&os->versionID, &os->version); ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename); + // On release builds, ro.build.version.codename reports "REL" instead of the real codename. + // In that case, look up the codename from the version table. + if (ffStrbufEqualS(&os->codename, "REL")) { + for (size_t i = 0; i < ARRAY_SIZE(androidCodenames); i++) { + if (ffStrbufEqualS(&os->version, androidCodenames[i].version)) { + ffStrbufSetStatic(&os->codename, androidCodenames[i].codename); + break; + } + } + } + ffSettingsGetAndroidProperty("ro.build.id", &os->buildID); } From a0452b8323aaa9d3b5b6ded435ed6660cee2bbb9 Mon Sep 17 00:00:00 2001 From: JunaidQrysh <163889347+JunaidQrysh@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:11:45 +0530 Subject: [PATCH 17/26] Logo (Image): don't block images support in zellij --- src/logo/image/image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logo/image/image.c b/src/logo/image/image.c index bc33e67f70..c97e1f7ba9 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -996,7 +996,7 @@ bool ffLogoPrintImageIfExists(FFLogoType type, bool printError) { } const char* term = getenv("TERM"); - if ((term && ffStrEquals(term, "screen")) || getenv("ZELLIJ")) { + if (term && ffStrEquals(term, "screen")) { if (printError) { fputs("Logo: Image logo is not supported in terminal multiplexers\n", stderr); } From 51cfd4b5edc589b5a632d527636b994dadecc447 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 11 Aug 2026 13:52:59 +0800 Subject: [PATCH 18/26] OS (Android): optimises code --- src/detection/os/os_android.c | 76 +++++++++++++---------------------- 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/src/detection/os/os_android.c b/src/detection/os/os_android.c index 0e8a7c1b2e..1e1279d3f2 100644 --- a/src/detection/os/os_android.c +++ b/src/detection/os/os_android.c @@ -1,43 +1,6 @@ #include "os.h" #include "common/settings.h" -// https://en.wikipedia.org/wiki/Android_version_history -static const struct { - const char* version; - const char* codename; -} androidCodenames[] = { - { "17", "Cinnamon Bun" }, - { "16", "Baklava" }, - { "15", "Vanilla Ice Cream" }, - { "14", "Upside Down Cake" }, - { "13", "Tiramisu" }, - { "12", "Snow Cone" }, - { "11", "Red Velvet Cake" }, - { "10", "Quince Tart" }, - { "9", "Pie" }, - { "8.1", "Oreo" }, - { "8.0", "Oreo" }, - { "7.1", "Nougat" }, - { "7.0", "Nougat" }, - { "6.0", "Marshmallow" }, - { "5.1", "Lollipop" }, - { "5.0", "Lollipop" }, - { "4.4", "KitKat" }, - { "4.3", "Jelly Bean" }, - { "4.2", "Jelly Bean" }, - { "4.1", "Jelly Bean" }, - { "4.0", "Ice Cream Sandwich" }, - { "3.2", "Honeycomb" }, - { "3.1", "Honeycomb" }, - { "3.0", "Honeycomb" }, - { "2.3", "Gingerbread" }, - { "2.2", "Froyo" }, - { "2.1", "Eclair" }, - { "2.0", "Eclair" }, - { "1.6", "Donut" }, - { "1.5", "Cupcake" }, -}; - void ffDetectOSImpl(FFOSResult* os) { ffStrbufSetStatic(&os->name, "Android"); @@ -47,17 +10,36 @@ void ffDetectOSImpl(FFOSResult* os) { ffStrbufSet(&os->versionID, &os->version); - ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename); + unsigned major = 0; + for (const char* p = os->version.chars; *p >= '0' && *p <= '9'; ++p) { + major = major * 10 + (unsigned) (*p - '0'); + } + + const char* codename = NULL; + // https://en.wikipedia.org/wiki/Android_version_history + // Android 5 is the oldest version supported by Termux + // clang-format off + switch (major) { + case 17: codename = "Cinnamon Bun"; break; + case 16: codename = "Baklava"; break; + case 15: codename = "Vanilla Ice Cream"; break; + case 14: codename = "Upside Down Cake"; break; + case 13: codename = "Tiramisu"; break; + case 12: codename = "Snow Cone"; break; + case 11: codename = "Red Velvet Cake"; break; + case 10: codename = "Quince Tart"; break; + case 9: codename = "Pie"; break; + case 8: codename = "Oreo"; break; + case 7: codename = "Nougat"; break; + case 6: codename = "Marshmallow"; break; + case 5: codename = "Lollipop"; break; + } + // clang-format on - // On release builds, ro.build.version.codename reports "REL" instead of the real codename. - // In that case, look up the codename from the version table. - if (ffStrbufEqualS(&os->codename, "REL")) { - for (size_t i = 0; i < ARRAY_SIZE(androidCodenames); i++) { - if (ffStrbufEqualS(&os->version, androidCodenames[i].version)) { - ffStrbufSetStatic(&os->codename, androidCodenames[i].codename); - break; - } - } + if (codename) { + ffStrbufSetStatic(&os->codename, codename); + } else { + ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename); } ffSettingsGetAndroidProperty("ro.build.id", &os->buildID); From 16b10c162b11e0cea3a368d6d5d4f4a6eb206eaa Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 12 Aug 2026 10:07:34 +0800 Subject: [PATCH 19/26] Revert "Locale (macOS): queries system-wide locale preference" This reverts commit 8b8efcdcce100594fc81f10b79df5b13632754c3. --- CMakeLists.txt | 2 +- src/detection/locale/locale_apple.c | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 src/detection/locale/locale_apple.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e86d3d400..94400df859 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1038,7 +1038,7 @@ elseif(APPLE) src/detection/lm/lm_nosupport.c src/detection/loadavg/loadavg_bsd.c src/detection/libc/libc_apple.c - src/detection/locale/locale_apple.c + src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_apple.c src/detection/media/media_apple.m diff --git a/src/detection/locale/locale_apple.c b/src/detection/locale/locale_apple.c deleted file mode 100644 index c5a5e8e1a3..0000000000 --- a/src/detection/locale/locale_apple.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "detection/locale/locale.h" -#include "common/apple/cf_helpers.h" - -const char* ffDetectLocale(FFstrbuf* result) { - // Read the system-wide locale preference (equivalent to `defaults read -g AppleLocale`), - // which is NOT affected by user environment variables (LANG, LC_ALL, etc.) - FF_CFTYPE_AUTO_RELEASE CFStringRef appleLocale = CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesAnyApplication); - if (!appleLocale) { - return "Failed to read AppleLocale"; - } - - return ffCfStrGetString(appleLocale, result); -} From 1d120035557c04002fbb5660e43e6175dbfa3871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 12 Aug 2026 10:19:22 +0800 Subject: [PATCH 20/26] Locale (Windows): uses $LANG if available e.g. MSYS2 --- src/detection/locale/locale_windows.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/detection/locale/locale_windows.c b/src/detection/locale/locale_windows.c index 0f17e8bfae..4f5896667f 100644 --- a/src/detection/locale/locale_windows.c +++ b/src/detection/locale/locale_windows.c @@ -1,9 +1,19 @@ #include "detection/locale/locale.h" #include "common/windows/unicode.h" -#include +#include const char* ffDetectLocale(FFstrbuf* result) { + ffStrbufAppendS(result, getenv("LC_ALL")); + if (result->length > 0) { + return nullptr; + } + + ffStrbufAppendS(result, getenv("LANG")); // Available in MSYS2 and Cygwin + if (result->length > 0) { + return nullptr; + } + wchar_t name[LOCALE_NAME_MAX_LENGTH]; int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH); if (size <= 1) { // including '\0' From c4695b8cf10faabe69fce8f8971d034678453886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 12 Aug 2026 10:29:29 +0800 Subject: [PATCH 21/26] Processing (Windows): sets `LANG=C` when spawning child processes --- src/common/impl/processing_windows.c | 56 +++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/src/common/impl/processing_windows.c b/src/common/impl/processing_windows.c index 5df9f90576..c3f5792613 100644 --- a/src/common/impl/processing_windows.c +++ b/src/common/impl/processing_windows.c @@ -48,6 +48,41 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result) { } } +static wchar_t* createChildEnvironment(void) { + wchar_t* source = GetEnvironmentStringsW(); + if (!source) { + return nullptr; + } + + size_t sourceLength = 0; + for (const wchar_t* entry = source; *entry; entry += wcslen(entry) + 1) { + sourceLength += wcslen(entry) + 1; + } + + wchar_t* result = malloc((sourceLength + 7) * sizeof(wchar_t)); + wchar_t* write = result; + bool foundLang = false; + for (const wchar_t* entry = source; *entry; entry += wcslen(entry) + 1) { + if (_wcsnicmp(entry, L"LANG=", 5) == 0) { + wcscpy(write, L"LANG=C"); + write += 6; + foundLang = true; + } else { + size_t entryLength = wcslen(entry) + 1; + memcpy(write, entry, entryLength * sizeof(wchar_t)); + write += entryLength; + } + } + if (!foundLang) { + wcscpy(write, L"LANG=C"); + write += 6; + } + *write = L'\0'; + + FreeEnvironmentStringsW(source); + return result; +} + const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle) { const int32_t timeout = instance.config.general.processingTimeout; @@ -108,17 +143,18 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* } } + FF_AUTO_FREE wchar_t* environment = createChildEnvironment(); BOOL success = CreateProcessW( - nullptr, // application name - cmdline, // command line - nullptr, // process security attributes - nullptr, // primary thread security attributes - TRUE, // handles are inherited - 0, // creation flags - nullptr, // use parent's environment - nullptr, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &piProcInfo // receives PROCESS_INFORMATION + nullptr, // application name + cmdline, // command line + nullptr, // process security attributes + nullptr, // primary thread security attributes + TRUE, // handles are inherited + CREATE_UNICODE_ENVIRONMENT, // creation flags + environment, // child environment + nullptr, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &piProcInfo // receives PROCESS_INFORMATION ); NtClose(hChildPipeWrite); From 681749ed5401c74c0e68e0062fa6d3a838748dfe Mon Sep 17 00:00:00 2001 From: njk Date: Wed, 12 Aug 2026 20:04:19 -0500 Subject: [PATCH 22/26] TerminalFont (Ghostty): fixes font-family fallback order (#2510) --- src/detection/terminalfont/terminalfont.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index 8c54a85009..463abeed76 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -98,13 +98,17 @@ static void parseGhosttyConfig(FFstrbuf* path, FFstrbuf* fontName, FFstrbuf* fon while (ffStrbufGetline(&line, &len, &buffer)) { if (ffParsePropLine(line, "font-family =", &temp)) { FF_DEBUG("found font-family='%s' in %s", temp.chars, path->chars); - // Latter overrides former; former becomes the fallback font - if (fontName->length > 0) { - ffStrbufDestroy(fontNameFallback); - ffStrbufInitMove(fontNameFallback, fontName); + // Ghostty appends to a fallback list; the first entry is the primary font. + // An empty value resets the list. + if (temp.length == 0) { + ffStrbufClear(fontName); + ffStrbufClear(fontNameFallback); + } else if (fontName->length == 0) { + ffStrbufSet(fontName, &temp); + } else if (fontNameFallback->length == 0) { + ffStrbufSet(fontNameFallback, &temp); } - ffStrbufDestroy(fontName); - ffStrbufInitMove(fontName, &temp); + ffStrbufClear(&temp); } else if (ffParsePropLine(line, "font-size =", &temp)) { FF_DEBUG("found font-size='%s' in %s", temp.chars, path->chars); // Latter overrides former From 7098cd86cb4f2c3d12175e583f4d53707a10541d Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 13 Aug 2026 09:46:58 +0800 Subject: [PATCH 23/26] Display: fixes bright colours incorrectly active in light theme Fixes #2509 --- src/common/impl/init.c | 12 ------------ src/fastfetch.h | 1 - src/options/display.c | 29 ++++++++++++++++++++++------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/common/impl/init.c b/src/common/impl/init.c index 8f6edbe7f4..885b0b6ee8 100644 --- a/src/common/impl/init.c +++ b/src/common/impl/init.c @@ -5,7 +5,6 @@ #include "common/textModifier.h" #include "common/strutil.h" #include "detection/displayserver/displayserver.h" -#include "detection/terminaltheme/terminaltheme.h" #include "logo/logo.h" #include @@ -27,21 +26,10 @@ static void initState(FFstate* state) { state->logoWidth = 0; state->logoHeight = 0; state->keysHeight = 0; - state->terminalLightTheme = false; state->titleFqdn = false; ffPlatformInit(&state->platform); state->dynamicInterval = 0; - - #if !FF_MODULE_DISABLE_TERMINALTHEME - { - // don't enable bright color if the terminal is in light mode - FFTerminalThemeResult result; - if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark) { - state->terminalLightTheme = true; - } - } - #endif } static void defaultConfig(void) { diff --git a/src/fastfetch.h b/src/fastfetch.h index ac9fa6c260..a8d34869f7 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -31,7 +31,6 @@ typedef struct FFstate { uint32_t logoWidth; uint32_t logoHeight; uint32_t keysHeight; - bool terminalLightTheme; bool titleFqdn; uint32_t dynamicInterval; FFPlatform platform; diff --git a/src/options/display.c b/src/options/display.c index a1136e7b1a..d515e92c1b 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -5,6 +5,10 @@ #include "common/strutil.h" #include "options/display.h" +#if !FF_MODULE_DISABLE_TERMINALTHEME + #include "detection/terminaltheme/terminaltheme.h" +#endif + #include const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_val* root, yyjson_val** pkey) { @@ -825,11 +829,22 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key } void ffOptionsInitDisplay(FFOptionsDisplay* options) { + bool terminalLightTheme = false; + #if !FF_MODULE_DISABLE_TERMINALTHEME + { + // don't enable bright color if the terminal is in light mode + FFTerminalThemeResult result; + if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark) { + terminalLightTheme = true; + } + } + #endif + ffStrbufInit(&options->colorKeys); ffStrbufInit(&options->colorTitle); ffStrbufInit(&options->colorOutput); ffStrbufInit(&options->colorSeparator); - options->brightColor = !instance.state.terminalLightTheme; + options->brightColor = !terminalLightTheme; ffStrbufInitStatic(&options->keyValueSeparator, ": "); options->showErrors = false; @@ -856,8 +871,8 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) { options->tempUnit = FF_TEMPERATURE_UNIT_DEFAULT; options->tempNdigits = 1; ffStrbufInitStatic(&options->tempColorGreen, FF_COLOR_FG_GREEN); - ffStrbufInitStatic(&options->tempColorYellow, instance.state.terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW); - ffStrbufInitStatic(&options->tempColorRed, instance.state.terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED); + ffStrbufInitStatic(&options->tempColorYellow, terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW); + ffStrbufInitStatic(&options->tempColorRed, terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED); options->tempSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT; ffStrbufInitStatic(&options->barCharElapsed, "■"); @@ -867,8 +882,8 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) { ffStrbufInit(&options->barBorderLeftElapsed); ffStrbufInit(&options->barBorderRightElapsed); ffStrbufInitStatic(&options->barColorElapsed, "auto"); - ffStrbufInitStatic(&options->barColorTotal, instance.state.terminalLightTheme ? FF_COLOR_FG_WHITE : FF_COLOR_FG_LIGHT_WHITE); - ffStrbufInitStatic(&options->barColorBorder, instance.state.terminalLightTheme ? FF_COLOR_FG_WHITE : FF_COLOR_FG_LIGHT_WHITE); + ffStrbufInitStatic(&options->barColorTotal, terminalLightTheme ? FF_COLOR_FG_WHITE : FF_COLOR_FG_LIGHT_WHITE); + ffStrbufInitStatic(&options->barColorBorder, terminalLightTheme ? FF_COLOR_FG_WHITE : FF_COLOR_FG_LIGHT_WHITE); options->barWidth = 10; options->durationAbbreviation = false; @@ -876,8 +891,8 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) { options->percentType = FF_PERCENTAGE_TYPE_NUM_BIT | FF_PERCENTAGE_TYPE_NUM_COLOR_BIT; options->percentNdigits = 0; ffStrbufInitStatic(&options->percentColorGreen, FF_COLOR_FG_GREEN); - ffStrbufInitStatic(&options->percentColorYellow, instance.state.terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW); - ffStrbufInitStatic(&options->percentColorRed, instance.state.terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED); + ffStrbufInitStatic(&options->percentColorYellow, terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW); + ffStrbufInitStatic(&options->percentColorRed, terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED); options->percentSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT; options->percentWidth = 0; From 8df0a1c97e32a5009d8f238d856104be44f9f416 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 13 Aug 2026 09:50:04 +0800 Subject: [PATCH 24/26] Doc: removes Star History in README.md Fixes #2508 --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index d2b0a53d92..32c2283144 100644 --- a/README.md +++ b/README.md @@ -330,15 +330,3 @@ If you find Fastfetch useful, please consider donating. * Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/) * This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it - -## Star History - -Give us a star to show your support! - - - - - - Star History Chart - - From 368a4c5a73ceceba97ee0eb069a4c04350dd4839 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 13 Aug 2026 10:58:11 +0800 Subject: [PATCH 25/26] Release v2.67.1 --- CHANGELOG.md | 17 ++++++++++++++--- CMakeLists.txt | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1088ace296..2bfcb457c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,20 @@ # 2.67.1 Bugfixes: -* Fixed `Symbol not found` error when running on macOS 10.15 (macOS) -* Fixed building on Apple clang 16 (the default compiler of macOS 14) -* Added a C23 compiler check so the build process exits during CMake configuration +* Fixed a `Symbol not found` error when running on macOS 10.15. (Codec, macOS) +* Fixed Alacritty font size never being parsed from the TOML config. (TerminalFont) +* Fixed Ghostty `font-family` fallback order. (#2510, TerminalFont) +* Fixed bright colors incorrectly being active when the terminal uses a light theme. (#2509, Display) +* Fixed Ghostty terminal font detection by trying to load the config with the `.ghostty` extension. (#2500, TerminalFont) +* Added compatibility workarounds for Apple Clang 14 to fix building on macOS 14. (CMake, macOS) +* Some internal cleanups and optimizations. + +Features: +* Added a C23 compiler check so the build process gracefully exits during CMake configuration if the compiler is unsupported. (CMake) +* Reported real Android version codenames (e.g., "Baklava", "Vanilla Ice Cream") instead of "REL". (OS, Android) +* Added Loadavg detection support on Haiku R1B6. (Loadavg, Haiku) +* Enabled image logo support in the Zellij terminal multiplexer. (Logo) +* Improved Locale detection on Windows to use `$LC_ALL` or `$LANG` environment variables if available (e.g., in MSYS2 or Cygwin). (Locale, Windows) # 2.67.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 94400df859..687e89b5e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.67.0 + VERSION 2.67.1 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" From 5ea299a8d2f6121d09bd67f467ccf5aa8f0970f8 Mon Sep 17 00:00:00 2001 From: OctoBored <212877535+OctoBored@users.noreply.github.com> Date: Thu, 13 Aug 2026 09:26:14 +0000 Subject: [PATCH 26/26] Doc: restores Star History in README.md The Star History chart was removed in 8df0a1c9 (Fixes #2508) because the previous chart was broken due to GitHub stargazer API restrictions. This restores it at the same location using a working data source that requires no API token, so the chart renders correctly again. --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 32c2283144..7f2481cbd2 100644 --- a/README.md +++ b/README.md @@ -330,3 +330,15 @@ If you find Fastfetch useful, please consider donating. * Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/) * This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it + +## Star History + +Give us a star to show your support! + + + + + + Star History Chart + +