Compare commits

...

115 Commits

Author SHA1 Message Date
Carter Li 7a2bf4e0ac Merge pull request #2049 from fastfetch-cli/dev
Releases: v2.55.0
2025-11-11 18:51:24 +08:00
李通洲 662f5127fa Shell: makes fish shell version detection more robust (v2) 2025-11-11 15:38:53 +08:00
李通洲 fb9117553b Shell: makes fish shell version detection more robust 2025-11-11 15:19:40 +08:00
李通洲 9f24e4363f Media (Linux): handles invalid percent-encoding in cover metadata 2025-11-11 15:16:12 +08:00
李通洲 084f9294f2 Media: updates naming convention from mediacover to media-cover for media cover logo sources 2025-11-11 14:42:55 +08:00
李通洲 a9f1f9a647 Doc: update changelog 2025-11-11 14:31:23 +08:00
李通洲 0aed89036b Chore: silenses some compiler warnings 2025-11-11 14:24:32 +08:00
李通洲 df15bbc5f2 Media: moves media cover cleanup logic to media detection 2025-11-11 14:00:43 +08:00
李通洲 e6b0bd3817 Media: fixes album cover serialization in JSON result 2025-11-11 13:58:45 +08:00
李通洲 11cd7153a2 Logo (Builtin): tidy [ci skip] 2025-11-11 13:53:34 +08:00
李通洲 f8bc1cb605 Releases: v2.55.0 2025-11-11 11:01:54 +08:00
李通洲 8b8eb6f290 TerminalShell (Linux): ignores run-parts
Ref: #2048
2025-11-11 10:10:47 +08:00
李通洲 056fe21ee2 Examples/25: removes parallel: true since we had it enabled by default [ci skip] 2025-11-11 10:07:58 +08:00
Carter Li cb0a88df22 [Command] enables parallel command execution by default 2025-11-11 09:28:44 +08:00
Carter Li 298c0431c3 Examples: improves clang version extraction method in 25.jsonc [ci skip] 2025-11-11 09:00:01 +08:00
Carter Li 448de9afa5 Command: makes compiler happy 2025-11-10 22:48:22 +08:00
Carter Li 9401a4b9ad Processing: adds a missing header 2025-11-10 18:09:19 +08:00
李通洲 ea92ad3785 Command: adds parallel and useStdErr options
Fixes #2045
2025-11-10 16:34:23 +08:00
李通洲 7aaad5e03e Processing: refactors process execution to separate spawning and reading 2025-11-10 16:34:23 +08:00
李通洲 645bf5c839 Disk: moves disk hiding by folder and FS type to detection code
Don't probe if hided

Fixes #2043
2025-11-06 13:39:30 +08:00
李通洲 7638e0e4a1 CMake: improves wordexp/glob detection and messaging 2025-11-05 10:21:05 +08:00
李通洲 302b8a7b1b CommandLine: adds dynamic output refresh support with interval option 2025-11-05 10:21:05 +08:00
李通洲 dbb9d8a660 Display: adds missing #include 2025-11-05 09:59:27 +08:00
李通洲 c51a164042 PublicIP / Weather: cleans up states after detection 2025-11-05 09:56:23 +08:00
李通洲 6b8a62da6e Linux (Host): improves Mac family detection by using prefix match 2025-11-04 09:12:35 +08:00
李通洲 578ca23e75 GPU (Hurd): adds support (requires libpciaccess) 2025-11-01 09:57:52 +00:00
李通洲 2e73a90835 GPU (OpenBSD): adds native GPU detection support 2025-11-01 17:23:59 +08:00
李通洲 cc6273fecc GPU (NetBSD): don't use system function name 2025-11-01 17:19:25 +08:00
李通洲 e63b777916 GPU: handles missing GPU type as null in JSON output 2025-11-01 16:44:36 +08:00
李通洲 907567f511 GPU (NetBSD): improves performance; drops libpciaccess dependency 2025-11-01 16:42:19 +08:00
李通洲 e0fd7308be Logo (Builtin): add Vincent OS
Fixes #2030
2025-10-31 11:04:18 +08:00
李通洲 b761034aae OS (Linux): prints debian version on Raspbery Pi OS
Fixes #2032
2025-10-31 11:04:18 +08:00
李通洲 04d6b1453d GPU (NetBSD): adds native GPU detection support 2025-10-31 11:04:18 +08:00
Carter Li 11d1754686 GPU: skips auxiliary display controllers
Fixes #2034
2025-10-30 14:46:30 +08:00
Carter Li 25e84decff GPU: unifies non-pci GPU device ID formatting across platforms 2025-10-30 11:01:06 +08:00
Carter Li 7d665b203f GPU: unifies GPU PCI device ID calculation logic across different platforms 2025-10-30 10:26:35 +08:00
李通洲 ac62442798 CMake: refines yyjson config and Apple rpath handling
Fixes #1998
2025-10-28 09:30:46 +08:00
李通洲 758f96de60 Icons (Windows): hides module when no icons are found
Fixes #2023
2025-10-24 14:46:09 +08:00
李通洲 db623b9c86 CI (Linux): adds Debian i386 packaging and verify deb package in CI
Fixes #2019
2025-10-22 17:45:50 +08:00
李通洲 c353bf3c96 Logo: adds automatic cleanup of temporary media cover files 2025-10-22 13:51:36 +08:00
李通洲 338b552499 Logo: adds support for using media cover as logo source 2025-10-21 15:05:25 +08:00
李通洲 5d73cc1232 Media: save media cover to temp file 2025-10-21 14:36:35 +08:00
李通洲 faddef7a3b Media (Windows): adds media cover extraction 2025-10-21 14:01:26 +08:00
Carter Li 2d9bbc8049 Media (Linux): adds media cover extraction 2025-10-21 09:44:36 +08:00
李通洲 64afaa07e7 Media (macOS): adds media cover extraction 2025-10-21 09:44:36 +08:00
李通洲 5cf3ab23b0 Utils (macOS): adds ffCfDictGetDataAsString 2025-10-21 08:49:34 +08:00
李通洲 3fe926d3a0 Doc: adds code-signing credit and privacy statement in README [ci skip]
As required by signpath
2025-10-20 23:43:32 +08:00
李通洲 f71bb682de Logo (Builtin): adds MacaroniOS
Fixes #2018
2025-10-20 15:12:11 +08:00
Carter Li 904f860f3c Packaging: builds for all Ubuntu versions [ci skip] 2025-10-20 14:58:23 +08:00
Carter Li 8f15c9604c Merge remote-tracking branch 'origin/master' into dev 2025-10-20 14:57:59 +08:00
李通洲 ff28f5807b Shell: supports brush version detection 2025-10-19 10:25:28 +08:00
李通洲 6a317366d7 Shell: fix fish version detection when LC_ALL is set
Fixes #2014
2025-10-19 10:25:28 +08:00
李通洲 dc3e4a2d18 JsonSchema: fixes copy-paste errors [ci skip]
Fixes #2013
2025-10-18 18:38:39 +08:00
Carter Li 46c4a71ba3 Merge pull request #2012 from fastfetch-cli/dev
Release: v2.54.0
2025-10-18 10:15:23 +08:00
Carter Li f0759acd11 Brightness (macOS): tidy 2025-10-18 09:35:34 +08:00
李通洲 96c7c2966d Brightness (macOS): prioritizes DDC/CI reply over simple I²C transaction 2025-10-18 01:11:03 +08:00
李通洲 554e7bce4a Logo (Builtin): adds Zraxyl
Fixes #1860
2025-10-18 00:56:14 +08:00
李通洲 70377a8afd Release: v2.54.0 2025-10-18 00:47:35 +08:00
李通洲 51bc6d421a CI (Windows): switches CI to use the release signing policy on the master branch 2025-10-18 00:47:35 +08:00
李通洲 be0756f8ba CMake: adds a new build option to gate wordexp usage and detection 2025-10-16 15:29:24 +08:00
李通洲 71a2cb4e1b Doc: adds security warning for Command module in README 2025-10-16 14:34:51 +08:00
李通洲 2eba761bed IO (OpenBSD): fixes incorrect glob usage 2025-10-16 14:33:53 +08:00
李通洲 4b5e1a816b Display (Windows): rename VRR to DRR 2025-10-16 13:24:44 +08:00
Dariqq a92e4b2d67 Chore (Windows): standardize more windows header casing.
Followup to 25353261d0
2025-10-14 15:49:06 +08:00
李通洲 a32404ba98 Doc: updates changelog 2025-10-14 14:51:44 +08:00
李通洲 0a792e4935 CPU (Android): adds detection support for Samsung Exynos SoCs 2025-10-14 14:49:29 +08:00
李通洲 05108977e8 CPU (Android): improves Android SoC vendor and model detection 2025-10-14 14:49:29 +08:00
李通洲 25353261d0 Chore (Windows): standardizes Windows header include casing. NOOP.
Fixes #2006
2025-10-14 09:10:24 +08:00
李通洲 4b517263d0 Chore (macOS): refactors code for better resource management 2025-10-13 14:27:23 +08:00
李通洲 98a65966e7 Doc: update changelog [ci skip] 2025-10-13 10:19:22 +08:00
李通洲 32dcf9487f Option: adds configurable spacing between icon and string keys
Fixes #2004
2025-10-13 09:54:34 +08:00
Carter Li e3a698f7b1 Brightness (macOS): fixes detection for external monitor on Intel platform 2025-10-11 21:26:37 +08:00
李通洲 1631f74700 Disk (Linux): revisits 78c6d71049 2025-10-11 18:20:56 +08:00
李通洲 78c6d71049 Disk (Linux): adds glob pattern matching for hidden disk folders
Fixes #1999
2025-10-11 16:19:11 +08:00
李通洲 0b9ecdeade Doc: adds Chinese README [ci skip] 2025-10-11 09:31:59 +08:00
李通洲 185a9211f1 Doc: update changelog 2025-10-10 15:09:25 +08:00
李通洲 24459b2fbf Brightness (macOS): enhance DDC/CI detection by enumerating all I2C buses 2025-10-10 14:24:11 +08:00
Carter Li 88c8dcb3e8 CPU (Linux): improves detection for T-Head CPU vendor
Ref: #1997
2025-10-10 10:55:12 +08:00
Carter Li f3a8fedf0a CPU (Linux): improves SoC name detection from device tree
Fixes #1997
2025-10-10 10:50:20 +08:00
李通洲 6b8b7c1a62 CI (Windows): signs PE files 2025-10-08 00:39:22 +08:00
李通洲 af26828f91 CPU (Linux): adds support for HP PA‑RISC & SuperH CPU architecture detection 2025-10-05 09:22:06 +08:00
李通洲 f4c43abbf7 Display (Windows): adds VRR status detection support 2025-10-05 09:17:30 +08:00
李通洲 e84739bff0 Logo (Builtin): update T2 2025-10-05 09:15:59 +08:00
李通洲 66aad0e4f1 Revert "Display (Windows): fixes incorrect refresh rate when VRR is enabled"
Doesn't work

This reverts commit 31ae7a642a.
2025-10-05 00:16:49 +08:00
Carter Li 77c43c0214 Display (Linux): prefer resolutions reported by randr mode info 2025-10-04 22:19:25 +08:00
李通洲 31ae7a642a Display (Windows): fixes incorrect refresh rate when VRR is enabled
Fixes #1994
2025-10-03 23:42:57 +08:00
Carter Li 1bbb21486c Disk (Linux): f* Android
Fixes #1993
2025-10-03 16:53:09 +08:00
李通洲 316d8ddf9b CI (Linux): disables post operations for polyfilled binaries
Fixes #1990
2025-10-03 12:16:15 +08:00
Carter Li 5d8c21a5ca Memory (Linux): fallbacks to calcuate ourselves when MemAvailable seems unreasonable
Fixes #1988
2025-10-02 07:39:20 +08:00
李通洲 240ba5c00c Platform (Windows): adds missing else for Wine version detection 2025-10-01 16:45:13 +08:00
Carter Li 554184ec72 OS (Windows): restores compatibility with WINE
Revert "OS (Windows): hard linking winbrand"

This reverts commit 4146bb6731.
2025-10-01 16:12:45 +08:00
李通洲 7a055a2254 CI: upgrades compiler versions 2025-10-01 10:07:28 +08:00
Carter Li 0a807ac1a3 TerminalFont (Linux): fixes default font size for ghostty
Fixes #1986
2025-10-01 08:09:04 +08:00
Carter Li 4d831c8c73 OS (Linux): don't change prettyName on Ubuntu development branch
Ref: #1483
2025-09-30 15:24:52 +08:00
李通洲 e6e78a7aae OS (macOS): improves OS detection accuracy and sets pretty name 2025-09-30 13:35:48 +08:00
李通洲 09bef5f41d OS (macOS): removes fallback parsing of legacy macOS license file
Doesn't work on Tahoe anymore
2025-09-30 13:22:00 +08:00
李通洲 e394efdd85 OS (macOS): trims whitespace from full user name 2025-09-30 13:19:58 +08:00
李通洲 c10b652a2e Swap (Windows): prevents integer overflow in swap size
Regression from 7ec0c664c5
2025-09-30 10:05:08 +08:00
李通洲 1594a69d6c Kernel (Windows): move kernel.displayVersion to OS.codeName 2025-09-30 10:01:01 +08:00
李通洲 9b1e318bd1 OS (Linux): sets code name for Ubuntu 2025-09-30 09:09:36 +08:00
李通洲 e292bf1dee OS (Linux): sets point release for Debian
Fixes #1985
2025-09-30 09:06:12 +08:00
李通洲 55a0c6e97d Logo (Builtin): adds EmperorOS
Fixes #1963
2025-09-29 10:07:26 +08:00
Rain Xelelo 8b8e4a40a4 Logo (Builtin): adds PrismLinux
Fixes #1983
2025-09-28 21:01:03 -05:00
李通洲 8be070998f Theme (Windows): moves Windows theme detection logic from DE to dedicated module
Like the last commit
2025-09-29 09:40:10 +08:00
李通洲 093f56a03d Theme (macOS): moves macOS theme detection logic from DE to dedicated module
The old behavior was inherited from neofetch. However `Aqua` and `Liquid Glass` are actually design language, not a DE. There is no DE on macOS.
2025-09-29 09:25:24 +08:00
李通洲 bd9744c27c CommandLine: adds --json flag as a shortcut for enabling JSON output 2025-09-28 15:07:45 +08:00
李通洲 adc25f4420 CI: adds Debian libc6 dependency to package config
Fixes #1981
2025-09-28 14:43:38 +08:00
李通洲 229fe7c7bf CMake: update contact info 2025-09-28 14:43:38 +08:00
李通洲 5d571752ae Chore: updates FUNDING info 2025-09-28 14:43:38 +08:00
李通洲 512ddfae6b Doc: adds padding check to logo request template 2025-09-28 09:40:48 +08:00
李通洲 7b689f94df Logo (Builtin): adds secureblue
Fixes #1979
2025-09-28 09:40:21 +08:00
李通洲 9eed149b09 CMake (Linux): adds i686 CI build and unify processor naming
Fixes #1978
2025-09-25 16:30:59 +08:00
李通洲 0f5d321df8 Chore: updates comments to use English descriptions 2025-09-24 10:11:02 +08:00
李通洲 4e84094fd8 CI (OpenBSD): updates CI workflow to upgrade packages before install 2025-09-23 16:41:18 +08:00
李通洲 7b9fce0189 CI (Linux): adds GCC 13 toolchain to CI build environment 2025-09-23 16:00:45 +08:00
111 changed files with 2035 additions and 563 deletions
+3
View File
@@ -0,0 +1,3 @@
github: LinusDierheimer
ko_fi: carterli
custom: https://paypal.me/zhangsongcui
+2
View File
@@ -36,3 +36,5 @@ body:
required: true
- label: The ASCII art contains color codes, or the color codes are available in `os-release`
required: true
- label: The ASCII art contains no internal paddings (spaces at the start and the end of lines)
required: true
+119 -18
View File
@@ -89,8 +89,11 @@ jobs:
- name: cat /proc/cpuinfo
run: cat /proc/cpuinfo
- name: add gcc-13 repo
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build
run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build
- name: install linuxbrew packages
run: |
@@ -104,7 +107,7 @@ jobs:
languages: c
- name: configure project
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: CC=gcc-13 CXX=g++-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -142,7 +145,10 @@ jobs:
strip fastfetch && ./polyfill-glibc fastfetch --target-glibc=2.17
strip flashfetch && ./polyfill-glibc flashfetch --target-glibc=2.17
echo 'set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-polyfilled")' >> CPackConfig.cmake
cpack
echo 'set(CPACK_PACKAGE_RELOCATABLE OFF)' >> CPackConfig.cmake
echo 'set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17)")' >> CPackConfig.cmake
echo 'set(CPACK_RPM_SPEC_MORE_DEFINE "%global __os_install_post %{nil}")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v4
@@ -150,6 +156,72 @@ jobs:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
linux-i686:
name: Linux-i686
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: uname -a
run: uname -a
- name: cat /etc/os-release
run: cat /etc/os-release
- name: cat /proc/cpuinfo
run: cat /proc/cpuinfo
- name: add gcc-13 repo
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
- name: cmake version
run: cmake --version
- name: configure project
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_DIRECTX_HEADERS=Off .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: check deb package
run: dpkg -I fastfetch-*.deb
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: ldd fastfetch
- name: run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-i686
path: ./fastfetch-*.*
linux-armv7l:
name: Linux-armv7l
runs-on: ubuntu-24.04
@@ -169,12 +241,13 @@ jobs:
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y ca-certificates gpg curl
apt-get update && apt-get install -y software-properties-common ca-certificates gpg curl
add-apt-repository -y ppa:ubuntu-toolchain-r/test
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -209,8 +282,8 @@ jobs:
run: |
uname -a
apt-get update && apt-get install -y wget
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -246,12 +319,14 @@ jobs:
id: runcmd
with:
arch: ${{ matrix.arch }}
distro: ubuntu20.04
distro: ubuntu22.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
apt-get update && apt-get install -y software-properties-common
add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -449,8 +524,9 @@ jobs:
version: '7.7'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
sudo pkg_add -u
sudo pkg_add -r llvm-19.1.7p3 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
CC=clang-19 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -485,8 +561,8 @@ jobs:
version: '10.1'
run: |
uname -a
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -518,10 +594,10 @@ jobs:
prepare: |
uname -a
pkg update
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -634,17 +710,41 @@ jobs:
- name: run tests
run: ctest --output-on-failure
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
id: upload-unsigned-artifact
name: upload artifacts for signing
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-${{ matrix.arch }}
path: |
*.dll
fastfetch.exe
flashfetch.exe
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
name: submit signing request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
project-slug: 'fastfetch'
signing-policy-slug: ${{ github.ref == 'refs/heads/master' && 'release-signing' || 'test-signing' }}
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '.'
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
- name: upload true artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-${{ matrix.arch }}
path: ./fastfetch-windows-${{ matrix.arch }}.*
overwrite: true
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
@@ -652,6 +752,7 @@ jobs:
runs-on: ubuntu-latest
needs:
- linux-hosts
- linux-i686
- linux-armv7l
- linux-armv6l
- linux-vms
+79
View File
@@ -1,3 +1,82 @@
# 2.55.0
Changes:
* Commands are now executed in parallel by default to improve performance (#2045, Command)
* This behavior can be disabled in the config file with `"parallel": false` if it causes problems with certain scripts
* Folder/filesystem hiding is moved to the detection stage; hidden entries are no longer probed, improving performance (#2043, Disk)
Features:
* Adds `command.parallel` and `command.useStdErr` config options (Command)
* `parallel`: set to `false` to disable parallel execution (see Changes above)
* `useStdErr`: set to `true` to use stderr output instead of stdout
* Adds the command-line flag `--dynamic-interval <interval-in-ms>` to enable dynamic output auto-refresh (#2041)
* Due to internal limitations, some modules do not support dynamic updates (notably Display and Media)
* Adds support for using the current playing media's cover art as a logo source (Media / Logo)
* Usage: `"logo": { "type": "<image-protocol>", "source": "media-cover" }` in JSON config; or `--<image-protocol> media-cover` in command line
* Supports local sources only
* Adds native GPU detection support on OpenBSD and NetBSD (instead of depending on `libpciaccess`) (GPU)
* No functional changes
* Root privileges are required to access PCI config space on OpenBSD (as always)
* Adds GPU detection support on GNU/Hurd (GPU)
* Requires building with `libpciaccess`
* Shows Debian point release on Raspberry Pi OS (#2032, OS, Linux)
* Adds `Brush` shell version detection (Shell)
* Improves Mac family detection via prefix matching (Host)
Bugfixes:
* Ignores `run-parts` during terminal/shell detection (#2048, Terminal / Shell, Linux)
* Fixes fish version detection when `LC_ALL` is set (#2014, Shell, Linux)
* Hides the module when no desktop icons are found (#2023, Icons, Windows)
* Skips auxiliary display controllers to prevent the module from reporting duplicate entries (#2034, GPU, Linux)
* Refines Apple rpath handling; fixes building for the Homebrew version on macOS (#1998, CMake)
Logos:
* Adds Vincent OS and MacaroniOS
# 2.54.0
Windows binaries in Release page are now signed by SignPath.
Changes:
* Moves macOS and Windows design language detection from the DE module to the Theme module
Features:
* Adds `--json` and `-j` command line flags as a shortcut for `--format json`
* Various improvements to the OS module (OS)
* Displays point releases for Debian
* Displays code names for Ubuntu
* Displays build ID for macOS
* Displays code names for Windows (previously shown in the Kernel module)
* Adds basic support for Wine (Windows)
* Adds basic support for hppa and sh architectures (CPU, Linux)
* Improves T-Head SoC name detection from the device tree (#1997, CPU, Linux)
* Supports glob patterns in `Disk.hideFolders` (Disk)
* For example, `/boot/*` will match both `/boot/efi` and `/boot/firmware`
* Adds brightness-level detection for external monitor support on Intel macOS (Brightness, macOS)
* Adds configurable spacing between icon and text in keys
* `display.key.type: "both-N"` where N is `0-4`
* Useful for non-monospaced Nerd Fonts
* Adds detection support for modern Samsung Exynos SoCs (CPU, Android)
* Adds a new CMake option `-DENABLE_WORDEXP=<ON|OFF>` to enable or disable using `wordexp(3)` for acquiring logo file paths (`logo.source`)
* Enabled by default for compatibility
* Disabling this option reverts to using `glob(3)`, which is less functional but more secure
Bugfixes:
* Avoids integer overflow when calculating swap size (#1988, Swap, Windows)
* Trims whitespace from full user name (Title, macOS)
* Fixes default font size for Ghostty (#1986, TerminalFont, Linux)
* Works around an issue that could report impossibly high memory usage in rare cases (#1988, Memory, Linux)
* Fixes incorrect glibc dependency in polyfilled DEB packages (#1983, Linux)
* Fixes corrupted binaries in polyfilled RPM packages (#1990, Linux)
* Fixes crashes on ancient Android kernels (#1993, Disk, Android)
* Fixes incorrect usage of `glob(3)` (OpenBSD)
* Prefers resolutions reported by RandR mode info, fixing incorrect resolutions on XFCE when DPI scaling is enabled (Display, Linux)
* Various code cleanups and minor fixes
Logos:
* Adds secureblue, PrismLinux, EmperorOS and Zraxyl
* Updates T2
# 2.53.0
Changes:
+52 -38
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.53.0
VERSION 2.55.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -9,6 +9,17 @@ project(fastfetch
set(PROJECT_LICENSE "MIT license")
if(DEFINED CMAKE_SYSTEM_PROCESSOR_OVERRIDE) # Used by github actions for i686 build
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR_OVERRIDE} CACHE INTERNAL "")
endif()
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" CMAKE_SYSTEM_PROCESSOR)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
message(STATUS "Build for system processor: ${CMAKE_SYSTEM_PROCESSOR}")
###################
# Target Platform #
###################
@@ -82,7 +93,7 @@ cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" O
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "GNU" OFF)
option(ENABLE_ZLIB "Enable zlib" ON)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
@@ -95,6 +106,7 @@ option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions
option(INSTALL_LICENSE "Install license into /usr/share/licenses" ON)
option(ENABLE_EMBEDDED_PCIIDS "Embed pci.ids into fastfetch, requires `python`" OFF)
option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `python`" OFF)
option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON)
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch")
@@ -377,6 +389,7 @@ set(LIBFASTFETCH_SRC
src/detection/chassis/chassis.c
src/detection/cpu/cpu.c
src/detection/cpuusage/cpuusage.c
src/detection/command/command.c
src/detection/disk/disk.c
src/detection/diskio/diskio.c
src/detection/displayserver/displayserver.c
@@ -782,7 +795,7 @@ elseif(NetBSD)
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_nbsd.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_nbsd.c
@@ -866,7 +879,7 @@ elseif(OpenBSD)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_pci.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_obsd.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_obsd.c
src/detection/lm/lm_nosupport.c
@@ -963,7 +976,7 @@ elseif(APPLE)
src/detection/terminalfont/terminalfont_apple.m
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_nosupport.c
src/detection/theme/theme_apple.c
src/detection/tpm/tpm_apple.c
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
@@ -1024,7 +1037,7 @@ elseif(WIN32)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/netio/netio_windows.c
src/detection/opengl/opengl_windows.c
src/detection/os/os_windows.c
src/detection/os/os_windows.cpp
src/detection/packages/packages_windows.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_windows.c
@@ -1033,7 +1046,7 @@ elseif(WIN32)
src/detection/terminalfont/terminalfont_windows.c
src/detection/terminalshell/terminalshell_windows.c
src/detection/terminalsize/terminalsize_windows.c
src/detection/theme/theme_nosupport.c
src/detection/theme/theme_windows.c
src/detection/tpm/tpm_windows.c
src/detection/uptime/uptime_windows.c
src/detection/users/users_windows.c
@@ -1242,7 +1255,7 @@ elseif(GNU)
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_nosupport.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_nosupport.c
@@ -1328,15 +1341,15 @@ add_library(libfastfetch OBJECT
)
if(yyjson_FOUND)
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON)
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON=1)
target_link_libraries(libfastfetch PUBLIC yyjson::yyjson)
# `target_link_libraries(yyjson::yyjson)` sets rpath implicitly
else()
# Used for dlopen finding dylibs installed by homebrew
# `/opt/homebrew/lib` is not on in dlopen search path by default
if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/opt/homebrew/lib -Wl,-rpath,/usr/local/lib")
endif()
endif()
# Used for dlopen finding dylibs installed by homebrew
# `/opt/homebrew/lib` is not on in dlopen search path by default
if(APPLE AND NOT BINARY_LINK_TYPE STREQUAL "dlopen")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/opt/homebrew/lib -Wl,-rpath,/usr/local/lib")
endif()
if(ANDROID)
@@ -1678,11 +1691,10 @@ elseif(WIN32)
PRIVATE "wtsapi32"
PRIVATE "imagehlp"
PRIVATE "cfgmgr32"
PRIVATE "winbrand"
PRIVATE "propsys"
PRIVATE "secur32"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
# WoA only works on Windows 10 or higher
target_link_libraries(libfastfetch
PRIVATE "mincore"
@@ -1733,17 +1745,20 @@ elseif(ANDROID)
target_link_libraries(libfastfetch
PRIVATE "m"
)
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
if(HAVE_LIBANDROID_WORDEXP_STATIC)
target_link_libraries(libfastfetch
PRIVATE -l:libandroid-wordexp.a
)
else()
CHECK_LIBRARY_EXISTS(android-wordexp wordexp "" HAVE_LIBANDROID_WORDEXP)
if(HAVE_LIBANDROID_WORDEXP)
if(ENABLE_WORDEXP)
# https://github.com/termux/termux-packages/pull/7056
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
if(HAVE_LIBANDROID_WORDEXP_STATIC)
target_link_libraries(libfastfetch
PRIVATE android-wordexp
PRIVATE -l:libandroid-wordexp.a
)
else()
CHECK_LIBRARY_EXISTS(android-wordexp wordexp "" HAVE_LIBANDROID_WORDEXP)
if(HAVE_LIBANDROID_WORDEXP)
target_link_libraries(libfastfetch
PRIVATE android-wordexp
)
endif()
endif()
endif()
elseif(Haiku)
@@ -1805,13 +1820,17 @@ if(NOT WIN32)
if(HAVE_UTMPX)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_UTMPX=1)
endif()
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
if(HAVE_WORDEXP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
if(ENABLE_WORDEXP)
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
if(HAVE_WORDEXP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
message(STATUS "wordexp.h found, wordexp support enabled")
else()
set(ENABLE_WORDEXP OFF)
endif()
endif()
CHECK_INCLUDE_FILE("glob.h" HAVE_GLOB)
if(HAVE_GLOB)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GLOB=1)
if(NOT ENABLE_WORDEXP)
message(STATUS "wordexp.h not found or disabled, glob used instead")
endif()
if(ENABLE_THREADS AND CMAKE_USE_PTHREADS_INIT)
CHECK_INCLUDE_FILE("pthread_np.h" HAVE_PTHREAD_NP)
@@ -2020,11 +2039,6 @@ install(
##################
set(CPACK_GENERATOR "TGZ;ZIP")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
if(APPLE)
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
elseif(IS_MUSL)
@@ -2071,7 +2085,7 @@ endif()
set(CPACK_SET_DESTDIR ON)
set(CPACK_PACKAGE_CONTACT "Linus Dierheimer <Linus@Dierheimer.de>")
set(CPACK_PACKAGE_CONTACT "Carter Li <zhangsongcui@live.cn>")
set(CPACK_PACKAGE_DESCRIPTION "\
fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way. \
It is written mostly in C to achieve much better performance.\
+75
View File
@@ -0,0 +1,75 @@
# Fastfetch
Fastfetch 是一款类似 neofetch 的系统信息展示工具,主要用 C 编写,强调性能和可定制性。支持 Linux、macOS、Windows 7+、Android、FreeBSD、OpenBSD、NetBSD、DragonFly、Haiku、SunOS。
示例配置见 presets/examples,更多截图与平台说明见 Wiki。
## 安装
Linux(部分):
- Debian 13+ / Ubuntu: apt install fastfetch
- Arch: pacman -S fastfetch
- Fedora: dnf install fastfetch
- openSUSE: zypper install fastfetch
- Linuxbrewbrew install fastfetch
- 各发行版打包状态:https://repology.org/project/fastfetch/versions
macOS
- Homebrewbrew install fastfetch
- MacPortssudo port install fastfetch
Windows
- scoop install fastfetch
- choco install fastfetch
- winget install fastfetch
- MSYS2pacman -S mingw-w64-<subsystem>-<arch>-fastfetch
BSD
- FreeBSDpkg install fastfetch
- NetBSDpkgin in fastfetch
- OpenBSDpkg_add fastfetch
AndroidTermux):
- pkg install fastfetch
Nightly 构建:
- https://nightly.link/fastfetch-cli/fastfetch/workflows/ci/dev?preview
## 源码构建
基本上是 `cmake . && make`。详见 Wikihttps://github.com/fastfetch-cli/fastfetch/wiki/Building
## 使用
- 默认运行:`fastfetch`
- 查看所有可用模块示例:`fastfetch -c all.jsonc`
- 以 JSON 输出指定模块:`fastfetch -s <module1>[:<module2>] --format json`
- 完整命令行帮助:`fastfetch --help`
- 生成最小配置:`fastfetch --gen-config [</path/to/config.jsonc>]`
- 生成完整配置:`fastfetch --gen-config-full`
- 请使用支持 JSON schema 的编辑器(如 VSCode)编辑配置文件!
- 如果你连接 Github 有网络困难(智能提示不生效),可将配置文件中的 `$schema` 的值替换为 `https://gitee.com/carterl/fastfetch/raw/dev/doc/json_schema.json`
## 定制
- 配置使用 JSONC,语法与选项见 Wikihttps://github.com/fastfetch-cli/fastfetch/wiki/Configuration
- 预设示例位于 presets,可用 `-c <filename>` 加载
- Logo 选项与图像显示见文档:https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options
- 模块格式化(示例,仅显示 GPU 名称):
```jsonc
{
"modules": [
{ "type": "gpu", "format": "{name}" }
]
}
```
详见:https://github.com/fastfetch-cli/fastfetch/wiki/Format-String-Guide
## 反馈与支持
- 使用问题:Discussions https://github.com/fastfetch-cli/fastfetch/discussions
- 疑似缺陷:Issues https://github.com/fastfetch-cli/fastfetch/issues(请填写模版)
## 赞助
<img src="https://github.com/user-attachments/assets/a36a6501-e8b0-4a10-9061-b9206d12ffba" width="220">
+10
View File
@@ -11,6 +11,7 @@
[![latest packaged version(s)](https://repology.org/badge/latest-versions/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Packaging status](https://repology.org/badge/tiny-repos/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch)
[![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-red)](README-cn.md)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
@@ -103,6 +104,10 @@ Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for d
Logos can also be heavily customized; see the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for more information.
### WARNING
Fastfetch supports a `Command` module that can run arbitrary shell commands. If you copy-paste a config file from an untrusted source, it may contain malicious commands that can harm your system or compromise your privacy. Please always review the config file before using it.
## FAQ
### Q: Neofetch is good enough. Why do I need fastfetch?
@@ -317,6 +322,11 @@ If you find Fastfetch useful, please consider donating.
* Current maintainer: [@CarterLi](https://paypal.me/zhangsongcui)
* Original author: [@LinusDierheimer](https://github.com/sponsors/LinusDierheimer)
## Code signing
* 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!
+13 -1
View File
@@ -1,3 +1,16 @@
fastfetch (2.54.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Fix building on plucky
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 14:27:02 +0800
fastfetch (2.54.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.54.0
* Test independent changelog entries for different Ubuntu releases
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 10:47:02 +0800
fastfetch (2.53.0) jammy; urgency=medium
* Update to 2.53.0
@@ -435,4 +448,3 @@ fastfetch (2.7.1) jammy; urgency=medium
* Initial release.
-- Carter Li <zhangsongcui@live.cn> Tue, 06 Feb 2024 15:01:11 +0800
+1 -1
View File
@@ -2,7 +2,7 @@ Source: fastfetch
Section: universe/utils
Priority: optional
Maintainer: Carter Li <zhangsongcui@live.cn>
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
Standards-Version: 4.0.0
Homepage: https://github.com/fastfetch-cli/fastfetch
-1
View File
@@ -1 +0,0 @@
fastfetch_2.53.0_source.buildinfo universe/utils optional
+74 -2
View File
@@ -1,4 +1,76 @@
#!/usr/bin/env bash
# WARNING: DO NOT RUN THIS SCRIPT UNLESS YOU KNOW WHAT YOU ARE DOING.
debuild -S -i -I
dput ppa:zhangsongcui3371/fastfetch ~/fastfetch_*.changes
set -euo pipefail
command -v debuild >/dev/null 2>&1 || { echo "debuild not found. Install devscripts." >&2; exit 1; }
command -v dput >/dev/null 2>&1 || { echo "dput not found." >&2; exit 1; }
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
OUT_DIR="$(dirname "$ROOT_DIR")"
PPA="ppa:zhangsongcui3371/fastfetch"
CODENAMES=( jammy noble plucky questing resolute )
DRY_RUN=0
if [[ -d "$OUT_DIR/build" ]]; then
echo "Output directory exists: $OUT_DIR/build" >&2
echo "Please move or delete it before proceeding." >&2
exit 1
fi
TEMPLATE="$ROOT_DIR/debian/changelog.tpl"
CHANGELOG_DEBIAN="$ROOT_DIR/debian/changelog"
if [[ ! -f "$TEMPLATE" ]]; then
echo "Template not found: $TEMPLATE" >&2
exit 1
fi
if ! grep -q '#UBUNTU_CODENAME#' "$TEMPLATE"; then
echo "Template missing placeholder: #UBUNTU_CODENAME#" >&2
exit 1
fi
echo "IMPORTANT: Before proceeding, please ensure that 'debian/changelog.tpl' is up-to-date"
echo " with the correct version number, release notes, and maintainer information."
echo
echo " The template must contain a placeholder like '#UBUNTU_CODENAME#' for the codename."
echo
read -p "Have you reviewed and updated 'debian/changelog.tpl'? (y/N): " -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
cleanup() {
rm -f "$CHANGELOG_DEBIAN"
rm -f "$ROOT_DIR/debian/files"
}
trap cleanup EXIT
shopt -s nullglob
for codename in "${CODENAMES[@]}"; do
echo "==> Publishing distro: $codename"
sed "s/#UBUNTU_CODENAME#/${codename}/g" "$TEMPLATE" > "$CHANGELOG_DEBIAN"
( cd "$ROOT_DIR" && debuild -S -i -I )
changes=( "$OUT_DIR"/fastfetch_*~${codename}_source.changes )
if [[ ${#changes[@]} -ne 1 ]]; then
echo "Unable to uniquely identify .changes for '$codename' in: $OUT_DIR" >&2
printf 'Found:\n'; printf ' %s\n' "${changes[@]}" >&2 || true
exit 1
fi
if [[ $DRY_RUN -eq 1 ]]; then
echo "[DRY-RUN] dput \"$PPA\" \"${changes[0]}\""
else
dput "$PPA" "${changes[0]}"
fi
rm -f "$OUT_DIR"/fastfetch_*~${codename}_source.{changes,dsc,tar.*}
echo "<== Done: $codename"
done
+35 -5
View File
@@ -1008,7 +1008,7 @@
},
"type": {
"type": "string",
"description": "Set whether to show icon before string keys",
"description": "Set whether to show builtin icon before string keys",
"oneOf": [
{
"const": "none",
@@ -1020,11 +1020,31 @@
},
{
"const": "icon",
"description": "Show icon keys (requires newest nerd font)"
"description": "Show builtin icon (requires newest nerd font)"
},
{
"const": "both",
"description": "Show both icon and string keys"
"description": "Show both icon and string keys (alias of `both-1`)"
},
{
"const": "both-0",
"description": "Show both icon and string with no spaces between them"
},
{
"const": "both-1",
"description": "Show both icon and string with a space between them"
},
{
"const": "both-2",
"description": "Show both icon and string with 2 spaces between them"
},
{
"const": "both-3",
"description": "Show both icon and string with 3 spaces between them"
},
{
"const": "both-4",
"description": "Show both icon and string with 4 spaces between them"
}
],
"default": "string"
@@ -2081,6 +2101,16 @@
"description": "Set the command text to be executed",
"type": "string"
},
"useStdErr": {
"description": "Set if stderr should be used instead of stdout for command output",
"type": "boolean",
"default": false
},
"parallel": {
"description": "Set if the command should be executed in parallel with other commands\nImprove performance when using multiple commands, but may cause issues with some commands",
"type": "boolean",
"default": true
},
"key": {
"$ref": "#/$defs/key"
},
@@ -2326,7 +2356,7 @@
]
},
"hideFolders": {
"description": "A list of folder paths to hide from the disk output",
"description": "A list of folder paths (or glob patterns) to hide from the disk output",
"oneOf": [
{
"type": "string",
@@ -2342,7 +2372,7 @@
"uniqueItems": true
}
],
"default": "/efi:/boot:/boot/efi:/boot/firmware"
"default": "/efi:/boot:/boot/*"
},
"hideFS": {
"description": "A list of file systems to hide from the disk output",
+1 -1
View File
@@ -183,7 +183,7 @@
},
"keyIcon": "",
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
"text": "clang --version | head -1 | awk '{print $NF}'",
"text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'",
"format": "clang {}"
},
{
+10 -3
View File
@@ -30,6 +30,7 @@ static void initState(FFstate* state)
ffPlatformInit(&state->platform);
state->configDoc = NULL;
state->resultDoc = NULL;
state->dynamicInterval = 0;
{
// don't enable bright color if the terminal is in light mode
@@ -74,6 +75,9 @@ static void resetConsole(void)
#if defined(_WIN32)
fflush(stdout);
#endif
if(instance.state.dynamicInterval > 0)
fputs("\033[?1049l", stdout); // Disable alternate buffer
}
#ifdef _WIN32
@@ -130,14 +134,17 @@ void ffStart(void)
if(ffDisableLinewrap)
fputs("\033[?7l", stdout);
if(instance.state.dynamicInterval > 0)
{
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
fflush(stdout);
}
ffLogoPrint();
}
void ffFinish(void)
{
if(instance.config.logo.printRemaining)
ffLogoPrintRemaining();
resetConsole();
}
+1
View File
@@ -241,6 +241,7 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
}
FFNativeFD ffGetNullFD(void);
bool ffRemoveFile(const char* fileName);
#ifdef _WIN32
// Only O_RDONLY is supported
+20 -11
View File
@@ -15,11 +15,8 @@
#if FF_HAVE_WORDEXP
#include <wordexp.h>
#elif FF_HAVE_GLOB
#warning "<wordexp.h> is not available, use <glob.h> instead"
#include <glob.h>
#else
#warning "Neither <wordexp.h> nor <glob.h> is available"
#include <glob.h>
#endif
static void createSubfolders(const char* fileName)
@@ -136,14 +133,14 @@ bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer)
return ffAppendFDBuffer(fd, buffer);
}
bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* out)
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
{
bool result = false;
#if FF_HAVE_WORDEXP // https://github.com/termux/termux-packages/pull/7056
#if FF_HAVE_WORDEXP
wordexp_t exp;
if (wordexp(in, &exp, 0) != 0)
if (wordexp(in, &exp, 0) != 0) // WARN: 0 = no safety flags; command substitution allowed
return false;
if (exp.we_wordc >= 1)
@@ -154,16 +151,23 @@ bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* o
wordfree(&exp);
#elif FF_HAVE_GLOB
#else
glob_t gb;
if (glob(in, GLOB_NOSORT | GLOB_TILDE, NULL, &gb) != 0)
if (glob(in, GLOB_NOSORT
#ifdef GLOB_TILDE
| GLOB_TILDE
#endif
#ifdef GLOB_BRACE
| GLOB_BRACE
#endif
, NULL, &gb) != 0)
return false;
if (gb.gl_matchc >= 1)
if (gb.gl_pathc >= 1)
{
result = true;
ffStrbufSetS(out, gb.gl_pathv[gb.gl_matchc > 1 ? ffTimeGetNow() % gb.gl_matchc : 0]);
ffStrbufSetS(out, gb.gl_pathv[gb.gl_pathc > 1 ? ffTimeGetNow() % (unsigned) gb.gl_pathc : 0]);
}
globfree(&gb);
@@ -367,3 +371,8 @@ FFNativeFD ffGetNullFD(void)
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
return hNullFile;
}
bool ffRemoveFile(const char* fileName)
{
return unlink(fileName) == 0;
}
+5
View File
@@ -371,3 +371,8 @@ FFNativeFD ffGetNullFD(void)
});
return hNullFile;
}
bool ffRemoveFile(const char* fileName)
{
return DeleteFileA(fileName) != FALSE;
}
+10
View File
@@ -158,6 +158,16 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
ffPrepareCPUUsage();
break;
}
case 'c': case 'C': {
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME))
{
__attribute__((__cleanup__(ffDestroyCommandOptions))) FFCommandOptions options;
ffInitCommandOptions(&options);
if (module) ffCommandModuleInfo.parseJsonObject(&options, module);
ffPrepareCommand(&options);
}
break;
}
case 'd': case 'D': {
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
{
+2 -2
View File
@@ -89,7 +89,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
int routeCount = 0;
FF_MAYBE_UNUSED int routeCount = 0;
while (true)
{
@@ -299,7 +299,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
int routeCount = 0;
FF_MAYBE_UNUSED int routeCount = 0;
while (true)
{
+7 -1
View File
@@ -44,7 +44,13 @@ typedef enum __attribute__((__packed__)) FFModuleKeyType
FF_MODULE_KEY_TYPE_NONE = 0,
FF_MODULE_KEY_TYPE_STRING = 1 << 0,
FF_MODULE_KEY_TYPE_ICON = 1 << 1,
FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
FF_MODULE_KEY_TYPE_SPACE_SHIFT = 4,
FF_MODULE_KEY_TYPE_BOTH_0 = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
FF_MODULE_KEY_TYPE_BOTH_1 = FF_MODULE_KEY_TYPE_BOTH_0 | (1 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_BOTH_1, // alias
FF_MODULE_KEY_TYPE_BOTH_2 = FF_MODULE_KEY_TYPE_BOTH_0 | (2 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_BOTH_3 = FF_MODULE_KEY_TYPE_BOTH_0 | (3 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_BOTH_4 = FF_MODULE_KEY_TYPE_BOTH_0 | (4 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFModuleKeyType;
+7 -6
View File
@@ -28,17 +28,12 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
ffPrintColor(&instance.config.display.colorKeys);
}
bool hasIcon = false;
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_ICON && moduleArgs && moduleArgs->keyIcon.length > 0)
{
ffStrbufWriteTo(&moduleArgs->keyIcon, stdout);
hasIcon = true;
}
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING)
{
if(hasIcon)
putchar(' ');
ffPrintCharTimes(' ', instance.config.display.keyType >> FF_MODULE_KEY_TYPE_SPACE_SHIFT);
//NULL check is required for modules with custom keys, e.g. disk with the folder path
if((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0)
@@ -136,6 +131,12 @@ void ffPrintCharTimes(char c, uint32_t times)
if(times == 0)
return;
if(times == 1)
{
putchar(c);
return;
}
char str[32];
memset(str, c, sizeof(str)); //2 instructions when compiling with AVX2 enabled
for(uint32_t i = sizeof(str); i <= times; i += (uint32_t)sizeof(str))
+25 -4
View File
@@ -2,13 +2,30 @@
#include "util/FFstrbuf.h"
#include <sys/types.h>
#ifndef _WIN32
#include <sys/types.h> // pid_t
#endif
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr);
typedef struct FFProcessHandle {
#if _WIN32
void* pid; // HANDLE
void* pipeRead; // HANDLE
#else
pid_t pid;
int pipeRead;
#endif
} FFProcessHandle;
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle);
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer); // Destroys handle internally
static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
{
const char* error = ffProcessAppendOutput(buffer, argv, false);
FFProcessHandle handle;
const char* error = ffProcessSpawn(argv, false, &handle);
if (error) return error;
error = ffProcessReadOutput(&handle, buffer);
if (!error)
ffStrbufTrimRightSpace(buffer);
return error;
@@ -16,7 +33,11 @@ static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const ar
static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const argv[])
{
const char* error = ffProcessAppendOutput(buffer, argv, true);
FFProcessHandle handle;
const char* error = ffProcessSpawn(argv, true, &handle);
if (error) return error;
error = ffProcessReadOutput(&handle, buffer);
if (!error)
ffStrbufTrimRightSpace(buffer);
return error;
+21 -10
View File
@@ -58,11 +58,9 @@ static inline int ffPipe2(int* fds, int flags)
// Not thread-safe
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
{
int pipes[2];
const int timeout = instance.config.general.processingTimeout;
if(ffPipe2(pipes, O_CLOEXEC) == -1)
return "pipe() failed";
@@ -146,7 +144,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if(childPid == 0)
{
//Child
// Child process
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
putenv("LANG=C.UTF-8");
@@ -157,11 +155,24 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
#endif
close(pipes[1]);
outHandle->pid = childPid;
outHandle->pipeRead = pipes[0];
return NULL;
}
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
{
assert(handle->pipeRead != -1);
assert(handle->pid != -1);
const int32_t timeout = instance.config.general.processingTimeout;
FF_AUTO_CLOSE_FD int childPipeFd = handle->pipeRead;
pid_t childPid = handle->pid;
handle->pipeRead = -1;
handle->pid = -1;
char str[FF_PIPE_BUFSIZ];
while(1)
for (;;)
{
if (timeout >= 0)
{
@@ -189,14 +200,14 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
return "poll(&pollfd, 1, timeout) error: not EINTR";
}
}
else if (pollfd.revents & POLLERR)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
return "poll(&pollfd, 1, timeout) error: POLLERR";
}
}
@@ -211,7 +222,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (!WIFEXITED(stat_loc))
return "child process exited abnormally";
if (WEXITSTATUS(stat_loc) == 127)
return "command was not found";
return "command not found";
// We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c`
return NULL;
}
@@ -224,7 +235,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
else
break;
}
};
}
return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";
}
+64 -41
View File
@@ -2,7 +2,7 @@
#include "common/processing.h"
#include "common/io/io.h"
#include <Windows.h>
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
@@ -45,12 +45,13 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result)
}
}
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
{
int timeout = instance.config.general.processingTimeout;
const int32_t timeout = instance.config.general.processingTimeout;
wchar_t pipeName[32];
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u", GetCurrentProcessId());
static unsigned pidCounter = 0;
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", GetCurrentProcessId(), ++pidCounter);
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
pipeName,
@@ -82,52 +83,67 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
PROCESS_INFORMATION piProcInfo = {};
BOOL success;
STARTUPINFOA siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
{
STARTUPINFOA siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
{
siStartInfo.hStdOutput = ffGetNullFD();
siStartInfo.hStdError = hChildPipeWrite;
}
else
{
siStartInfo.hStdOutput = hChildPipeWrite;
siStartInfo.hStdError = ffGetNullFD();
}
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
argvToCmdline(argv, &cmdline);
success = CreateProcessA(
NULL, // application name
cmdline.chars, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
siStartInfo.hStdOutput = ffGetNullFD();
siStartInfo.hStdError = hChildPipeWrite;
}
else
{
siStartInfo.hStdOutput = hChildPipeWrite;
siStartInfo.hStdError = ffGetNullFD();
}
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
argvToCmdline(argv, &cmdline);
BOOL success = CreateProcessA(
NULL, // application name
cmdline.chars, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
CloseHandle(hChildPipeWrite);
if(!success)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
return "command not found";
return "CreateProcessA() failed";
}
FF_AUTO_CLOSE_FD HANDLE hProcess = piProcInfo.hProcess;
FF_MAYBE_UNUSED FF_AUTO_CLOSE_FD HANDLE hThread = piProcInfo.hThread;
CloseHandle(piProcInfo.hThread); // we don't need the thread handle
outHandle->pid = piProcInfo.hProcess;
outHandle->pipeRead = hChildPipeRead;
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
return NULL;
}
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
{
assert(handle->pipeRead != INVALID_HANDLE_VALUE);
assert(handle->pid != INVALID_HANDLE_VALUE);
int32_t timeout = instance.config.general.processingTimeout;
FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid;
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead;
handle->pid = INVALID_HANDLE_VALUE;
handle->pipeRead = INVALID_HANDLE_VALUE;
char str[FF_PIPE_BUFSIZ];
DWORD nRead = 0;
OVERLAPPED overlapped = { };
OVERLAPPED overlapped = {};
// ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
do
{
@@ -164,7 +180,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
break;
case ERROR_BROKEN_PIPE:
return NULL;
goto exit;
default:
CancelIo(hChildPipeRead);
@@ -175,6 +191,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
ffStrbufAppendNS(buffer, nRead, str);
} while (nRead > 0);
exit:
{
DWORD exitCode = 0;
if (GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE && exitCode != 0)
return "Child process exited with an error";
}
return NULL;
}
+26 -1
View File
@@ -63,6 +63,26 @@
},
"default": "default"
}
},
{
"long": "json",
"short": "j",
"arg": {
"type": "bool",
"default": false,
"optional": true
},
"desc": "Enable or disable JSON output",
"remark": "Shortcut for `--format json`"
},
{
"long": "dynamic-interval",
"desc": "Keep fastfetch open and update the output every <num> milliseconds",
"remark": "0 (default) to disable the behavior; don't work with --json",
"arg": {
"type": "num",
"default": 0
}
}
],
"Config": [
@@ -555,7 +575,12 @@
"none": "Disable keys",
"string": "Show string",
"icon": "Show icon (requires newest nerd font)",
"both": "Show both icon and string"
"both": "Show both icon and string (alias of `both-1`)",
"both-0": "Show both icon and string with no spaces between them",
"both-1": "Show both icon and string with a space between them",
"both-2": "Show both icon and string with 2 spaces between them",
"both-3": "Show both icon and string with 3 spaces between them",
"both-4": "Show both icon and string with 4 spaces between them"
},
"default": "string"
}
+28 -42
View File
@@ -5,69 +5,55 @@
const char* ffDetectBios(FFBiosResult* bios)
{
io_registry_entry_t registryEntry;
#ifndef __aarch64__
//https://github.com/osquery/osquery/blob/master/osquery/tables/system/darwin/smbios_tables.cpp
//For Intel
if((registryEntry = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/rom")))
{
CFMutableDictionaryRef properties;
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
{
IOObjectRelease(registryEntry);
return "IORegistryEntryCreateCFProperties(registryEntry) failed";
}
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceRom = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/rom");
if (!deviceRom)
return "IODeviceTree:/rom not found";
ffCfDictGetString(properties, CFSTR("vendor"), &bios->vendor);
ffCfDictGetString(properties, CFSTR("version"), &bios->version);
ffCfDictGetString(properties, CFSTR("release-date"), &bios->date);
ffStrbufSetStatic(&bios->type, "UEFI");
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceRomProps = NULL;
if(IORegistryEntryCreateCFProperties(deviceRom, &deviceRomProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
return "IORegistryEntryCreateCFProperties(deviceRom) failed";
CFRelease(properties);
IOObjectRelease(registryEntry);
return NULL;
}
ffCfDictGetString(deviceRomProps, CFSTR("vendor"), &bios->vendor);
ffCfDictGetString(deviceRomProps, CFSTR("version"), &bios->version);
ffCfDictGetString(deviceRomProps, CFSTR("release-date"), &bios->date);
ffStrbufSetStatic(&bios->type, "UEFI");
#else
//For arm64
if((registryEntry = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/")))
{
CFMutableDictionaryRef properties;
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) == kIOReturnSuccess)
{
ffCfDictGetString(properties, CFSTR("manufacturer"), &bios->vendor);
ffCfDictGetString(properties, CFSTR("time-stamp"), &bios->date);
CFRelease(properties);
}
IOObjectRelease(registryEntry);
}
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t device = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/");
if (!device)
return "IODeviceTree:/ not found";
if((registryEntry = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen")))
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceProps = NULL;
if(IORegistryEntryCreateCFProperties(device, &deviceProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
return "IORegistryEntryCreateCFProperties(device) failed";
ffCfDictGetString(deviceProps, CFSTR("manufacturer"), &bios->vendor);
ffCfDictGetString(deviceProps, CFSTR("time-stamp"), &bios->date);
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
if (deviceChosen)
{
CFMutableDictionaryRef properties;
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) == kIOReturnSuccess)
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmWareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
if (systemFirmWareVersion)
{
ffCfDictGetString(properties, CFSTR("system-firmware-version"), &bios->version);
ffCfStrGetString(systemFirmWareVersion, &bios->version);
uint32_t index = ffStrbufFirstIndexC(&bios->version, '-');
if (index != bios->version.length)
{
ffStrbufAppendNS(&bios->type, index, bios->version.chars);
ffStrbufRemoveSubstr(&bios->version, 0, index + 1);
}
else
{
ffStrbufSetStatic(&bios->type, "iBoot");
}
CFRelease(properties);
}
IOObjectRelease(registryEntry);
return NULL;
}
if (!bios->type.length)
ffStrbufSetStatic(&bios->type, "iBoot");
#endif
return "Failed to query bios info";
return NULL;
}
+82 -47
View File
@@ -55,7 +55,7 @@ static const char* detectWithDisplayServices(const FFDisplayServerResult* displa
// Works for Apple Silicon and USB-C adapter connection ( but not HTMI )
static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result)
{
if (!IOAVServiceCreate || !IOAVServiceReadI2C)
if (!IOAVServiceCreate || !IOAVServiceReadI2C || !IOAVServiceWriteI2C)
return "IOAVService is not available";
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
@@ -123,65 +123,100 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult*
return NULL;
}
#else
static IOOptionBits getSupportedTransactionType(void)
{
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("IOFramebufferI2CInterface"), &iterator) != KERN_SUCCESS)
return kIOI2CNoTransactionType;
io_registry_entry_t registryEntry;
while ((registryEntry = IOIteratorNext(iterator)) != MACH_PORT_NULL)
{
FF_IOOBJECT_AUTO_RELEASE io_service_t io_service = registryEntry;
FF_CFTYPE_AUTO_RELEASE CFNumberRef IOI2CTransactionTypes = IORegistryEntryCreateCFProperty(io_service, CFSTR(kIOI2CTransactionTypesKey), kCFAllocatorDefault, kNilOptions);
if (IOI2CTransactionTypes)
{
int64_t types = 0;
ffCfNumGetInt64(IOI2CTransactionTypes, &types);
if (types) {
if ((1 << kIOI2CDDCciReplyTransactionType) & (uint64_t) types)
return kIOI2CDDCciReplyTransactionType;
if ((1 << kIOI2CSimpleTransactionType) & (uint64_t) types)
return kIOI2CSimpleTransactionType;
}
}
break;
}
return kIOI2CNoTransactionType;
}
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result)
{
if (!CGSServiceForDisplayNumber) return "CGSServiceForDisplayNumber is not available";
IOOptionBits transactionType = getSupportedTransactionType();
if (transactionType == kIOI2CNoTransactionType)
return "No supported IOI2C transaction type found";
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
{
if (display->type == FF_DISPLAY_TYPE_EXTERNAL)
{
io_service_t framebuffer = 0;
FF_IOOBJECT_AUTO_RELEASE io_service_t framebuffer = IO_OBJECT_NULL;
CGSServiceForDisplayNumber((CGDirectDisplayID)display->id, &framebuffer);
if (framebuffer == 0) continue;
if (framebuffer == IO_OBJECT_NULL) continue;
IOItemCount count;
if (IOFBGetI2CInterfaceCount(framebuffer, &count) != KERN_SUCCESS || count == 0) continue;
io_service_t interface = 0;
if (IOFBCopyI2CInterfaceForBus(framebuffer, 0, &interface) != KERN_SUCCESS) continue;
uint8_t i2cOut[12] = {};
IOI2CConnectRef connect;
if (IOI2CInterfaceOpen(interface, kNilOptions, &connect) != KERN_SUCCESS)
{
IOObjectRelease(interface);
if (IOFBGetI2CInterfaceCount(framebuffer, &count) != KERN_SUCCESS || count == 0)
continue;
for (IOItemCount bus = 0; bus < count; ++bus)
{
FF_IOOBJECT_AUTO_RELEASE io_service_t interface = IO_OBJECT_NULL;
if (IOFBCopyI2CInterfaceForBus(framebuffer, bus, &interface) != KERN_SUCCESS) continue;
uint8_t i2cOut[12] = {};
IOI2CConnectRef connect = NULL;
if (IOI2CInterfaceOpen(interface, kNilOptions, &connect) != KERN_SUCCESS)
continue;
uint8_t i2cIn[] = { 0x51, 0x82, 0x01, 0x10 /* luminance */, 0 };
i2cIn[4] = 0x6E ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
IOI2CRequest request = {
.commFlags = kNilOptions,
.sendAddress = 0x6e,
.sendTransactionType = kIOI2CSimpleTransactionType,
.sendBuffer = (vm_address_t) i2cIn,
.sendBytes = ARRAY_SIZE(i2cIn),
.minReplyDelay = options->ddcciSleep * 1000ULL,
.replyAddress = 0x6F,
.replySubAddress = 0x51,
.replyTransactionType = transactionType,
.replyBytes = ARRAY_SIZE(i2cOut),
.replyBuffer = (vm_address_t) i2cOut,
};
IOReturn ret = IOI2CSendRequest(connect, kNilOptions, &request);
IOI2CInterfaceClose(connect, kNilOptions);
if (ret != KERN_SUCCESS || request.result != kIOReturnSuccess || request.replyBytes < 10) continue;
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) continue;
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
brightness->max = max;
brightness->min = 0;
brightness->current = current;
ffStrbufInitCopy(&brightness->name, &display->name);
brightness->builtin = false;
break;
}
uint8_t i2cIn[] = { 0x51, 0x82, 0x01, 0x10 /* luminance */, 0 };
i2cIn[4] = 0x6E ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
IOI2CRequest request = {
.commFlags = kNilOptions,
.sendAddress = 0x6e,
.sendTransactionType = kIOI2CSimpleTransactionType,
.sendBuffer = (vm_address_t) i2cIn,
.sendBytes = ARRAY_SIZE(i2cIn),
.minReplyDelay = options->ddcciSleep,
.replyAddress = 0x6F,
.replySubAddress = 0x51,
.replyTransactionType = kIOI2CDDCciReplyTransactionType,
.replyBytes = ARRAY_SIZE(i2cOut),
.replyBuffer = (vm_address_t) i2cOut,
};
IOReturn ret = IOI2CSendRequest(connect, kNilOptions, &request);
IOI2CInterfaceClose(connect, kNilOptions);
IOObjectRelease(interface);
if (ret != KERN_SUCCESS || request.result != kIOReturnSuccess) continue;
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) continue;
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
brightness->max = max;
brightness->min = 0;
brightness->current = current;
ffStrbufInitCopy(&brightness->name, &display->name);
brightness->builtin = false;
}
}
+60
View File
@@ -0,0 +1,60 @@
#include "common/processing.h"
#include "util/FFstrbuf.h"
#include "detection/command/command.h"
typedef struct FFCommandResultBundle
{
FFProcessHandle handle;
const char* error;
} FFCommandResultBundle;
// FIFO, non-thread-safe list of running commands
static FFlist commandQueue = {
.elementSize = sizeof(FFCommandResultBundle),
};
static const char* spawnProcess(FFCommandOptions* options, FFProcessHandle* handle)
{
if (options->text.length == 0)
return "No command text specified";
return ffProcessSpawn(options->param.length ? (char* const[]){
options->shell.chars,
options->param.chars,
options->text.chars,
NULL
} : (char* const[]){
options->shell.chars,
options->text.chars,
NULL
}, options->useStdErr, handle);
}
bool ffPrepareCommand(FFCommandOptions* options)
{
if (!options->parallel) return false;
FFCommandResultBundle* bundle = ffListAdd(&commandQueue);
bundle->error = spawnProcess(options, &bundle->handle);
return true;
}
const char* ffDetectCommand(FFCommandOptions* options, FFstrbuf* result)
{
FFCommandResultBundle bundle = {};
if (!options->parallel)
bundle.error = spawnProcess(options, &bundle.handle);
else if (!ffListShift(&commandQueue, &bundle))
return "[BUG] command queue is empty";
if (bundle.error)
return bundle.error;
bundle.error = ffProcessReadOutput(&bundle.handle, result);
if (bundle.error)
return bundle.error;
ffStrbufTrimRightSpace(result);
return NULL;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "fastfetch.h"
#include "modules/command/option.h"
const char* ffDetectCommand(FFCommandOptions* options, FFstrbuf* result);
+1 -1
View File
@@ -39,7 +39,7 @@ static const char* detectFrequency(FFCPUResult* cpu)
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr"));
if (!entryDevice)
return "IOServiceGetMatchingServices() failed";
return "IOServiceGetMatchingService() failed";
if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice"))
return "\"pmgr\" should conform to \"AppleARMIODevice\"";
+108 -15
View File
@@ -145,6 +145,7 @@ static void detectQualcomm(FFCPUResult* cpu)
{
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips
assert(cpu->name.length >= 2);
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 2, NULL, 10);
const char* name = NULL;
@@ -189,6 +190,7 @@ static void detectMediaTek(FFCPUResult* cpu)
{
// https://en.wikipedia.org/wiki/List_of_MediaTek_systems_on_chips
assert(cpu->name.length >= 2);
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 2, NULL, 10);
const char* name = NULL;
@@ -219,25 +221,78 @@ static void detectMediaTek(FFCPUResult* cpu)
}
}
static void detectExynos(FFCPUResult* cpu)
{
// https://en.wikipedia.org/wiki/Exynos
assert(cpu->name.length > 3);
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 3, NULL, 10);
const char* name = NULL;
switch (code)
{
case 9955: name = "2500"; break;
case 9945: name = "2400"; break;
// No 2300
case 9925: name = "2200"; break;
case 9840: name = "2100"; break;
case 8855: name = "1580"; break;
case 8845: name = "1480"; break;
case 8835: name = "1380"; break;
case 8535: name = "1330"; break;
case 8825: name = "1280"; break;
case 9815: name = "1080"; break;
case 9830: name = "990"; break;
case 9630: name = "980"; break;
case 8805: name = "880"; break;
case 3830: name = "850"; break;
}
if (name)
{
char str[32];
ffStrCopy(str, cpu->name.chars, sizeof(str));
ffStrbufSetF(&cpu->name, "Samsung Exynos %s [%s]", name, str);
return;
}
}
static void detectAndroid(FFCPUResult* cpu)
{
if (cpu->name.length == 0)
{
if (ffSettingsGetAndroidProperty("ro.soc.model", &cpu->name))
ffStrbufClear(&cpu->vendor); // We usually detect the vendor of CPU core as ARM, but instead we want the vendor of SOC
else if(ffSettingsGetAndroidProperty("ro.mediatek.platform", &cpu->name))
ffStrbufSetStatic(&cpu->vendor, "MTK");
}
if (cpu->vendor.length == 0)
{
if (!ffSettingsGetAndroidProperty("ro.soc.manufacturer", &cpu->vendor))
ffSettingsGetAndroidProperty("ro.product.product.manufacturer", &cpu->vendor);
if (!ffSettingsGetAndroidProperty("ro.product.product.manufacturer", &cpu->vendor))
if (!ffSettingsGetAndroidProperty("ro.product.vendor.manufacturer", &cpu->vendor))
if(ffSettingsGetAndroidProperty("ro.mediatek.platform", &cpu->name))
ffStrbufSetStatic(&cpu->vendor, "MediaTek");
}
if (ffStrbufEqualS(&cpu->vendor, "QTI") && ffStrbufStartsWithS(&cpu->name, "SM"))
if (ffStrbufEqualS(&cpu->vendor, "QTI"))
ffStrbufSetStatic(&cpu->vendor, "Qualcomm");
else if (ffStrbufIgnCaseEqualS(&cpu->vendor, "MediaTek")) // sometimes "Mediatek"
ffStrbufSetStatic(&cpu->vendor, "MediaTek");
else if (cpu->vendor.length > 0)
cpu->vendor.chars[0] = (char) toupper(cpu->vendor.chars[0]);
if (ffStrbufEqualS(&cpu->vendor, "Qualcomm") && ffStrbufStartsWithS(&cpu->name, "SM"))
detectQualcomm(cpu);
else if (ffStrbufEqualS(&cpu->vendor, "MTK") && ffStrbufStartsWithS(&cpu->name, "MT"))
else if (ffStrbufEqualS(&cpu->vendor, "MediaTek") && ffStrbufStartsWithS(&cpu->name, "MT"))
detectMediaTek(cpu);
else if (ffStrbufEqualS(&cpu->vendor, "Samsung") && ffStrbufStartsWithS(&cpu->name, "s5e"))
{
cpu->name.chars[0] = 'S';
cpu->name.chars[2] = 'E';
detectExynos(cpu);
}
}
#endif
@@ -360,6 +415,10 @@ static const char* parseCpuInfo(
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor :", &cpu->vendor)) ||
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) ||
#elif __hppa__
(cpu->name.length == 0 && ffParsePropLine(line, "cpu :", &cpu->name)) ||
#elif __sh__
(cpu->name.length == 0 && ffParsePropLine(line, "cpu type :", &cpu->name)) ||
#else
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
(cpu->name.length == 0 && ffParsePropLine(line, "model :", &cpu->name)) ||
@@ -617,19 +676,46 @@ FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu)
if (cpu->name.length > 0)
return;
// device-vendor,device-model\0soc-vendor,soc-model\0
char content[256];
// [x-vendor,x-model\0]*N
char content[512];
ssize_t length = ffReadFileData("/proc/device-tree/compatible", ARRAY_SIZE(content), content);
if (length <= 2) return;
if (length < 4) return; // v,m\0
// get the second NUL terminated string if it exists
char* vendor = memchr(content, '\0', (size_t) length) + 1;
if (!vendor || vendor - content >= length) vendor = content;
if (content[length - 1] != '\0') return; // must end with \0
char* model = strchr(vendor, ',');
if (!model) return;
*model = '\0';
++model;
--length;
char* vendor = NULL;
char* model = NULL;
for (char* p; length > 0; length = p ? (ssize_t) (p - content) - 1 : 0)
{
p = memrchr(content, '\0', (size_t) length);
vendor = p /* first entry */ ? p + 1 : content;
size_t partLen = (size_t) (length - (vendor - content));
if (partLen < 3) continue;
char* comma = memchr(vendor, ',', partLen);
if (!comma) continue;
size_t vendorLen = (size_t) (comma - vendor);
if (vendorLen == 0) continue;
model = comma + 1;
size_t modelLen = (size_t) (partLen - (size_t) (model - vendor));
if (modelLen == 0) continue;
if ((modelLen >= strlen("-platform") && ffStrEndsWith(model, "-platform")) ||
(modelLen >= strlen("-soc") && ffStrEndsWith(model, "-soc")))
continue;
*comma = '\0';
break;
}
if (!length) return;
if (false) {}
#if __aarch64__
@@ -685,6 +771,13 @@ FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu)
for (const char* p = model; *p; ++p)
ffStrbufAppendC(&cpu->name, (char) toupper(*p));
}
else if (ffStrEquals(vendor, "thead"))
{
// Lichee Pi?
ffStrbufSetStatic(&cpu->vendor, "T-Head");
for (const char* p = model; *p; ++p)
ffStrbufAppendC(&cpu->name, (char) toupper(*p));
}
else
{
ffStrbufSetS(&cpu->name, model);
+25 -1
View File
@@ -10,7 +10,7 @@ const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks)
const char* error = ffDetectDisksImpl(options, disks);
if (error) return error;
if (disks->length == 0) return "No disks found";
if (disks->length == 0) return NULL;
//We need to sort the disks, so that we can detect, which disk a path resides on
// For example for /boot/efi/bootmgr we need to check /boot/efi before /boot
@@ -31,3 +31,27 @@ const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks)
return NULL;
}
#ifndef _WIN32
#include <fnmatch.h>
bool ffDiskMatchesFolderPatterns(FFstrbuf* folders, const char* path, char separator)
{
uint32_t startIndex = 0;
while(startIndex < folders->length)
{
uint32_t sepIndex = ffStrbufNextIndexC(folders, startIndex, separator);
char savedSep = folders->chars[sepIndex]; // Can be '\0' if at end
folders->chars[sepIndex] = '\0';
bool matched = fnmatch(&folders->chars[startIndex], path, 0) == 0;
folders->chars[sepIndex] = savedSep;
if (matched) return true;
startIndex = sepIndex + 1;
}
return false;
}
#endif
+4
View File
@@ -35,3 +35,7 @@ typedef struct FFDisk
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
#ifndef _WIN32
bool ffDiskMatchesFolderPatterns(FFstrbuf* folders, const char* path, char separator);
#endif
+6
View File
@@ -151,6 +151,12 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
continue;
if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, fs->f_mntonname, FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, fs->f_fstypename, ':'))
continue;
#ifdef __FreeBSD__
// f_bavail and f_ffree are signed on FreeBSD...
if(fs->f_bavail < 0) fs->f_bavail = 0;
+6
View File
@@ -27,6 +27,12 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
continue;
}
if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, path.Path(), FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, fs.fsh_name, ':'))
continue;
FFDisk* disk = (FFDisk*) ffListAdd(disks);
disk->bytesTotal = (uint64_t)fs.total_blocks * (uint64_t) fs.block_size;
+7 -1
View File
@@ -10,7 +10,7 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifdef STATX_BTIME
#if defined(STATX_BTIME) && !defined(__ANDROID__)
#include <sys/syscall.h>
#endif
@@ -297,6 +297,12 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
else if(!isPhysicalDevice(device))
continue;
if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, device->mnt_dir, FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, device->mnt_type, ':'))
continue;
//We have a valid device, add it to the list
FFDisk* disk = ffListAdd(disks);
disk->type = FF_DISK_VOLUME_TYPE_NONE;
+6
View File
@@ -119,6 +119,12 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
else if(!isPhysicalDevice(&device))
continue;
if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, device.mnt_fstype, ':'))
continue;
//We have a valid device, add it to the list
FFDisk* disk = ffListAdd(disks);
disk->type = FF_DISK_VOLUME_TYPE_NONE;
+25 -13
View File
@@ -53,6 +53,29 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
else if(driveType == DRIVE_NO_ROOT_DIR)
continue;
if (options->hideFolders.length && ffStrbufSeparatedContain(&options->hideFolders, &buffer, FF_DISK_FOLDER_SEPARATOR))
continue;
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
DWORD diskFlags;
BOOL volumeInfoAvailable = GetVolumeInformationW(mountpoint,
diskName, ARRAY_SIZE(diskName), //Volume name
NULL, //Serial number
NULL, //Max component length
&diskFlags, //File system flags
diskFileSystem, ARRAY_SIZE(diskFileSystem)
);
FF_STRBUF_AUTO_DESTROY diskFileSystemBuf = ffStrbufCreate();
if (volumeInfoAvailable)
{
ffStrbufSetWS(&diskFileSystemBuf, diskFileSystem);
if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &diskFileSystemBuf, ':'))
continue;
}
FFDisk* disk = ffListAdd(disks);
disk->filesUsed = 0;
@@ -97,20 +120,9 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
(PULARGE_INTEGER)&disk->bytesFree
);
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
DWORD diskFlags;
BOOL result = GetVolumeInformationW(mountpoint,
diskName, ARRAY_SIZE(diskName), //Volume name
NULL, //Serial number
NULL, //Max component length
&diskFlags, //File system flags
diskFileSystem, ARRAY_SIZE(diskFileSystem)
);
if(result)
if(volumeInfoAvailable)
{
ffStrbufSetWS(&disk->filesystem, diskFileSystem);
ffStrbufInitMove(&disk->filesystem, &diskFileSystemBuf);
ffStrbufSetWS(&disk->name, diskName);
if(diskFlags & FILE_READ_ONLY_VOLUME)
disk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
@@ -45,6 +45,7 @@ FFDisplayResult* ffdsAppendDisplay(
display->manufactureYear = 0;
display->manufactureWeek = 0;
display->serial = 0;
display->drrStatus = FF_DISPLAY_DRR_STATUS_UNKNOWN;
return display;
}
@@ -60,6 +60,13 @@ typedef enum __attribute__((__packed__)) FFDisplayHdrStatus
FF_DISPLAY_HDR_STATUS_ENABLED,
} FFDisplayHdrStatus;
typedef enum __attribute__((__packed__)) FFDisplayVrrStatus
{
FF_DISPLAY_DRR_STATUS_UNKNOWN,
FF_DISPLAY_DRR_STATUS_DISABLED,
FF_DISPLAY_DRR_STATUS_ENABLED,
} FFDisplayVrrStatus;
typedef struct FFDisplayResult
{
uint32_t width; // in px
@@ -83,6 +90,7 @@ typedef struct FFDisplayResult
uint16_t manufactureYear;
uint16_t manufactureWeek;
uint32_t serial;
FFDisplayVrrStatus drrStatus;
} FFDisplayResult;
typedef struct FFDisplayServerResult
@@ -196,21 +196,5 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
}
}
const FFOSResult* os = ffDetectOS();
char* str_end;
const char* version = os->version.chars;
unsigned long osNum = strtoul(version, &str_end, 10);
if (str_end != version)
{
if (osNum > 15) { // Tahoe
ffStrbufSetStatic(&ds->dePrettyName, "Liquid Glass");
} else if (osNum < 10) {
ffStrbufSetStatic(&ds->dePrettyName, "Platinum");
} else {
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
}
}
detectDisplays(ds);
}
@@ -1,12 +1,9 @@
#include "displayserver.h"
#include "detection/os/os.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
#include "util/mallocHelper.h"
#include "util/edidHelper.h"
#include <dwmapi.h>
#include <WinUser.h>
#include <winuser.h>
#include <wchar.h>
typedef struct FFMonitorInfo
@@ -232,6 +229,7 @@ static void detectDisplays(FFDisplayServerResult* ds)
}
if (edidLength > 0)
ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek);
display->drrStatus = path->flags & DISPLAYCONFIG_PATH_BOOST_REFRESH_RATE ? FF_DISPLAY_DRR_STATUS_ENABLED : FF_DISPLAY_DRR_STATUS_DISABLED;
}
}
}
@@ -254,27 +252,4 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
}
detectDisplays(ds);
//https://github.com/hykilpikonna/hyfetch/blob/master/neofetch#L2067
const FFOSResult* os = ffDetectOS();
uint32_t ver = (uint32_t) ffStrbufToUInt(&os->version, 0);
if (ver > 1000)
{
// Windows Server
if (ver >= 2016)
ffStrbufSetStatic(&ds->dePrettyName, "Fluent");
else if (ver >= 2012)
ffStrbufSetStatic(&ds->dePrettyName, "Metro");
else
ffStrbufSetStatic(&ds->dePrettyName, "Aero");
}
else
{
if (ver >= 10)
ffStrbufSetStatic(&ds->dePrettyName, "Fluent");
else if (ver >= 8)
ffStrbufSetStatic(&ds->dePrettyName, "Metro");
else
ffStrbufSetStatic(&ds->dePrettyName, "Aero");
}
}
+3 -3
View File
@@ -215,8 +215,8 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
FFDisplayResult* item = ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
(uint32_t) (currentMode ? currentMode->width : crtcInfoReply->width),
(uint32_t) (currentMode ? currentMode->height : crtcInfoReply->height),
currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0,
(uint32_t) (crtcInfoReply->width / scaleFactor + .5),
(uint32_t) (crtcInfoReply->height / scaleFactor + .5),
@@ -230,7 +230,7 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
0,
(uint32_t) outputInfoReply->mm_width,
(uint32_t) outputInfoReply->mm_height,
"xcb-randr-crtc"
currentMode ? "xcb-randr-mode" : "xcb-randr-crtc"
);
if (item && edidLength)
{
+3 -3
View File
@@ -134,8 +134,8 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
FFDisplayResult* item = ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfo->width,
(uint32_t) crtcInfo->height,
(uint32_t) (currentMode ? currentMode->width : crtcInfo->width),
(uint32_t) (currentMode ? currentMode->height : crtcInfo->height),
currentMode ? (double) currentMode->dotClock / (double) ((uint32_t) currentMode->hTotal * currentMode->vTotal) : 0,
(uint32_t) (crtcInfo->width / scaleFactor + .5),
(uint32_t) (crtcInfo->height / scaleFactor + .5),
@@ -149,7 +149,7 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
0,
(uint32_t) output->mm_width,
(uint32_t) output->mm_height,
"xlib-randr-crtc"
currentMode ? "xlib-randr-mode" : "xlib-randr-crtc"
);
if (item)
+12 -1
View File
@@ -58,7 +58,7 @@ typedef struct FFGpuDriverPciBusId
uint32_t func;
} FFGpuDriverPciBusId;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) || defined(__GNU__)
void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu);
void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu);
@@ -73,3 +73,14 @@ const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd);
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId);
#endif // defined(XXX)
static inline uint64_t ffGPUPciAddr2Id(uint64_t domain, uint64_t bus, uint64_t device, uint64_t function)
{
return (domain << 16) | (bus << 8) | (device << 3) | function;
}
static inline uint64_t ffGPUGeneral2Id(uint64_t originalId)
{
// Note: originalId may already have the MSB set
return (1ULL << 63) | originalId;
}
+6 -3
View File
@@ -30,7 +30,7 @@ static void fillGPUTypeGeneric(FFGPUResult* gpu)
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
}
@@ -80,7 +80,7 @@ static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus)
{
case DRM_BUS_PCI:
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id));
gpu->deviceId = (dev->businfo.pci->domain * 100000ull) + (dev->businfo.pci->bus * 1000ull) + (dev->businfo.pci->dev * 10ull) + dev->businfo.pci->func;
gpu->deviceId = ffGPUPciAddr2Id(dev->businfo.pci->domain, dev->businfo.pci->bus, dev->businfo.pci->dev, dev->businfo.pci->func);
break;
case DRM_BUS_HOST1X:
ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]);
@@ -179,6 +179,9 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus)
{
struct pci_conf* pc = &confs[i];
if (pc->pc_sel.pc_func > 0 && pc->pc_subclass == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/)
continue; // Likely an auxiliary display controller (#2034)
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pc->pc_vendor));
ffStrbufInit(&gpu->name);
@@ -191,7 +194,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus)
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = (pc->pc_sel.pc_domain * 100000ull) + (pc->pc_sel.pc_bus * 1000ull) + (pc->pc_sel.pc_dev * 10ull) + pc->pc_sel.pc_func;
gpu->deviceId = ffGPUPciAddr2Id(pc->pc_sel.pc_domain, pc->pc_sel.pc_bus, pc->pc_sel.pc_dev, pc->pc_sel.pc_func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
+1 -1
View File
@@ -313,7 +313,7 @@ const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd)
// They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes.
gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster);
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
gpu->deviceId = paramsGlobal.chip_id;
gpu->deviceId = ffGPUGeneral2Id(paramsGlobal.chip_id);
if (!gpu->name.length)
{
+9 -2
View File
@@ -14,6 +14,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_slot_match_iterator_create)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_device_next)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_system_cleanup)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_iterator_destroy)
{
// Requires root access
@@ -29,6 +30,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (dev->device_class >> 16 != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
continue;
uint8_t subclass = (dev->device_class >> 8) & 0xFF;
if (dev->func > 0 && subclass == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/)
continue; // Likely an auxiliary display controller (#2034)
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->vendor_id));
ffStrbufInit(&gpu->name);
@@ -40,15 +46,16 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ((uint64_t) dev->domain << 6) | ((uint64_t) dev->bus << 4) | ((uint64_t) dev->dev << 2) | (uint64_t) dev->func;
gpu->deviceId = ffGPUPciAddr2Id(dev->domain, dev->bus, dev->dev, dev->func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(dev->device_id, dev->revision, gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName((dev->device_class >> 8) & 0xFF, dev->vendor_id, dev->device_id, gpu);
ffGPUFillVendorAndName(subclass, dev->vendor_id, dev->device_id, gpu);
}
ffpci_iterator_destroy(iter);
ffpci_system_cleanup();
return NULL;
+4 -1
View File
@@ -19,6 +19,9 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (dev.class_base != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
continue;
if (dev.function > 0 && dev.class_sub == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/)
continue; // Likely an auxiliary display controller (#2034)
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev.vendor_id));
ffStrbufInit(&gpu->name);
@@ -30,7 +33,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ((uint64_t) dev.bus << 4) | ((uint64_t) dev.device << 2) | (uint64_t) dev.function;
gpu->deviceId = ffGPUPciAddr2Id(0, dev.bus, dev.device, dev.function);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
+5 -2
View File
@@ -198,7 +198,7 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu
// https://patchwork.kernel.org/project/intel-gfx/patch/1422039866-11572-3-git-send-email-ville.syrjala@linux.intel.com/
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
if (!drmKey) return;
@@ -342,6 +342,9 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
if (sscanf(pPciPath, "%" SCNx32 ":%" SCNx32 ":%" SCNx32 ".%" SCNx32, &pciDomain, &pciBus, &pciDevice, &pciFunc) != 4)
return "Invalid PCI device path";
if (pciFunc > 0 && subclassId == 0x80 /*PCI_CLASS_DISPLAY_OTHER*/)
return "Likely an auxiliary display controller"; // #2034
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString((uint16_t) vendorId));
ffStrbufInit(&gpu->name);
@@ -354,7 +357,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = (pciDomain * 100000ull) + (pciBus * 1000ull) + (pciDevice * 10ull) + pciFunc;
gpu->deviceId = ffGPUPciAddr2Id(pciDomain, pciBus, pciDevice, pciFunc);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
char drmKeyBuffer[8];
+113
View File
@@ -0,0 +1,113 @@
#include "gpu.h"
#include "common/io/io.h"
#include <sys/param.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/pciio.h>
static inline int pciReadConf(int fd, uint32_t bus, uint32_t device, uint32_t func, uint32_t reg, uint32_t* result)
{
struct pciio_bdf_cfgreg bdfr = {
.bus = bus,
.device = device,
.function = func,
.cfgreg = {
.reg = reg,
},
};
if (ioctl(fd, PCI_IOC_BDF_CFGREAD, &bdfr) == -1)
return -1;
*result = bdfr.cfgreg.val;
return 0;
}
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
char pciDevPath[] = "/dev/pciXXX";
for (uint32_t idev = 0; idev <= 255; idev++)
{
snprintf(pciDevPath + strlen("/dev/pci"), 4, "%u", idev);
FF_AUTO_CLOSE_FD int pcifd = open(pciDevPath, O_RDONLY | O_CLOEXEC);
if (pcifd < 0)
{
if (errno == ENOENT)
break; // No more /dev/pciN devices
return "open(\"/dev/pciN\", O_RDONLY | O_CLOEXEC) failed";
}
struct pciio_businfo businfo;
if (ioctl(pcifd, PCI_IOC_BUSINFO, &businfo) != 0)
continue;
uint32_t bus = businfo.busno;
for (uint32_t dev = 0; dev < businfo.maxdevs; dev++)
{
uint32_t maxfuncs = 0;
for (uint32_t func = 0; func <= maxfuncs; func++)
{
uint32_t pciid, pciclass;
if (pciReadConf(pcifd, bus, dev, func, PCI_ID_REG, &pciid) != 0)
continue;
if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID || PCI_VENDOR(pciid) == 0)
continue;
if (pciReadConf(pcifd, bus, dev, func, PCI_CLASS_REG, &pciclass) != 0)
continue;
if (func == 0)
{
// For some reason, pciReadConf returns success even for non-existing devices.
// So we need to check for `PCI_VENDOR(pciid) == PCI_VENDOR_INVALID` above to filter them out.
uint32_t bhlcr;
if (pciReadConf(pcifd, bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0)
continue;
if (PCI_HDRTYPE_MULTIFN(bhlcr)) maxfuncs = 7;
}
if (PCI_CLASS(pciclass) != PCI_CLASS_DISPLAY)
continue;
if (func > 0 && PCI_SUBCLASS(pciclass) == PCI_SUBCLASS_DISPLAY_MISC)
continue; // Likely an auxiliary display controller (#2034)
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(PCI_VENDOR(pciid)));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitS(&gpu->platformApi, pciDevPath);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName(PCI_SUBCLASS(pciclass), PCI_VENDOR(pciid), PCI_PRODUCT(pciid), gpu);
struct pciio_drvname drvname = {
.device = dev,
.function = func,
};
if (ioctl(pcifd, PCI_IOC_DRVNAME, &drvname) == 0)
ffStrbufInitS(&gpu->driver, drvname.name);
}
}
}
return NULL;
}
+95
View File
@@ -0,0 +1,95 @@
#include "gpu.h"
#include "common/io/io.h"
#include <sys/param.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
#include <sys/pciio.h>
static inline int pciReadConf(int fd, uint32_t bus, uint32_t device, uint32_t func, uint32_t reg, uint32_t* result)
{
struct pci_io bdfr = {
.pi_sel = {
.pc_bus = bus,
.pc_dev = device,
.pc_func = func,
},
.pi_reg = reg,
.pi_width = 4,
};
if (ioctl(fd, PCIOCREAD, &bdfr) == -1)
return -1;
*result = bdfr.pi_data;
return 0;
}
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
char pciDevPath[] = "/dev/pci0";
FF_AUTO_CLOSE_FD int pcifd = open(pciDevPath, O_RDONLY | O_CLOEXEC);
if (pcifd < 0)
return "open(\"/dev/pci0\", O_RDONLY | O_CLOEXEC) failed";
for (uint32_t bus = 0; bus <= 255; bus++)
{
for (uint32_t dev = 0; dev < 32; dev++)
{
uint32_t maxfuncs = 0;
for (uint32_t func = 0; func <= maxfuncs; func++)
{
uint32_t pciid, pciclass;
if (pciReadConf(pcifd, bus, dev, func, PCI_ID_REG, &pciid) != 0)
continue;
if (PCI_VENDOR(pciid) == PCI_VENDOR_INVALID || PCI_VENDOR(pciid) == 0)
continue;
if (pciReadConf(pcifd, bus, dev, func, PCI_CLASS_REG, &pciclass) != 0)
continue;
if (func == 0)
{
// For some reason, pciReadConf returns success even for non-existing devices.
// So we need to check for `PCI_VENDOR(pciid) == PCI_VENDOR_INVALID` above to filter them out.
uint32_t bhlcr;
if (pciReadConf(pcifd, bus, dev, 0, PCI_BHLC_REG, &bhlcr) != 0)
continue;
if (PCI_HDRTYPE_MULTIFN(bhlcr)) maxfuncs = 7;
}
if (PCI_CLASS(pciclass) != PCI_CLASS_DISPLAY)
continue;
if (func > 0 && PCI_SUBCLASS(pciclass) == PCI_SUBCLASS_DISPLAY_MISC)
continue; // Likely an auxiliary display controller (#2034)
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(PCI_VENDOR(pciid)));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitS(&gpu->platformApi, "/dev/pci0");
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu);
if (gpu->name.length == 0)
ffGPUFillVendorAndName(PCI_SUBCLASS(pciclass), PCI_VENDOR(pciid), PCI_PRODUCT(pciid), gpu);
}
}
}
return NULL;
}
+3 -3
View File
@@ -95,7 +95,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
{
pciDev = (pciAddr >> 16) & 0xFFFF;
pciFunc = pciAddr & 0xFFFF;
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
gpu->deviceId = ffGPUPciAddr2Id(0, pciBus, pciDev, pciFunc);
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
FF_DEBUG("PCI location - Bus: %u, Device: %u, Function: %u, DeviceID: %llu", pciBus, pciDev, pciFunc, gpu->deviceId);
}
@@ -182,7 +182,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
{
FF_DEBUG("Found adapter LUID: %llu", adapterLuid);
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
if (!gpu->deviceId) gpu->deviceId = ffGPUGeneral2Id(adapterLuid);
}
uint32_t featureLevel = 0;
@@ -449,7 +449,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
FF_DEBUG("Using fallback GPU type detection");
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
FF_DEBUG("Intel GPU type determined: %s", gpu->type == FF_GPU_TYPE_INTEGRATED ? "Integrated" : "Discrete");
}
else if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
+7
View File
@@ -79,6 +79,13 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
gpu->deviceId = 0;
ffStrbufInitStatic(&gpu->platformApi, "DXCore");
LUID luid;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::InstanceLuid, sizeof(luid), &luid)))
{
static_assert(sizeof(luid) == sizeof(uint64_t), "LUID size mismatch");
gpu->deviceId = ffGPUGeneral2Id(*(uint64_t*)&luid);
}
ffStrbufInit(&gpu->driver);
uint64_t value = 0;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::DriverVersion, sizeof(value), &value)))
+1 -1
View File
@@ -181,7 +181,7 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
#ifdef __x86_64__
bool ffHostDetectMac(FFHostResult* host)
{
if (ffStrbufEqualS(&host->family, "Mac") && ffStrbufEqualS(&host->vendor, "Apple Inc."))
if (ffStrbufStartsWithS(&host->family, "Mac") && ffStrbufEqualS(&host->vendor, "Apple Inc."))
{
const char* productName = ffHostGetMacProductNameWithHwModel(&host->name);
if (productName)
+3
View File
@@ -16,6 +16,9 @@ const char* ffDetectIcons(FFIconsResult* result)
ffRegReadUint(hKey, L"{645FF040-5081-101B-9F08-00AA002F954E}", &RecycleBin, NULL);
ffRegReadUint(hKey, L"{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}", &ControlPanel, NULL);
if (ThisPC && UsersFiles && RemoteNetwork && RecycleBin && ControlPanel)
return "All icons are hidden";
if (!ThisPC)
ffStrbufAppendS(&result->icons1, "This PC, ");
if (!UsersFiles)
+19 -4
View File
@@ -1,11 +1,21 @@
#include "media.h"
#include "common/io/io.h"
void ffDetectMediaImpl(FFMediaResult* media);
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover);
const FFMediaResult* ffDetectMedia(void)
static FFMediaResult result;
static void removeMediaCoverFile(void)
{
static FFMediaResult result;
if (result.cover.length > 0)
{
ffRemoveFile(result.cover.chars);
ffStrbufDestroy(&result.cover);
}
}
const FFMediaResult* ffDetectMedia(bool saveCover)
{
if (result.error.chars == NULL)
{
ffStrbufInit(&result.error);
@@ -16,7 +26,9 @@ const FFMediaResult* ffDetectMedia(void)
ffStrbufInit(&result.album);
ffStrbufInit(&result.url);
ffStrbufInit(&result.status);
ffDetectMediaImpl(&result);
ffStrbufInit(&result.cover);
result.removeCoverAfterUse = false;
ffDetectMediaImpl(&result, saveCover);
if(result.song.length == 0 && result.error.length == 0)
ffStrbufAppendS(&result.error, "No media found");
@@ -24,6 +36,9 @@ const FFMediaResult* ffDetectMedia(void)
ffStrbufTrimRightSpace(&result.artist);
ffStrbufTrimRightSpace(&result.album);
ffStrbufTrimRightSpace(&result.player);
if (saveCover && result.removeCoverAfterUse)
atexit(removeMediaCoverFile);
}
return &result;
+3 -1
View File
@@ -13,6 +13,8 @@ typedef struct FFMediaResult
FFstrbuf album;
FFstrbuf url;
FFstrbuf status;
FFstrbuf cover;
bool removeCoverAfterUse;
} FFMediaResult;
const FFMediaResult* ffDetectMedia();
const FFMediaResult* ffDetectMedia(bool saveCover);
+34 -9
View File
@@ -5,6 +5,7 @@
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <CoreServices/CoreServices.h>
// https://github.com/andrewwiik/iOS-Blocks/blob/master/Widgets/Music/MediaRemote.h
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
@@ -12,7 +13,7 @@ extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queu
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) __attribute__((weak_import));
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) __attribute__((weak_import));
static const char* getMediaByMediaRemote(FFMediaResult* result)
static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
{
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
@@ -30,6 +31,25 @@ static const char* getMediaByMediaRemote(FFMediaResult* result)
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
if (saveCover)
{
NSData* artworkData = (__bridge NSData*) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"));
if (artworkData)
{
CFStringRef mime = (CFStringRef) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkMIMEType"));
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
FF_CFTYPE_AUTO_RELEASE CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mime, NULL);
FF_CFTYPE_AUTO_RELEASE CFStringRef ext = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
#pragma clang diagnostic pop
NSString *tmpDir = NSTemporaryDirectory();
NSString *uuid = NSUUID.UUID.UUIDString;
NSString *path = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"ff_%@.%@", uuid, ext ? (__bridge NSString *) ext : @"img"]];
if ([artworkData writeToFile:path atomically:NO])
ffStrbufSetS(&result->cover, path.UTF8String);
}
}
}
else
error = "MRMediaRemoteGetNowPlayingInfo() failed";
@@ -71,7 +91,7 @@ static const char* getMediaByMediaRemote(FFMediaResult* result)
}
__attribute__((visibility("default"), used))
int ffPrintMediaByMediaRemote(void)
int ffPrintMediaByMediaRemote(bool saveCover)
{
FFMediaResult media = {
.status = ffStrbufCreate(),
@@ -80,8 +100,9 @@ int ffPrintMediaByMediaRemote(void)
.album = ffStrbufCreate(),
.playerId = ffStrbufCreate(),
.player = ffStrbufCreate(),
.cover = ffStrbufCreate(),
};
if (getMediaByMediaRemote(&media) != NULL)
if (getMediaByMediaRemote(&media, saveCover) != NULL)
return 1;
ffStrbufPutTo(&media.status, stdout);
ffStrbufPutTo(&media.song, stdout);
@@ -89,19 +110,21 @@ int ffPrintMediaByMediaRemote(void)
ffStrbufPutTo(&media.album, stdout);
ffStrbufPutTo(&media.playerId, stdout);
ffStrbufPutTo(&media.player, stdout);
ffStrbufWriteTo(&media.cover, stdout);
ffStrbufDestroy(&media.status);
ffStrbufDestroy(&media.song);
ffStrbufDestroy(&media.artist);
ffStrbufDestroy(&media.album);
ffStrbufDestroy(&media.playerId);
ffStrbufDestroy(&media.player);
ffStrbufDestroy(&media.cover);
return 0;
}
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
static const char* getMediaByAuthorizedProcess(FFMediaResult* result, bool saveCover)
{
// #1737
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote(%s)", instance.state.platform.exePath.chars, saveCover ? "True" : "False");
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
@@ -114,7 +137,7 @@ static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
if (buffer.length == 0) return "No media found";
// status\ntitle\nartist\nalbum\nbundleName\nappName
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player };
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player, &result->cover };
char* line = NULL;
size_t len = 0;
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
@@ -122,13 +145,13 @@ static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
return NULL;
}
void ffDetectMediaImpl(FFMediaResult* media)
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
{
const char* error;
if (@available(macOS 15.4, *))
error = getMediaByAuthorizedProcess(media);
error = getMediaByAuthorizedProcess(media, saveCover);
else
error = getMediaByMediaRemote(media);
error = getMediaByMediaRemote(media, saveCover);
if (error)
ffStrbufAppendS(&media->error, error);
else if (media->player.length == 0 && media->playerId.length > 0)
@@ -137,5 +160,7 @@ void ffDetectMediaImpl(FFMediaResult* media)
if (ffStrbufStartsWithIgnCaseS(&media->player, "com."))
ffStrbufSubstrAfter(&media->player, strlen("com.") - 1);
ffStrbufReplaceAllC(&media->player, '.', ' ');
if (media->cover.length > 0)
media->removeCoverAfterUse = true;
}
}
+53 -15
View File
@@ -1,6 +1,8 @@
#include "common/io/io.h"
#include "fastfetch.h"
#include "detection/media/media.h"
#include "util/stringUtils.h"
#include "util/unused.h"
#include <string.h>
@@ -52,21 +54,56 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator,
data->lib->ffdbus_message_iter_next(&dictIterator);
if(!ffStrStartsWith(key, "xesam:"))
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
if(ffStrStartsWith(key, "xesam:"))
{
const char* xesam = key + strlen("xesam:");
if(ffStrEquals(xesam, "title"))
ffDBusGetString(data, &dictIterator, &result->song);
else if(ffStrEquals(xesam, "album"))
ffDBusGetString(data, &dictIterator, &result->album);
else if(ffStrEquals(xesam, "artist"))
ffDBusGetString(data, &dictIterator, &result->artist);
else if(ffStrEquals(xesam, "url"))
ffDBusGetString(data, &dictIterator, &result->url);
key += strlen("xesam:");
if(ffStrEquals(key, "title"))
ffDBusGetString(data, &dictIterator, &result->song);
else if(ffStrEquals(key, "album"))
ffDBusGetString(data, &dictIterator, &result->album);
else if(ffStrEquals(key, "artist"))
ffDBusGetString(data, &dictIterator, &result->artist);
else if(ffStrEquals(key, "url"))
ffDBusGetString(data, &dictIterator, &result->url);
if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0 && result->url.length > 0)
break;
if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0 && result->url.length > 0)
break;
}
else if (ffStrStartsWith(key, "mpris:"))
{
const char* xesam = key + strlen("mpris:");
if(ffStrEquals(xesam, "artUrl"))
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
ffDBusGetString(data, &dictIterator, &path);
if (ffStrbufStartsWithS(&path, "file:///"))
{
ffStrbufEnsureFree(&result->cover, path.length - (uint32_t) strlen("file://"));
for (uint32_t i = (uint32_t) strlen("file://"); i < path.length; ++i)
{
if (path.chars[i] == '%')
{
if (i + 2 >= path.length)
break;
char str[] = { path.chars[i + 1], path.chars[i + 2], 0 };
char* end = NULL;
const char decodedChar = (char) strtoul(str, &end, 16);
if (end == &str[2])
{
i += 2;
ffStrbufAppendC(&result->cover, decodedChar);
}
else
ffStrbufAppendC(&result->cover, '%');
}
else
{
ffStrbufAppendC(&result->cover, path.chars[i]);
}
}
}
}
}
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
}
@@ -241,8 +278,9 @@ static const char* getMedia(FFMediaResult* result)
#endif
void ffDetectMediaImpl(FFMediaResult* media)
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
{
FF_UNUSED(saveCover); // We don't save the cover to a file for Mpris implementation
#ifdef FF_HAVE_DBUS
const char* error = getMedia(media);
ffStrbufAppendS(&media->error, error);
+7 -4
View File
@@ -3,7 +3,7 @@
#include "media.h"
#include "media_windows.dll.h"
static const char* getMedia(FFMediaResult* media)
static const char* getMedia(FFMediaResult* media, bool saveCover)
{
FF_LIBRARY_LOAD(libffwinrt, "dlopen libffwinrt" FF_LIBRARY_EXTENSION " failed", "libffwinrt" FF_LIBRARY_EXTENSION, 0)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libffwinrt, ffWinrtDetectMedia)
@@ -11,7 +11,7 @@ static const char* getMedia(FFMediaResult* media)
FFWinrtMediaResult result = {};
const char* error = ffffWinrtDetectMedia(&result);
const char* error = ffffWinrtDetectMedia(&result, saveCover);
if (error)
{
ffStrbufSetStatic(&media->error, error);
@@ -32,12 +32,15 @@ static const char* getMedia(FFMediaResult* media)
ffStrbufSetWS(&media->song, result.song);
ffStrbufSetWS(&media->artist, result.artist);
ffStrbufSetWS(&media->album, result.album);
ffStrbufSetWS(&media->cover, result.cover);
ffStrbufSetStatic(&media->status, result.status);
if (media->cover.length > 0)
media->removeCoverAfterUse = true;
return NULL;
}
void ffDetectMediaImpl(FFMediaResult* media)
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
{
const char* error = getMedia(media);
const char* error = getMedia(media, saveCover);
ffStrbufAppendS(&media->error, error);
}
+45 -2
View File
@@ -1,13 +1,16 @@
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Media.Control.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Storage.h>
#include <wchar.h>
#include <windows.h>
extern "C"
{
#include "media_windows.dll.h"
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover)
{
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
// Make it a separate dll in order not to break Windows 7 support
@@ -47,15 +50,55 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
}
::wcsncpy(result->playerId, session.SourceAppUserModelId().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->playerId[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->song[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->artist[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->album[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
try
{
// Only works for UWP apps
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->playerName[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
} catch (...) { }
if (saveCover)
{
using namespace winrt::Windows::Storage;
using namespace winrt::Windows::Storage::Streams;
if (auto thumbRef = mediaProps.Thumbnail())
{
try
{
if (auto stream = thumbRef.OpenReadAsync().get())
{
if (stream.Size() > 0)
{
Buffer buffer(static_cast<uint32_t>(stream.Size()));
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
wchar_t tempPath[MAX_PATH];
if (GetTempPathW(MAX_PATH, tempPath) > 0)
{
auto tempFolder = StorageFolder::GetFolderFromPathAsync(tempPath).get();
auto tempFile = tempFolder.CreateFileAsync(L"ff_thumb.img", CreationCollisionOption::GenerateUniqueName).get();
FileIO::WriteBufferAsync(tempFile, buffer).get();
::wcsncpy(result->cover, tempFile.Path().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
result->cover[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
}
}
}
}
catch (...)
{
// Ignore thumbnail errors
}
}
}
return NULL;
}
catch (...)
+2 -1
View File
@@ -9,8 +9,9 @@ typedef struct FFWinrtMediaResult
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
wchar_t cover[FF_MEDIA_WIN_RESULT_BUFLEN];
const char* status;
} FFWinrtMediaResult;
__attribute__((__dllexport__))
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result);
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover);
+1 -1
View File
@@ -28,7 +28,7 @@ const char* ffDetectMemory(FFMemoryResult* ram)
if((token = strstr(buf, "MemAvailable:")) != NULL)
memAvailable = strtoul(token + strlen("MemAvailable:"), NULL, 10);
else
if (memAvailable == 0 || memAvailable >= memTotal) // MemAvailable can be unreasonable. #1988
{
if((token = strstr(buf, "MemFree:")) != NULL)
memFree = strtoul(token + strlen("MemFree:"), NULL, 10);
+1 -1
View File
@@ -2,7 +2,7 @@
#include "common/library.h"
#include "common/printing.h"
#include <Windows.h>
#include <windows.h>
#include <GL/gl.h>
typedef struct WGLData
+12 -27
View File
@@ -8,14 +8,14 @@
#include <string.h>
#import <Foundation/Foundation.h>
static void parseSystemVersion(FFOSResult* os)
static bool parseSystemVersion(FFOSResult* os)
{
NSError* error;
NSString* fileName = @"file:///System/Library/CoreServices/SystemVersion.plist";
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
error:&error];
if(error)
return;
return false;
NSString* value;
@@ -30,6 +30,8 @@ static void parseSystemVersion(FFOSResult* os)
// macOS 26 Tahoe. #1809
os->version.chars[0] = '2';
}
return true;
}
static bool detectOSCodeName(FFOSResult* os)
@@ -80,41 +82,24 @@ static bool detectOSCodeName(FFOSResult* os)
return false;
}
static void parseOSXSoftwareLicense(FFOSResult* os)
{
FF_AUTO_CLOSE_FILE FILE* rtf = fopen("/System/Library/CoreServices/Setup Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf", "r");
if(rtf == NULL)
return;
FF_AUTO_FREE char* line = NULL;
size_t len = 0;
const char* searchStr = "\\f0\\b SOFTWARE LICENSE AGREEMENT FOR macOS ";
while(getline(&line, &len, rtf) != EOF)
{
if (ffStrStartsWith(line, searchStr))
{
ffStrbufAppendS(&os->codename, line + strlen(searchStr));
ffStrbufTrimRight(&os->codename, '\n');
ffStrbufTrimRight(&os->codename, '\\');
break;
}
}
}
void ffDetectOSImpl(FFOSResult* os)
{
parseSystemVersion(os);
ffStrbufSetStatic(&os->id, "macos");
if(os->version.length == 0)
if(__builtin_expect(os->name.length == 0, 0))
ffStrbufSetStatic(&os->name, "macOS");
if(__builtin_expect(os->version.length == 0, 0))
ffSysctlGetString("kern.osproductversion", &os->version);
if(os->buildID.length == 0)
if(__builtin_expect(os->buildID.length == 0, 0))
ffSysctlGetString("kern.osversion", &os->buildID);
ffStrbufAppend(&os->versionID, &os->version);
if(!detectOSCodeName(os))
parseOSXSoftwareLicense(os);
detectOSCodeName(os);
ffStrbufSetF(&os->prettyName, "%s %s %s (%s)", os->name.chars, os->codename.chars, os->version.chars, os->buildID.chars);
}
+31 -28
View File
@@ -59,17 +59,18 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
return true;
}
FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
// Returns false if PrettyName should be updated by caller
FF_MAYBE_UNUSED static bool getUbuntuFlavour(FFOSResult* result)
{
if (detectArmbianVersion(result))
return;
return true;
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
{
ffStrbufSetStatic(&result->name, "Linux Lite");
ffStrbufSetStatic(&result->id, "linuxlite");
ffStrbufSetStatic(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Linux Lite "));
return;
return true;
}
else if(ffStrbufStartsWithS(&result->prettyName, "Rhino Linux "))
{
@@ -77,12 +78,13 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
ffStrbufSetStatic(&result->id, "rhinolinux");
ffStrbufSetStatic(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Rhino Linux "));
return;
return true;
}
else if(ffStrbufStartsWithS(&result->prettyName, "VanillaOS "))
{
ffStrbufSetStatic(&result->id, "vanilla");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return true;
}
if (ffPathExists("/usr/bin/lliurex-version", FF_PATHTYPE_FILE))
@@ -97,93 +99,86 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
ffStrbufTrimRightSpace(&result->version);
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return true;
}
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
return false;
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
{
ffStrbufSetStatic(&result->name, "Kubuntu");
ffStrbufSetF(&result->prettyName, "Kubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "kubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "xfce") || ffStrContains(xdgConfigDirs, "xubuntu"))
{
ffStrbufSetStatic(&result->name, "Xubuntu");
ffStrbufSetF(&result->prettyName, "Xubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "xubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "lxqt") || ffStrContains(xdgConfigDirs, "lubuntu"))
{
ffStrbufSetStatic(&result->name, "Lubuntu");
ffStrbufSetF(&result->prettyName, "Lubuntu %s", result->version.chars);
ffStrbufSetStatic(&result->id, "lubuntu");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "budgie"))
{
ffStrbufSetStatic(&result->name, "Ubuntu Budgie");
ffStrbufSetF(&result->prettyName, "Ubuntu Budgie %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-budgie");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "cinnamon"))
{
ffStrbufSetStatic(&result->name, "Ubuntu Cinnamon");
ffStrbufSetF(&result->prettyName, "Ubuntu Cinnamon %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-cinnamon");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "mate"))
{
ffStrbufSetStatic(&result->name, "Ubuntu MATE");
ffStrbufSetF(&result->prettyName, "Ubuntu MATE %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-mate");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "studio"))
{
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
ffStrbufSetF(&result->prettyName, "Ubuntu Studio %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-studio");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "sway"))
{
ffStrbufSetStatic(&result->name, "Ubuntu Sway");
ffStrbufSetF(&result->prettyName, "Ubuntu Sway %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-sway");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
if(ffStrContains(xdgConfigDirs, "touch"))
{
ffStrbufSetStatic(&result->name, "Ubuntu Touch");
ffStrbufSetF(&result->prettyName, "Ubuntu Touch %s", result->version.chars);
ffStrbufSetStatic(&result->id, "ubuntu-touch");
ffStrbufSetStatic(&result->idLike, "ubuntu");
return;
return false;
}
return false;
}
FF_MAYBE_UNUSED static void getDebianVersion(FFOSResult* result)
@@ -192,8 +187,10 @@ FF_MAYBE_UNUSED static void getDebianVersion(FFOSResult* result)
ffAppendFileBuffer("/etc/debian_version", &debianVersion);
ffStrbufTrimRightSpace(&debianVersion);
if (!debianVersion.length) return;
ffStrbufSet(&result->version, &debianVersion);
ffStrbufSet(&result->versionID, &debianVersion);
ffStrbufDestroy(&result->versionID);
ffStrbufInitMove(&result->versionID, &debianVersion);
ffStrbufSetF(&result->prettyName, "%s %s (%s)", result->name.chars, result->versionID.chars, result->codename.chars);
}
FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
@@ -243,7 +240,7 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
ffStrbufSetStatic(&result->id, "raspbian");
ffStrbufSetStatic(&result->idLike, "debian");
ffStrbufSetStatic(&result->name, "Raspberry Pi OS");
ffStrbufSetStatic(&result->prettyName, "Raspberry Pi OS");
getDebianVersion(result);
return true;
}
else if (ffPathExists("/boot/dietpi/.version", FF_PATHTYPE_FILE))
@@ -372,7 +369,13 @@ void ffDetectOSImpl(FFOSResult* os)
#if __linux__ || __GNU__
if(ffStrbufEqualS(&os->id, "ubuntu"))
getUbuntuFlavour(os);
{
if (!getUbuntuFlavour(os))
{
if (!ffStrbufEndsWithS(&os->prettyName, " (development branch)"))
ffStrbufSetF(&os->prettyName, "%s %s", os->name.chars, os->version.chars); // os->version contains code name
}
}
else if(ffStrbufEqualS(&os->id, "debian"))
{
if (!detectDebianDerived(os))
@@ -1,25 +1,76 @@
extern "C" {
#include "os.h"
#include "common/library.h"
#include "util/windows/unicode.h"
#include "util/stringUtils.h"
#include "util/windows/registry.h"
}
#include "util/windows/unicode.hpp"
#include "util/windows/wmi.hpp"
#include <windows.h>
static const char* getOsNameByWmi(FFstrbuf* osName)
{
FFWmiQuery query(L"SELECT Caption FROM Win32_OperatingSystem");
if(!query)
return "Query WMI service failed";
if(FFWmiRecord record = query.next())
{
if(auto vtCaption = record.get(L"Caption"))
{
ffStrbufSetWSV(osName, vtCaption.get<std::wstring_view>());
ffStrbufTrimRight(osName, ' ');
return NULL;
}
return "Get Caption failed";
}
return "No WMI result returned";
}
PWSTR WINAPI BrandingFormatString(PCWSTR format);
void ffDetectOSImpl(FFOSResult* os)
static bool getCodeName(FFOSResult* os)
{
FF_HKEY_AUTO_DESTROY hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
return false;
if(!ffRegReadStrbuf(hKey, L"DisplayVersion", &os->codename, NULL))
{
if (!ffRegReadStrbuf(hKey, L"CSDVersion", &os->codename, NULL)) // For Windows 7 and Windows 8
if (!ffRegReadStrbuf(hKey, L"ReleaseId", &os->codename, NULL)) // For old Windows 10
return false;
}
return true;
}
static const char* getOsNameByWinbrand(FFstrbuf* osName)
{
//https://dennisbabkin.com/blog/?t=how-to-tell-the-real-version-of-windows-your-app-is-running-on#ver_string
const wchar_t* rawName = BrandingFormatString(L"%WINDOWS_LONG%");
ffStrbufSetWS(&os->variant, rawName);
FF_LIBRARY_LOAD(winbrand, "dlopen winbrand" FF_LIBRARY_EXTENSION " failed", "winbrand" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(winbrand, BrandingFormatString);
const wchar_t* rawName = ffBrandingFormatString(L"%WINDOWS_LONG%");
ffStrbufSetWS(osName, rawName);
GlobalFree((HGLOBAL)rawName);
ffStrbufSet(&os->prettyName, &os->variant);
return NULL;
}
extern "C"
void ffDetectOSImpl(FFOSResult* os)
{
if(getOsNameByWinbrand(&os->variant) && getOsNameByWmi(&os->variant))
return;
ffStrbufTrimRight(&os->variant, ' ');
//WMI returns the "Microsoft" prefix while BrandingFormatString doesn't. Make them consistent.
if(ffStrbufStartsWithS(&os->variant, "Microsoft "))
ffStrbufSubstrAfter(&os->variant, strlen("Microsoft ") - 1);
ffStrbufSet(&os->prettyName, &os->variant);
if(ffStrbufStartsWithS(&os->variant, "Windows "))
{
ffStrbufAppendS(&os->name, "Windows");
@@ -57,4 +108,7 @@ void ffDetectOSImpl(FFOSResult* os)
ffStrbufAppendF(&os->id, "%s %s", os->name.chars, os->version.chars);
ffStrbufSetStatic(&os->idLike, "Windows");
if (getCodeName(os) && os->codename.length > 0)
ffStrbufAppendF(&os->prettyName, " (%s)", os->codename.chars);
}
@@ -124,7 +124,7 @@ const char* ffDetectPhysicalMemory(FFlist* result)
ffStrbufSetS(&device->locator, ldevice);
const char* formFactorNames[] = {
NULL, // 0x00 (用于索引,实际上没有0x00的类型)
NULL, // 0x00 (Placeholder for indexing)
"Other", // 0x01
"Unknown", // 0x02
"SIMM", // 0x03
@@ -148,7 +148,7 @@ const char* ffDetectPhysicalMemory(FFlist* result)
ffStrbufSetF(&device->formFactor, "Unknown (%d)", (int) data->FormFactor);
const char* memoryTypeNames[] = {
NULL, // 0x00 (用于索引,实际上没有0x00的类型)
NULL, // 0x00 (Placeholder for indexing)
"Other", // 0x01
"Unknown", // 0x02
"DRAM", // 0x03
+4
View File
@@ -70,6 +70,10 @@ const char* ffDetectPublicIp(FFPublicIPOptions* options, FFPublicIpResult* resul
FF_STRBUF_AUTO_DESTROY response = ffStrbufCreateA(4096);
const char* error = ffNetworkingRecvHttpResponse(state, &response);
*state = (FFNetworkingState){};
*status = FF_UNITIALIZED;
if (error == NULL)
ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n");
else
+2 -2
View File
@@ -21,8 +21,8 @@ const char* ffDetectSwap(FFlist* result)
ffStrbufInitNWS(&swap->name, current->FileName.Length / sizeof(wchar_t), current->FileName.Buffer);
if (ffStrbufStartsWithS(&swap->name, "\\??\\"))
ffStrbufSubstrAfter(&swap->name, strlen("\\??\\") - 1);
swap->bytesUsed = current->TotalUsed * pageSize;
swap->bytesTotal = current->CurrentSize * pageSize;
swap->bytesUsed = (uint64_t) current->TotalUsed * pageSize;
swap->bytesTotal = (uint64_t) current->CurrentSize * pageSize;
if (current->NextEntryOffset == 0)
break;
}
+7 -1
View File
@@ -105,7 +105,13 @@ static void detectGhostty(const FFstrbuf* exe, FFTerminalFontResult* terminalFon
}
if (fontSize.length == 0) {
ffStrbufAppendS(&fontSize, "13");
ffStrbufAppendS(&fontSize,
#if __APPLE__
"13"
#else
"12"
#endif
);
FF_DEBUG("using default size='%s'", fontSize.chars);
}
+7 -2
View File
@@ -6,6 +6,7 @@
#include "util/binary.h"
#include <ctype.h>
#include <stdint.h>
#ifdef __FreeBSD__
#include <paths.h>
#ifndef _PATH_LOCALBASE
@@ -85,8 +86,10 @@ static bool getShellVersionFish(FFstrbuf* exe, FFstrbuf* version)
if(!getExeVersionRaw(exe, version))
return false;
//fish, version 4.0.2-1 (Built by MSYS2 project)
ffStrbufSubstrAfterFirstS(version, "version ");
//fish, version 4.0.2-1 (Built by MSYS2 project) // version can be localized if LC_ALL is set
if (version->length < strlen("fish, v") || !ffStrbufStartsWithS(version, "fish")) return false;
uint32_t index = ffStrbufNextIndexC(version, strlen("fish, "), ' ');
ffStrbufSubstrAfter(version, index);
ffStrbufSubstrBeforeFirstC(version, ' ');
return true;
}
@@ -291,6 +294,8 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* exePath,
return getShellVersionAsh(exe, version);
if(ffStrEqualsIgnCase(exeName, "xonsh"))
return getShellVersionXonsh(exe, version);
if(ffStrEqualsIgnCase(exeName, "brush"))
return getExeVersionGeneral(exe, version); // brush 0.2.23 (git:2835487)
#ifdef _WIN32
if(ffStrEqualsIgnCase(exeName, "powershell") || ffStrEqualsIgnCase(exeName, "powershell_ise"))
@@ -57,6 +57,9 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
ffStrbufEqualS(&result->processName, "flashfetch") ||
ffStrbufEqualS(&result->processName, "proot") ||
ffStrbufEqualS(&result->processName, "script") ||
#ifdef __linux__
ffStrbufEqualS(&result->processName, "run-parts") ||
#endif
ffStrbufContainS(&result->processName, "debug") ||
ffStrbufContainS(&result->processName, "command-not-") ||
ffStrbufEndsWithS(&result->processName, ".sh")
@@ -113,6 +116,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
#ifdef __linux__
ffStrbufStartsWithS(&result->processName, "Relay(") || // Unknown process in WSL2
ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707
ffStrbufEqualS(&result->processName, "run-parts") || // #2048
#endif
ffStrbufEndsWithS(&result->processName, ".sh")
)
+24
View File
@@ -0,0 +1,24 @@
#include "theme.h"
#include "detection/os/os.h"
const char* ffDetectTheme(FFThemeResult* result)
{
const FFOSResult* os = ffDetectOS();
char* str_end;
const char* version = os->version.chars;
unsigned long osNum = strtoul(version, &str_end, 10);
if (str_end != version)
{
if (osNum > 15) { // Tahoe
ffStrbufSetStatic(&result->theme1, "Liquid Glass");
} else if (osNum < 10) {
ffStrbufSetStatic(&result->theme1, "Platinum");
} else {
ffStrbufSetStatic(&result->theme1, "Aqua");
}
}
return NULL;
}
+29
View File
@@ -0,0 +1,29 @@
#include "theme.h"
#include "detection/os/os.h"
const char* ffDetectTheme(FFThemeResult* result)
{
const FFOSResult* os = ffDetectOS();
uint32_t ver = (uint32_t) ffStrbufToUInt(&os->version, 0);
if (ver > 1000)
{
// Windows Server
if (ver >= 2016)
ffStrbufSetStatic(&result->theme1, "Fluent");
else if (ver >= 2012)
ffStrbufSetStatic(&result->theme1, "Metro");
else
ffStrbufSetStatic(&result->theme1, "Aero");
}
else
{
if (ver >= 10)
ffStrbufSetStatic(&result->theme1, "Fluent");
else if (ver >= 8)
ffStrbufSetStatic(&result->theme1, "Metro");
else
ffStrbufSetStatic(&result->theme1, "Aero");
}
return NULL;
}
+2
View File
@@ -26,6 +26,8 @@
#define FF_ARCHITECTURE "alpha"
#elif defined(__hppa__)
#define FF_ARCHITECTURE "hppa"
#elif defined(__sh__)
#define FF_ARCHITECTURE "sh"
#elif defined(__m68k__)
#define FF_ARCHITECTURE "m68k"
#else
+4
View File
@@ -44,6 +44,10 @@ const char* ffDetectWeather(FFWeatherOptions* options, FFstrbuf* result)
ffStrbufEnsureFree(result, 4095);
const char* error = ffNetworkingRecvHttpResponse(&state, result);
state = (FFNetworkingState){};
status = FF_UNITIALIZED;
if (error == NULL)
{
ffStrbufSubstrAfterFirstS(result, "\r\n\r\n");
+1 -1
View File
@@ -12,7 +12,7 @@ extern "C"
#include <windows.h>
#include <tlhelp32.h>
#include <shlobj.h>
#include <Propkey.h>
#include <propkey.h>
template <typename Fn>
struct on_scope_exit {
+55 -24
View File
@@ -3,6 +3,7 @@
#include "common/init.h"
#include "common/io/io.h"
#include "common/jsonconfig.h"
#include "common/time.h"
#include "detection/version/version.h"
#include "logo/logo.h"
#include "util/stringUtils.h"
@@ -549,6 +550,26 @@ static void printVersion()
printf("%s %s%s%s (%s)\n", result->projectName, result->version, result->versionTweak, result->debugMode ? "-debug" : "", result->architecture);
}
static void enableJsonOutput(bool enable)
{
if (!enable)
{
if (instance.state.resultDoc)
{
yyjson_mut_doc_free(instance.state.resultDoc);
instance.state.resultDoc = NULL;
}
}
else
{
if (!instance.state.resultDoc)
{
instance.state.resultDoc = yyjson_mut_doc_new(NULL);
yyjson_mut_doc_set_root(instance.state.resultDoc, yyjson_mut_arr(instance.state.resultDoc));
}
}
}
static void parseCommand(FFdata* data, char* key, char* value)
{
if(ffStrEqualsIgnCase(key, "-h") || ffStrEqualsIgnCase(key, "--help"))
@@ -640,30 +661,18 @@ static void parseCommand(FFdata* data, char* key, char* value)
generateConfigFile(true, value, true);
else if(ffStrEqualsIgnCase(key, "-c") || ffStrEqualsIgnCase(key, "--config"))
optionParseConfigFile(data, key, value);
else if(ffStrEqualsIgnCase(key, "-j") || ffStrEqualsIgnCase(key, "--json"))
enableJsonOutput(ffOptionParseBoolean(value));
else if(ffStrEqualsIgnCase(key, "--format"))
{
switch (ffOptionParseEnum(key, value, (FFKeyValuePair[]) {
{ "default", 0},
{ "json", 1 },
enableJsonOutput(!!ffOptionParseEnum(key, value, (FFKeyValuePair[]) {
{ "default", false},
{ "json", true },
{},
}))
{
case 0:
if (instance.state.resultDoc)
{
yyjson_mut_doc_free(instance.state.resultDoc);
instance.state.resultDoc = NULL;
}
break;
case 1:
if (!instance.state.resultDoc)
{
instance.state.resultDoc = yyjson_mut_doc_new(NULL);
yyjson_mut_doc_set_root(instance.state.resultDoc, yyjson_mut_arr(instance.state.resultDoc));
}
break;
}
}));
}
else if(ffStrEqualsIgnCase(key, "--dynamic-interval"))
instance.state.dynamicInterval = ffOptionParseUInt32(key, value); // seconds to milliseconds
else
return;
@@ -762,15 +771,31 @@ static void run(FFdata* data)
if (!instance.config.display.noBuffer) fflush(stdout);
#endif
if (useJsonConfig)
ffPrintJsonConfig(false, instance.state.resultDoc);
else
ffPrintCommandOption(data, instance.state.resultDoc);
while (true)
{
if (useJsonConfig)
ffPrintJsonConfig(false, instance.state.resultDoc);
else
ffPrintCommandOption(data, instance.state.resultDoc);
if (instance.state.dynamicInterval > 0)
{
fflush(stdout);
ffTimeSleep(instance.state.dynamicInterval);
fputs("\e[H", stdout);
}
else
break;
}
if (instance.state.resultDoc)
yyjson_mut_write_fp(stdout, instance.state.resultDoc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES | YYJSON_WRITE_NEWLINE_AT_END, NULL, NULL);
else
{
if (instance.config.logo.printRemaining)
ffLogoPrintRemaining();
ffFinish();
}
}
static void writeConfigFile(FFdata* data)
@@ -829,6 +854,12 @@ int main(int argc, char** argv)
};
parseArguments(&data, argc, argv, parseCommand);
if(instance.state.dynamicInterval && instance.state.resultDoc)
{
fprintf(stderr, "Error: --dynamic-interval cannot be used with --json\n");
exit(400);
}
if(!data.configLoaded && !getenv("NO_CONFIG"))
parseConfigFiles();
parseArguments(&data, argc, argv, (void*) parseOption);
+1
View File
@@ -46,6 +46,7 @@ typedef struct FFstate
yyjson_mut_doc* resultDoc;
FFstrbuf genConfigPath;
bool fullConfig;
uint32_t dynamicInterval;
} FFstate;
typedef struct FFinstance
+2
View File
@@ -1,6 +1,7 @@
#include "fastfetch.h"
#include "common/init.h"
#include "logo/logo.h"
#include "modules/modules.h"
// A dirty replicate of neofetch
@@ -136,6 +137,7 @@ int main(void)
ffPrintColors(&options);
}
ffLogoPrintRemaining();
ffFinish();
ffDestroyInstance();
return 0;
+13
View File
@@ -0,0 +1,13 @@
!!
!!!!
llllll
llllll
IIIIIIIIII
IIIIIIIIIIIIIIIIIIII
;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;
:;;::;:;::
::::::
,,,,,,
,,,,
""
+11
View File
@@ -0,0 +1,11 @@
.::-::::. :======---:.
.-=++++++++==-:. .:-++===--=**+=:
.=. ...:::::--=****+++=-:. --
-: $2.-==-.$1 .::. ::
. $2:*%@@@@@#. .:::.
:#%%%%%@%#+. :*##%%%%#+.
*%%%%%%*. =. +*#%%%%%%%#:
*%%%%%%- +%%%%%%#@=
:%%%%%%#-. .:+%%%%%%%%+
:*%%%%%%+. .-+*###*=:
:=+=-.
+17
View File
@@ -0,0 +1,17 @@
.;oo;.
.;ldddol;.
.:cldddddolc:.
':lloddddoooolcc:'
':lllodddddooooolccc:,
,:lllloddddooooollllccccc,.
.,clllllddddooooollllllccc::::,.
.,clllllloodoooooooollllccc:::::::,.
'cllllllllllllloooooollcccc::::::::::,
,lllllllllllllooooolllccc::::::::::,
,cllllllllllllloollllcc::::::::::;
'clllllllllllllllcccc::::::::;:,
.clllllllccccc::cc:::::::::;:'
.cllllccccc:;;;:cc::::::;;:.
.cccccccc;;;:::::cc:::;;:.
.:cccc;;;:::::::::c::;:.
.;::::;;;;;;;;;;;;;::.
+20
View File
@@ -0,0 +1,20 @@
==++++++++++
:========++++++++++++:
===============+++++++++++
====================++++++++++
:=============$3#%@@%$1======++++++++-
-============$3%@%+++*$3@@$1========+++++=
-============$3%@#======$3@@$1==========+++-
=============$3%@+======$3@@$1==============.
$2--$1=========$3+@@@@@@@@@@@@@@@%+$1==========-
$2------$1=====$3%@@@@@@@@@@@@@@@@*$1===========
$2---------$1==$3%@@@@@@@%%@@@@@@@*$1===========
$2:----------$3%@@@@@#$1===$3+%@@@@@*$1==========-
$2----------$3%@@@@@%$1===$3*@@@@@@*$1==========.
$2:---------$3%@@@@@@@@@@@@@@@@*$1=========-
$2:--------$3%@@@@@@@@@@@@@@@@*$1========-
$2:--------$3+##############+$1========:
$2-------------------------$1====-
$2--------------------------
.--------------------.
------------
+13 -13
View File
@@ -1,14 +1,14 @@
$3//$2
$3//$2
$1TTTTTTTTTTTTTTT$2 $3//$2 $1..::$2 $4:-:.$2
$4ttt$2 $3//$2 $1.::.$2 $4.:-:$2
$4ttt$2 $3//$2 $1.:.$2 $4--$2
$4ttt$2 $3//$2 $4:-:$2
$4ttt$2 $3//$2 $4.:-:$2
$4ttt$2 $3//$2 $4:-:.$2
$4ttt$2 $3//$2 $4.--.$2
$4ttt$2 $3//$2 $4.:-:$2
$4ttt$2 $3//$2 $4...$2
$4ttt$2 $3//$2
$3//$2 $3.:::::::::::.$2
$3//$2
$1TTTTTTTTTTTTTTT$2 $3//$2
$1TTTTTTTTTTTTTTT$2 $3//$2 $1..::$2 $4:-:.$2
$4ttt$2 $3//$2 $1.::.$2 $4.:-:$2
$4ttt$2 $3//$2 $1.:.$2 $4--$2
$4ttt$2 $3//$2 $4:-:$2
$4ttt$2 $3//$2 $4.:-:$2
$4ttt$2 $3//$2 $4:-:.$2
$4ttt$2 $3//$2 $4.--.$2
$4ttt$2 $3//$2 $4.:-:$2
$4ttt$2 $3//$2 $4...$2
$4ttt$2 $3//$2
$3//$2 $3.:::::::::::.$2
$3//$2
+16
View File
@@ -0,0 +1,16 @@
__agggg
_g@@@@@@@P
a@@@@@@@@F
_@@@@@@@@F
$2a@@@@@@_ _@@@@@@_$1`
$2_a@@@~@@@@, @@@@~M@@&_
_@@@~ `@@@@ @@@@~ `@@@_
@@@" ~@@@@ @@@@~ "@@@
@@@ ~@@@@ @@@@F @@@
@@@ 4@@@@ @@@@F @@@
@@@_ 4@@@b @@@@F _@@@
"@@@_ 4@@@yy@@@F _@@@"
"R@@g_ 5@@@@@@@ _g@@@"
~@@@gy_ @@@@@@ _yg@@@~
`T@@@@gyyy@@@@yyag@@@@F~
~~FRR@@@@@@RPF~~
+10
View File
@@ -0,0 +1,10 @@
__________
/ __________ \
/ / \ \
/ / .-"````"-. \ \
| | |/ \| | |
| | Z R A X Y L | |
| | \ ¯¯¯¯¯¯¯¯¯¯¯¯ / | |
\ \ `-.___..___.-' / /
'.'._ _.' .'
'-.| M - C | .-'
+58
View File
@@ -1558,6 +1558,15 @@ static const FFlogo E[] = {
.colorKeys = FF_COLOR_FG_DEFAULT,
.colorTitle = FF_COLOR_FG_CYAN,
},
// EmperorOS
{
.names = {"Emperor"},
.lines = FASTFETCH_DATATEXT_LOGO_EMPEROROS,
.colors = {
FF_COLOR_FG_YELLOW,
FF_COLOR_FG_DEFAULT,
},
},
// EncryptOS
{
.names = {"EncryptOS"},
@@ -2847,6 +2856,17 @@ static const FFlogo L[] = {
};
static const FFlogo M[] = {
// Macaroni
{
.names = {"Macaroni"},
.lines = FASTFETCH_DATATEXT_LOGO_MACARONIOS,
.colors = {
FF_COLOR_FG_YELLOW,
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_YELLOW,
.colorTitle = FF_COLOR_FG_GREEN,
},
// MacOS
{
.names = {"macos", "mac"},
@@ -3998,6 +4018,15 @@ static const FFlogo P[] = {
FF_COLOR_FG_WHITE,
},
},
// PrismLinux
{
.names = {"PrismLinux"},
.lines = FASTFETCH_DATATEXT_LOGO_PRISMLINUX,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_BLUE,
},
},
// LAST
{},
};
@@ -4379,6 +4408,16 @@ static const FFlogo S[] = {
FF_COLOR_FG_RED,
},
},
// Secureblue
{
.names = {"secureblue"},
.lines = FASTFETCH_DATATEXT_LOGO_SECUREBLUE,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_MAGENTA,
FF_COLOR_FG_DEFAULT,
},
},
// Serpent OS
{
.names = {"Serpent OS"},
@@ -5172,6 +5211,15 @@ static const FFlogo V[] = {
FF_COLOR_FG_BLUE,
},
},
// VincentOS
{
.names = {"VincentOS"},
.lines = FASTFETCH_DATATEXT_LOGO_VINCENTOS,
.colors = {
FF_COLOR_FG_GREEN,
FF_COLOR_FG_DEFAULT,
},
},
// Vnux
{
.names = {"Vnux"},
@@ -5461,6 +5509,16 @@ static const FFlogo Z[] = {
FF_COLOR_FG_BLUE,
},
},
// Zraxyl
{
.names = {"Zraxyl" },
.lines = FASTFETCH_DATATEXT_LOGO_ZRAXYL,
.colors = {
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// LAST
{},
};
+14
View File
@@ -2,12 +2,14 @@
#include "common/io/io.h"
#include "common/printing.h"
#include "common/processing.h"
#include "detection/media/media.h"
#include "detection/os/os.h"
#include "detection/terminalshell/terminalshell.h"
#include "util/textModifier.h"
#include "util/stringUtils.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
typedef enum __attribute__((__packed__)) FFLogoSize
@@ -483,6 +485,15 @@ static bool updateLogoPath(void)
if (ffStrbufEqualS(&options->source, "-")) // stdin
return true;
if (ffStrbufIgnCaseEqualS(&options->source, "media-cover"))
{
const FFMediaResult* media = ffDetectMedia(true);
if (media->cover.length == 0)
return false;
ffStrbufSet(&options->source, &media->cover);
return true;
}
FF_STRBUF_AUTO_DESTROY fullPath = ffStrbufCreate();
if (ffPathExpandEnv(options->source.chars, &fullPath) && ffPathExists(fullPath.chars, FF_PATHTYPE_FILE))
{
@@ -706,6 +717,9 @@ void ffLogoPrintLine(void)
if(instance.state.logoWidth > 0)
printf("\033[%uC", instance.state.logoWidth);
if (instance.state.dynamicInterval > 0)
fputs("\033[K", stdout);
++instance.state.keysHeight;
}
+21 -26
View File
@@ -1,30 +1,20 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "common/processing.h"
#include "modules/command/command.h"
#include "util/stringUtils.h"
#include "detection/command/command.h"
bool ffPrintCommand(FFCommandOptions* options)
{
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&result, options->param.length ? (char* const[]){
options->shell.chars,
options->param.chars,
options->text.chars,
NULL
} : (char* const[]){
options->shell.chars,
options->text.chars,
NULL
});
const char* error = ffDetectCommand(options, &result);
if(error)
if (error)
{
ffPrintError(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if(!result.length)
if (!result.length)
{
ffPrintError(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No result generated");
return false;
@@ -72,6 +62,18 @@ void ffParseCommandJsonObject(FFCommandOptions* options, yyjson_val* module)
continue;
}
if (unsafe_yyjson_equals_str(key, "useStdErr"))
{
options->useStdErr = yyjson_get_bool(val);
continue;
}
if (unsafe_yyjson_equals_str(key, "parallel"))
{
options->parallel = yyjson_get_bool(val);
continue;
}
ffPrintError(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -81,25 +83,16 @@ void ffGenerateCommandJsonConfig(FFCommandOptions* options, yyjson_mut_doc* doc,
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
yyjson_mut_obj_add_strbuf(doc, module, "shell", &options->shell);
yyjson_mut_obj_add_strbuf(doc, module, "param", &options->param);
yyjson_mut_obj_add_strbuf(doc, module, "text", &options->text);
yyjson_mut_obj_add_bool(doc, module, "useStdErr", options->useStdErr);
yyjson_mut_obj_add_bool(doc, module, "parallel", options->parallel);
}
bool ffGenerateCommandJsonResult(FF_MAYBE_UNUSED FFCommandOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&result, options->param.length ? (char* const[]){
options->shell.chars,
options->param.chars,
options->text.chars,
NULL
} : (char* const[]){
options->shell.chars,
options->text.chars,
NULL
});
const char* error = ffDetectCommand(options, &result);
if(error)
{
@@ -137,6 +130,8 @@ void ffInitCommandOptions(FFCommandOptions* options)
#endif
);
ffStrbufInit(&options->text);
options->useStdErr = false;
options->parallel = true;
}
void ffDestroyCommandOptions(FFCommandOptions* options)
+2
View File
@@ -4,6 +4,8 @@
#define FF_COMMAND_MODULE_NAME "Command"
bool ffPrepareCommand(FFCommandOptions* options);
bool ffPrintCommand(FFCommandOptions* options);
void ffInitCommandOptions(FFCommandOptions* options);
void ffDestroyCommandOptions(FFCommandOptions* options);
+2
View File
@@ -9,6 +9,8 @@ typedef struct FFCommandOptions
FFstrbuf shell;
FFstrbuf param;
FFstrbuf text;
bool useStdErr;
bool parallel;
} FFCommandOptions;
static_assert(sizeof(FFCommandOptions) <= FF_OPTION_MAX_SIZE, "FFCommandOptions size exceeds maximum allowed size");
+12 -9
View File
@@ -5,7 +5,10 @@
#include "common/time.h"
#include "detection/disk/disk.h"
#include "modules/disk/disk.h"
#include "util/stringUtils.h"
#ifndef _WIN32
#include <fnmatch.h>
#endif
#pragma GCC diagnostic ignored "-Wsign-conversion"
@@ -197,18 +200,18 @@ bool ffPrintDisk(FFDiskOptions* options)
return false;
}
if(disks.length == 0)
{
ffPrintError(FF_DISK_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No disks found");
return false;
}
uint32_t index = 0;
FF_LIST_FOR_EACH(FFDisk, disk, disks)
{
if(__builtin_expect(options->folders.length == 0, 1) && (disk->type & ~options->showTypes))
continue;
if (options->hideFolders.length && ffStrbufSeparatedContain(&options->hideFolders, &disk->mountpoint, FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &disk->filesystem, ':'))
continue;
printDisk(options, disk, ++index);
}
@@ -380,7 +383,7 @@ bool ffGenerateDiskJsonResult(FFDiskOptions* options, yyjson_mut_doc* doc, yyjso
if(error)
{
yyjson_mut_obj_add_str(doc, module, "result", error);
yyjson_mut_obj_add_str(doc, module, "error", error);
return false;
}
@@ -452,7 +455,7 @@ void ffInitDiskOptions(FFDiskOptions* options)
#if _WIN32 || __APPLE__ || __ANDROID__
ffStrbufInit(&options->hideFolders);
#else
ffStrbufInitStatic(&options->hideFolders, "/efi:/boot:/boot/efi:/boot/firmware");
ffStrbufInitS(&options->hideFolders, "/efi:/boot:/boot/*");
#endif
ffStrbufInit(&options->hideFS);
options->showTypes = FF_DISK_VOLUME_TYPE_REGULAR_BIT | FF_DISK_VOLUME_TYPE_EXTERNAL_BIT | FF_DISK_VOLUME_TYPE_READONLY_BIT;
+15
View File
@@ -348,6 +348,21 @@ bool ffGenerateDisplayJsonResult(FF_MAYBE_UNUSED FFDisplayOptions* options, yyjs
yyjson_mut_obj_add_uint(doc, output, "height", item->height);
yyjson_mut_obj_add_real(doc, output, "refreshRate", item->refreshRate);
if (item->drrStatus == FF_DISPLAY_DRR_STATUS_UNKNOWN)
yyjson_mut_obj_add_null(doc, output, "drrStatus");
else switch (item->drrStatus)
{
case FF_DISPLAY_DRR_STATUS_DISABLED:
yyjson_mut_obj_add_str(doc, output, "drrStatus", "Disabled");
break;
case FF_DISPLAY_DRR_STATUS_ENABLED:
yyjson_mut_obj_add_str(doc, output, "drrStatus", "Enabled");
break;
default:
yyjson_mut_obj_add_str(doc, output, "drrStatus", "Unknown");
break;
}
yyjson_mut_val* scaled = yyjson_mut_obj_add_obj(doc, obj, "scaled");
yyjson_mut_obj_add_uint(doc, scaled, "width", item->scaledWidth);
yyjson_mut_obj_add_uint(doc, scaled, "height", item->scaledHeight);
+5 -2
View File
@@ -386,9 +386,12 @@ bool ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_
{
case FF_GPU_TYPE_INTEGRATED: type = "Integrated"; break;
case FF_GPU_TYPE_DISCRETE: type = "Discrete"; break;
default: type = "Unknown"; break;
default: type = NULL; break;
}
yyjson_mut_obj_add_str(doc, obj, "type", type);
if (type)
yyjson_mut_obj_add_str(doc, obj, "type", type);
else
yyjson_mut_obj_add_null(doc, obj, "type");
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &gpu->vendor);
+1 -8
View File
@@ -10,12 +10,7 @@ bool ffPrintKernel(FFKernelOptions* options)
if(options->moduleArgs.outputFormat.length == 0)
{
ffPrintLogoAndKey(FF_KERNEL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
printf("%s %s", info->name.chars, info->release.chars);
if(info->displayVersion.length > 0)
printf(" (%s)\n", info->displayVersion.chars);
else
putchar('\n');
printf("%s %s\n", info->name.chars, info->release.chars);
}
else
{
@@ -26,7 +21,6 @@ bool ffPrintKernel(FFKernelOptions* options)
FF_FORMAT_ARG(info->release, "release"),
FF_FORMAT_ARG(info->version, "version"),
FF_FORMAT_ARG(info->architecture, "arch"),
FF_FORMAT_ARG(info->displayVersion, "display-version"),
FF_FORMAT_ARG(str, "page-size"),
}));
}
@@ -61,7 +55,6 @@ bool ffGenerateKernelJsonResult(FF_MAYBE_UNUSED FFKernelOptions* options, yyjson
yyjson_mut_obj_add_strbuf(doc, obj, "name", &info->name);
yyjson_mut_obj_add_strbuf(doc, obj, "release", &info->release);
yyjson_mut_obj_add_strbuf(doc, obj, "version", &info->version);
yyjson_mut_obj_add_strbuf(doc, obj, "displayVersion", &info->displayVersion);
yyjson_mut_obj_add_uint(doc, obj, "pageSize", info->pageSize);
return true;
+6 -2
View File
@@ -43,7 +43,7 @@ static bool artistInSongTitle(const FFstrbuf* song, const FFstrbuf* artist)
bool ffPrintMedia(FFMediaOptions* options)
{
const FFMediaResult* media = ffDetectMedia();
const FFMediaResult* media = ffDetectMedia(false);
if(media->error.length > 0)
{
@@ -128,7 +128,7 @@ void ffGenerateMediaJsonConfig(FFMediaOptions* options, yyjson_mut_doc* doc, yyj
bool ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
const FFMediaResult* media = ffDetectMedia();
const FFMediaResult* media = ffDetectMedia(false);
if(media->error.length > 0)
{
@@ -143,6 +143,10 @@ bool ffGenerateMediaJsonResult(FF_MAYBE_UNUSED FFMediaOptions* options, yyjson_m
yyjson_mut_obj_add_strbuf(doc, song, "artist", &media->artist);
yyjson_mut_obj_add_strbuf(doc, song, "album", &media->album);
yyjson_mut_obj_add_strbuf(doc, song, "status", &media->status);
if (media->cover.length > 0)
yyjson_mut_obj_add_strbuf(doc, song, "cover", &media->cover);
else
yyjson_mut_obj_add_null(doc, song, "cover");
yyjson_mut_val* player = yyjson_mut_obj_add_obj(doc, obj, "player");
yyjson_mut_obj_add_strbuf(doc, player, "name", &media->player);
+1 -1
View File
@@ -10,7 +10,7 @@
bool ffPrintPlayer(FFPlayerOptions* options)
{
const FFMediaResult* media = ffDetectMedia();
const FFMediaResult* media = ffDetectMedia(false);
if(media->error.length > 0)
{

Some files were not shown because too many files have changed in this diff Show More