mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 10:22:12 +02:00
Compare commits
329 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ac1f1f889 | |||
| 14f1278485 | |||
| c2c6856159 | |||
| c89f3d2896 | |||
| 8e773470df | |||
| ea4fc7bdda | |||
| 468d1e0903 | |||
| 6851e7b082 | |||
| a734f18fd5 | |||
| 30b1e29785 | |||
| dde0c22195 | |||
| 1311a809db | |||
| 60a54f4880 | |||
| b4e65e7e48 | |||
| 6f3ed4a7b4 | |||
| cc8f8ff0f7 | |||
| 8a00f2d901 | |||
| c5c0e543e4 | |||
| 97255f37da | |||
| fb8a04f97a | |||
| c3ce5ac947 | |||
| eae69049b2 | |||
| 102e8fcc72 | |||
| 8372708f98 | |||
| 5011edc9d9 | |||
| 94a5228ffc | |||
| 382c0cd7c3 | |||
| ab496b23b7 | |||
| 939f428da7 | |||
| 2d496c91e1 | |||
| 442d58b646 | |||
| 4d377b94b7 | |||
| 7248868e33 | |||
| 2eda6464ad | |||
| 2622fc12a6 | |||
| b178e43428 | |||
| d00fca26c5 | |||
| 23e4d1c4aa | |||
| 6871c8bb73 | |||
| 61adc7cf64 | |||
| 9ba30adcba | |||
| 010b2c6262 | |||
| c65fb1a868 | |||
| 2029679ea5 | |||
| 817f70c2cd | |||
| 3a1f0485f4 | |||
| 64910d0781 | |||
| 821462e152 | |||
| b015fd579c | |||
| 8b40a81e22 | |||
| 8be64714ba | |||
| fe5d739cba | |||
| dba0672a11 | |||
| 3ed6acf3ca | |||
| 8c74c54bb0 | |||
| 818473102c | |||
| f1cc4a7805 | |||
| c574af97a4 | |||
| 74ae84e719 | |||
| 98738b6920 | |||
| 2e5769def2 | |||
| 18a6929662 | |||
| 0e61d1134d | |||
| 4abb183735 | |||
| d5b56be4ff | |||
| 1854953d8c | |||
| 2406015c81 | |||
| ec7f14ab96 | |||
| d94cdf4424 | |||
| 40e57b7698 | |||
| 974c658fff | |||
| ad0ddfd7f1 | |||
| 1da8367f55 | |||
| bdbc885811 | |||
| 86e5a5997b | |||
| 9832a0e45b | |||
| addf674621 | |||
| 863c5583ef | |||
| 45cbc6de83 | |||
| e68f766b4d | |||
| 29d7a1acac | |||
| 8d59d14b80 | |||
| ed1883909a | |||
| 049701a8a9 | |||
| 13b7bc89eb | |||
| 92fe44183d | |||
| 8ebc980c17 | |||
| dbeb338bda | |||
| 65ff11a8d0 | |||
| 7a73211484 | |||
| ca049997b1 | |||
| a9f021ccb9 | |||
| 55249c2294 | |||
| c13da56959 | |||
| 665c7cd5d3 | |||
| 469e21cce9 | |||
| 925e09c88a | |||
| 488454c1aa | |||
| c67c52d606 | |||
| e4e11ee509 | |||
| a3e2592555 | |||
| e0e966dadf | |||
| b079a8643b | |||
| 3291a9945f | |||
| 68fd21d0e4 | |||
| 0e1ef96992 | |||
| c377872438 | |||
| 4f42d38e4d | |||
| 7b2243496b | |||
| 960a817d03 | |||
| 6917f9479e | |||
| 8559cc45eb | |||
| 40e33c676d | |||
| d20371040e | |||
| 71faf1c7e3 | |||
| d182f3f743 | |||
| 39e009b945 | |||
| a1873f3e9e | |||
| 636bcaaaf9 | |||
| 3fcbd80ef0 | |||
| 38887e7fbd | |||
| da958e11f9 | |||
| c2ed71c4eb | |||
| 2e1ddcf9f8 | |||
| f1cc2d124c | |||
| 1e32a95f83 | |||
| 9e959bc57f | |||
| e68406ee22 | |||
| ba69e316b2 | |||
| f3e8e8af52 | |||
| c9adab3892 | |||
| c8d1d29017 | |||
| 541acca7c0 | |||
| ddf5099461 | |||
| 781a692b06 | |||
| 9c37f1b370 | |||
| a66c26f4df | |||
| 3bd750bedf | |||
| 4a1ada604c | |||
| e5f57a34a2 | |||
| 20a3737dce | |||
| e0452d9db5 | |||
| d8e74ba84c | |||
| 04b13096ac | |||
| 64d4035cae | |||
| 5e0ba57f53 | |||
| d89263c218 | |||
| 6a42588786 | |||
| 5883bf359c | |||
| 6a6b4070ca | |||
| 2c80cd6d29 | |||
| fa4b00b027 | |||
| 5fdc924b5d | |||
| 3d4a117093 | |||
| 7ec0c664c5 | |||
| 9d2df589b5 | |||
| 7107d08e92 | |||
| 4c34f99c12 | |||
| d7a8c92b46 | |||
| bbb29ff766 | |||
| 35235b9557 | |||
| 6b94605804 | |||
| 4b2fa07fdc | |||
| e203f4eeaf | |||
| 8db70b40e2 | |||
| 1f967849e5 | |||
| d60b2ddfd4 | |||
| fb68d8a841 | |||
| 047411ba87 | |||
| 08ed14b42a | |||
| d94a41cc1b | |||
| 81b7fb06c1 | |||
| c8debccd16 | |||
| 2853bd15c0 | |||
| 2f4146fde8 | |||
| eeceade14e | |||
| 1875c78e96 | |||
| f389864e17 | |||
| b9317734b9 | |||
| 4df4a1de78 | |||
| 0cd8c6ead6 | |||
| f8479dae94 | |||
| a7d623fa75 | |||
| 7a8ffb27bd | |||
| 73c0347469 | |||
| fde5f3bd0f | |||
| 9e1b1302fb | |||
| 7e235b6be0 | |||
| f43e1fd614 | |||
| c7b061eebd | |||
| a0f579072f | |||
| d439ce8eb5 | |||
| e2a714732a | |||
| a993a6f126 | |||
| 8eb8f710d0 | |||
| 526868e355 | |||
| 768238cb46 | |||
| 2d938042d0 | |||
| 9a54d92e9f | |||
| 839abab744 | |||
| c054570308 | |||
| ed69a7059b | |||
| 6b92659512 | |||
| 7e04305d1c | |||
| 87e13543da | |||
| 7a2cbc060f | |||
| f22d73d473 | |||
| e629126d73 | |||
| 9ac635e2e6 | |||
| 1b1b0521f4 | |||
| 41d0f61ee0 | |||
| 9de5d9008b | |||
| 576a9cc6fe | |||
| bd61d08afe | |||
| 4672b78481 | |||
| 36b0fdbcda | |||
| 7626ef6eaa | |||
| 115108b3f1 | |||
| 154f9f462b | |||
| a96a9fc31d | |||
| 23b43244c5 | |||
| 9dfb404a0d | |||
| ff3028c656 | |||
| 2f706ed494 | |||
| 06427ee62b | |||
| fe66eb3df0 | |||
| 6e1ab12399 | |||
| 484e05eae3 | |||
| 5d3fb98072 | |||
| 0c30590088 | |||
| 20cd4ce125 | |||
| 1c7aa89228 | |||
| f270255770 | |||
| 4b62a3c75b | |||
| 1557f0c556 | |||
| ef7f61309f | |||
| f59491b25d | |||
| e3592eb2c3 | |||
| 305776eb94 | |||
| 599e0d393d | |||
| 561574ae94 | |||
| 3dd78422eb | |||
| 5c546ab8e7 | |||
| 3e9274040d | |||
| 630d876e2d | |||
| 1938be86ff | |||
| 0980d5f0ad | |||
| d8c1b3b61b | |||
| 969523ae8a | |||
| 5d960ec744 | |||
| 3b36b8ca57 | |||
| 05f14764e6 | |||
| 3a180b24e3 | |||
| 02ab58e001 | |||
| fd158b41e1 | |||
| 89e0ede12f | |||
| 4d7b2410ef | |||
| c1f6a2f755 | |||
| 9c455c3b0f | |||
| d4ea9dfd21 | |||
| 08071e6e7e | |||
| ec87174f30 | |||
| 835e5b51c9 | |||
| 07c5ef255e | |||
| 476b55c17d | |||
| 4a53cfa312 | |||
| 50ea515476 | |||
| cbd9f72bc8 | |||
| 29eaa35f4c | |||
| 97c89c39d3 | |||
| 5769791185 | |||
| 894c66d793 | |||
| 75290154b0 | |||
| b08eea76b1 | |||
| 61d83af9ea | |||
| 2d497038eb | |||
| f8a5d5561a | |||
| 2e7e68ef23 | |||
| b812f3ccde | |||
| 6da8181bbe | |||
| a51dd641c1 | |||
| 0d20164d40 | |||
| 3320532668 | |||
| bcc6492115 | |||
| c60bc8ee5b | |||
| 4eefab8ccf | |||
| 9cda7e20fb | |||
| 79d0197dcf | |||
| ba01b1e4ce | |||
| 58908f69ba | |||
| 114088b845 | |||
| 6e77b592cb | |||
| 73bc71e922 | |||
| 090529ffef | |||
| 3c291f1af9 | |||
| fc31fe4aa4 | |||
| 563f9598be | |||
| 03bc2dade9 | |||
| 09d683b706 | |||
| 523a9590b8 | |||
| 3c3188eb05 | |||
| 354062118f | |||
| 85d7390fa8 | |||
| 8509f97054 | |||
| 8d5d8b4c90 | |||
| 536ad9594e | |||
| a57bbbadf4 | |||
| 3def466ee0 | |||
| 59868c66a0 | |||
| e13eb05073 | |||
| cdda65e6ad | |||
| a7ac89818c | |||
| 06956d2cf4 | |||
| ac52ea1afb | |||
| b68e0ce8ae | |||
| 8d6ed2e847 | |||
| 4211d15cdb | |||
| 2ff8d8864d | |||
| 884c902d93 | |||
| 16c56254b0 | |||
| 88eaab670f | |||
| 3e7630e074 | |||
| 744455d8b7 | |||
| bcc8f6d0b8 | |||
| 90ca6ee3cd | |||
| b679185c87 | |||
| 6bbed12083 | |||
| f04851891e | |||
| f94d9ca3bd |
+2
-2
@@ -1,5 +1,5 @@
|
||||
[codespell]
|
||||
check-filenames =
|
||||
builtin = clear,rare,usage,informal
|
||||
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
|
||||
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags
|
||||
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
|
||||
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
|
||||
|
||||
+230
-13
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
linux-amd64:
|
||||
name: Linux-amd64
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -80,12 +80,12 @@ jobs:
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- 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 libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev
|
||||
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 libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev
|
||||
|
||||
- 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 ddcutil --ignore-dependencies
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
@@ -151,8 +151,13 @@ jobs:
|
||||
- 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 libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
|
||||
|
||||
- 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: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -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
|
||||
@@ -378,7 +383,7 @@ jobs:
|
||||
run: |
|
||||
cat /etc/alpine-release
|
||||
uname -a
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
shell: alpine.sh --root {0}
|
||||
|
||||
- name: build
|
||||
@@ -403,9 +408,9 @@ jobs:
|
||||
name: fastfetch-musl-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-universal:
|
||||
name: macOS-universal
|
||||
runs-on: macos-latest
|
||||
macos-amd64:
|
||||
name: macOS-amd64
|
||||
runs-on: macos-13
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
@@ -421,7 +426,7 @@ jobs:
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -447,7 +452,54 @@ jobs:
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-macos-universal
|
||||
name: fastfetch-macos-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-aarch64:
|
||||
name: macOS-aarch64
|
||||
runs-on: macos-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
|
||||
- name: install required packages
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- 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: otool -L fastfetch
|
||||
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-macos-aarch64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
sunos-amd64:
|
||||
@@ -500,7 +552,7 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '14.2'
|
||||
version: '14.3'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
@@ -537,7 +589,7 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '7.6'
|
||||
version: '7.7'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
|
||||
@@ -592,6 +644,106 @@ jobs:
|
||||
name: fastfetch-netbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
dragonfly-amd64:
|
||||
name: DragonFly-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
with:
|
||||
usesh: yes
|
||||
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 xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
|
||||
|
||||
run: |
|
||||
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
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-dragonfly-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
haiku-amd64:
|
||||
name: Haiku-amd64
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Fixup VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
sync_files: false
|
||||
shutdown_vm: false
|
||||
run: |
|
||||
mv '/home/runner/work' '/boot/home/work'
|
||||
ln -sf '/boot/home/work' '/home/runner/work'
|
||||
|
||||
- name: Sync files to VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
sync_files: runner-to-vm
|
||||
shutdown_vm: false
|
||||
run: |
|
||||
chown -R $(id -u):$(id -g) $(pwd)
|
||||
ls -l
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
sync_files: vm-to-runner
|
||||
run: |
|
||||
uname -a
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
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
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-haiku-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
windows-amd64:
|
||||
name: Windows-amd64
|
||||
runs-on: windows-latest
|
||||
@@ -654,6 +806,68 @@ jobs:
|
||||
name: fastfetch-windows-amd64
|
||||
path: ./fastfetch-windows-amd64.*
|
||||
|
||||
windows-aarch64:
|
||||
name: Windows-aarch64
|
||||
runs-on: windows-11-arm
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: CLANGARM64
|
||||
update: true
|
||||
install: git mingw-w64-clang-aarch64-7zip mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-vulkan-loader mingw-w64-clang-aarch64-vulkan-headers mingw-w64-clang-aarch64-opencl-icd mingw-w64-clang-aarch64-opencl-headers mingw-w64-clang-aarch64-cppwinrt mingw-w64-clang-aarch64-imagemagick
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/clangarm64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /clangarm64/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- 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: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-windows-aarch64
|
||||
path: ./fastfetch-windows-aarch64.*
|
||||
|
||||
release:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
name: Release
|
||||
@@ -667,12 +881,15 @@ jobs:
|
||||
- linux-ppc64le
|
||||
- linux-s390x
|
||||
- musl-amd64
|
||||
- macos-universal
|
||||
- macos-amd64
|
||||
- macos-aarch64
|
||||
- freebsd-amd64
|
||||
- openbsd-amd64
|
||||
- netbsd-amd64
|
||||
- sunos-amd64
|
||||
- haiku-amd64
|
||||
- windows-amd64
|
||||
- windows-aarch64
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
|
||||
+250
-1
@@ -1,3 +1,252 @@
|
||||
# 2.48.0
|
||||
|
||||
Features:
|
||||
* Add support for detecting Fedora variants (#1830, OS, Linux)
|
||||
* Currently supported variants: CoreOS, Kinoite, Sericea, Silverblue
|
||||
* Optimize GPU detection on Windows when `--gpu-driver-specific` is not used (GPU, Windows)
|
||||
* Improve accuracy of GPU type detection. Previously it was guessed based on the dedicated vmem size, which causes issues on newer AMD integrated GPUs such as 9000 HX and AI 9 HX series. Supported on Windows 8.1 or later.
|
||||
* Add support for generic frequency detection of GPU 3D engine on Windows 11 22H2 or later.
|
||||
* Improve performance. GPU temperature detection is significantly improved when `--gpu-driver-specific` is not used.
|
||||
* Improve performance and security when spawning child processes by replacing `fork-exec` with `posix_spawn` (*nix)
|
||||
* Improve accuracy of sound device detection on macOS (Sound, macOS)
|
||||
* Trim leading and trailing whitespaces in disk serial numbers (PhysicalDisk)
|
||||
* Add `/etc/profiles/per-user` detection for Nix user packages (#1782, Packages, Linux)
|
||||
* Introduce `years` (whole years as integer), `days-of-year` (days since the last anniversary) and `years-fraction` (years as fraction, e.g. 1.5 means 1 year and 6 months) formatting placeholder to `Disk` (since disk creation), `Users` (since user login) and `Uptime` (since system boot) modules
|
||||
* For example: `fastfetch -s disk --disk-key 'OS Installation' --disk-format '{years} years {days-of-year} days'`
|
||||
* Add `--fraction-ndigits` option to specify the number of digits after the decimal point when displaying ordinary fractional values
|
||||
* Typically used with `{years-fraction}` above
|
||||
* This option does not affect percentage values, sizes, etc, which are controlled by individual options.
|
||||
|
||||
Bugfixes:
|
||||
* Fix compilation issues when not using `-DBINARY_LINK_TYPE=dlopen`
|
||||
* Regression from v2.47.0
|
||||
* Note: this option was added for debugging purposes only and is not recommended for production use
|
||||
* Replace `MTLDevice::hasUnifiedMemory` with `MTLDevice::location` for GPU type Detection (GPU, macOS)
|
||||
* This should resolve the issue where discrete GPUs were detected as integrated GPUs on Intel MacBooks with multi-GPU configurations.
|
||||
* Prevent text files from being loaded as image files (#1843, Logo)
|
||||
|
||||
Logos:
|
||||
* Add Minimal System
|
||||
* Add AxOS
|
||||
* Rename Ada to Xray OS
|
||||
|
||||
# 2.47.0
|
||||
|
||||
Features:
|
||||
* Various improvements for Solaris / OpenIndiana support
|
||||
* Support BIOS (UEFI or legacy) type detection (BIOS)
|
||||
* Support physical disk detection (PhysicalDisk)
|
||||
* Remove leading `-` from login shells (Shell)
|
||||
* Improve GPU detection performance (GPU)
|
||||
* Drop `libpciaccess` dependency
|
||||
* Use native API to detect sound devices (Sound)
|
||||
* Drop `PulseAudio` dependency
|
||||
* Improve DietPi OS and Raspberry Pi OS detection (#1816, OS, Linux)
|
||||
* Force reporting version 26 on macOS Tahoe (OS, macOS)
|
||||
* Append version string to Ubuntu variants (OS, Linux)
|
||||
* Improve performance of media detection for macOS 15.4+ (Media, macOS)
|
||||
* Increase `PROC_FILE_BUFFSIZ` to avoid possible short reads (Linux)
|
||||
* Fix potential bugs in `DiskIO`, `NetIO` and `CPUUsage` modules
|
||||
* Improve accuracy of CPU usage calculations by including interrupt and softirq times (CPUUsage, Linux / *BSD)
|
||||
* Ignore `init` and `systemd` processes when detecting terminals (Terminal, Linux)
|
||||
* Improve accuracy of CPU usage detection on Windows 10+ with perflib, which matches values reported by Task Manager (CPUUsage, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix `pci.ids` file location (#1819, GPU, OpenBSD)
|
||||
* Fix compiling on FreeBSD when `libdrm` support is disabled (#1820, GPU, FreeBSD)
|
||||
|
||||
Logos:
|
||||
* Improve visibility on white-background terminals for some logos by replacing white with the default foreground color
|
||||
* According to Wikipedia, the default foreground color is implementation-defined. It's usually black for white themes and white for dark themes. However, some terminals, notably Konsole with the default theme, use a different color, which may cause issues with some logos.
|
||||
* Add Xubuntu
|
||||
|
||||
# 2.46.0
|
||||
|
||||
Features:
|
||||
* Support Rio terminal font detection (#1789, TerminalFont, Linux)
|
||||
* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD)
|
||||
* Enable by `--gpu-detection-method auto`
|
||||
* Require proper DRM drivers installed and loaded
|
||||
* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD)
|
||||
* Support Aerospace WM detection (#1796, WM, macOS)
|
||||
* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux)
|
||||
* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux)
|
||||
* Use `board-id` as board name if available (Board, macOS)
|
||||
* Intel only
|
||||
* Support shared VRAM usage detection for AMD GPUs (GPU, Linux)
|
||||
* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of `pdh.dll` dependency (#1787, CPU, Windows)
|
||||
* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux)
|
||||
* Add macOS 26 Tahoe support (macOS)
|
||||
* Report macOS 26 code name (OS)
|
||||
* Report Liquid Glass DE on macOS 26+ (DE)
|
||||
* Detect Metal 4 support (GPU)
|
||||
|
||||
Bugfixes:
|
||||
* Fix packages counting by ignoring hidden folders (Packages, OpenBSD)
|
||||
* Fix Hyprland version detection (WM, FreeBSD)
|
||||
* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows)
|
||||
* Hide `/boot/firmware` by default (Disk, Linux)
|
||||
|
||||
Logos:
|
||||
* Rename Hydra Framework to HydraPwk (#1812)
|
||||
* Add AnushOS (#1806)
|
||||
* Add HarmonyOS (#1804)
|
||||
* Add GhostFreak (#1801)
|
||||
* Add TrueNAS Scale (#1795)
|
||||
* Add Fedora2_small (#1785)
|
||||
* Add xenia_old; update colors of xenia (#1797)
|
||||
* Improve colors of bedrock_small (#1790)
|
||||
* Add Kalpa Desktop (#1807)
|
||||
|
||||
# 2.45.0
|
||||
|
||||
Features:
|
||||
* Support OnePlus marketing name detection (#1768, Host, Android)
|
||||
* Recognize additional GPU vendors (GPU, Linux)
|
||||
* Support CTWM, FVWM and I3 window manager version detection (WM)
|
||||
* Support KDE version detection on *BSD (DE, FreeBSD)
|
||||
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
|
||||
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
|
||||
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
|
||||
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
|
||||
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
|
||||
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
|
||||
|
||||
Bugfixes
|
||||
* Fix MacBook Air model name (#1779, Host, macOS)
|
||||
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
|
||||
* Fix dnf package count detection (#1777, Packages, Linux)
|
||||
|
||||
Logos:
|
||||
* Add Starry Linux (#1771)
|
||||
* Add rhel_small (#1774)
|
||||
* Update color palette of voidlinux (#1775)
|
||||
* Add void2
|
||||
* Update Xenia Linux (#1783)
|
||||
|
||||
# 2.44.0
|
||||
|
||||
Features:
|
||||
* Add option `--disk-hide-folders` and `--disk-hide-fs` to hide specific mountpoints and filesystems in Disk module (Disk)
|
||||
* `--disk-hide-folders` defaults to `/efi:/boot:/boot/efi` on Linux and *BSD. Previously these EFI-related folders were hardcoded to be hidden on Linux.
|
||||
|
||||
Bugfixes:
|
||||
* Fix Apple Terminal compatibility with `--stat` (macOS, #1755)
|
||||
* Ignore `/usr/bin/script` when detecting shell and terminal (Terminal / Shell, #1761)
|
||||
* Fix compatibility with KDE Plasma 6.4 which is in beta currently (Display, Linux, #1765)
|
||||
|
||||
Logos:
|
||||
* Add Kylin (#1760)
|
||||
* Add UBLinux (#1764)
|
||||
|
||||
# 2.43.0
|
||||
|
||||
Features:
|
||||
* Support physical core count and package count detection on Solaris (CPU, SunOS)
|
||||
* Improve physical core count detection on FreeBSD (CPU, FreeBSD)
|
||||
* Add option to hide unknown GPUs (GPU)
|
||||
* Detect VRAM type of AMD GPUs on Linux (GPU, Linux)
|
||||
* Support playing media detection on macOS 15.4 (#1737, Media, macOS)
|
||||
* Whether it works on newer versions is unknown
|
||||
* Detect player name for Windows UMP apps (Media, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix disk usage detection on 32-bit Linux (#1734, Disk, Linux)
|
||||
* Fix compiling on Asahi Linux (GPU, Linux)
|
||||
* Fix duplicated playback status (Media, Linux)
|
||||
* Don't show 255 in custom format when muted on macOS (#1750, Sound, macOS)
|
||||
* Remove shared memory detection for AMD GPUs, which doesn't work as expected (GPU, Windows)
|
||||
|
||||
Logos:
|
||||
* new AthenaOS
|
||||
* add Hydra Framework
|
||||
|
||||
# 2.42.0
|
||||
|
||||
Changes:
|
||||
* Normalize the module name `Bios` to `BIOS` (#1721)
|
||||
* No configuration file changes are required because fastfetch parses module names case-insensitively.
|
||||
|
||||
Bugfixes:
|
||||
* Disable disk type detection for virtual disks (PhysicalDisk, Linux, #1669)
|
||||
* Fix incorrect CPU temperature reporting (CPU, OpenBSD)
|
||||
* Fix setting `logo.chafa.symbols` in JSON configuration (Logo, #1709)
|
||||
* Fix non-normalized time display (Uptime, #1720)
|
||||
* Miscellaneous minor fixes
|
||||
|
||||
Features:
|
||||
* Add CPU temperature detection support (CPU, SunOS)
|
||||
* Improve CPU frequency detection (CPU, NetBSD)
|
||||
* Add Wi-Fi detection support (Wifi, NetBSD)
|
||||
* Add Webcam detection support (Camera, OpenBSD)
|
||||
* Requires root privileges
|
||||
|
||||
Logos:
|
||||
* Remove GoralixOS logo (#1699)
|
||||
* Add Aurora logo (#1700)
|
||||
* Add Codex Linux logo (#1701)
|
||||
|
||||
# 2.41.0
|
||||
|
||||
Changes:
|
||||
* Due to [the deprecation](https://github.com/actions/runner-images/issues/11101), Linux x86_64 binaries are now built with Ubuntu 22.04 (Glibc 2.35, Debian 12)
|
||||
* You can always build fastfetch yourself on your own. Please don't report bugs related to this change.
|
||||
|
||||
Features:
|
||||
* Support physical core count detection on non-x86 platforms (CPU, Linux / FreeBSD)
|
||||
* Support CPU frequency detection on PPC64 (CPU, FreeBSD)
|
||||
* Support soar packages count detection (Packages, Linux)
|
||||
* Support `~` path expanding on Windows (Logo, Windows)
|
||||
* Support retrieving full user name (Title)
|
||||
* Exposed with `--title-format '{full-user-name}'`
|
||||
* Improve CPU (thermal zone) temperature detection on Windows (CPU, Windows)
|
||||
* Administrator privileges are no longer needed
|
||||
* Support base Wifi info detection on OpenBSD (Wifi, OpenBSD)
|
||||
* To be tested
|
||||
* Support GPU temperature detection for Intel dGPU on Linux (GPU, Linux)
|
||||
* To be tested
|
||||
* Add new ARM CPU part numbers (CPU, Linux)
|
||||
* Add base implementation of Bluetooth device detection (Bluetooth, NetBSD, #1690)
|
||||
* Some small improvements
|
||||
|
||||
Logo:
|
||||
* Add anduinos
|
||||
* Add 2 more Alpine logos
|
||||
|
||||
# 2.40.4
|
||||
|
||||
Bugfixes:
|
||||
* Fix loading presets config on Windows (Windows, #1682)
|
||||
* Regression of v2.40.0
|
||||
* Remove the prefix `v` of Hyprland version on Arch Linux (WM, Linux)
|
||||
|
||||
# 2.40.3
|
||||
|
||||
Bugfixes:
|
||||
* Fix loading example configs from presets directory (#1672)
|
||||
* Regression of v2.40.2
|
||||
* Mark kitty image protocol support for warp terminal on macOS too (Logo)
|
||||
|
||||
# 2.40.2
|
||||
|
||||
Changes:
|
||||
* Since v2.40.0, we've been loading config files from the directory where the fastfetch binary is located. However, this approach may lead to loading unexpected files. For example, `fastfetch -c groups` would attempt to load `/usr/bin/groups`. Therefore, we now enforce the `.jsonc` extension when loading config files. Examples:
|
||||
1. `-c filename`: loads `filename.jsonc`
|
||||
2. `-c filename.jsonc`: loads `filename.jsonc`
|
||||
3. `-c filename.json`: loads `filename.json` and enforces strict JSON syntax (no comments or trailing commas)
|
||||
4. `-c filename.ext`: loads `filename.ext.jsonc` (`.jsonc` extension is enforced)
|
||||
|
||||
Features:
|
||||
* Mark kitty image protocol support for warp terminal (Logo)
|
||||
* Documentation improvements
|
||||
|
||||
# 2.40.1
|
||||
|
||||
Bugfixes:
|
||||
* Fix compiling error on old intel platform (TPM, macOS)
|
||||
* Fix `--file-raw -` no longer working (Logo, #1659)
|
||||
* Regression of v2.40.0
|
||||
|
||||
# 2.40.0
|
||||
|
||||
Changes:
|
||||
@@ -817,7 +1066,7 @@ Bugfixes:
|
||||
* Fix some presets
|
||||
* Better detection for XTerm terminal fonts (#1095, TerminalFont, Linux)
|
||||
* Remove debug output (#1097, Windows)
|
||||
* Fix command line option `--gpu-hide-type` doesn't work (#1098, GPU)
|
||||
* Fix flag `--gpu-hide-type` doesn't work (#1098, GPU)
|
||||
* Fix wrong date on Raspbian 10 (#1108, DateTime, Linux)
|
||||
* Use `brightness` instead of `actuall_brightness` when detecting current brightness level (Brightness, Linux)
|
||||
* Ref: https://bugzilla.kernel.org/show_bug.cgi?id=203905
|
||||
|
||||
+61
-35
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.40.0
|
||||
VERSION 2.48.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -61,7 +61,7 @@ cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeB
|
||||
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD" OFF)
|
||||
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
|
||||
@@ -76,13 +76,13 @@ cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD O
|
||||
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku" 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 OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
|
||||
|
||||
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
|
||||
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
|
||||
@@ -102,7 +102,7 @@ if(NOT BINARY_LINK_TYPE IN_LIST BINARY_LINK_TYPE_OPTIONS)
|
||||
message(FATAL_ERROR "BINARY_LINK_TYPE must be one of ${BINARY_LINK_TYPE_OPTIONS}")
|
||||
endif()
|
||||
|
||||
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SORCERY WINGET XBPS)
|
||||
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SOAR SORCERY WINGET XBPS)
|
||||
foreach(package_manager ${PACKAGE_MANAGERS})
|
||||
if(package_manager STREQUAL "WINGET")
|
||||
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON)
|
||||
@@ -325,9 +325,6 @@ endif()
|
||||
|
||||
fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP)
|
||||
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
|
||||
fastfetch_load_text(src/data/help_footer.txt DATATEXT_HELP_FOOTER)
|
||||
fastfetch_load_text(src/data/help_color.txt DATATEXT_HELP_COLOR)
|
||||
fastfetch_load_text(src/data/help_format.txt DATATEXT_HELP_FORMAT)
|
||||
|
||||
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
|
||||
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
|
||||
@@ -339,13 +336,12 @@ endif()
|
||||
# Ascii image data #
|
||||
####################
|
||||
|
||||
file(GLOB LOGO_FILES "src/logo/ascii/*.txt")
|
||||
file(GLOB LOGO_FILES CONFIGURE_DEPENDS "src/logo/ascii/*.txt")
|
||||
set(LOGO_BUILTIN_H "#pragma once\n#pragma GCC diagnostic ignored \"-Wtrigraphs\"\n\n")
|
||||
foreach(file ${LOGO_FILES})
|
||||
fastfetch_load_text("${file}" content)
|
||||
get_filename_component(file "${file}" NAME_WE)
|
||||
string(TOUPPER "${file}" file)
|
||||
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
|
||||
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
|
||||
endforeach()
|
||||
file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
|
||||
@@ -528,6 +524,7 @@ if(LINUX)
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_linux.c
|
||||
src/detection/gpu/gpu_drm.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_linux.c
|
||||
@@ -675,6 +672,7 @@ elseif(FreeBSD)
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_bsd.c
|
||||
src/detection/gpu/gpu_drm.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_bsd.c
|
||||
@@ -708,7 +706,7 @@ elseif(FreeBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -737,7 +735,7 @@ elseif(NetBSD)
|
||||
src/common/sysctl.c
|
||||
src/detection/battery/battery_nbsd.c
|
||||
src/detection/bios/bios_nbsd.c
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
src/detection/bluetooth/bluetooth_bsd.c
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/board/board_nbsd.c
|
||||
src/detection/bootmgr/bootmgr_bsd.c
|
||||
@@ -786,7 +784,7 @@ elseif(NetBSD)
|
||||
src/detection/netio/netio_bsd.c
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_nbsd.c
|
||||
src/detection/packages/packages_obsd.c
|
||||
src/detection/packages/packages_nbsd.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_nbsd.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
@@ -800,8 +798,8 @@ elseif(NetBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wifi/wifi_nbsd.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -882,8 +880,8 @@ elseif(OpenBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_obsd.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wifi/wifi_obsd.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -980,7 +978,6 @@ elseif(WIN32)
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/cpu/cpu_windows.c
|
||||
src/detection/cpu/cpu_windows.cpp
|
||||
src/detection/cpucache/cpucache_windows.c
|
||||
src/detection/cpuusage/cpuusage_windows.c
|
||||
src/detection/cursor/cursor_windows.c
|
||||
@@ -1060,7 +1057,7 @@ elseif(SunOS)
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/disk/disk_sunos.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_nosupport.c
|
||||
src/detection/physicaldisk/physicaldisk_sunos.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_sunos.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
@@ -1100,7 +1097,7 @@ elseif(SunOS)
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
src/detection/sound/sound_linux.c
|
||||
src/detection/sound/sound_sunos.c
|
||||
src/detection/swap/swap_sunos.c
|
||||
src/detection/terminalfont/terminalfont_linux.c
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
@@ -1585,14 +1582,20 @@ elseif(WIN32)
|
||||
PRIVATE "ws2_32"
|
||||
PRIVATE "ntdll"
|
||||
PRIVATE "version"
|
||||
PRIVATE "setupapi"
|
||||
PRIVATE "hid"
|
||||
PRIVATE "wtsapi32"
|
||||
PRIVATE "imagehlp"
|
||||
PRIVATE "cfgmgr32"
|
||||
PRIVATE "winbrand"
|
||||
PRIVATE "propsys"
|
||||
PRIVATE "secur32"
|
||||
)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
# WoA only works on Windows 10 or higher
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "mincore"
|
||||
)
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "m"
|
||||
@@ -1616,6 +1619,7 @@ elseif(OpenBSD)
|
||||
)
|
||||
elseif(NetBSD)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "bluetooth"
|
||||
PRIVATE "m"
|
||||
PRIVATE "prop"
|
||||
)
|
||||
@@ -1627,6 +1631,7 @@ elseif(SunOS)
|
||||
PRIVATE "proc"
|
||||
PRIVATE "zfs"
|
||||
PRIVATE "nvpair"
|
||||
PRIVATE "devinfo"
|
||||
)
|
||||
elseif(ANDROID)
|
||||
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
|
||||
@@ -1829,10 +1834,26 @@ if (BUILD_TESTS)
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-color
|
||||
tests/color.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-color
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-duration
|
||||
tests/duration.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-duration
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
|
||||
add_test(NAME test-list COMMAND fastfetch-test-list)
|
||||
add_test(NAME test-format COMMAND fastfetch-test-format)
|
||||
add_test(NAME test-color COMMAND fastfetch-test-color)
|
||||
add_test(NAME test-duration COMMAND fastfetch-test-duration)
|
||||
endif()
|
||||
|
||||
##################
|
||||
@@ -1900,17 +1921,17 @@ 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-universal" CPACK_PACKAGE_FILE_NAME)
|
||||
else() # We don't use this in Windows
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "amd64")
|
||||
endif()
|
||||
if(IS_MUSL)
|
||||
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
|
||||
else()
|
||||
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
|
||||
endif()
|
||||
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
|
||||
elseif(IS_MUSL)
|
||||
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
|
||||
else()
|
||||
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
@@ -1936,12 +1957,17 @@ if(LINUX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(HAVE_RPMBUILD "rpmbuild")
|
||||
if(HAVE_RPMBUILD)
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||
if(NOT IS_MUSL)
|
||||
find_program(HAVE_RPMBUILD "rpmbuild")
|
||||
if(HAVE_RPMBUILD)
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
endif()
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
|
||||
endif()
|
||||
|
||||
set(CPACK_SET_DESTDIR ON)
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
[](https://github.com/fastfetch-cli/fastfetch/releases)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://deepwiki.com/fastfetch-cli/fastfetch)
|
||||
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it prettily. It is written mainly in C, with performance and customizability in mind. Currently, Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS are supported.
|
||||
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.
|
||||
|
||||
<img src="screenshots/example1.png" width="49%" align="left" />
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
|
||||
@@ -21,13 +22,15 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
|
||||
<img src="screenshots/example3.png" width="48%" align="top" />
|
||||
<img src="screenshots/example5.png" height="15%" align="top" />
|
||||
|
||||
According configuration files for examples are located [here](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets/examples).
|
||||
|
||||
There are [screenshots on different platforms](https://github.com/fastfetch-cli/fastfetch/wiki).
|
||||
|
||||
## Installation
|
||||
|
||||
### Linux
|
||||
|
||||
Some distros package an outdated fastfetch version. Older versions receive no support, so please try always to use the latest version.
|
||||
Some distributions package outdated versions of fastfetch. Older versions receive no support, so please always try to use the latest version.
|
||||
|
||||
<a href="https://repology.org/project/fastfetch/versions">
|
||||
<img src="https://repology.org/badge/vertical-allrepos/fastfetch.svg?columns=2" alt="Packaging status" align="right">
|
||||
@@ -49,9 +52,9 @@ Some distros package an outdated fastfetch version. Older versions receive no su
|
||||
* Void Linux: `xbps-install fastfetch`
|
||||
* Venom Linux: `scratch install fastfetch`
|
||||
|
||||
You may need `sudo`, `doas` or `sup` to run these commands.
|
||||
You may need `sudo`, `doas`, or `sup` to run these commands.
|
||||
|
||||
If fastfetch is not packaged for your distro or an outdated version is packaged, [linuxbrew](https://brew.sh/) is a good alternative: `brew install fastfetch`
|
||||
If fastfetch is not packaged for your distribution or an outdated version is packaged, [linuxbrew](https://brew.sh/) is a good alternative: `brew install fastfetch`
|
||||
|
||||
### macOS
|
||||
|
||||
@@ -67,9 +70,12 @@ If fastfetch is not packaged for your distro or an outdated version is packaged,
|
||||
|
||||
You may also download the program directly from [the GitHub releases page](https://github.com/fastfetch-cli/fastfetch/releases/latest) in the form of an archive file.
|
||||
|
||||
### FreeBSD
|
||||
### BSD systems
|
||||
|
||||
* `pkg install fastfetch`
|
||||
* FreeBSD: `pkg install fastfetch`
|
||||
* NetBSD: `pkgin in fastfetch`
|
||||
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
|
||||
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
|
||||
|
||||
### Android (Termux)
|
||||
|
||||
@@ -81,19 +87,19 @@ You may also download the program directly from [the GitHub releases page](https
|
||||
|
||||
## Build from source
|
||||
|
||||
See Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
|
||||
## Usage
|
||||
|
||||
* Run it with default configuration: `fastfetch`
|
||||
* Run it with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) and find what interests you: `fastfetch -c all.jsonc`
|
||||
* Find all data that fastfetch detects: `fastfetch -s <module> --format json`
|
||||
* Run with default configuration: `fastfetch`
|
||||
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
|
||||
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
|
||||
* Display help messages: `fastfetch --help`
|
||||
* Generate config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
|
||||
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
|
||||
|
||||
## Customization
|
||||
|
||||
Fastfetch uses the JSONC (or JSON with comments) for configuration. [See Wiki for detail](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration). There are some premade config files in [`presets`](presets), including the ones used for the screenshots above. You can load them using `-c <filename>`. Those files can serve as examples of the configuration syntax.
|
||||
Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for details](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration). There are some premade config files in the [`presets`](presets) directory, including those used for the screenshots above. You can load them using `-c <filename>`. These files can serve as examples of the configuration syntax.
|
||||
|
||||
Logos can also be heavily customized; see the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for more information.
|
||||
|
||||
@@ -102,29 +108,29 @@ Logos can also be heavily customized; see the [logo documentation](https://githu
|
||||
### Q: Neofetch is good enough. Why do I need fastfetch?
|
||||
|
||||
1. Fastfetch is actively maintained.
|
||||
2. Fastfetch is faster. As the name suggests.
|
||||
3. Fastfetch has a greater number of features, though by default fastfetch only has a few modules enabled; use `fastfetch -c all` to find what you want.
|
||||
2. Fastfetch is faster, as the name suggests.
|
||||
3. Fastfetch has a greater number of features, though by default it only has a few modules enabled; use `fastfetch -c all` to discover what you want.
|
||||
4. Fastfetch is more configurable. You can find more information in the Wiki: <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration>.
|
||||
5. Fastfetch is more polished. For example, neofetch prints `555 MiB` in the Memory module and `23 G` in the Disk module, whereas fastfetch prints `555.00 MiB` and `22.97 GiB` respectively.
|
||||
6. Fastfetch is more accurate. For example, [neofetch never actually supports the Wayland protocol](https://github.com/dylanaraps/neofetch/pull/2395).
|
||||
|
||||
### Q: Fastfetch shows my local IP address. It leaks my privacy!
|
||||
### Q: Fastfetch shows my local IP address. Does it leak my privacy?
|
||||
|
||||
A local IP (10.x.x.x, 172.x.x.x, 192.168.x.x) has nothing to do with privacy. It only makes sense if you are on the same network, for example, if you connect to the same Wi-Fi network.
|
||||
A local IP address (10.x.x.x, 172.x.x.x, 192.168.x.x) has nothing to do with privacy. It only has meaning if you are on the same network, for example, if you connect to the same Wi-Fi network.
|
||||
|
||||
Actually the `Local IP` module is the most useful module for me personally. I (@CarterLi) have several VMs installed to test fastfetch and often need to SSH into them. I have fastfetch running on shell startup and I never need to type `ip addr` manually.
|
||||
Actually, the `Local IP` module is the most useful module for me personally. I (@CarterLi) have several VMs installed to test fastfetch and often need to SSH into them. With fastfetch running on shell startup, I never need to type `ip addr` manually.
|
||||
|
||||
If you really don't like it, you can disable the `Local IP` module in `config.jsonc`.
|
||||
|
||||
### Q: Where is the config file? I can't find it.
|
||||
|
||||
`Fastfetch` does not generate config file automatically. You can use `fastfetch --gen-config` to generate one. The config file will be saved in `~/.config/fastfetch/config.jsonc` by default. See [Wiki for detail](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration).
|
||||
Fastfetch does not generate a config file automatically. You can use `fastfetch --gen-config` to generate one. The config file will be saved in `~/.config/fastfetch/config.jsonc` by default. See the [Wiki for details](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration).
|
||||
|
||||
### Q: The configuration is so complex. Where is the documentation?
|
||||
|
||||
Fastfetch uses JSON (with comments) for configuration. I suggest you use an IDE with JSON schema support (like VSCode) to edit it.
|
||||
Fastfetch uses JSON (with comments) for configuration. I suggest using an IDE with JSON schema support (like VSCode) to edit it.
|
||||
|
||||
Alternatively, you can refer to the presets in [`presets` directory](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets).
|
||||
Alternatively, you can refer to the presets in the [`presets` directory](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets).
|
||||
|
||||
The **correct** way to edit the configuration:
|
||||
|
||||
@@ -134,32 +140,32 @@ This is an example that [changes size prefix from MiB / GiB to MB / GB](https://
|
||||
|
||||
### Q: I WANT THE DOCUMENTATION!
|
||||
|
||||
[Here is the documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Json-Schema). It is generated from [JSON schema](https://github.com/fastfetch-cli/fastfetch/blob/dev/doc/json_schema.json) but you won't like it.
|
||||
[Here is the documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Json-Schema). It is generated from the [JSON schema](https://github.com/fastfetch-cli/fastfetch/blob/dev/doc/json_schema.json), but you might not find it very user-friendly.
|
||||
|
||||
### Q: How can I customize the module output?
|
||||
|
||||
Fastfetch uses `format` to generate output. For example, to make the `GPU` module show only the GPU name (leaving other information undisplayed), you can use
|
||||
Fastfetch uses `format` to generate output. For example, to make the `GPU` module show only the GPU name (leaving other information undisplayed), you can use:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"modules": [
|
||||
{
|
||||
"type": "gpu",
|
||||
"format": "{name}" // See `fastfetch -h gpu-format` for detail
|
||||
"format": "{name}" // See `fastfetch -h gpu-format` for details
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
. . which is equivalent to `fastfetch -s gpu --gpu-format '{name}'`
|
||||
...which is equivalent to `fastfetch -s gpu --gpu-format '{name}'`
|
||||
|
||||
See `fastfetch -h format` for information on basic usage. For module specific formattion, see `fastfetch -h <module>-format`
|
||||
See `fastfetch -h format` for information on basic usage. For module-specific formatting, see `fastfetch -h <module>-format`
|
||||
|
||||
### Q: I have my own ascii-art / image file. How can I show it with fastfetch?
|
||||
### Q: I have my own ASCII art / image file. How can I show it with fastfetch?
|
||||
|
||||
Try `fastfetch -l /path/to/logo`. See [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for detail.
|
||||
Try `fastfetch -l /path/to/logo`. See the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for details.
|
||||
|
||||
If you just want to display distro name in [FIGlet text](https://github.com/pwaller/pyfiglet):
|
||||
If you just want to display the distro name in [FIGlet text](https://github.com/pwaller/pyfiglet):
|
||||
|
||||
```bash
|
||||
# install pyfiglet and jq first
|
||||
@@ -168,32 +174,32 @@ pyfiglet -s -f small_slant $(fastfetch -s os --format json | jq -r '.[0].result.
|
||||
|
||||

|
||||
|
||||
### Q: My image logo behaves weird. How can I fix it?
|
||||
### Q: My image logo behaves strangely. How can I fix it?
|
||||
|
||||
See troubleshooting section: <https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options#troubleshooting>
|
||||
See the troubleshooting section: <https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options#troubleshooting>
|
||||
|
||||
### Q: Fastfetch runs in white and black on shell startup. Why?
|
||||
### Q: Fastfetch runs in black and white on shell startup. Why?
|
||||
|
||||
This issue usually happens when using fastfetch with `p10k`. There are known incompatibility between fastfetch and p10k instant prompt.
|
||||
The p10k doc clearly states that you should NOT print anything to stdout after `p10k-instant-prompt` is initialized. You should either put `fastfetch` before initialization of `p10k-instant-prompt` (recommended)
|
||||
This issue usually occurs when using fastfetch with `p10k`. There are known incompatibilities between fastfetch and p10k instant prompt.
|
||||
The p10k documentation clearly states that you should NOT print anything to stdout after `p10k-instant-prompt` is initialized. You should put `fastfetch` before the initialization of `p10k-instant-prompt` (recommended).
|
||||
|
||||
You can always use `fastfetch --pipe false` to force fastfetch running in colorful mode.
|
||||
You can always use `fastfetch --pipe false` to force fastfetch to run in colorful mode.
|
||||
|
||||
### Q: Why do fastfetch and neofetch show different memory usage result?
|
||||
### Q: Why do fastfetch and neofetch show different memory usage results?
|
||||
|
||||
See [#1096](https://github.com/fastfetch-cli/fastfetch/issues/1096).
|
||||
|
||||
### Q: Fastfetch shows less dpkg packages than neofetch, is it a bug?
|
||||
### Q: Fastfetch shows fewer dpkg packages than neofetch. Is it a bug?
|
||||
|
||||
Neofetch incorrectly counts `rc` packages ( the package has been removed, but that the configuration files remain ). Bug https://github.com/dylanaraps/neofetch/issues/2278
|
||||
Neofetch incorrectly counts `rc` packages (packages that have been removed but still have configuration files remaining). See bug: https://github.com/dylanaraps/neofetch/issues/2278
|
||||
|
||||
### Q: I use Debian / Ubuntu / Debian derived distro. My GPU is detected as `XXXX Device XXXX (VGA compatible)`. Is it a bug?
|
||||
### Q: I use Debian / Ubuntu / Debian-derived distro. My GPU is detected as `XXXX Device XXXX (VGA compatible)`. Is this a bug?
|
||||
|
||||
Try upgrading `pci.ids`: Download <https://pci-ids.ucw.cz/v2.2/pci.ids> and overwrite file `/usr/share/hwdata/pci.ids`. For AMD GPUs, you should also upgrade `amdgpu.ids`: Download <https://gitlab.freedesktop.org/mesa/drm/-/raw/main/data/amdgpu.ids> and overwrite file `/usr/share/libdrm/amdgpu.ids`
|
||||
Try upgrading `pci.ids`: Download <https://pci-ids.ucw.cz/v2.2/pci.ids> and overwrite the file `/usr/share/hwdata/pci.ids`. For AMD GPUs, you should also upgrade `amdgpu.ids`: Download <https://gitlab.freedesktop.org/mesa/drm/-/raw/main/data/amdgpu.ids> and overwrite the file `/usr/share/libdrm/amdgpu.ids`
|
||||
|
||||
Alternatively, you may try to use `fastfetch --gpu-driver-specific`, so that `fastfetch` will try to ask the driver for GPU name if supported.
|
||||
Alternatively, you may try using `fastfetch --gpu-driver-specific`, which will make fastfetch attempt to ask the driver for the GPU name if supported.
|
||||
|
||||
### Q: I get error `Authorization required, but no authorization protocol specified` when running fastfetch in root
|
||||
### Q: I get the error `Authorization required, but no authorization protocol specified` when running fastfetch as root
|
||||
|
||||
Try `export XAUTHORITY=$HOME/.Xauthority`
|
||||
|
||||
@@ -203,7 +209,7 @@ Try `fastfetch --wm-detect-plugin`. See also [#984](https://github.com/fastfetch
|
||||
|
||||
### Q: How can I change the colors of my ASCII logo?
|
||||
|
||||
Try `fastfetch --logo-color-[1-9] <color>`. `[1-9]` is the index of color placeholders.
|
||||
Try `fastfetch --logo-color-[1-9] <color>`, where `[1-9]` is the index of color placeholders.
|
||||
|
||||
For example: `fastfetch --logo-color-1 red --logo-color-2 green`.
|
||||
|
||||
@@ -220,7 +226,7 @@ In JSONC, you can use:
|
||||
}
|
||||
```
|
||||
|
||||
### Q: How to hide a key?
|
||||
### Q: How do I hide a key?
|
||||
|
||||
Set the key to a white space.
|
||||
|
||||
@@ -230,9 +236,59 @@ Set the key to a white space.
|
||||
}
|
||||
```
|
||||
|
||||
### Q: How can I display images on Windows?
|
||||
|
||||
As of April 2025:
|
||||
|
||||
#### mintty and Wezterm
|
||||
|
||||
mintty (used by Bash on Windows and MSYS2) and Wezterm (nightly build only) support the iTerm image protocol on Windows.
|
||||
|
||||
In `config.jsonc`:
|
||||
```json
|
||||
{
|
||||
"logo": {
|
||||
"type": "iterm",
|
||||
"source": "C:/path/to/image.png",
|
||||
"width": <num-in-chars>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Windows Terminal
|
||||
|
||||
Windows Terminal supports the sixel image protocol only.
|
||||
|
||||
* If you installed fastfetch through MSYS2:
|
||||
1. Install imagemagick: `pacman -S mingw-w64-<subsystem>-x86_64-imagemagick`
|
||||
2. In `config.jsonc`:
|
||||
```jsonc
|
||||
{
|
||||
"logo": {
|
||||
"type": "sixel", // DO NOT USE "auto"
|
||||
"source": "C:/path/to/image.png", // Do NOT use `~` as fastfetch is a native Windows program and doesn't apply cygwin path conversion
|
||||
"width": <image-width-in-chars>, // Optional
|
||||
"height": <image-height-in-chars> // Optional
|
||||
}
|
||||
}
|
||||
```
|
||||
* If you installed fastfetch via scoop or downloaded the binary directly from the GitHub Releases page:
|
||||
1. Convert your image manually to sixel format using [any online image conversion service](https://www.google.com/search?q=convert+image+to+sixel)
|
||||
2. In `config.jsonc`:
|
||||
```jsonc
|
||||
{
|
||||
"logo": {
|
||||
"type": "raw", // DO NOT USE "auto"
|
||||
"source": "C:/path/to/image.sixel",
|
||||
"width": <image-width-in-chars>, // Required
|
||||
"height": <image-height-in-chars> // Required
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Q: I want feature A / B / C. Will fastfetch support it?
|
||||
|
||||
Fastfetch is a system information tool. We only accept hardware or system level software feature requests. For most personal uses, I recommend using `Command` module to detect it yourself, which can be used to grab output from a custom shell script:
|
||||
Fastfetch is a system information tool. We only accept hardware or system-level software feature requests. For most personal uses, I recommend using the `Command` module to implement custom functionality, which can be used to grab output from a custom shell script:
|
||||
|
||||
```jsonc
|
||||
// This module shows the default editor
|
||||
@@ -247,23 +303,23 @@ Fastfetch is a system information tool. We only accept hardware or system level
|
||||
}
|
||||
```
|
||||
|
||||
Otherwise, open a feature request in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues).
|
||||
Otherwise, please open a feature request in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues).
|
||||
|
||||
### Q: I have questions. Where can I get help?
|
||||
|
||||
* For usage questions, please start a discussion in [GitHub Discussions](https://github.com/fastfetch-cli/fastfetch/discussions).
|
||||
* For possible bugs, please open an issue in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues). Be sure to fill the bug-report template carefully for developers to investigate.
|
||||
* For possible bugs, please open an issue in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues). Be sure to fill out the bug report template carefully to help developers investigate.
|
||||
|
||||
## Donate
|
||||
|
||||
If you find Fastfetch to be useful, please consider donating.
|
||||
If you find Fastfetch useful, please consider donating.
|
||||
|
||||
* Current maintainer: [@CarterLi](https://paypal.me/zhangsongcui)
|
||||
* Original author: [@LinusDierheimer](https://github.com/sponsors/LinusDierheimer)
|
||||
|
||||
## Star History
|
||||
|
||||
Give it a star to support us!
|
||||
Give us a star to show your support!
|
||||
|
||||
<a href="https://star-history.com/#fastfetch-cli/fastfetch&Date">
|
||||
<picture>
|
||||
|
||||
@@ -62,11 +62,17 @@ end
|
||||
echo '
|
||||
import json, subprocess, sys
|
||||
|
||||
|
||||
def main():
|
||||
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
|
||||
|
||||
for key in data:
|
||||
for flag in data[key]:
|
||||
if flag["long"] == "logo-color-[1-9]":
|
||||
for i in range(1, 10):
|
||||
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
|
||||
continue
|
||||
|
||||
if flag.get("pseudo", False):
|
||||
continue
|
||||
|
||||
@@ -75,7 +81,7 @@ def main():
|
||||
command_prefix += f""" -o {flag["short"]}"""
|
||||
|
||||
if "arg" in flag:
|
||||
type: str = flag["arg"]["type"];
|
||||
type: str = flag["arg"]["type"]
|
||||
if type == "bool":
|
||||
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
|
||||
elif type == "color":
|
||||
@@ -98,6 +104,7 @@ def main():
|
||||
else:
|
||||
print(f"{command_prefix} -f")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
|
||||
Vendored
+60
@@ -1,3 +1,63 @@
|
||||
fastfetch (2.47.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.47.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Jul 2025 14:51:45 +0800
|
||||
|
||||
fastfetch (2.46.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.46.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 20 Jun 2025 15:01:21 +0800
|
||||
|
||||
fastfetch (2.45.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.45.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
|
||||
|
||||
fastfetch (2.44.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.44.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
|
||||
|
||||
fastfetch (2.43.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.43.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 14 May 2025 09:49:50 +0800
|
||||
|
||||
fastfetch (2.42.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.42.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 30 Apr 2025 14:08:57 +0800
|
||||
|
||||
fastfetch (2.41.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.41.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 16 Apr 2025 13:42:58 +0800
|
||||
|
||||
fastfetch (2.40.4) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.4
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 10 Apr 2025 15:38:21 +0800
|
||||
|
||||
fastfetch (2.40.3) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.3
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 07 Apr 2025 09:29:27 +0800
|
||||
|
||||
fastfetch (2.40.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Apr 2025 08:46:54 +0800
|
||||
|
||||
fastfetch (2.39.1) jammy; urgency=medium
|
||||
|
||||
* Update to 2.39.1
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.39.1_source.buildinfo universe/utils optional
|
||||
fastfetch_2.47.0_source.buildinfo universe/utils optional
|
||||
|
||||
+140
-59
@@ -1,8 +1,7 @@
|
||||
.TH FASTFETCH 1 "@FASTFETCH_BUILD_DATE@" "@CMAKE_PROJECT_NAME@ @CMAKE_PROJECT_VERSION@"
|
||||
|
||||
.SH NAME
|
||||
fastfetch \- a neofetch\-like tool for fetching system information and
|
||||
displaying them in a pretty way
|
||||
fastfetch \- a fast and customizable system information tool similar to neofetch
|
||||
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -11,15 +10,12 @@ displaying them in a pretty way
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Fastfetch is a neofetch\-like tool for fetching system information and
|
||||
displaying them in a pretty way. It is written mainly in C, with performance
|
||||
and customizability in mind.
|
||||
Currently, Linux, Android, FreeBSD, MacOS and Windows 7+ are supported.
|
||||
Fastfetch is a tool for displaying system information in a visually appealing way. Written primarily in C, it focuses on performance and customizability while providing functionality similar to neofetch.
|
||||
It supports Linux, Android, *BSD, macOS, Haiku, and Windows 7 or newer.
|
||||
|
||||
.SH "EXIT STATUS"
|
||||
|
||||
On successful execution, fastfetch returns zero. If any error happened,
|
||||
the exit code will be non\-zero.
|
||||
Fastfetch returns zero on successful execution. Any errors result in a non-zero exit code.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
@@ -27,115 +23,200 @@ the exit code will be non\-zero.
|
||||
.TP
|
||||
|
||||
.B \-h, \-\-help \fI[command]
|
||||
Show help output, displaying all available options or help for given command
|
||||
Display help information for all available options or for a specific command
|
||||
.TP
|
||||
|
||||
.B \-v, \-\-version
|
||||
Show version of fastfetch
|
||||
Display the version of fastfetch
|
||||
.TP
|
||||
|
||||
.B \-\-version\-raw
|
||||
Display the raw version string (major.minor.patch)
|
||||
.TP
|
||||
|
||||
.B \-\-list\-config\-paths
|
||||
List search paths of config files
|
||||
List search paths for configuration files
|
||||
.TP
|
||||
|
||||
.B \-\-list\-data\-paths
|
||||
List search paths of presets and logos
|
||||
List search paths for presets and logos
|
||||
.TP
|
||||
|
||||
.B \-\-list\-logos
|
||||
List available logos, they can be loaded with \fI\-\-logo
|
||||
List available logos that can be loaded with \fI\-\-logo
|
||||
.TP
|
||||
|
||||
.B \-\-list\-modules
|
||||
List available modules
|
||||
List all available modules
|
||||
.TP
|
||||
|
||||
.B \-\-list\-presets
|
||||
List available presets, they can be loaded with \fI\-\-config
|
||||
List available presets that can be loaded with \fI\-\-config
|
||||
.TP
|
||||
|
||||
.B \-\-list\-features
|
||||
List the supported features fastfetch was compiled with
|
||||
List the features that fastfetch was compiled with (mainly for development)
|
||||
.TP
|
||||
|
||||
.B \-\-print\-logos
|
||||
Print available logos
|
||||
Display all available logos
|
||||
.TP
|
||||
|
||||
.B \-\-print\-structure
|
||||
Print the default structure
|
||||
Display the default structure
|
||||
.TP
|
||||
|
||||
.B \-\-format \fI<type>
|
||||
Set the output format. Besides the
|
||||
.I default
|
||||
format, only
|
||||
.I json
|
||||
is supported currently.
|
||||
|
||||
|
||||
.SS "Display Options"
|
||||
.TP
|
||||
|
||||
.B \-l, \-\-logo \fI<logo>
|
||||
Set the logo to display
|
||||
.TP
|
||||
|
||||
.B \-s, \-\-structure \fI<structure>
|
||||
Set the structure of the fetch. For details about the structure,
|
||||
see the CONFIGURATION section.
|
||||
|
||||
Set the output format. Available options are:
|
||||
.RS
|
||||
.IP \(bu 2
|
||||
\fIdefault\fR: Default human-readable format
|
||||
.IP \(bu 2
|
||||
\fIjson\fR: JSON format for machine processing
|
||||
.RE
|
||||
|
||||
.SS "Config Options"
|
||||
.TP
|
||||
|
||||
.B \-c, \-\-config \fI<config>
|
||||
Use the specified config file or preset. If
|
||||
.I none
|
||||
is specified, disable further config loading. For details about
|
||||
config files, see the CONFIGURATION section
|
||||
Use the specified config file or preset. Specify \fInone\fR to disable further config loading. See the CONFIGURATION section for details on config files.
|
||||
.TP
|
||||
|
||||
.B \-\-gen\-config \fI[file]
|
||||
Generate a config file with options specified on the command line.
|
||||
If \fIfile\fR is specified, the configuration will be written to the
|
||||
file, otherwise it will be written to stdout.
|
||||
.B \-\-gen\-config \fI[path]
|
||||
Generate a config file with options specified on the command line. If \fIpath\fR is not specified, it defaults to \fB~/.config/fastfetch/config.jsonc\fR. If \fIpath\fR is "\-", the configuration will be written to stdout.
|
||||
.TP
|
||||
|
||||
.B \-\-gen\-config\-force \fI[file]
|
||||
Same as \fB\-\-gen\-config\fR, but overwrites existing config
|
||||
.B \-\-gen\-config\-force \fI[path]
|
||||
Same as \fB\-\-gen\-config\fR, but overwrites any existing file at the destination path.
|
||||
.TP
|
||||
|
||||
.SS "Logo Options"
|
||||
.TP
|
||||
|
||||
To list all options, use \fB\-\-help\fR. It will also print all available module options.
|
||||
.B \-l, \-\-logo \fI<logo>
|
||||
Set the logo to display. Can be the name of a built-in logo or a path to an image file. Use \fInone\fR to disable the logo.
|
||||
.TP
|
||||
|
||||
.B \-\-logo\-type \fI<type>
|
||||
Set the type of the logo specified with \fI\-\-logo\fR. Available types include \fIauto\fR, \fIbuiltin\fR, \fIfile\fR, \fIsixel\fR, \fIkitty\fR, and others. See \fB\-\-help logo\-type\fR for details.
|
||||
.TP
|
||||
|
||||
.B \-\-logo\-width \fI<width>
|
||||
Set the width of the logo in characters (for image logos)
|
||||
.TP
|
||||
|
||||
.B \-\-logo\-height \fI<height>
|
||||
Set the height of the logo in characters (for image logos)
|
||||
.TP
|
||||
|
||||
.B \-\-logo\-color\-[1\-9] \fI<color>
|
||||
Override specific colors in the logo
|
||||
|
||||
.SS "Display Options"
|
||||
.TP
|
||||
|
||||
.B \-s, \-\-structure \fI<structure>
|
||||
Set the structure of the fetch (a colon-separated list of module names)
|
||||
.TP
|
||||
|
||||
.B \-\-color \fI<color>
|
||||
Set the color of keys and title. See \fB\-\-help color\fR for available colors.
|
||||
.TP
|
||||
|
||||
.B \-\-color\-keys \fI<color>
|
||||
Set the color of keys only
|
||||
.TP
|
||||
|
||||
.B \-\-color\-title \fI<color>
|
||||
Set the color of the title only
|
||||
.TP
|
||||
|
||||
.B \-\-separator \fI<string>
|
||||
Set the separator between key and value (default: ": ")
|
||||
.TP
|
||||
|
||||
.B \-\-key\-width \fI<num>
|
||||
Align the width of keys to \fI<num>\fR characters
|
||||
.TP
|
||||
|
||||
.B \-\-show\-errors
|
||||
Display errors when they occur (default: false)
|
||||
.TP
|
||||
|
||||
.B \-\-pipe
|
||||
Disable colors (automatically detected based on whether stdout is a terminal)
|
||||
|
||||
To list all available options including module-specific options, use \fB\-\-help\fR.
|
||||
|
||||
.SH CONFIGURATION
|
||||
.SS "Fetch Structure"
|
||||
The structure of a fetch describes the modules that should be included in
|
||||
the output. It consists of a string of modules, separated by a colon (:).
|
||||
The structure defines which modules to display and in what order. It consists of module names separated by colons (:).
|
||||
For example: \fBtitle:separator:os:kernel:uptime\fR
|
||||
|
||||
To list all available modules, use \fB\-\-list\-modules\fR
|
||||
|
||||
.SS "Config Files"
|
||||
|
||||
Fastfetch uses JSONC based format for configuration. Fastfetch doesn't generate
|
||||
config file automatically; it should be generated manually by \fB\-\-gen\-config\fR.
|
||||
The config file will be saved in \fB~/.config/fastfetch/config.jsonc\fR by default.
|
||||
Fastfetch uses JSONC for configuration files. JSONC is JSON with support for comments (// and /* */). Configuration files must have the .jsonc extension.
|
||||
|
||||
A JSONC config file is a JSON file that also supports comments with (// and /* */).
|
||||
Those files must have the extension '.jsonc'.
|
||||
You can generate a default config file using \fB\-\-gen\-config\fR. By default, the config file is saved at \fB~/.config/fastfetch/config.jsonc\fR.
|
||||
|
||||
The specified configuration/preset files are searched in the following order:
|
||||
The configuration/preset files are searched in the following locations (in order):
|
||||
|
||||
1. relative to the current working directory
|
||||
.RS
|
||||
.IP 1. 4
|
||||
Relative to the current working directory
|
||||
.IP 2. 4
|
||||
Relative to ~/.local/share/fastfetch/presets/
|
||||
.IP 3. 4
|
||||
Relative to /usr/share/fastfetch/presets/
|
||||
.RE
|
||||
|
||||
2. relative to ~/.local/share/fastfetch/presets/
|
||||
For detailed information on logo options, module configuration, and formatting, visit:
|
||||
.RS
|
||||
\fIhttps://github.com/fastfetch-cli/fastfetch/wiki/Configuration\fR
|
||||
.RE
|
||||
|
||||
3. relative to /usr/share/fastfetch/presets/
|
||||
Fastfetch provides several built-in presets. List them with \fB\-\-list\-presets\fR.
|
||||
|
||||
Fastfetch provides some default presets. List them with \fB\-\-list\-presets\fR.
|
||||
.SS "JSON Schema"
|
||||
A JSON schema is available for editor intelligence when editing the configuration file. Add the following line at the beginning of your config file:
|
||||
.PP
|
||||
\fB"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"\fR
|
||||
|
||||
.SH EXAMPLES
|
||||
.TP
|
||||
Basic usage:
|
||||
.RS
|
||||
\fBfastfetch\fR
|
||||
.RE
|
||||
.TP
|
||||
Use a specific logo:
|
||||
.RS
|
||||
\fBfastfetch \-\-logo arch\fR
|
||||
.RE
|
||||
.TP
|
||||
Custom structure:
|
||||
.RS
|
||||
\fBfastfetch \-\-structure title:os:kernel:uptime:memory\fR
|
||||
.RE
|
||||
.TP
|
||||
Generate a config file:
|
||||
.RS
|
||||
\fBfastfetch \-\-gen\-config\fR
|
||||
.RE
|
||||
.TP
|
||||
Use a preset:
|
||||
.RS
|
||||
\fBfastfetch \-\-config neofetch\fR
|
||||
.RE
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR neofetch (1)
|
||||
|
||||
.SH BUGS
|
||||
Please report bugs to: \fIhttps://github.com/fastfetch\-cli/fastfetch/issues\fR
|
||||
|
||||
.SH AUTHORS
|
||||
Fastfetch is developed by a team of contributors on GitHub.
|
||||
Visit \fIhttps://github.com/fastfetch-cli/fastfetch\fR for more information.
|
||||
|
||||
+154
-119
@@ -35,14 +35,14 @@
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "number",
|
||||
"description": "1 for percentage number, 2 for multi-color bar, 3 for both, 6 for bar only, 9 for colored number, 10 for monochrome bar",
|
||||
"description": "0 to use global setting, 1 for percentage number, 2 for multi-color bar, 3 for both, 6 for bar only, 9 for colored number, 10 for monochrome bar",
|
||||
"minimum": 0,
|
||||
"maximum": 255,
|
||||
"default": 9
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "array of string flags",
|
||||
"description": "Array of string flags",
|
||||
"items": {
|
||||
"enum": [
|
||||
"num",
|
||||
@@ -60,7 +60,7 @@
|
||||
]
|
||||
},
|
||||
"percent": {
|
||||
"description": "Threshold of percentage colors",
|
||||
"description": "Thresholds for percentage colors",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -68,13 +68,13 @@
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Value less then green will be shown in green"
|
||||
"description": "Values less than green will be shown in green"
|
||||
},
|
||||
"yellow": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Value greater than green and less then yellow will be shown in yellow.\nValue greater than yellow will be shown in red"
|
||||
"description": "Values greater than green and less than yellow will be shown in yellow.\nValues greater than yellow will be shown in red"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "#/$defs/percentType"
|
||||
@@ -96,13 +96,13 @@
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Value (in celsius) less then green will be shown in green"
|
||||
"description": "Values (in celsius) less than green will be shown in green"
|
||||
},
|
||||
"yellow": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Value (in celsius) greater than green and less then yellow will be shown in yellow.\nValue greater than yellow will be shown in red"
|
||||
"description": "Values (in celsius) greater than green and less than yellow will be shown in yellow.\nValues greater than yellow will be shown in red"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,290 +111,286 @@
|
||||
|
||||
|
||||
"batteryFormat": {
|
||||
"description": "Output format of the module `Battery`. See `-h format` for formatting syntax\n 1. {manufacturer}: Battery manufacturer\n 2. {model-name}: Battery model name\n 3. {technology}: Battery technology\n 4. {capacity}: Battery capacity (percentage num)\n 5. {status}: Battery status\n 6. {temperature}: Battery temperature (formatted)\n 7. {cycle-count}: Battery cycle count\n 8. {serial}: Battery serial number\n 9. {manufacture-date}: Battery manufactor date\n 10. {capacity-bar}: Battery capacity (percentage bar)\n 11. {time-days}: Battery time remaining days\n 12. {time-hours}: Battery time remaining hours\n 13. {time-minutes}: Battery time remaining minutes\n 14. {time-seconds}: Battery time remaining seconds",
|
||||
"description": "Output format of the module `Battery`. See Wiki for formatting syntax\n 1. {manufacturer}: Battery manufacturer\n 2. {model-name}: Battery model name\n 3. {technology}: Battery technology\n 4. {capacity}: Battery capacity (percentage num)\n 5. {status}: Battery status\n 6. {temperature}: Battery temperature (formatted)\n 7. {cycle-count}: Battery cycle count\n 8. {serial}: Battery serial number\n 9. {manufacture-date}: Battery manufactor date\n 10. {capacity-bar}: Battery capacity (percentage bar)\n 11. {time-days}: Battery time remaining days\n 12. {time-hours}: Battery time remaining hours\n 13. {time-minutes}: Battery time remaining minutes\n 14. {time-seconds}: Battery time remaining seconds",
|
||||
"type": "string"
|
||||
},
|
||||
"biosFormat": {
|
||||
"description": "Output format of the module `Bios`. See `-h format` for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
|
||||
"description": "Output format of the module `BIOS`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
|
||||
"type": "string"
|
||||
},
|
||||
"bluetoothFormat": {
|
||||
"description": "Output format of the module `Bluetooth`. See `-h format` for formatting syntax\n 1. {name}: Name\n 2. {address}: Address\n 3. {type}: Type\n 4. {battery-percentage}: Battery percentage number\n 5. {connected}: Is connected\n 6. {battery-percentage-bar}: Battery percentage bar",
|
||||
"description": "Output format of the module `Bluetooth`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {address}: Address\n 3. {type}: Type\n 4. {battery-percentage}: Battery percentage number\n 5. {connected}: Is connected\n 6. {battery-percentage-bar}: Battery percentage bar",
|
||||
"type": "string"
|
||||
},
|
||||
"bluetoothradioFormat": {
|
||||
"description": "Output format of the module `BluetoothRadio`. See `-h format` for formatting syntax\n 1. {name}: Radio name for discovering\n 2. {address}: Address\n 3. {lmp-version}: LMP version\n 4. {lmp-subversion}: LMP subversion\n 5. {version}: Bluetooth version\n 6. {vendor}: Vendor\n 7. {discoverable}: Discoverable\n 8. {connectable}: Connectable / Pairable",
|
||||
"description": "Output format of the module `BluetoothRadio`. See Wiki for formatting syntax\n 1. {name}: Radio name for discovering\n 2. {address}: Address\n 3. {lmp-version}: LMP version\n 4. {lmp-subversion}: LMP subversion\n 5. {version}: Bluetooth version\n 6. {vendor}: Vendor\n 7. {discoverable}: Discoverable\n 8. {connectable}: Connectable / Pairable",
|
||||
"type": "string"
|
||||
},
|
||||
"boardFormat": {
|
||||
"description": "Output format of the module `Board`. See `-h format` for formatting syntax\n 1. {name}: Board name\n 2. {vendor}: Board vendor\n 3. {version}: Board version\n 4. {serial}: Board serial number",
|
||||
"description": "Output format of the module `Board`. See Wiki for formatting syntax\n 1. {name}: Board name\n 2. {vendor}: Board vendor\n 3. {version}: Board version\n 4. {serial}: Board serial number",
|
||||
"type": "string"
|
||||
},
|
||||
"bootmgrFormat": {
|
||||
"description": "Output format of the module `Bootmgr`. See `-h format` for formatting syntax\n 1. {name}: Name / description\n 2. {firmware-path}: Firmware file path\n 3. {firmware-name}: Firmware file name\n 4. {secure-boot}: Is secure boot enabled",
|
||||
"description": "Output format of the module `Bootmgr`. See Wiki for formatting syntax\n 1. {name}: Name / description\n 2. {firmware-path}: Firmware file path\n 3. {firmware-name}: Firmware file name\n 4. {secure-boot}: Is secure boot enabled\n 5. {order}: Boot order",
|
||||
"type": "string"
|
||||
},
|
||||
"brightnessFormat": {
|
||||
"description": "Output format of the module `Brightness`. See `-h format` for formatting syntax\n 1. {percentage}: Screen brightness (percentage num)\n 2. {name}: Screen name\n 3. {max}: Maximum brightness value\n 4. {min}: Minimum brightness value\n 5. {current}: Current brightness value\n 6. {percentage-bar}: Screen brightness (percentage bar)",
|
||||
"description": "Output format of the module `Brightness`. See Wiki for formatting syntax\n 1. {percentage}: Screen brightness (percentage num)\n 2. {name}: Screen name\n 3. {max}: Maximum brightness value\n 4. {min}: Minimum brightness value\n 5. {current}: Current brightness value\n 6. {percentage-bar}: Screen brightness (percentage bar)\n 7. {is-builtin}: Is built-in screen",
|
||||
"type": "string"
|
||||
},
|
||||
"btrfsFormat": {
|
||||
"description": "Output format of the module `Btrfs`. See `-h format` for formatting syntax\n 1. {name}: Name / Label\n 2. {uuid}: UUID\n 3. {devices}: Associated devices\n 4. {features}: Enabled features\n 5. {used}: Size used\n 6. {allocated}: Size allocated\n 7. {total}: Size total\n 8. {used-percentage}: Used percentage num\n 9. {allocated-percentage}: Allocated percentage num\n 10. {used-percentage-bar}: Used percentage bar\n 11. {allocated-percentage-bar}: Allocated percentage bar\n 12. {node-size}: Node size\n 13. {sector-size}: Sector size",
|
||||
"description": "Output format of the module `Btrfs`. See Wiki for formatting syntax\n 1. {name}: Name / Label\n 2. {uuid}: UUID\n 3. {devices}: Associated devices\n 4. {features}: Enabled features\n 5. {used}: Size used\n 6. {allocated}: Size allocated\n 7. {total}: Size total\n 8. {used-percentage}: Used percentage num\n 9. {allocated-percentage}: Allocated percentage num\n 10. {used-percentage-bar}: Used percentage bar\n 11. {allocated-percentage-bar}: Allocated percentage bar\n 12. {node-size}: Node size\n 13. {sector-size}: Sector size",
|
||||
"type": "string"
|
||||
},
|
||||
"cameraFormat": {
|
||||
"description": "Output format of the module `Camera`. See `-h format` for formatting syntax\n 1. {name}: Device name\n 2. {vendor}: Vendor\n 3. {colorspace}: Color space\n 4. {id}: Identifier\n 5. {width}: Width (in px)\n 6. {height}: Height (in px)",
|
||||
"description": "Output format of the module `Camera`. See Wiki for formatting syntax\n 1. {name}: Device name\n 2. {vendor}: Vendor\n 3. {colorspace}: Color space\n 4. {id}: Identifier\n 5. {width}: Width (in px)\n 6. {height}: Height (in px)",
|
||||
"type": "string"
|
||||
},
|
||||
"chassisFormat": {
|
||||
"description": "Output format of the module `Chassis`. See `-h format` for formatting syntax\n 1. {type}: Chassis type\n 2. {vendor}: Chassis vendor\n 3. {version}: Chassis version\n 4. {serial}: Chassis serial number",
|
||||
"description": "Output format of the module `Chassis`. See Wiki for formatting syntax\n 1. {type}: Chassis type\n 2. {vendor}: Chassis vendor\n 3. {version}: Chassis version\n 4. {serial}: Chassis serial number",
|
||||
"type": "string"
|
||||
},
|
||||
"commandFormat": {
|
||||
"description": "Output format of the module `Command`. See `-h format` for formatting syntax\n 1. {result}: Command result",
|
||||
"description": "Output format of the module `Command`. See Wiki for formatting syntax\n 1. {result}: Command result",
|
||||
"type": "string"
|
||||
},
|
||||
"cpuFormat": {
|
||||
"description": "Output format of the module `CPU`. See `-h format` for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count",
|
||||
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count",
|
||||
"type": "string"
|
||||
},
|
||||
"cpucacheFormat": {
|
||||
"description": "Output format of the module `CPUCache`. See `-h format` for formatting syntax\n 1. {result}: Separate result\n 2. {sum}: Sum result",
|
||||
"description": "Output format of the module `CPUCache`. See Wiki for formatting syntax\n 1. {result}: Separate result\n 2. {sum}: Sum result",
|
||||
"type": "string"
|
||||
},
|
||||
"cpuusageFormat": {
|
||||
"description": "Output format of the module `CPUUsage`. See `-h format` for formatting syntax\n 1. {avg}: CPU usage (percentage num, average)\n 2. {max}: CPU usage (percentage num, maximum)\n 3. {max-index}: CPU core index of maximum usage\n 4. {min}: CPU usage (percentage num, minimum)\n 5. {min-index}: CPU core index of minimum usage\n 6. {avg-bar}: CPU usage (percentage bar, average)\n 7. {max-bar}: CPU usage (percentage bar, maximum)\n 8. {min-bar}: CPU usage (percentage bar, minimum)",
|
||||
"description": "Output format of the module `CPUUsage`. See Wiki for formatting syntax\n 1. {avg}: CPU usage (percentage num, average)\n 2. {max}: CPU usage (percentage num, maximum)\n 3. {max-index}: CPU core index of maximum usage\n 4. {min}: CPU usage (percentage num, minimum)\n 5. {min-index}: CPU core index of minimum usage\n 6. {avg-bar}: CPU usage (percentage bar, average)\n 7. {max-bar}: CPU usage (percentage bar, maximum)\n 8. {min-bar}: CPU usage (percentage bar, minimum)",
|
||||
"type": "string"
|
||||
},
|
||||
"cursorFormat": {
|
||||
"description": "Output format of the module `Cursor`. See `-h format` for formatting syntax\n 1. {theme}: Cursor theme\n 2. {size}: Cursor size",
|
||||
"description": "Output format of the module `Cursor`. See Wiki for formatting syntax\n 1. {theme}: Cursor theme\n 2. {size}: Cursor size",
|
||||
"type": "string"
|
||||
},
|
||||
"datetimeFormat": {
|
||||
"description": "Output format of the module `DateTime`. See `-h format` for formatting syntax\n 1. {year}: Year\n 2. {year-short}: Last two digits of year\n 3. {month}: Month\n 4. {month-pretty}: Month with leading zero\n 5. {month-name}: Month name\n 6. {month-name-short}: Month name short\n 7. {week}: Week number on year\n 8. {weekday}: Weekday\n 9. {weekday-short}: Weekday short\n 10. {day-in-year}: Day in year\n 11. {day-in-month}: Day in month\n 12. {day-in-week}: Day in week\n 13. {hour}: Hour\n 14. {hour-pretty}: Hour with leading zero\n 15. {hour-12}: Hour 12h format\n 16. {hour-12-pretty}: Hour 12h format with leading zero\n 17. {minute}: Minute\n 18. {minute-pretty}: Minute with leading zero\n 19. {second}: Second\n 20. {second-pretty}: Second with leading zero\n 21. {offset-from-utc}: Offset from UTC in the ISO 8601 format\n 22. {timezone-name}: Locale-dependent timezone name or abbreviation\n 23. {day-pretty}: Day in month with leading zero",
|
||||
"description": "Output format of the module `DateTime`. See Wiki for formatting syntax\n 1. {year}: Year\n 2. {year-short}: Last two digits of year\n 3. {month}: Month\n 4. {month-pretty}: Month with leading zero\n 5. {month-name}: Month name\n 6. {month-name-short}: Month name short\n 7. {week}: Week number on year\n 8. {weekday}: Weekday\n 9. {weekday-short}: Weekday short\n 10. {day-in-year}: Day in year\n 11. {day-in-month}: Day in month\n 12. {day-in-week}: Day in week\n 13. {hour}: Hour\n 14. {hour-pretty}: Hour with leading zero\n 15. {hour-12}: Hour 12h format\n 16. {hour-12-pretty}: Hour 12h format with leading zero\n 17. {minute}: Minute\n 18. {minute-pretty}: Minute with leading zero\n 19. {second}: Second\n 20. {second-pretty}: Second with leading zero\n 21. {offset-from-utc}: Offset from UTC in the ISO 8601 format\n 22. {timezone-name}: Locale-dependent timezone name or abbreviation\n 23. {day-pretty}: Day in month with leading zero",
|
||||
"type": "string"
|
||||
},
|
||||
"deFormat": {
|
||||
"description": "Output format of the module `DE`. See `-h format` for formatting syntax\n 1. {process-name}: DE process name\n 2. {pretty-name}: DE pretty name\n 3. {version}: DE version",
|
||||
"description": "Output format of the module `DE`. See Wiki for formatting syntax\n 1. {process-name}: DE process name\n 2. {pretty-name}: DE pretty name\n 3. {version}: DE version",
|
||||
"type": "string"
|
||||
},
|
||||
"displayFormat": {
|
||||
"description": "Output format of the module `Display`. See `-h format` for formatting syntax\n 1. {width}: Screen configured width (in pixels)\n 2. {height}: Screen configured height (in pixels)\n 3. {refresh-rate}: Screen configured refresh rate (in Hz)\n 4. {scaled-width}: Screen scaled width (in pixels)\n 5. {scaled-height}: Screen scaled height (in pixels)\n 6. {name}: Screen name\n 7. {type}: Screen type (Built-in or External)\n 8. {rotation}: Screen rotation (in degrees)\n 9. {is-primary}: True if being the primary screen\n 10. {physical-width}: Screen physical width (in millimeters)\n 11. {physical-height}: Screen physical height (in millimeters)\n 12. {inch}: Physical diagonal length in inches\n 13. {ppi}: Pixels per inch (PPI)\n 14. {bit-depth}: Bits per color channel\n 15. {hdr-enabled}: True if high dynamic range (HDR) mode is enabled\n 16. {manufacture-year}: Year of manufacturing\n 17. {manufacture-week}: Nth week of manufacturing in the year\n 18. {serial}: Serial number\n 19. {platform-api}: The platform API used when detecting the display\n 20. {hdr-compatible}: True if the display is HDR compatible\n 21. {scale-factor}: HiDPI scale factor\n 22. {preferred-width}: Screen preferred width (in pixels)\n 23. {preferred-height}: Screen preferred height (in pixels)\n 24. {preferred-refresh-rate}: Screen preferred refresh rate (in Hz)",
|
||||
"description": "Output format of the module `Display`. See Wiki for formatting syntax\n 1. {width}: Screen configured width (in pixels)\n 2. {height}: Screen configured height (in pixels)\n 3. {refresh-rate}: Screen configured refresh rate (in Hz)\n 4. {scaled-width}: Screen scaled width (in pixels)\n 5. {scaled-height}: Screen scaled height (in pixels)\n 6. {name}: Screen name\n 7. {type}: Screen type (Built-in or External)\n 8. {rotation}: Screen rotation (in degrees)\n 9. {is-primary}: True if being the primary screen\n 10. {physical-width}: Screen physical width (in millimeters)\n 11. {physical-height}: Screen physical height (in millimeters)\n 12. {inch}: Physical diagonal length in inches\n 13. {ppi}: Pixels per inch (PPI)\n 14. {bit-depth}: Bits per color channel\n 15. {hdr-enabled}: True if high dynamic range (HDR) mode is enabled\n 16. {manufacture-year}: Year of manufacturing\n 17. {manufacture-week}: Nth week of manufacturing in the year\n 18. {serial}: Serial number\n 19. {platform-api}: The platform API used when detecting the display\n 20. {hdr-compatible}: True if the display is HDR compatible\n 21. {scale-factor}: HiDPI scale factor\n 22. {preferred-width}: Screen preferred width (in pixels)\n 23. {preferred-height}: Screen preferred height (in pixels)\n 24. {preferred-refresh-rate}: Screen preferred refresh rate (in Hz)",
|
||||
"type": "string"
|
||||
},
|
||||
"diskFormat": {
|
||||
"description": "Output format of the module `Disk`. See `-h format` for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)",
|
||||
"description": "Output format of the module `Disk`. See Wiki for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)\n 22. {years}: Years integer after creation\n 23. {days-of-year}: Days of year after creation\n 24. {years-fraction}: Years fraction after creation",
|
||||
"type": "string"
|
||||
},
|
||||
"diskioFormat": {
|
||||
"description": "Output format of the module `DiskIO`. See `-h format` for formatting syntax\n 1. {size-read}: Size of data read [per second] (formatted)\n 2. {size-written}: Size of data written [per second] (formatted)\n 3. {name}: Device name\n 4. {dev-path}: Device raw file path\n 5. {bytes-read}: Size of data read [per second] (in bytes)\n 6. {bytes-written}: Size of data written [per second] (in bytes)\n 7. {read-count}: Number of reads\n 8. {write-count}: Number of writes",
|
||||
"description": "Output format of the module `DiskIO`. See Wiki for formatting syntax\n 1. {size-read}: Size of data read [per second] (formatted)\n 2. {size-written}: Size of data written [per second] (formatted)\n 3. {name}: Device name\n 4. {dev-path}: Device raw file path\n 5. {bytes-read}: Size of data read [per second] (in bytes)\n 6. {bytes-written}: Size of data written [per second] (in bytes)\n 7. {read-count}: Number of reads\n 8. {write-count}: Number of writes",
|
||||
"type": "string"
|
||||
},
|
||||
"dnsFormat": {
|
||||
"description": "Output format of the module `DNS`. See `-h format` for formatting syntax\n 1. {result}: DNS result",
|
||||
"description": "Output format of the module `DNS`. See Wiki for formatting syntax\n 1. {result}: DNS result",
|
||||
"type": "string"
|
||||
},
|
||||
"editorFormat": {
|
||||
"description": "Output format of the module `Editor`. See `-h format` for formatting syntax\n 1. {type}: Type (Visual / Editor)\n 2. {name}: Name\n 3. {exe-name}: Exe name of real path\n 4. {full-path}: Full path of real path\n 5. {version}: Version",
|
||||
"description": "Output format of the module `Editor`. See Wiki for formatting syntax\n 1. {type}: Type (Visual / Editor)\n 2. {name}: Name\n 3. {exe-name}: Exe name of real path\n 4. {full-path}: Full path of real path\n 5. {version}: Version",
|
||||
"type": "string"
|
||||
},
|
||||
"fontFormat": {
|
||||
"description": "Output format of the module `Font`. See `-h format` for formatting syntax\n 1. {font1}: Font 1\n 2. {font2}: Font 2\n 3. {font3}: Font 3\n 4. {font4}: Font 4\n 5. {combined}: Combined fonts for display",
|
||||
"description": "Output format of the module `Font`. See Wiki for formatting syntax\n 1. {font1}: Font 1\n 2. {font2}: Font 2\n 3. {font3}: Font 3\n 4. {font4}: Font 4\n 5. {combined}: Combined fonts for display",
|
||||
"type": "string"
|
||||
},
|
||||
"gamepadFormat": {
|
||||
"description": "Output format of the module `Gamepad`. See `-h format` for formatting syntax\n 1. {name}: Name\n 2. {serial}: Serial number\n 3. {battery-percentage}: Battery percentage num\n 4. {battery-percentage-bar}: Battery percentage bar",
|
||||
"description": "Output format of the module `Gamepad`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {serial}: Serial number\n 3. {battery-percentage}: Battery percentage num\n 4. {battery-percentage-bar}: Battery percentage bar",
|
||||
"type": "string"
|
||||
},
|
||||
"gpuFormat": {
|
||||
"description": "Output format of the module `GPU`. See `-h format` for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num (supports Nvidia & Apple GPU only)\n 19. {core-usage-bar}: Core usage percentage bar (supports Nvidia & Apple GPU only)",
|
||||
"description": "Output format of the module `GPU`. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)",
|
||||
"type": "string"
|
||||
},
|
||||
"hostFormat": {
|
||||
"description": "Output format of the module `Host`. See `-h format` for formatting syntax\n 1. {family}: Product family\n 2. {name}: Product name\n 3. {version}: Product version\n 4. {sku}: Product sku\n 5. {vendor}: Product vendor\n 6. {serial}: Product serial number\n 7. {uuid}: Product uuid",
|
||||
"description": "Output format of the module `Host`. See Wiki for formatting syntax\n 1. {family}: Product family\n 2. {name}: Product name\n 3. {version}: Product version\n 4. {sku}: Product sku\n 5. {vendor}: Product vendor\n 6. {serial}: Product serial number\n 7. {uuid}: Product uuid",
|
||||
"type": "string"
|
||||
},
|
||||
"iconsFormat": {
|
||||
"description": "Output format of the module `Icons`. See `-h format` for formatting syntax\n 1. {icons1}: Icons part 1\n 2. {icons2}: Icons part 2",
|
||||
"description": "Output format of the module `Icons`. See Wiki for formatting syntax\n 1. {icons1}: Icons part 1\n 2. {icons2}: Icons part 2",
|
||||
"type": "string"
|
||||
},
|
||||
"initsystemFormat": {
|
||||
"description": "Output format of the module `InitSystem`. See `-h format` for formatting syntax\n 1. {name}: Init system name\n 2. {exe}: Init system exe path\n 3. {version}: Init system version path\n 4. {pid}: Init system pid",
|
||||
"description": "Output format of the module `InitSystem`. See Wiki for formatting syntax\n 1. {name}: Init system name\n 2. {exe}: Init system exe path\n 3. {version}: Init system version path\n 4. {pid}: Init system pid",
|
||||
"type": "string"
|
||||
},
|
||||
"kernelFormat": {
|
||||
"description": "Output format of the module `Kernel`. See `-h format` for formatting syntax\n 1. {sysname}: Sysname\n 2. {release}: Release\n 3. {version}: Version\n 4. {arch}: Architecture\n 5. {display-version}: Display version\n 6. {page-size}: Page size",
|
||||
"description": "Output format of the module `Kernel`. See Wiki for formatting syntax\n 1. {sysname}: Sysname\n 2. {release}: Release\n 3. {version}: Version\n 4. {arch}: Architecture\n 5. {display-version}: Display version\n 6. {page-size}: Page size",
|
||||
"type": "string"
|
||||
},
|
||||
"keyboardFormat": {
|
||||
"description": "Output format of the module `Keyboard`. See `-h format` for formatting syntax\n 1. {name}: Name\n 2. {serial}: Serial number",
|
||||
"description": "Output format of the module `Keyboard`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {serial}: Serial number",
|
||||
"type": "string"
|
||||
},
|
||||
"lmFormat": {
|
||||
"description": "Output format of the module `LM`. See `-h format` for formatting syntax\n 1. {service}: LM service\n 2. {type}: LM type\n 3. {version}: LM version",
|
||||
"description": "Output format of the module `LM`. See Wiki for formatting syntax\n 1. {service}: LM service\n 2. {type}: LM type\n 3. {version}: LM version",
|
||||
"type": "string"
|
||||
},
|
||||
"loadavgFormat": {
|
||||
"description": "Output format of the module `Loadavg`. See `-h format` for formatting syntax\n 1. {loadavg1}: Load average over 1min\n 2. {loadavg2}: Load average over 5min\n 3. {loadavg3}: Load average over 15min",
|
||||
"description": "Output format of the module `Loadavg`. See Wiki for formatting syntax\n 1. {loadavg1}: Load average over 1min\n 2. {loadavg2}: Load average over 5min\n 3. {loadavg3}: Load average over 15min",
|
||||
"type": "string"
|
||||
},
|
||||
"localeFormat": {
|
||||
"description": "Output format of the module `Locale`. See `-h format` for formatting syntax\n 1. {result}: Locale code",
|
||||
"description": "Output format of the module `Locale`. See Wiki for formatting syntax\n 1. {result}: Locale code",
|
||||
"type": "string"
|
||||
},
|
||||
"localipFormat": {
|
||||
"description": "Output format of the module `LocalIp`. See `-h format` for formatting syntax\n 1. {ipv4}: IPv4 address\n 2. {ipv6}: IPv6 address\n 3. {mac}: MAC address\n 4. {ifname}: Interface name\n 5. {is-default-route}: Is default route\n 6. {mtu}: MTU size in bytes\n 7. {speed}: Link speed (formatted)\n 8. {flags}: Interface flags",
|
||||
"description": "Output format of the module `LocalIp`. See Wiki for formatting syntax\n 1. {ipv4}: IPv4 address\n 2. {ipv6}: IPv6 address\n 3. {mac}: MAC address\n 4. {ifname}: Interface name\n 5. {is-default-route}: Is default route\n 6. {mtu}: MTU size in bytes\n 7. {speed}: Link speed (formatted)\n 8. {flags}: Interface flags",
|
||||
"type": "string"
|
||||
},
|
||||
"mediaFormat": {
|
||||
"description": "Output format of the module `Media`. See `-h format` for formatting syntax\n 1. {combined}: Pretty media name\n 2. {title}: Media name\n 3. {artist}: Artist name\n 4. {album}: Album name\n 5. {status}: Status",
|
||||
"description": "Output format of the module `Media`. See Wiki for formatting syntax\n 1. {combined}: Pretty media name\n 2. {title}: Media name\n 3. {artist}: Artist name\n 4. {album}: Album name\n 5. {status}: Status",
|
||||
"type": "string"
|
||||
},
|
||||
"memoryFormat": {
|
||||
"description": "Output format of the module `Memory`. See `-h format` for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)",
|
||||
"description": "Output format of the module `Memory`. See Wiki for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)",
|
||||
"type": "string"
|
||||
},
|
||||
"monitorFormat": {
|
||||
"description": "Output format of the module `Monitor`. See `-h format` for formatting syntax\n 1. {name}: Display name\n 2. {width}: Native resolution width in pixels\n 3. {height}: Native resolution height in pixels\n 4. {physical-width}: Physical width in millimeters\n 5. {physical-height}: Physical height in millimeters\n 6. {inch}: Physical diagonal length in inches\n 7. {ppi}: Pixels per inch (PPI)\n 8. {manufacture-year}: Year of manufacturing\n 9. {manufacture-week}: Nth week of manufacturing in the year\n 10. {serial}: Serial number\n 11. {refresh-rate}: Maximum refresh rate in Hz\n 12. {hdr-compatible}: True if the display is HDR compatible",
|
||||
"description": "Output format of the module `Monitor`. See Wiki for formatting syntax\n 1. {name}: Display name\n 2. {width}: Native resolution width in pixels\n 3. {height}: Native resolution height in pixels\n 4. {physical-width}: Physical width in millimeters\n 5. {physical-height}: Physical height in millimeters\n 6. {inch}: Physical diagonal length in inches\n 7. {ppi}: Pixels per inch (PPI)\n 8. {manufacture-year}: Year of manufacturing\n 9. {manufacture-week}: Nth week of manufacturing in the year\n 10. {serial}: Serial number\n 11. {refresh-rate}: Maximum refresh rate in Hz\n 12. {hdr-compatible}: True if the display is HDR compatible",
|
||||
"type": "string"
|
||||
},
|
||||
"mouseFormat": {
|
||||
"description": "Output format of the module `Mouse`. See `-h format` for formatting syntax\n 1. {name}: Mouse name\n 2. {serial}: Mouse serial number",
|
||||
"description": "Output format of the module `Mouse`. See Wiki for formatting syntax\n 1. {name}: Mouse name\n 2. {serial}: Mouse serial number",
|
||||
"type": "string"
|
||||
},
|
||||
"netioFormat": {
|
||||
"description": "Output format of the module `NetIO`. See `-h format` for formatting syntax\n 1. {rx-size}: Size of data received [per second] (formatted)\n 2. {tx-size}: Size of data sent [per second] (formatted)\n 3. {ifname}: Interface name\n 4. {is-default-route}: Is default route\n 5. {rx-bytes}: Size of data received [per second] (in bytes)\n 6. {tx-bytes}: Size of data sent [per second] (in bytes)\n 7. {rx-packets}: Number of packets received [per second]\n 8. {tx-packets}: Number of packets sent [per second]\n 9. {rx-errors}: Number of errors received [per second]\n 10. {tx-errors}: Number of errors sent [per second]\n 11. {rx-drops}: Number of packets dropped when receiving [per second]\n 12. {tx-drops}: Number of packets dropped when sending [per second]",
|
||||
"description": "Output format of the module `NetIO`. See Wiki for formatting syntax\n 1. {rx-size}: Size of data received [per second] (formatted)\n 2. {tx-size}: Size of data sent [per second] (formatted)\n 3. {ifname}: Interface name\n 4. {is-default-route}: Is default route\n 5. {rx-bytes}: Size of data received [per second] (in bytes)\n 6. {tx-bytes}: Size of data sent [per second] (in bytes)\n 7. {rx-packets}: Number of packets received [per second]\n 8. {tx-packets}: Number of packets sent [per second]\n 9. {rx-errors}: Number of errors received [per second]\n 10. {tx-errors}: Number of errors sent [per second]\n 11. {rx-drops}: Number of packets dropped when receiving [per second]\n 12. {tx-drops}: Number of packets dropped when sending [per second]",
|
||||
"type": "string"
|
||||
},
|
||||
"openclFormat": {
|
||||
"description": "Output format of the module `OpenCL`. See `-h format` for formatting syntax\n 1. {version}: Platform version\n 2. {name}: Platform name\n 3. {vendor}: Platform vendor",
|
||||
"description": "Output format of the module `OpenCL`. See Wiki for formatting syntax\n 1. {version}: Platform version\n 2. {name}: Platform name\n 3. {vendor}: Platform vendor",
|
||||
"type": "string"
|
||||
},
|
||||
"openglFormat": {
|
||||
"description": "Output format of the module `OpenGL`. See `-h format` for formatting syntax\n 1. {version}: OpenGL version\n 2. {renderer}: OpenGL renderer\n 3. {vendor}: OpenGL vendor\n 4. {slv}: OpenGL shading language version\n 5. {library}: OpenGL library used",
|
||||
"description": "Output format of the module `OpenGL`. See Wiki for formatting syntax\n 1. {version}: OpenGL version\n 2. {renderer}: OpenGL renderer\n 3. {vendor}: OpenGL vendor\n 4. {slv}: OpenGL shading language version\n 5. {library}: OpenGL library used",
|
||||
"type": "string"
|
||||
},
|
||||
"osFormat": {
|
||||
"description": "Output format of the module `OS`. See `-h format` for formatting syntax\n 1. {sysname}: Name of the kernel\n 2. {name}: Name of the OS\n 3. {pretty-name}: Pretty name of the OS, if available\n 4. {id}: ID of the OS\n 5. {id-like}: ID like of the OS\n 6. {variant}: Variant of the OS\n 7. {variant-id}: Variant ID of the OS\n 8. {version}: Version of the OS\n 9. {version-id}: Version ID of the OS\n 10. {codename}: Version codename of the OS\n 11. {build-id}: Build ID of the OS\n 12. {arch}: Architecture of the OS",
|
||||
"description": "Output format of the module `OS`. See Wiki for formatting syntax\n 1. {sysname}: Name of the kernel\n 2. {name}: Name of the OS\n 3. {pretty-name}: Pretty name of the OS, if available\n 4. {id}: ID of the OS\n 5. {id-like}: ID like of the OS\n 6. {variant}: Variant of the OS\n 7. {variant-id}: Variant ID of the OS\n 8. {version}: Version of the OS\n 9. {version-id}: Version ID of the OS\n 10. {codename}: Version codename of the OS\n 11. {build-id}: Build ID of the OS\n 12. {arch}: Architecture of the OS",
|
||||
"type": "string"
|
||||
},
|
||||
"packagesFormat": {
|
||||
"description": "Output format of the module `Packages`. See `-h format` for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {nix-all}: Total number of all nix packages\n 43. {flatpak-all}: Total number of all flatpak app packages\n 44. {brew-all}: Total number of all brew packages\n 45. {guix-all}: Total number of all guix packages\n 46. {hpkg-all}: Total number of all hpkg packages",
|
||||
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {nix-all}: Total number of all nix packages\n 44. {flatpak-all}: Total number of all flatpak app packages\n 45. {brew-all}: Total number of all brew packages\n 46. {guix-all}: Total number of all guix packages\n 47. {hpkg-all}: Total number of all hpkg packages",
|
||||
"type": "string"
|
||||
},
|
||||
"physicaldiskFormat": {
|
||||
"description": "Output format of the module `PhysicalDisk`. See `-h format` for formatting syntax\n 1. {size}: Device size (formatted)\n 2. {name}: Device name\n 3. {interconnect}: Device interconnect type\n 4. {dev-path}: Device raw file path\n 5. {serial}: Serial number\n 6. {physical-type}: Device kind (SSD or HDD)\n 7. {removable-type}: Device kind (Removable or Fixed)\n 8. {readonly-type}: Device kind (Read-only or Read-write)\n 9. {revision}: Product revision\n 10. {temperature}: Device temperature (formatted)",
|
||||
"description": "Output format of the module `PhysicalDisk`. See Wiki for formatting syntax\n 1. {size}: Device size (formatted)\n 2. {name}: Device name\n 3. {interconnect}: Device interconnect type\n 4. {dev-path}: Device raw file path\n 5. {serial}: Serial number\n 6. {physical-type}: Device kind (SSD or HDD)\n 7. {removable-type}: Device kind (Removable or Fixed)\n 8. {readonly-type}: Device kind (Read-only or Read-write)\n 9. {revision}: Product revision\n 10. {temperature}: Device temperature (formatted)",
|
||||
"type": "string"
|
||||
},
|
||||
"physicalmemoryFormat": {
|
||||
"description": "Output format of the module `PhysicalMemory`. See `-h format` for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled",
|
||||
"description": "Output format of the module `PhysicalMemory`. See Wiki for formatting syntax\n 1. {bytes}: Size (in bytes)\n 2. {size}: Size formatted\n 3. {max-speed}: Max speed (in MT/s)\n 4. {running-speed}: Running speed (in MT/s)\n 5. {type}: Type (DDR4, DDR5, etc.)\n 6. {form-factor}: Form factor (SODIMM, DIMM, etc.)\n 7. {locator}: Bank/Device Locator (BANK0/SIMM0, BANK0/SIMM1, etc.)\n 8. {vendor}: Vendor\n 9. {serial}: Serial number\n 10. {part-number}: Part number\n 11. {is-ecc-enabled}: True if ECC enabled",
|
||||
"type": "string"
|
||||
},
|
||||
"playerFormat": {
|
||||
"description": "Output format of the module `Player`. See `-h format` for formatting syntax\n 1. {player}: Pretty player name\n 2. {name}: Player name\n 3. {id}: Player Identifier\n 4. {url}: URL name",
|
||||
"description": "Output format of the module `Player`. See Wiki for formatting syntax\n 1. {player}: Pretty player name\n 2. {name}: Player name\n 3. {id}: Player Identifier\n 4. {url}: URL name",
|
||||
"type": "string"
|
||||
},
|
||||
"poweradapterFormat": {
|
||||
"description": "Output format of the module `PowerAdapter`. See `-h format` for formatting syntax\n 1. {watts}: Power adapter watts\n 2. {name}: Power adapter name\n 3. {manufacturer}: Power adapter manufacturer\n 4. {model}: Power adapter model\n 5. {description}: Power adapter description\n 6. {serial}: Power adapter serial number",
|
||||
"description": "Output format of the module `PowerAdapter`. See Wiki for formatting syntax\n 1. {watts}: Power adapter watts\n 2. {name}: Power adapter name\n 3. {manufacturer}: Power adapter manufacturer\n 4. {model}: Power adapter model\n 5. {description}: Power adapter description\n 6. {serial}: Power adapter serial number",
|
||||
"type": "string"
|
||||
},
|
||||
"processesFormat": {
|
||||
"description": "Output format of the module `Processes`. See `-h format` for formatting syntax\n 1. {result}: Process count",
|
||||
"description": "Output format of the module `Processes`. See Wiki for formatting syntax\n 1. {result}: Process count",
|
||||
"type": "string"
|
||||
},
|
||||
"publicipFormat": {
|
||||
"description": "Output format of the module `PublicIp`. See `-h format` for formatting syntax\n 1. {ip}: Public IP address\n 2. {location}: Location",
|
||||
"type": "string"
|
||||
},
|
||||
"separatorFormat": {
|
||||
"description": "Output format of the module `Separator`. See `-h format` for formatting syntax\n 1. {string}: Separator string\n 2. {outputColor}: Output color\n 3. {length}: Length",
|
||||
"description": "Output format of the module `PublicIp`. See Wiki for formatting syntax\n 1. {ip}: Public IP address\n 2. {location}: Location",
|
||||
"type": "string"
|
||||
},
|
||||
"shellFormat": {
|
||||
"description": "Output format of the module `Shell`. See `-h format` for formatting syntax\n 1. {process-name}: Shell process name\n 2. {exe}: The first argument of the command line when running the shell\n 3. {exe-name}: Shell base name of arg0\n 4. {version}: Shell version\n 5. {pid}: Shell pid\n 6. {pretty-name}: Shell pretty name\n 7. {exe-path}: Shell full exe path\n 8. {tty}: Shell tty used",
|
||||
"description": "Output format of the module `Shell`. See Wiki for formatting syntax\n 1. {process-name}: Shell process name\n 2. {exe}: The first argument of the command line when running the shell\n 3. {exe-name}: Shell base name of arg0\n 4. {version}: Shell version\n 5. {pid}: Shell pid\n 6. {pretty-name}: Shell pretty name\n 7. {exe-path}: Shell full exe path\n 8. {tty}: Shell tty used",
|
||||
"type": "string"
|
||||
},
|
||||
"soundFormat": {
|
||||
"description": "Output format of the module `Sound`. See `-h format` for formatting syntax\n 1. {is-main}: Is main sound device\n 2. {name}: Device name\n 3. {volume-percentage}: Volume (in percentage num)\n 4. {identifier}: Identifier\n 5. {volume-percentage-bar}: Volume (in percentage bar)\n 6. {platform-api}: Platform API used",
|
||||
"description": "Output format of the module `Sound`. See Wiki for formatting syntax\n 1. {is-main}: Is main sound device\n 2. {name}: Device name\n 3. {volume-percentage}: Volume (in percentage num)\n 4. {identifier}: Identifier\n 5. {volume-percentage-bar}: Volume (in percentage bar)\n 6. {platform-api}: Platform API used",
|
||||
"type": "string"
|
||||
},
|
||||
"swapFormat": {
|
||||
"description": "Output format of the module `Swap`. See `-h format` for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)",
|
||||
"description": "Output format of the module `Swap`. See Wiki for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)\n 5. {name}: Name",
|
||||
"type": "string"
|
||||
},
|
||||
"terminalFormat": {
|
||||
"description": "Output format of the module `Terminal`. See `-h format` for formatting syntax\n 1. {process-name}: Terminal process name\n 2. {exe}: The first argument of the command line when running the terminal\n 3. {exe-name}: Terminal base name of arg0\n 4. {pid}: Terminal pid\n 5. {pretty-name}: Terminal pretty name\n 6. {version}: Terminal version\n 7. {exe-path}: Terminal full exe path\n 8. {tty}: Terminal tty / pts used",
|
||||
"description": "Output format of the module `Terminal`. See Wiki for formatting syntax\n 1. {process-name}: Terminal process name\n 2. {exe}: The first argument of the command line when running the terminal\n 3. {exe-name}: Terminal base name of arg0\n 4. {pid}: Terminal pid\n 5. {pretty-name}: Terminal pretty name\n 6. {version}: Terminal version\n 7. {exe-path}: Terminal full exe path\n 8. {tty}: Terminal tty / pts used",
|
||||
"type": "string"
|
||||
},
|
||||
"terminalfontFormat": {
|
||||
"description": "Output format of the module `TerminalFont`. See `-h format` for formatting syntax\n 1. {combined}: Terminal font combined\n 2. {name}: Terminal font name\n 3. {size}: Terminal font size\n 4. {styles}: Terminal font styles",
|
||||
"description": "Output format of the module `TerminalFont`. See Wiki for formatting syntax\n 1. {combined}: Terminal font combined\n 2. {name}: Terminal font name\n 3. {size}: Terminal font size\n 4. {styles}: Terminal font styles",
|
||||
"type": "string"
|
||||
},
|
||||
"terminalsizeFormat": {
|
||||
"description": "Output format of the module `TerminalSize`. See `-h format` for formatting syntax\n 1. {rows}: Terminal rows\n 2. {columns}: Terminal columns\n 3. {width}: Terminal width (in pixels)\n 4. {height}: Terminal height (in pixels)",
|
||||
"description": "Output format of the module `TerminalSize`. See Wiki for formatting syntax\n 1. {rows}: Terminal rows\n 2. {columns}: Terminal columns\n 3. {width}: Terminal width (in pixels)\n 4. {height}: Terminal height (in pixels)",
|
||||
"type": "string"
|
||||
},
|
||||
"terminalthemeFormat": {
|
||||
"description": "Output format of the module `TerminalTheme`. See `-h format` for formatting syntax\n 1. {fg-color}: Terminal foreground color\n 2. {fg-type}: Terminal foreground type (Dark / Light)\n 3. {bg-color}: Terminal background color\n 4. {bg-type}: Terminal background type (Dark / Light)",
|
||||
"description": "Output format of the module `TerminalTheme`. See Wiki for formatting syntax\n 1. {fg-color}: Terminal foreground color\n 2. {fg-type}: Terminal foreground type (Dark / Light)\n 3. {bg-color}: Terminal background color\n 4. {bg-type}: Terminal background type (Dark / Light)",
|
||||
"type": "string"
|
||||
},
|
||||
"titleFormat": {
|
||||
"description": "Output format of the module `Title`. See `-h format` for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)",
|
||||
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
|
||||
"type": "string"
|
||||
},
|
||||
"themeFormat": {
|
||||
"description": "Output format of the module `Theme`. See `-h format` for formatting syntax\n 1. {theme1}: Theme part 1\n 2. {theme2}: Theme part 2",
|
||||
"description": "Output format of the module `Theme`. See Wiki for formatting syntax\n 1. {theme1}: Theme part 1\n 2. {theme2}: Theme part 2",
|
||||
"type": "string"
|
||||
},
|
||||
"tpmFormat": {
|
||||
"description": "Output format of the module `TPM`. See `-h format` for formatting syntax\n 1. {version}: TPM device version\n 2. {description}: TPM general description",
|
||||
"description": "Output format of the module `TPM`. See Wiki for formatting syntax\n 1. {version}: TPM device version\n 2. {description}: TPM general description",
|
||||
"type": "string"
|
||||
},
|
||||
"uptimeFormat": {
|
||||
"description": "Output format of the module `Uptime`. See `-h format` for formatting syntax\n 1. {days}: Days\n 2. {hours}: Hours\n 3. {minutes}: Minutes\n 4. {seconds}: Seconds\n 5. {milliseconds}: Milliseconds\n 6. {boot-time}: Boot time in local timezone",
|
||||
"description": "Output format of the module `Uptime`. See Wiki for formatting syntax\n 1. {days}: Days after boot\n 2. {hours}: Hours after boot\n 3. {minutes}: Minutes after boot\n 4. {seconds}: Seconds after boot\n 5. {milliseconds}: Milliseconds after boot\n 6. {boot-time}: Boot time in local timezone\n 7. {years}: Years integer after boot\n 8. {days-of-year}: Days of year after boot\n 9. {years-fraction}: Years fraction after boot",
|
||||
"type": "string"
|
||||
},
|
||||
"usersFormat": {
|
||||
"description": "Output format of the module `Users`. See `-h format` for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login",
|
||||
"description": "Output format of the module `Users`. See Wiki for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login\n 11. {years}: Years integer after login\n 12. {days-of-year}: Days of year after login\n 13. {years-fraction}: Years fraction after login",
|
||||
"type": "string"
|
||||
},
|
||||
"versionFormat": {
|
||||
"description": "Output format of the module `Version`. See `-h format` for formatting syntax\n 1. {name}: Project name\n 2. {version}: Version\n 3. {version-tweak}: Version tweak\n 4. {build-type}: Build type (debug or release)\n 5. {sysname}: System name\n 6. {arch}: Architecture\n 7. {cmake-built-type}: CMake build type when compiling (Debug, Release, RelWithDebInfo, MinSizeRel)\n 8. {compile-time}: Date time when compiling\n 9. {compiler}: Compiler used when compiling\n 10. {libc}: Libc used when compiling",
|
||||
"description": "Output format of the module `Version`. See Wiki for formatting syntax\n 1. {name}: Project name\n 2. {version}: Version\n 3. {version-tweak}: Version tweak\n 4. {build-type}: Build type (debug or release)\n 5. {sysname}: System name\n 6. {arch}: Architecture\n 7. {cmake-built-type}: CMake build type when compiling (Debug, Release, RelWithDebInfo, MinSizeRel)\n 8. {compile-time}: Date time when compiling\n 9. {compiler}: Compiler used when compiling\n 10. {libc}: Libc used when compiling",
|
||||
"type": "string"
|
||||
},
|
||||
"vulkanFormat": {
|
||||
"description": "Output format of the module `Vulkan`. See `-h format` for formatting syntax\n 1. {driver}: Driver name\n 2. {api-version}: API version\n 3. {conformance-version}: Conformance version\n 4. {instance-version}: Instance version",
|
||||
"description": "Output format of the module `Vulkan`. See Wiki for formatting syntax\n 1. {driver}: Driver name\n 2. {api-version}: API version\n 3. {conformance-version}: Conformance version\n 4. {instance-version}: Instance version",
|
||||
"type": "string"
|
||||
},
|
||||
"wallpaperFormat": {
|
||||
"description": "Output format of the module `Wallpaper`. See `-h format` for formatting syntax\n 1. {file-name}: File name\n 2. {full-path}: Full path",
|
||||
"description": "Output format of the module `Wallpaper`. See Wiki for formatting syntax\n 1. {file-name}: File name\n 2. {full-path}: Full path",
|
||||
"type": "string"
|
||||
},
|
||||
"weatherFormat": {
|
||||
"description": "Output format of the module `Weather`. See `-h format` for formatting syntax\n 1. {result}: Weather result",
|
||||
"description": "Output format of the module `Weather`. See Wiki for formatting syntax\n 1. {result}: Weather result",
|
||||
"type": "string"
|
||||
},
|
||||
"wmFormat": {
|
||||
"description": "Output format of the module `WM`. See `-h format` for formatting syntax\n 1. {process-name}: WM process name\n 2. {pretty-name}: WM pretty name\n 3. {protocol-name}: WM protocol name\n 4. {plugin-name}: WM plugin name\n 5. {version}: WM version",
|
||||
"description": "Output format of the module `WM`. See Wiki for formatting syntax\n 1. {process-name}: WM process name\n 2. {pretty-name}: WM pretty name\n 3. {protocol-name}: WM protocol name\n 4. {plugin-name}: WM plugin name\n 5. {version}: WM version",
|
||||
"type": "string"
|
||||
},
|
||||
"wifiFormat": {
|
||||
"description": "Output format of the module `Wifi`. See `-h format` for formatting syntax\n 1. {inf-desc}: Interface description\n 2. {inf-status}: Interface status\n 3. {status}: Connection status\n 4. {ssid}: Connection SSID\n 5. {bssid}: Connection BSSID\n 6. {protocol}: Connection protocol\n 7. {signal-quality}: Connection signal quality (percentage num)\n 8. {rx-rate}: Connection RX rate\n 9. {tx-rate}: Connection TX rate\n 10. {security}: Connection Security algorithm\n 11. {signal-quality-bar}: Connection signal quality (percentage bar)\n 12. {channel}: Connection channel number\n 13. {band}: Connection channel band in GHz",
|
||||
"description": "Output format of the module `Wifi`. See Wiki for formatting syntax\n 1. {inf-desc}: Interface description\n 2. {inf-status}: Interface status\n 3. {status}: Connection status\n 4. {ssid}: Connection SSID\n 5. {bssid}: Connection BSSID\n 6. {protocol}: Connection protocol\n 7. {signal-quality}: Connection signal quality (percentage num)\n 8. {rx-rate}: Connection RX rate\n 9. {tx-rate}: Connection TX rate\n 10. {security}: Connection Security algorithm\n 11. {signal-quality-bar}: Connection signal quality (percentage bar)\n 12. {channel}: Connection channel number\n 13. {band}: Connection channel band in GHz",
|
||||
"type": "string"
|
||||
},
|
||||
"wmthemeFormat": {
|
||||
"description": "Output format of the module `WMTheme`. See `-h format` for formatting syntax\n 1. {result}: WM theme",
|
||||
"description": "Output format of the module `WMTheme`. See Wiki for formatting syntax\n 1. {result}: WM theme",
|
||||
"type": "string"
|
||||
},
|
||||
"zpoolFormat": {
|
||||
"description": "Output format of the module `Zpool`. See `-h format` for formatting syntax\n 1. {name}: Zpool name\n 2. {state}: Zpool state\n 3. {used}: Size used\n 4. {total}: Size total\n 5. {used-percentage}: Size percentage num\n 6. {fragmentation-percentage}: Fragmentation percentage num\n 7. {used-percentage-bar}: Size percentage bar\n 8. {fragmentation-percentage-bar}: Fragmentation percentage bar",
|
||||
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {state}: Zpool state\n 3. {used}: Size used\n 4. {total}: Size total\n 5. {used-percentage}: Size percentage num\n 6. {fragmentation-percentage}: Fragmentation percentage num\n 7. {used-percentage-bar}: Size percentage bar\n 8. {fragmentation-percentage-bar}: Fragmentation percentage bar",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"title": "JSON config",
|
||||
"description": "JSON config file for fastfetch. Usually be `~/.config/fastfetch.jsonc`",
|
||||
"description": "JSON config file for fastfetch. Usually located at `~/.config/fastfetch/config.jsonc`",
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string",
|
||||
@@ -420,7 +416,7 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"description": "Set the type of the logo given",
|
||||
"description": "Set the type of the logo",
|
||||
"enum": [
|
||||
"auto",
|
||||
"builtin",
|
||||
@@ -429,6 +425,7 @@
|
||||
"file-raw",
|
||||
"data",
|
||||
"data-raw",
|
||||
"command-raw",
|
||||
"sixel",
|
||||
"kitty",
|
||||
"kitty-direct",
|
||||
@@ -447,7 +444,7 @@
|
||||
"color": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Overwrite a color in the logo",
|
||||
"description": "Override colors in the logo",
|
||||
"properties": {
|
||||
"1": {
|
||||
"description": "Color 1",
|
||||
@@ -521,12 +518,12 @@
|
||||
},
|
||||
"printRemaining": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to print the remaining logo, if it has more lines than modules to display",
|
||||
"default": false
|
||||
"description": "Whether to print the remaining logo if it has more lines than modules to display",
|
||||
"default": true
|
||||
},
|
||||
"preserveAspectRatio": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to preserve the aspect ratio of the logo. Supported by iTerm image protocol",
|
||||
"description": "Whether to preserve the aspect ratio of the logo. Supported by iTerm image protocol only",
|
||||
"default": false
|
||||
},
|
||||
"recache": {
|
||||
@@ -536,7 +533,7 @@
|
||||
},
|
||||
"position": {
|
||||
"type": "string",
|
||||
"description": "Set the position of the logo should be displayed",
|
||||
"description": "Set the position where the logo should be displayed",
|
||||
"enum": [
|
||||
"left",
|
||||
"top",
|
||||
@@ -547,7 +544,7 @@
|
||||
"chafa": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Chafa configuration. See chafa document for details",
|
||||
"description": "Chafa configuration. See chafa documentation for details",
|
||||
"properties": {
|
||||
"fgOnly": {
|
||||
"type": "boolean",
|
||||
@@ -560,7 +557,7 @@
|
||||
},
|
||||
"canvasMode": {
|
||||
"type": "string",
|
||||
"description": "Determine how colors are used in the output. This value maps the value of enum ChafaCanvasMode.",
|
||||
"description": "Determine how colors are used in the output. This value maps to enum ChafaCanvasMode.",
|
||||
"enum": [
|
||||
"TRUECOLOR",
|
||||
"INDEXED_256",
|
||||
@@ -574,7 +571,7 @@
|
||||
},
|
||||
"colorSpace": {
|
||||
"type": "string",
|
||||
"description": "Set color space used for quantization. This value maps the value of enum ChafaColorSpace.",
|
||||
"description": "Set color space used for quantization. This value maps to enum ChafaColorSpace.",
|
||||
"enum": [
|
||||
"RGB",
|
||||
"DIN99D"
|
||||
@@ -582,7 +579,7 @@
|
||||
},
|
||||
"ditherMode": {
|
||||
"type": "string",
|
||||
"description": "Set output dither mode (No effect with 24-bit color). This value maps the value of enum ChafaDitherMode.",
|
||||
"description": "Set output dither mode (No effect with 24-bit color). This value maps to enum ChafaDitherMode.",
|
||||
"enum": [
|
||||
"NONE",
|
||||
"ORDERED",
|
||||
@@ -600,14 +597,9 @@
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"multithreading": {
|
||||
"type": "boolean",
|
||||
"description": "Use multiple threads to detect values",
|
||||
"default": true
|
||||
},
|
||||
"thread": {
|
||||
"type": "boolean",
|
||||
"description": "Alias of multithreading",
|
||||
"description": "Use separate threads for HTTP requests",
|
||||
"default": true
|
||||
},
|
||||
"escapeBedrock": {
|
||||
@@ -617,7 +609,7 @@
|
||||
},
|
||||
"playerName": {
|
||||
"type": "string",
|
||||
"description": "The name of the player to use for module Media and Player. Linux only"
|
||||
"description": "The name of the player to use for Media and Player modules. Linux only"
|
||||
},
|
||||
"dsForceDrm": {
|
||||
"description": "Force display detection to use DRM. Linux only",
|
||||
@@ -629,13 +621,13 @@
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Use `/sys/class/drm` only.",
|
||||
"description": "Use `/sys/class/drm` only",
|
||||
"const": "sysfs-only"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"const": true,
|
||||
"description": "Try `libdrm` first, then `sysfs` if libdrm failed"
|
||||
"description": "Try `libdrm` first, then `sysfs` if libdrm fails"
|
||||
}
|
||||
],
|
||||
"default": false
|
||||
@@ -663,7 +655,7 @@
|
||||
}
|
||||
},
|
||||
"display": {
|
||||
"description": "Configure how things to be displayed",
|
||||
"description": "Configure how things should be displayed",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
@@ -682,7 +674,7 @@
|
||||
},
|
||||
"pipe": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable pipe mode (disable logo and all escape sequences)",
|
||||
"description": "Whether to disable colors (auto-detected based on isatty(1) by default)",
|
||||
"default": false
|
||||
},
|
||||
"showErrors": {
|
||||
@@ -692,12 +684,12 @@
|
||||
},
|
||||
"disableLinewrap": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to disable line wrap during the run",
|
||||
"description": "Whether to disable line wrap during execution",
|
||||
"default": true
|
||||
},
|
||||
"hideCursor": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to hide the cursor during the run",
|
||||
"description": "Whether to hide the cursor during execution",
|
||||
"default": true
|
||||
},
|
||||
"separator": {
|
||||
@@ -709,7 +701,7 @@
|
||||
"description": "Set the color of the keys and title",
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "Set the both color of the keys and title",
|
||||
"description": "Set both the colors of keys and title",
|
||||
"$ref": "#/$defs/colors"
|
||||
},
|
||||
{
|
||||
@@ -774,11 +766,11 @@
|
||||
"size": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set how a size value should be displayed",
|
||||
"description": "Set how size values should be displayed",
|
||||
"properties": {
|
||||
"binaryPrefix": {
|
||||
"type": "string",
|
||||
"description": "Set the binary prefix to used when formatting sizes",
|
||||
"description": "Set the binary prefix to use when formatting sizes",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "iec",
|
||||
@@ -792,7 +784,8 @@
|
||||
"const": "jedec",
|
||||
"description": "1024 Bytes = 1 KB, 1024 KB = 1 MB, ..."
|
||||
}
|
||||
]
|
||||
],
|
||||
"default": "iec"
|
||||
},
|
||||
"maxPrefix": {
|
||||
"type": "string",
|
||||
@@ -816,7 +809,7 @@
|
||||
"properties": {
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"description": "Set the unit of the temperature",
|
||||
"description": "Set the unit of temperature",
|
||||
"enum": ["D", "Default", "Celsius", "C", "Fahrenheit", "F", "Kelvin", "K"],
|
||||
"default": "D"
|
||||
},
|
||||
@@ -830,19 +823,22 @@
|
||||
"color": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set color used in different states of temperature values",
|
||||
"description": "Set colors used in different states of temperature values",
|
||||
"properties": {
|
||||
"green": {
|
||||
"description": "Color used in green state",
|
||||
"$ref": "#/$defs/colors"
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "green"
|
||||
},
|
||||
"yellow": {
|
||||
"description": "Color used in yellow state",
|
||||
"$ref": "#/$defs/colors"
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "light_yellow"
|
||||
},
|
||||
"red": {
|
||||
"description": "Color used in red state",
|
||||
"$ref": "#/$defs/colors"
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "light_red"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -884,7 +880,7 @@
|
||||
"percent": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set how a percentage value should be displayed",
|
||||
"description": "Set how percentage values should be displayed",
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/$defs/percentType"
|
||||
@@ -899,19 +895,22 @@
|
||||
"color": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set color used in different states of percentage bars and numbers",
|
||||
"description": "Set colors used in different states of percentage bars and numbers",
|
||||
"properties": {
|
||||
"green": {
|
||||
"description": "Color used in green state",
|
||||
"$ref": "#/$defs/colors"
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "green"
|
||||
},
|
||||
"yellow": {
|
||||
"description": "Color used in yellow state",
|
||||
"$ref": "#/$defs/colors"
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "light_yellow"
|
||||
},
|
||||
"red": {
|
||||
"description": "Color used in red state",
|
||||
"$ref": "#/$defs/colors"
|
||||
"$ref": "#/$defs/colors",
|
||||
"default": "light_red"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -924,13 +923,35 @@
|
||||
"properties": {
|
||||
"ndigits": {
|
||||
"type": "integer",
|
||||
"description": "Set the number of digits to keep after the decimal point when formatting frequency values\nA positive value will show the frequency in GHz of decimal\n-1 will show the frequency in MHz",
|
||||
"description": "Set the number of digits to keep after the decimal point when formatting frequency values\nA positive value will show the frequency in GHz with decimal\n-1 will show the frequency in MHz",
|
||||
"minimum": -1,
|
||||
"maximum": 9,
|
||||
"default": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"fraction": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Set how ordinary fraction numbers should be displayed",
|
||||
"properties": {
|
||||
"ndigits": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "number",
|
||||
"description": "Set the number of digits to keep after the decimal point when formatting ordinary fraction numbers",
|
||||
"minimum": 0,
|
||||
"maximum": 9
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
"description": "The number of digits will be automatically determined based on the value"
|
||||
}
|
||||
],
|
||||
"default": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"noBuffer": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to disable the stdout application buffer",
|
||||
@@ -1752,6 +1773,14 @@
|
||||
"type": "string",
|
||||
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
|
||||
},
|
||||
"hideFolders": {
|
||||
"type": "string",
|
||||
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output\nDefault: /efi:/boot:/boot/efi"
|
||||
},
|
||||
"hideFS": {
|
||||
"type": "string",
|
||||
"description": "A colon separated file systems to hide from the disk output"
|
||||
},
|
||||
"showExternal": {
|
||||
"type": "boolean",
|
||||
"description": "Set if external volume should be printed",
|
||||
@@ -2051,6 +2080,7 @@
|
||||
"enum": [
|
||||
"integrated",
|
||||
"discrete",
|
||||
"unknown",
|
||||
"none"
|
||||
],
|
||||
"default": "none"
|
||||
@@ -2990,6 +3020,11 @@
|
||||
"const": "swap",
|
||||
"description": "Print swap (paging file) space usage"
|
||||
},
|
||||
"separate": {
|
||||
"type": "boolean",
|
||||
"description": "Set if detailed swap devices should be reported on separate lines instead of a summary",
|
||||
"default": false
|
||||
},
|
||||
"percent": {
|
||||
"$ref": "#/$defs/percent"
|
||||
},
|
||||
|
||||
+4
-1
@@ -52,7 +52,10 @@
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
"swap",
|
||||
{
|
||||
"type": "swap",
|
||||
"separate": true
|
||||
},
|
||||
"disk",
|
||||
"btrfs",
|
||||
"zpool",
|
||||
|
||||
+4
-1
@@ -54,7 +54,10 @@
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
"swap",
|
||||
{
|
||||
"type": "swap",
|
||||
"separate": true
|
||||
},
|
||||
"disk",
|
||||
"btrfs",
|
||||
"zpool",
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small",
|
||||
"padding": {
|
||||
"top": 1
|
||||
}
|
||||
},
|
||||
"display": {
|
||||
"separator": " "
|
||||
},
|
||||
"modules": [
|
||||
"break",
|
||||
"title",
|
||||
{
|
||||
"type": "os",
|
||||
"key": "os ",
|
||||
"keyColor": "red"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "kernel",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "host",
|
||||
"format": "{vendor} {family}",
|
||||
"key": "host ",
|
||||
"keyColor": "yellow"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"key": "pkgs ",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"format": "{?days}{days}d {?}{hours}h {minutes}m",
|
||||
"key": "uptime",
|
||||
"keyColor": "magenta"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "memory",
|
||||
"keyColor": "cyan"
|
||||
},
|
||||
"break"
|
||||
]
|
||||
}
|
||||
+121
-52
@@ -1,11 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Python script to generate a man page for the command `fastfetch`.
|
||||
The man content will be printed to stdout so you will need to
|
||||
pipe it to a file if you want to save it.
|
||||
The command options will be generated using a JSON file.
|
||||
For the format of the JSON file, see https://github.com/fastfetch-cli/fastfetch/blob/dev/src/data/help.json
|
||||
Python script to generate a comprehensive man page for the command `fastfetch`.
|
||||
|
||||
The generated man page content will be printed to stdout,
|
||||
so you will need to pipe it to a file if you want to save it.
|
||||
Example: python3 gen-man.py > fastfetch.1
|
||||
|
||||
The command options are generated using a JSON file.
|
||||
For the JSON file format, see:
|
||||
https://github.com/fastfetch-cli/fastfetch/blob/dev/src/data/help.json
|
||||
"""
|
||||
|
||||
from json import load
|
||||
@@ -33,7 +37,7 @@ pathToHelpFile = path.join(pathToCurrentDir, "../src/data/help.json")
|
||||
# man page section
|
||||
manSection = 1
|
||||
# title (center header)
|
||||
titlePage = "Fastfetch man page"
|
||||
titlePage = "FASTFETCH"
|
||||
# date (center footer)
|
||||
# format : "Month (abbreviation) Day Year"
|
||||
todayDate = datetime.fromtimestamp(
|
||||
@@ -47,81 +51,118 @@ pathToVersionFile = path.join(pathToCurrentDir, "../CMakeLists.txt")
|
||||
###### Sections Text ######
|
||||
|
||||
# text displayed in the "NAME" section
|
||||
nameSection = r"fastfetch \- A maintained, feature\-rich and performance oriented, neofetch like system information tool"
|
||||
nameSection = r"fastfetch \- A fast and feature-rich system information tool similar to neofetch"
|
||||
|
||||
# text displayed in the "DESCRIPTION" section
|
||||
descriptionSection = r"""
|
||||
Fastfetch is a tool for displaying system information in a visually appealing way. Written primarily in C, it focuses on performance and customizability while providing functionality similar to neofetch.
|
||||
It supports Linux, Android, FreeBSD, macOS, and Windows 7 or newer.
|
||||
"""
|
||||
|
||||
# text displayed at the beginning of the "OPTIONS" section
|
||||
optionSection = r"""
|
||||
Parsing is not case sensitive. E.g. \fB--logo-type\fR is
|
||||
equal to \fB--LOGO-TYPE\fR.
|
||||
Options are parsed in a case-insensitive manner. For example, \fB--logo-type\fR and \fB--LOGO-TYPE\fR are treated identically.
|
||||
|
||||
If a value is between square brackets, it is optional.
|
||||
An optional boolean value defaults to true if not specified.
|
||||
Arguments in square brackets are optional. Optional boolean arguments default to 'true' when specified without a value.
|
||||
|
||||
More detailed help messages for each options can be printed
|
||||
with \fB-h <option_without_dash_prefix>\fR.
|
||||
For more detailed information about a specific option, use:
|
||||
\fBfastfetch -h <option_name_without_dashes>\fR
|
||||
|
||||
All options can be made permanent with command
|
||||
\fBfastfetch <options> --gen-config\fR.
|
||||
Any combination of options can be made permanent by generating a configuration file:
|
||||
\fBfastfetch <options> --gen-config\fR
|
||||
"""
|
||||
|
||||
# text displayed in the "CONFIGURATION"
|
||||
configurationSection = f"""
|
||||
.SS Fetch Structure
|
||||
|
||||
The structure of a fetch describes the modules that should
|
||||
be included in the output. It consists of a string of modules,
|
||||
separated by a colon (:). To list all available modules,
|
||||
use --list-modules.
|
||||
The structure defines which modules to display and in what order. It consists of module names separated by colons (:).
|
||||
For example: {startBold}title:separator:os:kernel:uptime{endBold}
|
||||
|
||||
To list all available modules, use {startBold}--list-modules{endBold}
|
||||
|
||||
|
||||
.SS Config Files
|
||||
|
||||
Fastfetch uses JSONC based format for configuration.
|
||||
Fastfetch doesn't generate config file automatically;
|
||||
it should be generated manually by {startBold}--gen-config{endBold}.
|
||||
The config file will be saved in
|
||||
{startBold}~/.config/fastfetch/config.jsonc{endBold} by default.
|
||||
Fastfetch uses JSONC (JSON with Comments) for configuration files. These files must have the .jsonc extension.
|
||||
|
||||
A JSONC config file is a JSON file that also supports comments
|
||||
with (// and /* */). Those files must have the extension '.jsonc'.
|
||||
You can generate a default config file using {startBold}--gen-config{endBold}. By default, the config file is saved at {startBold}~/.config/fastfetch/config.jsonc{endBold}.
|
||||
|
||||
The specified configuration/preset files are searched in the following order:
|
||||
The configuration/preset files are searched in the following locations (in order):
|
||||
|
||||
{startBold}1.{endBold} relative to the current working directory
|
||||
{startBold}1.{endBold} Relative to the current working directory
|
||||
|
||||
{startBold}2.{endBold} relative to ~/.local/share/fastfetch/presets/
|
||||
{startBold}2.{endBold} Relative to ~/.local/share/fastfetch/presets/
|
||||
|
||||
{startBold}3.{endBold} relative to /usr/share/fastfetch/presets/
|
||||
{startBold}3.{endBold} Relative to /usr/share/fastfetch/presets/
|
||||
|
||||
Fastfetch provides some default presets. List them with --list-presets.
|
||||
For detailed information on logo options, module configuration, and formatting, visit:
|
||||
{startBold}https://github.com/fastfetch-cli/fastfetch/wiki/Configuration{endBold}
|
||||
|
||||
Fastfetch provides several built-in presets. List them with {startBold}--list-presets{endBold}.
|
||||
|
||||
.SS JSON Schema
|
||||
A JSON schema is available for editor intelligence when editing the configuration file. Add the following line at the beginning of your config file:
|
||||
|
||||
{startBold}"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"{endBold}
|
||||
"""
|
||||
|
||||
# text displayed in the "EXAMPLE" section
|
||||
exampleSection = """
|
||||
.SS Config files:
|
||||
exampleSection = f"""
|
||||
.SS Basic Usage
|
||||
{startBold}fastfetch{endBold}
|
||||
|
||||
.SS Use a specific logo
|
||||
{startBold}fastfetch --logo arch{endBold}
|
||||
|
||||
.SS Custom structure
|
||||
{startBold}fastfetch --structure title:os:kernel:uptime:memory{endBold}
|
||||
|
||||
.SS Generate a config file
|
||||
{startBold}fastfetch --gen-config{endBold}
|
||||
|
||||
.SS Use a preset
|
||||
{startBold}fastfetch --config neofetch{endBold}
|
||||
|
||||
.SS Config File Example
|
||||
.nf
|
||||
// ~/.config/fastfetch/config.jsonc
|
||||
{
|
||||
{{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {{
|
||||
"type": "auto",
|
||||
"source": "arch"
|
||||
}},
|
||||
"display": {{
|
||||
"separator": ": ",
|
||||
"color": {{
|
||||
"keys": "blue",
|
||||
"title": "red"
|
||||
}},
|
||||
"key": {{
|
||||
"width": 12
|
||||
}}
|
||||
}},
|
||||
"modules": [
|
||||
"title",
|
||||
"separator",
|
||||
"module1",
|
||||
{
|
||||
"type": "module2",
|
||||
"module2-option": "value"
|
||||
}
|
||||
"os",
|
||||
"kernel",
|
||||
"uptime",
|
||||
{{
|
||||
"type": "memory",
|
||||
"format": "{{used}}/{{total}} ({{used_percent}}%)"
|
||||
}}
|
||||
]
|
||||
}
|
||||
}}
|
||||
.fi
|
||||
"""
|
||||
|
||||
# text displayed in the "BUGS" section
|
||||
bugSection = "Please report bugs to : \
|
||||
https://github.com/fastfetch-cli/fastfetch/issues"
|
||||
bugSection = "Please report bugs to: https://github.com/fastfetch-cli/fastfetch/issues"
|
||||
|
||||
# text displayed in the "WIKI" section
|
||||
wikiSection = "Fastfetch github wiki : https://github.com/fastfetch-cli/fastfetch/wiki/Configuration"
|
||||
# text displayed in the "AUTHORS" section
|
||||
authorsSection = "Fastfetch is developed by a team of contributors on GitHub.\nVisit https://github.com/fastfetch-cli/fastfetch for more information."
|
||||
|
||||
|
||||
###### Argument decoration ######
|
||||
@@ -130,7 +171,7 @@ wikiSection = "Fastfetch github wiki : https://github.com/fastfetch-cli/fastfetc
|
||||
|
||||
# if an optional argument is displayed as [?optArg] (with "optArg" underlined)
|
||||
# this value should be f"[?{startUnderline}"
|
||||
startOptionalArgument = f"[{startUnderline}?"
|
||||
startOptionalArgument = f"[{startUnderline}"
|
||||
# if an optional argument is displayed as [?optArg] (with "optArg underlined")
|
||||
# this value should be f"{endUnderline}]"
|
||||
endOptionalArgument = f"{endUnderline}]"
|
||||
@@ -161,7 +202,7 @@ def main():
|
||||
for line in versionFile:
|
||||
researchVersion = search(r"^\s*VERSION (\d+\.\d+\.\d+)$", line)
|
||||
if (researchVersion):
|
||||
print(f"\"{researchVersion.group(1)}\"", end=" ")
|
||||
print(f"\"Fastfetch {researchVersion.group(1)}\"", end=" ")
|
||||
break
|
||||
|
||||
print(f"\"{titlePage}\"")
|
||||
@@ -177,13 +218,13 @@ def main():
|
||||
|
||||
print(".SH SYNOPSIS")
|
||||
print(".B fastfetch")
|
||||
print(f"[{startUnderline}OPTIONS{endUnderline}]")\
|
||||
print(f"[{startUnderline}OPTIONS{endUnderline}...]")
|
||||
|
||||
|
||||
###### Wiki ######
|
||||
###### Description ######
|
||||
|
||||
print(".SH WIKI")
|
||||
print(wikiSection)
|
||||
print(".SH DESCRIPTION")
|
||||
print(descriptionSection)
|
||||
|
||||
|
||||
###### Configuration ######
|
||||
@@ -202,7 +243,7 @@ def main():
|
||||
for key, value in helpFileData.items():
|
||||
|
||||
# print new subsection
|
||||
print(f".SS {key}:")
|
||||
print(f".SS {key}")
|
||||
|
||||
# loop through every option in a section
|
||||
for option in value:
|
||||
@@ -237,7 +278,25 @@ def main():
|
||||
print(startMandatoryArgument + option['arg']['type'] + endMandatoryArgument, end="")
|
||||
|
||||
# description
|
||||
print(f"\n {option['desc']} \n")
|
||||
print()
|
||||
|
||||
# If desc is a list, join with newlines and proper spacing
|
||||
if isinstance(option['desc'], list):
|
||||
desc_text = "\n ".join(option['desc'])
|
||||
print(f" {desc_text}")
|
||||
else:
|
||||
print(f" {option['desc']}")
|
||||
|
||||
# Add remarks if available
|
||||
if "remark" in keyList:
|
||||
print()
|
||||
if isinstance(option['remark'], list):
|
||||
for remark in option['remark']:
|
||||
print(f" {remark}")
|
||||
else:
|
||||
print(f" {option['remark']}")
|
||||
|
||||
print()
|
||||
|
||||
|
||||
###### Examples ######
|
||||
@@ -246,12 +305,22 @@ def main():
|
||||
print(exampleSection)
|
||||
|
||||
|
||||
###### See Also ######
|
||||
|
||||
print(".SH \"SEE ALSO\"")
|
||||
print(".BR neofetch (1)")
|
||||
|
||||
|
||||
###### Bugs ######
|
||||
|
||||
print(".SH BUGS")
|
||||
print(bugSection)
|
||||
|
||||
|
||||
###### Authors ######
|
||||
|
||||
print(".SH AUTHORS")
|
||||
print(authorsSection)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ibireme/yyjson",
|
||||
"license": "MIT ( embed in source )",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.1",
|
||||
"author": "ibireme"
|
||||
}
|
||||
|
||||
Vendored
+2508
-1264
File diff suppressed because it is too large
Load Diff
Vendored
+800
-570
File diff suppressed because it is too large
Load Diff
@@ -134,7 +134,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-2
@@ -32,10 +32,16 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_FLOAT:
|
||||
ffStrbufAppendF(buffer, "%f", *(float*)formatarg->value);
|
||||
if (instance.config.display.fractionNdigits >= 0)
|
||||
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(float*)formatarg->value);
|
||||
else
|
||||
ffStrbufAppendF(buffer, "%g", *(float*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_DOUBLE:
|
||||
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
|
||||
if (instance.config.display.fractionNdigits >= 0)
|
||||
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(double*)formatarg->value);
|
||||
else
|
||||
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_BOOL:
|
||||
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
|
||||
@@ -108,6 +114,7 @@ static inline bool formatArgSet(const FFformatarg* arg)
|
||||
{
|
||||
return arg->value != NULL && (
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) || //Also is false for NaN
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/init.h"
|
||||
#include "common/parsing.h"
|
||||
#include "common/thread.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
@@ -104,6 +105,7 @@ void ffStart(void)
|
||||
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
|
||||
#ifdef _WIN32
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
if (instance.config.display.noBuffer)
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
else
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
void ffInitInstance(void);
|
||||
void ffStart(void);
|
||||
void ffFinish(void);
|
||||
void ffDestroyInstance(void);
|
||||
void ffListFeatures(void);
|
||||
+1
-21
@@ -19,8 +19,7 @@
|
||||
#define FF_INVALID_FD (-1)
|
||||
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
|
||||
// one safe way to read correct data is reading the whole file in a single read syscall
|
||||
// 8192 comes from procps-ng: https://gitlab.com/procps-ng/procps/-/blob/master/library/meminfo.c?ref_type=heads#L39
|
||||
#define PROC_FILE_BUFFSIZ 8192
|
||||
#define PROC_FILE_BUFFSIZ (32 * 1024)
|
||||
#endif
|
||||
|
||||
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
|
||||
@@ -119,7 +118,6 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (__APPLE__ || __HAIKU__) // #1395
|
||||
struct stat fileStat;
|
||||
if(stat(path, &fileStat) != 0)
|
||||
return false;
|
||||
@@ -131,24 +129,6 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
|
||||
if(pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR)
|
||||
return true;
|
||||
#else
|
||||
size_t len = strlen(path);
|
||||
assert(len < PATH_MAX);
|
||||
if (len == 0) return false;
|
||||
|
||||
int ret;
|
||||
if (path[len - 1] != '/')
|
||||
{
|
||||
char buf[PATH_MAX + 1];
|
||||
memcpy(buf, path, len);
|
||||
buf[len] = '/';
|
||||
buf[len + 1] = 0;
|
||||
ret = access(buf, F_OK);
|
||||
}
|
||||
else
|
||||
ret = access(path, F_OK);
|
||||
return pathType == FF_PATHTYPE_DIRECTORY ? ret == 0 : ret == -1 && errno == ENOTDIR;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -290,7 +290,7 @@ bool ffSuppressIO(bool suppress)
|
||||
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
|
||||
if (dfd < 0)
|
||||
return;
|
||||
|
||||
|
||||
@@ -147,6 +147,14 @@ ssize_t ffReadFileDataRelative(HANDLE dfd, const char* fileName, size_t dataSize
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
if (in[0] == '~') {
|
||||
if ((in[1] == '/' || in[1] == '\\' || in[1] == '\0') && !ffStrContainsC(in, '%')) {
|
||||
ffStrbufSet(out, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(out, in + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD length = ExpandEnvironmentStringsA(in, NULL, 0);
|
||||
if (length <= 1) return false;
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
|
||||
FF_MAYBE_UNUSED void* libraryObjectName = NULL; // Placeholder
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
|
||||
symbolMapping = (__typeof__(&symbolName)) &symbolName
|
||||
symbolMapping = (__typeof__(&symbolName)) &symbolName;
|
||||
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "util/debug.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
#include <poll.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
|
||||
@@ -177,6 +177,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
if (ffCharIsEnglishAlphabet(value[0]))
|
||||
{
|
||||
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
|
||||
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
|
||||
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
|
||||
@@ -212,6 +213,35 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
exit(479);
|
||||
}
|
||||
}
|
||||
else if (value[0] == '#')
|
||||
{
|
||||
// RGB color
|
||||
++value;
|
||||
char* pend = NULL;
|
||||
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
|
||||
if (pend == value) {
|
||||
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
if (pend - value > 6) {
|
||||
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
else if (pend - value == 3) {
|
||||
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
|
||||
((rgb & 0x0F0) >> 4) * 0x001100 +
|
||||
((rgb & 0x00F) >> 0) * 0x000011;
|
||||
}
|
||||
else if (pend - value != 6) {
|
||||
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
|
||||
uint32_t r = rgb >> 16, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
|
||||
ffStrbufAppendF(buffer, FF_COLOR_FG_RGB "%u;%u;%u", r, g, b);
|
||||
value = pend;
|
||||
continue;
|
||||
}
|
||||
ffStrbufAppendC(buffer, *value);
|
||||
++value;
|
||||
|
||||
|
||||
+15
-8
@@ -190,19 +190,26 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
}
|
||||
}
|
||||
|
||||
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result)
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
if(days == 0 && hours == 0 && minutes == 0)
|
||||
if(totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u seconds", seconds);
|
||||
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
if(seconds >= 30)
|
||||
{
|
||||
minutes++;
|
||||
seconds = 0;
|
||||
}
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
totalSeconds++;
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
uint32_t hours = (uint32_t) (totalSeconds % 24);
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if(days > 0)
|
||||
{
|
||||
|
||||
@@ -27,4 +27,4 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
|
||||
|
||||
void ffParseSize(uint64_t bytes, FFstrbuf* result);
|
||||
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
|
||||
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result);
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/printing.h"
|
||||
#include "logo/logo.h"
|
||||
#include "util/textModifier.h"
|
||||
|
||||
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType)
|
||||
@@ -99,7 +100,7 @@ void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleAr
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
|
||||
static void printError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, va_list arguments)
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
if(!instance.config.display.showErrors)
|
||||
return;
|
||||
@@ -109,7 +110,10 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
|
||||
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
vprintf(message, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
@@ -117,14 +121,6 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
printError(moduleName, moduleIndex, moduleArgs, printType, message, arguments);
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
void ffPrintColor(const FFstrbuf* colorValue)
|
||||
{
|
||||
//If the color is not set, this would reset in \033[m, which resets everything.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <spawn.h>
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
@@ -33,6 +34,10 @@
|
||||
#include <image.h>
|
||||
#endif
|
||||
|
||||
#ifndef environ
|
||||
extern char** environ;
|
||||
#endif
|
||||
|
||||
enum { FF_PIPE_BUFSIZ = 8192 };
|
||||
|
||||
static inline int ffPipe2(int* fds, int flags)
|
||||
@@ -48,6 +53,8 @@ static inline int ffPipe2(int* fds, int flags)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Not thread-safe
|
||||
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
|
||||
{
|
||||
int pipes[2];
|
||||
@@ -56,28 +63,63 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
if(ffPipe2(pipes, O_CLOEXEC) == -1)
|
||||
return "pipe() failed";
|
||||
|
||||
pid_t childPid = fork();
|
||||
if(childPid == -1)
|
||||
posix_spawn_file_actions_t file_actions;
|
||||
posix_spawn_file_actions_init(&file_actions);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
posix_spawn_file_actions_addopen(&file_actions, useStdErr ? STDOUT_FILENO : STDERR_FILENO, "/dev/null", O_WRONLY, 0);
|
||||
pid_t childPid = -1;
|
||||
|
||||
static char* oldLang = NULL;
|
||||
static int langIndex = -1;
|
||||
|
||||
if (langIndex >= 0)
|
||||
{
|
||||
// Found before
|
||||
if (oldLang) // oldLang was set only if it needed to be changed
|
||||
{
|
||||
if (environ[langIndex] != oldLang)
|
||||
{
|
||||
// environ is changed outside of this function
|
||||
langIndex = -1;
|
||||
}
|
||||
else
|
||||
environ[langIndex] = (char*) "LANG=C.UTF-8";
|
||||
}
|
||||
}
|
||||
if (langIndex < 0)
|
||||
{
|
||||
for (int i = 0; environ[i] != NULL; i++)
|
||||
{
|
||||
if (ffStrStartsWith(environ[i], "LANG="))
|
||||
{
|
||||
langIndex = i;
|
||||
const char* langValue = environ[i] + 5; // Skip "LANG="
|
||||
if (ffStrEqualsIgnCase(langValue, "C") ||
|
||||
ffStrStartsWithIgnCase(environ[i], "C.") ||
|
||||
ffStrEqualsIgnCase(langValue, "en_US") ||
|
||||
ffStrStartsWithIgnCase(langValue, "en_US."))
|
||||
break; // No need to change LANG
|
||||
oldLang = environ[i];
|
||||
environ[i] = (char*) "LANG=C.UTF-8"; // Set LANG to C.UTF-8 for consistent output
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
|
||||
|
||||
if (oldLang)
|
||||
environ[langIndex] = oldLang;
|
||||
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
close(pipes[1]);
|
||||
if (ret != 0)
|
||||
{
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
return "fork() failed";
|
||||
return "posix_spawnp() failed";
|
||||
}
|
||||
|
||||
//Child
|
||||
if(childPid == 0)
|
||||
{
|
||||
int nullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
|
||||
setenv("LANG", "C", 1);
|
||||
execvp(argv[0], argv);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
//Parent
|
||||
close(pipes[1]);
|
||||
|
||||
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
|
||||
@@ -86,20 +128,30 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
if (timeout >= 0)
|
||||
{
|
||||
struct pollfd pollfd = { childPipeFd, POLLIN, 0 };
|
||||
if (poll(&pollfd, 1, timeout) == 0)
|
||||
int pollret = poll(&pollfd, 1, timeout);
|
||||
if (pollret == 0)
|
||||
{
|
||||
kill(childPid, SIGTERM);
|
||||
waitpid(childPid, NULL, 0);
|
||||
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
|
||||
}
|
||||
else if (errno == EINTR)
|
||||
else if (pollret < 0)
|
||||
{
|
||||
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
|
||||
if (waitpid(childPid, NULL, WNOHANG) == childPid)
|
||||
if (errno == EINTR)
|
||||
{
|
||||
// Read remaining data from the pipe
|
||||
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
|
||||
childPid = -1;
|
||||
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
|
||||
if (waitpid(childPid, NULL, WNOHANG) == childPid)
|
||||
{
|
||||
// Read remaining data from the pipe
|
||||
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
|
||||
childPid = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kill(childPid, SIGTERM);
|
||||
waitpid(childPid, NULL, 0);
|
||||
return "poll(&pollfd, 1, timeout) error";
|
||||
}
|
||||
}
|
||||
else if (pollfd.revents & POLLERR)
|
||||
@@ -279,8 +331,10 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
|
||||
psinfo_t proc;
|
||||
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc))
|
||||
{
|
||||
ffStrbufSetS(exe, proc.pr_psargs);
|
||||
ffStrbufSubstrBeforeFirstC(exe, ' ');
|
||||
const char* args = proc.pr_psargs;
|
||||
if (args[0] == '-') ++args;
|
||||
const char* end = strchr(args, ' ');
|
||||
ffStrbufSetNS(exe, end ? (uint32_t) (end - args) : (uint32_t) strlen(args), args);
|
||||
}
|
||||
|
||||
if (exePath)
|
||||
|
||||
@@ -130,7 +130,11 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
if (!timeout || WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
#if __aarch64__
|
||||
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
|
||||
#else
|
||||
// To support Windows 7
|
||||
if (timeout >= 0 && WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
@@ -138,13 +142,18 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
}
|
||||
|
||||
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
|
||||
#endif
|
||||
{
|
||||
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||
return NULL;
|
||||
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
return "GetOverlappedResult(hChildPipeRead) failed";
|
||||
return "GetOverlappedResult"
|
||||
#if __aarch64__
|
||||
"Ex"
|
||||
#endif
|
||||
"(hChildPipeRead) failed";
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -97,3 +97,47 @@ static inline const char* ffTimeToTimeStr(uint64_t msec)
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
typedef struct FFTimeGetAgeResult
|
||||
{
|
||||
uint32_t years;
|
||||
uint32_t daysOfYear;
|
||||
double yearsFraction;
|
||||
} FFTimeGetAgeResult;
|
||||
|
||||
static inline FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
|
||||
{
|
||||
FFTimeGetAgeResult result = {};
|
||||
if (__builtin_expect(birthMs == 0 || nowMs < birthMs, 0))
|
||||
return result;
|
||||
|
||||
time_t birth_s = (time_t) (birthMs / 1000);
|
||||
struct tm birth_tm;
|
||||
#ifdef _WIN32
|
||||
localtime_s(&birth_tm, &birth_s);
|
||||
#else
|
||||
localtime_r(&birth_s, &birth_tm);
|
||||
#endif
|
||||
|
||||
time_t now_s = (time_t) (nowMs / 1000);
|
||||
struct tm now_tm;
|
||||
#ifdef _WIN32
|
||||
localtime_s(&now_tm, &now_s);
|
||||
#else
|
||||
localtime_r(&now_s, &now_tm);
|
||||
#endif
|
||||
|
||||
result.years = (uint32_t) (now_tm.tm_year - birth_tm.tm_year);
|
||||
if (now_tm.tm_yday < birth_tm.tm_yday)
|
||||
result.years--;
|
||||
|
||||
birth_tm.tm_year += (int) result.years;
|
||||
birth_s = mktime(&birth_tm);
|
||||
uint32_t diff_s = (uint32_t) (now_s - birth_s);
|
||||
result.daysOfYear = diff_s / (24 * 60 * 60);
|
||||
|
||||
birth_tm.tm_year += 1;
|
||||
result.yearsFraction = (double) diff_s / (double) (mktime(&birth_tm) - birth_s) + result.years;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+191
-165
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
||||
Usage: fastfetch --color <color>
|
||||
|
||||
Shortcut of `fastfetch --color-keys <color> --color-title <color>`.
|
||||
If no color is set, the main color of the logo will be used.
|
||||
|
||||
Following information applies to all settings
|
||||
|
||||
<color> must be a color encoding as ANSI escape sequences. It is inserted between "ESC[" and "m".
|
||||
Infos about them can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters.
|
||||
Examples:
|
||||
35: sets the color to magenta
|
||||
38;5;38: sets the color to 38th color of ANSI 256 colors
|
||||
4;92: sets the color to bright green with underline
|
||||
5;104: blinking text on a blue background
|
||||
|
||||
ANSI named colors are also supported:
|
||||
magenta: equivalent to `35`
|
||||
underline_bright_green: equivalent to `4;92`
|
||||
|
||||
After v2.15.0, some special keys can be used:
|
||||
keys: use the color set by `--color-keys`
|
||||
title: use the color set by `--color-title`
|
||||
output: use the color set by `--color-output`
|
||||
separator: use the color set by `--color-separator`
|
||||
@@ -1,4 +0,0 @@
|
||||
Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci"
|
||||
If a value starts with a ?, it is optional. An optional boolean value defaults to true if not specified.
|
||||
More detailed help messages for each options can be printed with "-h <option_without_dash_prefix>"
|
||||
All options can be made permanent with command "fastfetch <options> --gen-config"
|
||||
@@ -1,55 +0,0 @@
|
||||
A format string is a string that contains placeholders for values.
|
||||
These placeholders begin with a '{', containing the index of the value, and end with a '}'.
|
||||
For example the format string "Values: {1} ({2})", with the values "First" and "My second val", will produce "Values: First (My second val)".
|
||||
The format string can contain placeholders in any order and have multiple occurrences.
|
||||
To include spaces when setting from the command line, surround the whole string with double quotes (").
|
||||
|
||||
In 2.14.0 or newer, the value indices can be meaningful named tags.
|
||||
For example: "--title-format '{user-name-colored}{at-symbol-colored}{host-name-colored}'" is equivalent to "--title-format '{6}{7}{8}'"
|
||||
See "fastfetch -h title-format" for all supported tags.
|
||||
|
||||
In 2.17.0 or newer, a truncation length can be specified using syntax '<arg>:<trunc-length>`
|
||||
For example: "--title-format '{user-name:5}'" will truncate user name into 5-length string.
|
||||
If '<trunc-length>' is negative, an ellipsis … will be appended at the end when the original string is truncated.
|
||||
Note: The string length is counted in raw bytes. Multi-byte unicode characters and ANSI escape codes are not taken into account.
|
||||
|
||||
In 2.23.0 or newer, `<` or `>` can be specified instead of `:` to set a left or right padding.
|
||||
For example: "--title-format '{user-name<20}'" will generate `<user-name> `;
|
||||
"--title-format '{user-name>20}'" will generate ` <user-name>`
|
||||
|
||||
In 2.24.0 or newer, `{~startIndex,endIndex}` can be specified to slice a string. Negative index counts back from the end of the string.
|
||||
If an index is omitted, 0 is used. For example, both `{~,0}` `{~0,}` and `{~,}` are same as `{~0,0}` and will always generate a empty string.
|
||||
If `,endIndex` is omitted or greater than the length of the string, the length of string is used.
|
||||
|
||||
In 2.36.0 or newer, `{$NUM}` can be specified to reference a constant defined in `display.constants`. `{$ENV_VAR}` can be specified to reference an environment variable.
|
||||
|
||||
If the value index is missing, meaning the placeholder is "{}", an internal counter sets the value index.
|
||||
This means that the format string "Values: {1} ({2})" is equivalent to "Values: {} ({})".
|
||||
Note that this counter only counts empty placeholders, so the format string "{2} {} {}" will contain the second value, then the first, and then the second again.
|
||||
|
||||
To make formatting easier, a double open curly brace ("{{") will be printed as a single open curly brace and not counted as the beginning of a placeholder.
|
||||
If a value index is misformatted or wants a non-existing value, it will be printed as is, with the curly braces around it.
|
||||
If the last placeholder isn't closed, it will be treated like it was at the end of the format string.
|
||||
|
||||
To only print something if a variable is set, use "{?<index>} ... {?}".
|
||||
For example, to only print a second value if it is set, use "{?2} Second value: {2}{?}".
|
||||
If a "{?}" is found without an opener, it is printed as is.
|
||||
|
||||
To only print something if a variable is not set, do the same as with if, just replace every '?' with a '/'.
|
||||
For example to print a fallback for a second value if it is not set, use "{?2}{2}{?}{/2}Second value fallback{/}".
|
||||
|
||||
To stop formatting at any point in the format string, use "{-}".
|
||||
|
||||
To print something with color, start a placeholder with a '#' and then the linux terminal color encoding.
|
||||
"\033[" at the start, and an 'm' at the end is automatically added, so don't do that.
|
||||
A "{#}" is equivalent to a "{#0}" and resets everything to normal.
|
||||
For example to print something pink and underline, use "{#4;35}...{#}". "{#underline_magenta}" is also supported. See `fastfetch -h color` for detail.
|
||||
Information about what the numbers mean can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters.
|
||||
Which escape codes are supported and how they look is defined by your terminal.
|
||||
|
||||
If a format string evaluates to an empty value, the whole line in the output will be discarded.
|
||||
You can therefore use --host-format " " to disable host output.
|
||||
Note that --host-format "" would evaluate as not set, and therefore use the built-in host format
|
||||
|
||||
Format string is also the way to go to set a fixed value - just use one without placeholders.
|
||||
For example when running in headless mode, you could use "--display-format Preferred".
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
|
||||
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
|
||||
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
|
||||
|
||||
prop_dictionary_t root = NULL;
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (devfd < 0) return "open(dev/apm, O_RDONLY) failed";
|
||||
if (devfd < 0) return "open(dev/apm, O_RDONLY | O_CLOEXEC) failed";
|
||||
|
||||
struct apm_power_info info = {};
|
||||
|
||||
|
||||
@@ -8,40 +8,31 @@
|
||||
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <batclass.h>
|
||||
#include <devguid.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <winternl.h>
|
||||
|
||||
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
|
||||
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
if(*hdev)
|
||||
SetupDiDestroyDeviceInfoList(*hdev);
|
||||
}
|
||||
//https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces
|
||||
ULONG cchDeviceInterfaces = 0;
|
||||
CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&cchDeviceInterfaces, (LPGUID)&GUID_DEVCLASS_BATTERY, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
|
||||
if (cr != CR_SUCCESS)
|
||||
return "CM_Get_Device_Interface_List_SizeW() failed";
|
||||
|
||||
static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
//https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices
|
||||
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
|
||||
SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
||||
if(hdev == INVALID_HANDLE_VALUE)
|
||||
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY) failed";
|
||||
if (cchDeviceInterfaces <= 1)
|
||||
return NULL; // Not found
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA did = { .cbSize = sizeof(did) };
|
||||
for(DWORD idev = 0; SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did); idev++)
|
||||
wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*)malloc(cchDeviceInterfaces * sizeof(wchar_t));
|
||||
cr = CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVCLASS_BATTERY, NULL, mszDeviceInterfaces, cchDeviceInterfaces, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
|
||||
if (cr != CR_SUCCESS)
|
||||
return "CM_Get_Device_Interface_ListW() failed";
|
||||
|
||||
for (const wchar_t* pDeviceInterface = mszDeviceInterfaces; *pDeviceInterface; pDeviceInterface += wcslen(pDeviceInterface) + 1)
|
||||
{
|
||||
DWORD cbRequired = 0;
|
||||
SetupDiGetDeviceInterfaceDetailW(hdev, &did, NULL, 0, &cbRequired, NULL); //Fail with not enough buffer
|
||||
SP_DEVICE_INTERFACE_DETAIL_DATA_W* FF_AUTO_FREE pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)malloc(cbRequired);
|
||||
if(!pdidd)
|
||||
break; //Out of memory
|
||||
|
||||
pdidd->cbSize = sizeof(*pdidd);
|
||||
if(!SetupDiGetDeviceInterfaceDetailW(hdev, &did, pdidd, cbRequired, &cbRequired, NULL))
|
||||
continue;
|
||||
|
||||
HANDLE FF_AUTO_CLOSE_FD hBattery =
|
||||
CreateFileW(pdidd->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
CreateFileW(pDeviceInterface, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if(hBattery == INVALID_HANDLE_VALUE)
|
||||
continue;
|
||||
@@ -99,7 +90,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
|
||||
bqi.InformationLevel = BatteryManufactureDate;
|
||||
BATTERY_MANUFACTURE_DATE date;
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL))
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day);
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year < 1000 ? date.Year + 1900 : date.Year, date.Month, date.Day);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -131,7 +122,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
|
||||
{
|
||||
BATTERY_STATUS bs;
|
||||
BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi.BatteryTag };
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY)
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0)
|
||||
battery->capacity = bs.Capacity * 100.0 / bi.FullChargedCapacity;
|
||||
else
|
||||
battery->capacity = 0;
|
||||
@@ -271,6 +262,6 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
return options->useSetupApi
|
||||
? detectWithSetupApi(options, results)
|
||||
? detectWithCmApi(options, results)
|
||||
: detectWithNtApi(options, results);
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#elif __sun
|
||||
#include <libdevinfo.h>
|
||||
#include <sys/sunddi.h>
|
||||
#endif
|
||||
|
||||
typedef struct FFSmbiosBios
|
||||
@@ -59,6 +63,7 @@ typedef struct FFSmbiosBios
|
||||
static_assert(offsetof(FFSmbiosBios, ExtendedBiosRomSize) == 0x18,
|
||||
"FFSmbiosBios: Wrong struct alignment");
|
||||
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
@@ -94,6 +99,17 @@ const char* ffDetectBios(FFBiosResult* bios)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#elif __sun
|
||||
di_node_t rootNode = di_init("/", DINFOPROP);
|
||||
if (rootNode != DI_NODE_NIL)
|
||||
{
|
||||
char* efiVersion = NULL;
|
||||
if (di_prop_lookup_strings(DDI_DEV_T_ANY, rootNode, "efi-version", &efiVersion) > 0)
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
else
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
}
|
||||
di_fini(rootNode);
|
||||
#elif __HAIKU__ || __OpenBSD__
|
||||
// Currently SMBIOS detection is supported in legancy BIOS only
|
||||
ffStrbufSetStatic(&bios->type, "BIOS");
|
||||
|
||||
@@ -6,7 +6,13 @@
|
||||
static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFlist* devices)
|
||||
{
|
||||
FFBluetoothResult* device = ffListAdd(devices);
|
||||
ffStrbufInitS(&device->name, bt_devremote_name_gen(dev->devname, &dev->bdaddr));
|
||||
ffStrbufInitS(&device->name,
|
||||
#if __FreeBSD__
|
||||
bt_devremote_name_gen(dev->devname, &dev->bdaddr)
|
||||
#else
|
||||
dev->devname
|
||||
#endif
|
||||
);
|
||||
ffStrbufInitS(&device->address, bt_ntoa(&dev->bdaddr, NULL));
|
||||
ffStrbufUpperCase(&device->address);
|
||||
ffStrbufInit(&device->type);
|
||||
|
||||
@@ -232,7 +232,7 @@ static uint32_t connectedDevices(void)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
int32_t connectedCount = -1;
|
||||
|
||||
@@ -9,9 +9,19 @@ const char* ffDetectBoard(FFBoardResult* result)
|
||||
if (!service)
|
||||
return "No IOPlatformExpertDevice found";
|
||||
|
||||
io_name_t name;
|
||||
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
|
||||
ffStrbufSetS(&result->name, name);
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef boardId = IORegistryEntryCreateCFProperty(service, CFSTR("board-id"), kCFAllocatorDefault, kNilOptions);
|
||||
if (boardId)
|
||||
ffCfStrGetString(boardId, &result->name);
|
||||
else
|
||||
{
|
||||
io_name_t name;
|
||||
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
|
||||
ffStrbufSetS(&result->name, name);
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(service, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (version)
|
||||
ffCfStrGetString(version, &result->version);
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
|
||||
if (manufacturer)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR);
|
||||
FF_AUTO_CLOSE_FD int efifd = open("/dev/efi", O_RDWR | O_CLOEXEC);
|
||||
if (efifd < 0) return "open(/dev/efi) failed";
|
||||
|
||||
uint8_t buffer[2048];
|
||||
|
||||
@@ -12,7 +12,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
for (char i = '0'; i <= '9'; ++i) {
|
||||
path[strlen("/dev/ttyC")] = i;
|
||||
|
||||
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int devfd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (devfd < 0) {
|
||||
if (errno == EACCES && i == '0')
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
#include <linux/videodev2.h>
|
||||
#elif __has_include(<sys/videoio.h>) // OpenBSD
|
||||
#include <sys/videoio.h>
|
||||
#define FF_HAVE_LINUX_VIDEODEV2 1
|
||||
#endif
|
||||
|
||||
const char* ffDetectCamera(FFlist* result)
|
||||
@@ -17,9 +20,15 @@ const char* ffDetectCamera(FFlist* result)
|
||||
for (uint32_t i = 0; i <= 9; ++i)
|
||||
{
|
||||
path[ARRAY_SIZE(path) - 2] = (char) (i + '0');
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
break;
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
return "Failed to open /dev/videoN";
|
||||
}
|
||||
|
||||
struct v4l2_capability cap = {};
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
|
||||
@@ -106,9 +106,14 @@ static const char* armPartId2name(uint32_t partId)
|
||||
case 0xd80: return "Cortex-A520";
|
||||
case 0xd81: return "Cortex-A720";
|
||||
case 0xd82: return "Cortex-X4";
|
||||
case 0xd83: return "Neoverse-V3AE";
|
||||
case 0xd84: return "Neoverse-V3";
|
||||
case 0xd85: return "Cortex-X925";
|
||||
case 0xd87: return "Cortex-A725";
|
||||
case 0xd88: return "Cortex-A520AE";
|
||||
case 0xd89: return "Cortex-A720AE";
|
||||
case 0xd8e: return "Neoverse-N3";
|
||||
case 0xd8f: return "Cortex-A320";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -314,6 +319,7 @@ static const char* fujitsuPartId2name(uint32_t partId)
|
||||
switch (partId)
|
||||
{
|
||||
case 0x001: return "A64FX";
|
||||
case 0x003: return "MONAKA";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+36
-23
@@ -1,5 +1,6 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#if __has_include(<sys/cpuset.h>)
|
||||
@@ -34,36 +35,30 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if (ffSysctlGetString("hw.model", &cpu->name) != NULL)
|
||||
return "sysctlbyname(hw.model) failed";
|
||||
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresLogical = cpu->coresPhysical;
|
||||
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (ffSysctlGetString("kern.sched.topology_spec", &buffer) == NULL && buffer.length > 0)
|
||||
{
|
||||
// <groups>
|
||||
// <group level="1" cache-level="3">
|
||||
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
|
||||
// <children>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="3,0,0,0">0, 1</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="c,0,0,0">2, 3</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// </children>
|
||||
// </group>
|
||||
// <group level="1" cache-level="3">
|
||||
// <cpu count="4" mask="f,0,0,0">0, 1, 2, 3</cpu>
|
||||
// <children>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="3,0,0,0">0, 1</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// <group level="2" cache-level="2">
|
||||
// <cpu count="2" mask="c,0,0,0">2, 3</cpu>
|
||||
// <flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
|
||||
// </group>
|
||||
// </children>
|
||||
// </group>
|
||||
// </groups>
|
||||
uint32_t i = 0;
|
||||
while (true)
|
||||
{
|
||||
i = ffStrbufNextIndexS(&buffer, i, "<flag name=\"THREAD\">THREAD group</flag>"); // Find physical core with hyper-threading enabled
|
||||
if (i >= buffer.length) break;
|
||||
cpu->coresPhysical--;
|
||||
i += (uint32_t) strlen("<flag name=\"THREAD\">THREAD group</flag>");
|
||||
}
|
||||
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p)
|
||||
cpu->packages++;
|
||||
}
|
||||
|
||||
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
|
||||
@@ -79,6 +74,24 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
|
||||
uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
|
||||
if (clockrate > cpu->frequencyBase) cpu->frequencyBase = clockrate;
|
||||
|
||||
for (uint16_t i = 0; i < cpu->coresLogical; ++i)
|
||||
{
|
||||
ffStrbufClear(&buffer);
|
||||
char key[32];
|
||||
snprintf(key, sizeof(key), "dev.cpu.%u.freq_levels", i);
|
||||
if (ffSysctlGetString(key, &buffer) == NULL)
|
||||
{
|
||||
if (buffer.length == 0) continue;
|
||||
|
||||
// MHz/Watts pairs like: 2501/32000 2187/27125 2000/24000
|
||||
uint32_t fmax = (uint32_t) strtoul(buffer.chars, NULL, 10);
|
||||
if (cpu->frequencyMax < fmax) cpu->frequencyMax = fmax;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
if (options->temp)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FF_CPUINFO_PATH "/proc/cpuinfo"
|
||||
|
||||
@@ -432,11 +433,11 @@ FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo)
|
||||
{
|
||||
p += strlen("\nphysical id\t:");
|
||||
char* pend;
|
||||
unsigned long id = strtoul(p, &pend, 10);
|
||||
unsigned long long id = strtoul(p, &pend, 10);
|
||||
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
|
||||
high |= 1 << (id - 64);
|
||||
high |= 1ULL << (id - 64);
|
||||
else
|
||||
low |= 1 << id;
|
||||
low |= 1ULL << id;
|
||||
p = pend;
|
||||
}
|
||||
|
||||
@@ -458,9 +459,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
|
||||
cpu->coresOnline = (uint16_t) get_nprocs();
|
||||
cpu->packages = getPackageCount(&cpuinfo);
|
||||
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, 0); // physical cores in single package
|
||||
if (cpu->coresPhysical == 0)
|
||||
cpu->coresPhysical = cpu->coresLogical;
|
||||
else if (cpu->packages > 1)
|
||||
if (cpu->coresPhysical > 0 && cpu->packages > 1)
|
||||
cpu->coresPhysical *= cpu->packages;
|
||||
|
||||
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
|
||||
@@ -473,6 +472,82 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
|
||||
|
||||
#else
|
||||
|
||||
static const char* detectPhysicalCores(FFCPUResult* cpu)
|
||||
{
|
||||
int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if (dfd < 0) return "open(\"/sys/devices/system/cpu/\") failed";
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
|
||||
if (!dir) return "fdopendir(dfd) failed";
|
||||
|
||||
uint64_t pkgLow = 0, pkgHigh = 0;
|
||||
|
||||
struct dirent* entry;
|
||||
FF_LIST_AUTO_DESTROY cpuList = ffListCreate(sizeof(uint32_t));
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
if (entry->d_type != DT_DIR || !ffStrStartsWith(entry->d_name, "cpu") || !ffCharIsDigit(entry->d_name[strlen("cpu")]))
|
||||
continue;
|
||||
|
||||
FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY);
|
||||
if (cpuxfd < 0)
|
||||
continue;
|
||||
|
||||
char buf[128];
|
||||
|
||||
// Check if the directory contains a file named "topology/physical_package_id"
|
||||
// that lists the physical package id of the CPU.
|
||||
|
||||
ssize_t len = ffReadFileDataRelative(cpuxfd, "topology/physical_package_id", sizeof(buf) - 1, buf);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = '\0';
|
||||
unsigned long long id = strtoul(buf, NULL, 10);
|
||||
if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist?
|
||||
pkgHigh |= 1ULL << (id - 64);
|
||||
else
|
||||
pkgLow |= 1ULL << id;
|
||||
}
|
||||
|
||||
// Check if the directory contains a file named "topology/core_cpus_list"
|
||||
// that lists the physical cores in the package.
|
||||
|
||||
len = ffReadFileDataRelative(cpuxfd, "topology/core_cpus_list", sizeof(buf) - 1, buf);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = '\0'; // low-high or low
|
||||
|
||||
for (const char* p = buf; *p;)
|
||||
{
|
||||
char* pend;
|
||||
uint32_t coreId = (uint32_t) strtoul(p, &pend, 10);
|
||||
if (pend == p) break;
|
||||
|
||||
bool found = false;
|
||||
FF_LIST_FOR_EACH(uint32_t, id, cpuList)
|
||||
{
|
||||
if (*id == coreId)
|
||||
{
|
||||
// This core is already counted
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
*(uint32_t*) ffListAdd(&cpuList) = coreId;
|
||||
|
||||
p = strchr(pend, ',');
|
||||
if (!p) break;
|
||||
++p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu->coresPhysical = (uint16_t) cpuList.length;
|
||||
cpu->packages = (uint16_t) (__builtin_popcountll(pkgLow) + __builtin_popcountll(pkgHigh));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static void parseIsa(FFstrbuf* cpuIsa)
|
||||
{
|
||||
// Always use the last part of the ISA string. Ref: #590 #1204
|
||||
@@ -601,7 +676,7 @@ FF_MAYBE_UNUSED static uint16_t getLoongarchPropCount(FFstrbuf* cpuinfo, const c
|
||||
|
||||
FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
cpu->coresPhysical = cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
||||
cpu->coresLogical = (uint16_t) get_nprocs_conf();
|
||||
cpu->coresOnline = (uint16_t) get_nprocs();
|
||||
|
||||
#if __ANDROID__
|
||||
@@ -663,6 +738,9 @@ FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options,
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cpu->coresPhysical == 0)
|
||||
detectPhysicalCores(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,8 +18,8 @@ static void freePropDict(prop_dictionary_t* pdict)
|
||||
|
||||
static const char* detectCpuTemp(double* current)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
|
||||
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
|
||||
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY | O_CLOEXEC) failed";
|
||||
|
||||
__attribute__((__cleanup__(freePropDict))) prop_dictionary_t root = NULL;
|
||||
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
|
||||
@@ -51,7 +51,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString("machdep.cpu_brand", &cpu->name) != NULL &&
|
||||
ffSysctlGetString("machdep.dmi.processor-version", &cpu->name) != NULL &&
|
||||
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL)
|
||||
ffSysctlGetString("hw.cpu0.name", &cpu->name) != NULL &&
|
||||
ffSysctlGetString("hw.model", &cpu->name) != NULL)
|
||||
{
|
||||
ffStrbufSetS(&cpu->name, "Unknown CPU");
|
||||
}
|
||||
@@ -67,6 +68,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
|
||||
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
|
||||
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
|
||||
if (freq == 0) freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
|
||||
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
@@ -1,10 +1,53 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sensors.h>
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
static const char* detectCPUTemp(FFCPUResult* cpu)
|
||||
{
|
||||
int mib[5] = {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0};
|
||||
|
||||
for (mib[2] = 0; mib[2] < 1024; mib[2]++)
|
||||
{
|
||||
struct sensordev sensordev;
|
||||
size_t sdlen = sizeof(struct sensordev);
|
||||
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
return "sysctl(sensordev) failed";
|
||||
}
|
||||
|
||||
if (!ffStrStartsWith(sensordev.xname, "cpu"))
|
||||
continue;
|
||||
|
||||
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++)
|
||||
{
|
||||
struct sensor sensor;
|
||||
size_t slen = sizeof(struct sensor);
|
||||
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return "sysctl(sensor) failed";
|
||||
continue;
|
||||
}
|
||||
if (sensor.flags & SENSOR_FINVALID)
|
||||
continue;
|
||||
|
||||
cpu->temperature = (double)(sensor.value - 273150000) / 1E6;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "No sensor for CPU temp found";
|
||||
}
|
||||
|
||||
const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name))
|
||||
return "sysctl(hw.model) failed";
|
||||
@@ -19,13 +62,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
struct sensor sensors;
|
||||
size_t size = sizeof(sensors);
|
||||
if (sysctl((int[]) {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0}, 5, &sensors, &size, NULL, 0) == 0)
|
||||
cpu->temperature = (double) (sensors.value - 273150000) / 1E6;
|
||||
}
|
||||
if (options->temp) detectCPUTemp(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
#include "cpu.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include <kstat.h>
|
||||
|
||||
static const char* detectCPUTempByKstat(kstat_ctl_t* kc, FFCPUResult* cpu)
|
||||
{
|
||||
const char* possibleModules[] = {"temperature", "cpu_temp", "acpi_thermal", NULL};
|
||||
|
||||
for (int i = 0; possibleModules[i] != NULL; i++) {
|
||||
kstat_t* ks = kstat_lookup(kc, possibleModules[i], -1, NULL);
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0) {
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "temperature");
|
||||
if (kn) {
|
||||
switch (kn->data_type) {
|
||||
case KSTAT_DATA_INT32:
|
||||
cpu->temperature = (float)kn->value.i32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_UINT32:
|
||||
cpu->temperature = (float)kn->value.ui32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_FLOAT:
|
||||
cpu->temperature = kn->value.f;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "Failed to find CPU temperature using kstat";
|
||||
}
|
||||
|
||||
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
"ipmitool",
|
||||
"-c",
|
||||
"sdr",
|
||||
"list",
|
||||
NULL
|
||||
});
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, &buffer))
|
||||
{
|
||||
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "ipmitool sdr list failed to find CPU temperature";
|
||||
}
|
||||
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
{
|
||||
assert(pkc);
|
||||
@@ -8,7 +62,46 @@ static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
kstat_close(*pkc);
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
|
||||
{
|
||||
uint64_t low = 0, high = 0;
|
||||
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
|
||||
{
|
||||
if (ffStrStartsWith(ksp->ks_module, "cpu_info"))
|
||||
{
|
||||
if (kstat_read(kc, ksp, NULL) < 0)
|
||||
continue;
|
||||
|
||||
kstat_named_t* stat = kstat_data_lookup(ksp, type);
|
||||
if (!stat)
|
||||
continue;
|
||||
|
||||
uint32_t id = 0;
|
||||
switch (stat->data_type)
|
||||
{
|
||||
#ifdef _INT64_TYPE
|
||||
case KSTAT_DATA_INT64:
|
||||
case KSTAT_DATA_UINT64:
|
||||
id = (uint32_t) stat->value.ui64;
|
||||
break;
|
||||
#endif
|
||||
case KSTAT_DATA_INT32:
|
||||
case KSTAT_DATA_UINT32:
|
||||
id = stat->value.ui32;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (__builtin_expect(id > 64, false))
|
||||
high |= 1ULL << (id - 64);
|
||||
else
|
||||
low |= 1ULL << id;
|
||||
}
|
||||
}
|
||||
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
|
||||
if (!kc)
|
||||
@@ -40,7 +133,16 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0)
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
|
||||
if (kn) cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
if (kn) cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
}
|
||||
|
||||
cpu->packages = countTypeId(kc, "chip_id");
|
||||
cpu->coresPhysical = countTypeId(kc, "core_id");
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (detectCPUTempByKstat(kc, cpu) != NULL)
|
||||
detectCPUTempByIpmiTool(cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -4,6 +4,120 @@
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "util/windows/perflib_.h"
|
||||
#include <wchar.h>
|
||||
|
||||
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
|
||||
{
|
||||
if (*phQuery != NULL)
|
||||
{
|
||||
PerfCloseQueryHandle(*phQuery);
|
||||
*phQuery = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const char* detectThermalTemp(double* result)
|
||||
{
|
||||
struct FFPerfQuerySpec
|
||||
{
|
||||
PERF_COUNTER_IDENTIFIER Identifier;
|
||||
WCHAR Name[16];
|
||||
} querySpec = {
|
||||
.Identifier = {
|
||||
// Thermal Zone Information
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{52bc5412-dac2-449c-8bc2-96443888fe6b}
|
||||
.CounterSetGuid = { 0x52bc5412, 0xdac2, 0x449c, {0x8b, 0xc2, 0x96, 0x44, 0x38, 0x88, 0xfe, 0x6b} },
|
||||
.Size = sizeof(querySpec),
|
||||
.CounterId = PERF_WILDCARD_COUNTER,
|
||||
.InstanceId = PERF_WILDCARD_COUNTER,
|
||||
},
|
||||
.Name = L"\\_TZ.CPUZ", // The standard(?) instance name for CPU temperature in the thermal provider
|
||||
};
|
||||
|
||||
DWORD dataSize = 0;
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
return "PerfEnumerateCounterSetInstances() failed";
|
||||
|
||||
if (dataSize <= sizeof(PERF_INSTANCE_HEADER))
|
||||
return "No `Thermal Zone Information` instances found";
|
||||
|
||||
{
|
||||
FF_AUTO_FREE PERF_INSTANCE_HEADER* const pHead = malloc(dataSize);
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, pHead, dataSize, &dataSize) != ERROR_SUCCESS)
|
||||
return "PerfEnumerateCounterSetInstances() failed to get instance headers";
|
||||
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = pHead;
|
||||
while (1)
|
||||
{
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
if (wcscmp(instanceName, querySpec.Name) == 0)
|
||||
break;
|
||||
|
||||
dataSize -= pInstanceHeader->Size;
|
||||
if (dataSize == 0)
|
||||
break;
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
|
||||
}
|
||||
|
||||
if (dataSize == 0)
|
||||
{
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pHead + sizeof(*pHead));
|
||||
wcscpy(querySpec.Name, instanceName); // Use the first instance name if the specific one is not found
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((__cleanup__(ffPerfCloseQueryHandle)))
|
||||
HANDLE hQuery = NULL;
|
||||
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
|
||||
return "PerfOpenQueryHandle() failed";
|
||||
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
|
||||
return "PerfAddCounters() failed";
|
||||
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS)
|
||||
return "PerfAddCounters() reports invalid identifier";
|
||||
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
return "PerfQueryCounterData(NULL) failed";
|
||||
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER)) // PERF_ERROR_RETURN, should not happen
|
||||
return "instance doesn't exist";
|
||||
|
||||
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = malloc(dataSize);
|
||||
|
||||
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
|
||||
return "PerfQueryCounterData(pDataHeader) failed";
|
||||
|
||||
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
|
||||
if (pCounterHeader->dwType != PERF_MULTIPLE_COUNTERS)
|
||||
return "Invalid counter type";
|
||||
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
|
||||
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
|
||||
{
|
||||
if (pCounterData->dwDataSize == sizeof(int32_t))
|
||||
{
|
||||
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
|
||||
switch (pCounterIds[iCounter]) {
|
||||
case 0: // Temperature
|
||||
*result = *(int32_t*)(pCounterData + 1) - 273;
|
||||
break;
|
||||
case 3: // High Precision Temperature
|
||||
*result = *(int32_t*)(pCounterData + 1) / 10.0 - 273;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 7.5
|
||||
typedef struct FFSmbiosProcessorInfo
|
||||
{
|
||||
@@ -111,7 +225,7 @@ static const char* detectNCores(FFCPUResult* cpu)
|
||||
else if (ptr->Relationship == RelationProcessorCore)
|
||||
++cpu->coresPhysical;
|
||||
else if (ptr->Relationship == RelationProcessorPackage)
|
||||
cpu->packages++;
|
||||
++cpu->packages;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -165,8 +279,6 @@ static const char* detectCoreTypes(FFCPUResult* cpu)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* detectThermalTemp(double* current, double* critical);
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
detectNCores(cpu);
|
||||
@@ -182,7 +294,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
detectMaxSpeedBySmbios(cpu);
|
||||
|
||||
if(options->temp)
|
||||
detectThermalTemp(&cpu->temperature, NULL);
|
||||
detectThermalTemp(&cpu->temperature);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
#include "util/windows/wmi.hpp"
|
||||
|
||||
extern "C"
|
||||
const char* detectThermalTemp(double* current, double* critical)
|
||||
{
|
||||
// Requires Administrator privileges
|
||||
// https://wutils.com/wmi/root/wmi/msacpi_thermalzonetemperature/#properties
|
||||
FFWmiQuery query(L"SELECT CurrentTemperature, CriticalTripPoint FROM MSAcpi_ThermalZoneTemperature WHERE Active = TRUE", nullptr, FFWmiNamespace::WMI);
|
||||
if(!query)
|
||||
return "Query WMI service failed";
|
||||
|
||||
if(FFWmiRecord record = query.next())
|
||||
{
|
||||
if (current)
|
||||
{
|
||||
if(auto vtCurrent = record.get(L"CurrentTemperature"))
|
||||
*current = vtCurrent.get<int32_t>() / 10 - 273.15; // In tenth of degrees Kelvin
|
||||
else
|
||||
*current = 0.0/0.0;
|
||||
}
|
||||
|
||||
if (critical)
|
||||
{
|
||||
if(auto vtCritical = record.get(L"CriticalTripPoint"))
|
||||
*critical = vtCritical.get<int32_t>() / 10 - 273.15; // In tenth of degrees Kelvin
|
||||
else
|
||||
*critical = 0.0/0.0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "No WMI result returned";
|
||||
}
|
||||
@@ -5,12 +5,14 @@
|
||||
#include <stdint.h>
|
||||
|
||||
static FFlist cpuTimes1;
|
||||
static uint64_t startTime;
|
||||
|
||||
void ffPrepareCPUUsage(void)
|
||||
{
|
||||
assert(cpuTimes1.elementSize == 0);
|
||||
ffListInit(&cpuTimes1, sizeof(FFCpuUsageInfo));
|
||||
ffGetCpuUsageInfo(&cpuTimes1);
|
||||
startTime = ffTimeGetNow();
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
|
||||
@@ -23,6 +25,12 @@ const char* ffGetCpuUsageResult(FFCPUUsageOptions* options, FFlist* result)
|
||||
if(error) return error;
|
||||
ffTimeSleep(options->waitTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t elapsedTime = ffTimeGetNow() - startTime;
|
||||
if (elapsedTime < options->waitTime)
|
||||
ffTimeSleep(options->waitTime - (uint32_t)elapsedTime);
|
||||
}
|
||||
|
||||
if(cpuTimes1.length == 0) return "No CPU cores found";
|
||||
|
||||
@@ -57,5 +65,6 @@ retry:
|
||||
cpuTime1->inUseAll = cpuTime2->inUseAll;
|
||||
cpuTime1->totalAll = cpuTime2->totalAll;
|
||||
}
|
||||
startTime = ffTimeGetNow();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
for (uint32_t i = 0; i < coreCount; ++i)
|
||||
{
|
||||
uint64_t* cpTime = cpTimes[i];
|
||||
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS];
|
||||
uint64_t total = inUse + cpTime[CP_INTR] + cpTime[CP_IDLE];
|
||||
uint64_t inUse = cpTime[CP_USER] + cpTime[CP_NICE] + cpTime[CP_SYS] + cpTime[CP_INTR];
|
||||
uint64_t total = inUse + cpTime[CP_IDLE];
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
|
||||
@@ -31,8 +31,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
if(sscanf(start, "cpu%*d%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%" PRIu64 "%*[^\n]\n", &user, &nice, &system, &idle, &iowait, &irq, &softirq) == 7)
|
||||
{
|
||||
uint64_t inUse = user + nice + system;
|
||||
uint64_t total = inUse + idle + iowait + irq + softirq;
|
||||
uint64_t inUse = user + nice + system + irq + softirq;
|
||||
uint64_t total = inUse + idle + iowait;
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
|
||||
#include <ntstatus.h>
|
||||
#include <winternl.h>
|
||||
#include <windows.h>
|
||||
#include <wchar.h>
|
||||
#include "util/windows/perflib_.h"
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
static const char* getInfoByNqsi(FFlist* cpuTimes)
|
||||
{
|
||||
ULONG size = 0;
|
||||
if(NtQuerySystemInformation(SystemProcessorPerformanceInformation, NULL, 0, &size) != STATUS_INFO_LENGTH_MISMATCH)
|
||||
@@ -20,11 +23,8 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* coreInfo = pinfo + i;
|
||||
|
||||
// KernelTime includes idle time.
|
||||
LONGLONG dpcTime = coreInfo->Reserved1[0].QuadPart;
|
||||
LONGLONG interruptTime = coreInfo->Reserved1[1].QuadPart;
|
||||
// KernelTime includes IdleTime and DpcTime.
|
||||
coreInfo->KernelTime.QuadPart -= coreInfo->IdleTime.QuadPart;
|
||||
coreInfo->KernelTime.QuadPart += dpcTime + interruptTime;
|
||||
|
||||
uint64_t inUse = (uint64_t) (coreInfo->UserTime.QuadPart + coreInfo->KernelTime.QuadPart);
|
||||
uint64_t total = inUse + (uint64_t)coreInfo->IdleTime.QuadPart;
|
||||
@@ -38,3 +38,137 @@ const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* getInfoByPerflib(FFlist* cpuTimes)
|
||||
{
|
||||
static HANDLE hQuery = NULL;
|
||||
|
||||
if (hQuery == NULL)
|
||||
{
|
||||
struct FFPerfQuerySpec
|
||||
{
|
||||
PERF_COUNTER_IDENTIFIER Identifier;
|
||||
WCHAR Name[16];
|
||||
} querySpec = {
|
||||
.Identifier = {
|
||||
// Processor Information GUID
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\_V2Providers\{383487a6-3676-4870-a4e7-d45b30c35629}\{b4fc721a-0378-476f-89ba-a5a79f810b36}
|
||||
.CounterSetGuid = { 0xb4fc721a, 0x0378, 0x476f, {0x89, 0xba, 0xa5, 0xa7, 0x9f, 0x81, 0x0b, 0x36} },
|
||||
.Size = sizeof(querySpec),
|
||||
.CounterId = PERF_WILDCARD_COUNTER, // https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
|
||||
.InstanceId = PERF_WILDCARD_COUNTER,
|
||||
},
|
||||
.Name = PERF_WILDCARD_INSTANCE,
|
||||
};
|
||||
|
||||
if (PerfOpenQueryHandle(NULL, &hQuery) != ERROR_SUCCESS)
|
||||
{
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfOpenQueryHandle() failed";
|
||||
}
|
||||
|
||||
if (PerfAddCounters(hQuery, &querySpec.Identifier, sizeof(querySpec)) != ERROR_SUCCESS)
|
||||
{
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfAddCounters() failed";
|
||||
}
|
||||
|
||||
if (querySpec.Identifier.Status != ERROR_SUCCESS)
|
||||
{
|
||||
PerfCloseQueryHandle(hQuery);
|
||||
hQuery = INVALID_HANDLE_VALUE;
|
||||
return "PerfAddCounters() reports invalid identifier";
|
||||
}
|
||||
}
|
||||
|
||||
if (hQuery == INVALID_HANDLE_VALUE)
|
||||
return "Init hQuery failed";
|
||||
|
||||
DWORD dataSize = 0;
|
||||
if (PerfQueryCounterData(hQuery, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
return "PerfQueryCounterData(NULL) failed";
|
||||
|
||||
if (dataSize <= sizeof(PERF_DATA_HEADER) + sizeof(PERF_COUNTER_HEADER))
|
||||
return "instance doesn't exist";
|
||||
|
||||
FF_AUTO_FREE PERF_DATA_HEADER* const pDataHeader = (PERF_DATA_HEADER*)malloc(dataSize);
|
||||
if (PerfQueryCounterData(hQuery, pDataHeader, dataSize, &dataSize) != ERROR_SUCCESS)
|
||||
return "PerfQueryCounterData(pDataHeader) failed";
|
||||
|
||||
PERF_COUNTER_HEADER* pCounterHeader = (PERF_COUNTER_HEADER*)(pDataHeader + 1);
|
||||
if (pCounterHeader->dwType != PERF_COUNTERSET)
|
||||
return "Invalid counter type";
|
||||
|
||||
PERF_MULTI_COUNTERS* pMultiCounters = (PERF_MULTI_COUNTERS*)(pCounterHeader + 1);
|
||||
if (pMultiCounters->dwCounters == 0)
|
||||
return "No CPU counters found";
|
||||
|
||||
PERF_MULTI_INSTANCES* pMultiInstances = (PERF_MULTI_INSTANCES*)((BYTE*)pMultiCounters + pMultiCounters->dwSize);
|
||||
if (pMultiInstances->dwInstances == 0)
|
||||
return "No CPU instances found";
|
||||
|
||||
PERF_INSTANCE_HEADER* pInstanceHeader = (PERF_INSTANCE_HEADER*)(pMultiInstances + 1);
|
||||
for (DWORD iInstance = 0; iInstance < pMultiInstances->dwInstances; ++iInstance)
|
||||
{
|
||||
const wchar_t* instanceName = (const wchar_t*)((BYTE*)pInstanceHeader + sizeof(*pInstanceHeader));
|
||||
|
||||
PERF_COUNTER_DATA* pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
|
||||
|
||||
uint64_t processorUtility = UINT64_MAX, utilityBase = UINT64_MAX;
|
||||
for (ULONG iCounter = 0; iCounter != pMultiCounters->dwCounters; iCounter++)
|
||||
{
|
||||
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
|
||||
// https://learn.microsoft.com/en-us/windows/win32/perfctrs/using-the-perflib-functions-to-consume-counter-data
|
||||
switch (pCounterIds[iCounter]) {
|
||||
case 26: // % Processor Utility (#26, Type=PERF_AVERAGE_BULK)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint64_t));
|
||||
processorUtility = *(uint64_t*)(pCounterData + 1);
|
||||
break;
|
||||
case 27: // % Utility Base (#27, Type=PERF_AVERAGE_BASE)
|
||||
assert(pCounterData->dwDataSize == sizeof(uint32_t));
|
||||
utilityBase = *(uint32_t*)(pCounterData + 1) * 100LLU;
|
||||
break;
|
||||
}
|
||||
|
||||
pCounterData = (PERF_COUNTER_DATA*)((BYTE*)pCounterData + pCounterData->dwSize);
|
||||
}
|
||||
|
||||
if (wcschr(instanceName, L'_') == NULL /* ignore `_Total` */)
|
||||
{
|
||||
if (processorUtility == UINT64_MAX)
|
||||
return "Counter \"% Processor Utility\" are not supported";
|
||||
|
||||
FFCpuUsageInfo* info = (FFCpuUsageInfo*) ffListAdd(cpuTimes);
|
||||
*info = (FFCpuUsageInfo) {
|
||||
.inUseAll = processorUtility,
|
||||
.totalAll = utilityBase,
|
||||
};
|
||||
}
|
||||
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*)pCounterData;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffGetCpuUsageInfo(FFlist* cpuTimes)
|
||||
{
|
||||
#if __aarch64__
|
||||
static uint8_t winver = 10; // Assume Windows 10 or later for WoA
|
||||
#else
|
||||
static uint8_t winver = 0;
|
||||
if (winver == 0)
|
||||
winver = (uint8_t) ffStrbufToUInt(&instance.state.platform.sysinfo.release, 1);
|
||||
#endif
|
||||
|
||||
if (winver >= 10)
|
||||
{
|
||||
if (getInfoByPerflib(cpuTimes) == NULL) return NULL;
|
||||
ffListClear(cpuTimes);
|
||||
winver = 1; // Fall back to NQSI
|
||||
}
|
||||
|
||||
return getInfoByNqsi(cpuTimes);
|
||||
}
|
||||
|
||||
@@ -10,18 +10,29 @@
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <paths.h>
|
||||
#ifndef _PATH_LOCALBASE
|
||||
#define _PATH_LOCALBASE "/usr/local"
|
||||
#endif
|
||||
#elif __OpenBSD__
|
||||
#define _PATH_LOCALBASE "/usr/local"
|
||||
#elif __NetBSD__
|
||||
#define _PATH_LOCALBASE "/usr/pkg"
|
||||
#endif
|
||||
|
||||
static void getKDE(FFstrbuf* result, FFDEOptions* options)
|
||||
{
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
|
||||
{"X-KDE-PluginInfo-Version =", result}
|
||||
});
|
||||
#ifdef _PATH_LOCALBASE
|
||||
ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
{
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", 1, (FFpropquery[]) {
|
||||
{"X-KDE-PluginInfo-Version =", result}
|
||||
});
|
||||
}
|
||||
ffParsePropFile(_PATH_LOCALBASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
#else
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
#endif
|
||||
|
||||
if(result->length == 0)
|
||||
ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "disk.h"
|
||||
|
||||
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
|
||||
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char separator = ';';
|
||||
@@ -11,12 +11,12 @@ bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
|
||||
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < options->folders.length)
|
||||
while(startIndex < folders->length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator);
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
|
||||
|
||||
uint32_t folderLength = colonIndex - startIndex;
|
||||
if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0)
|
||||
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
|
||||
return true;
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
|
||||
@@ -28,4 +28,4 @@ typedef struct FFDisk
|
||||
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
|
||||
|
||||
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
|
||||
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint);
|
||||
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
|
||||
|
||||
@@ -52,7 +52,7 @@ static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
static const char* detectFsLabel(FF_MAYBE_UNUSED struct statfs* fs, FF_MAYBE_UNUSED FFDisk* disk)
|
||||
{
|
||||
return "Fastfetch was compiled without libgeom support";
|
||||
}
|
||||
@@ -145,10 +145,10 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if(__builtin_expect(options->folders.length > 0, 0))
|
||||
{
|
||||
if(!ffDiskMatchMountpoint(options, fs->f_mntonname))
|
||||
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
|
||||
continue;
|
||||
}
|
||||
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
|
||||
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
|
||||
continue;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
@@ -159,13 +159,13 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
FFDisk* disk = ffListAdd(disks);
|
||||
|
||||
disk->bytesTotal = (uint64_t)fs->f_blocks * fs->f_bsize;
|
||||
disk->bytesFree = (uint64_t)fs->f_bfree * fs->f_bsize;
|
||||
disk->bytesAvailable = (uint64_t)fs->f_bavail * fs->f_bsize;
|
||||
disk->bytesTotal = (uint64_t)fs->f_blocks * (uint64_t)fs->f_bsize;
|
||||
disk->bytesFree = (uint64_t)fs->f_bfree * (uint64_t)fs->f_bsize;
|
||||
disk->bytesAvailable = (uint64_t)fs->f_bavail * (uint64_t)fs->f_bsize;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
disk->filesTotal = (uint32_t) fs->f_files;
|
||||
disk->filesUsed = (uint32_t) (fs->f_files - fs->f_ffree);
|
||||
disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree;
|
||||
|
||||
ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname);
|
||||
ffStrbufInitS(&disk->mountpoint, fs->f_mntonname);
|
||||
|
||||
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, path.Path()))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ static bool isPhysicalDevice(const struct mntent* device)
|
||||
if(ffStrEquals(device->mnt_type, "zfs"))
|
||||
return true;
|
||||
|
||||
//sshfs
|
||||
if(ffStrEquals(device->mnt_type, "fuse.sshfs"))
|
||||
return true;
|
||||
|
||||
//Pseudo filesystems don't have a device in /dev
|
||||
if(!ffStrStartsWith(device->mnt_fsname, "/dev/"))
|
||||
return false;
|
||||
@@ -220,7 +224,7 @@ static bool isRemovable(FFDisk* currentDisk)
|
||||
|
||||
static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mntent* device)
|
||||
{
|
||||
if(ffStrbufStartsWithS(¤tDisk->mountpoint, "/boot") || ffStrbufStartsWithS(¤tDisk->mountpoint, "/efi"))
|
||||
if(hasmntopt(device, "x-gvfs-hide") || hasmntopt(device, "hidden"))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
|
||||
else if(isSubvolume(disks, currentDisk))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
|
||||
@@ -240,9 +244,9 @@ static void detectStats(FFDisk* disk)
|
||||
if(statvfs(disk->mountpoint.chars, &fs) != 0)
|
||||
memset(&fs, 0, sizeof(fs)); //Set all values to 0, so our values get initialized to 0 too
|
||||
|
||||
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
|
||||
disk->bytesFree = fs.f_bfree * fs.f_frsize;
|
||||
disk->bytesAvailable = fs.f_bavail * fs.f_frsize;
|
||||
disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize;
|
||||
disk->bytesFree = fs.f_bfree * (uint64_t) fs.f_frsize;
|
||||
disk->bytesAvailable = fs.f_bavail * (uint64_t) fs.f_frsize;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
if (fs.f_files >= fs.f_ffree)
|
||||
@@ -279,9 +283,9 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
while((device = getmntent(mountsFile)))
|
||||
{
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
if (__builtin_expect(options->folders.length > 0, false))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, device->mnt_dir))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
|
||||
continue;
|
||||
}
|
||||
else if(!isPhysicalDevice(device))
|
||||
|
||||
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, device.mnt_mountp))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
|
||||
continue;
|
||||
}
|
||||
else if(!isPhysicalDevice(&device))
|
||||
|
||||
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
if (__builtin_expect((long) options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, buffer.chars))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
|
||||
continue;
|
||||
}
|
||||
else if(driveType == DRIVE_NO_ROOT_DIR)
|
||||
@@ -99,9 +99,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
|
||||
|
||||
//https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#remarks
|
||||
UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
||||
DWORD diskFlags;
|
||||
BOOL result = GetVolumeInformationW(mountpoint,
|
||||
diskName, ARRAY_SIZE(diskName), //Volume name
|
||||
@@ -110,7 +107,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
&diskFlags, //File system flags
|
||||
diskFileSystem, ARRAY_SIZE(diskFileSystem)
|
||||
);
|
||||
SetErrorMode(errorMode);
|
||||
|
||||
if(result)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/edidHelper.h"
|
||||
#include "detection/os/os.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -194,7 +195,22 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "Quartz Compositor");
|
||||
}
|
||||
}
|
||||
ffStrbufSetStatic(&ds->dePrettyName, "Aqua");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffdsConnectDrm(FFDisplayServerResult* result)
|
||||
const char* ffdsConnectDrm(FF_MAYBE_UNUSED FFDisplayServerResult* result)
|
||||
{
|
||||
#ifdef FF_HAVE_DRM
|
||||
if (instance.config.general.dsForceDrm != FF_DS_FORCE_DRM_TYPE_SYSFS_ONLY)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -214,6 +214,26 @@ enum kde_output_device_v2_capability {
|
||||
* @since 9
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80,
|
||||
/**
|
||||
* if this outputdevice supports the built-in color profile
|
||||
* @since 12
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR = 0x100,
|
||||
/**
|
||||
* if this outputdevice supports DDC/CI
|
||||
* @since 14
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI = 0x200,
|
||||
/**
|
||||
* if this outputdevice supports setting max bpc
|
||||
* @since 15
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR = 0x400,
|
||||
/**
|
||||
* if this outputdevice supports EDR
|
||||
* @since 16
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800,
|
||||
};
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
@@ -235,6 +255,22 @@ enum kde_output_device_v2_capability {
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR_SINCE_VERSION 12
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI_SINCE_VERSION 14
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
|
||||
@@ -316,6 +352,18 @@ enum kde_output_device_v2_color_power_tradeoff {
|
||||
};
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
* when the compositor may make use of EDR
|
||||
*/
|
||||
enum kde_output_device_v2_edr_policy {
|
||||
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_NEVER = 0,
|
||||
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ALWAYS = 1,
|
||||
};
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
* @struct kde_output_device_v2_listener
|
||||
@@ -658,6 +706,74 @@ struct kde_output_device_v2_listener {
|
||||
void (*dimming)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t multiplier);
|
||||
/**
|
||||
* source output for mirroring
|
||||
*
|
||||
*
|
||||
* @param source uuid of the source output
|
||||
* @since 13
|
||||
*/
|
||||
void (*replication_source)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
const char *source);
|
||||
/**
|
||||
* if DDC/CI should be used to control brightness etc.
|
||||
*
|
||||
* If the ddc_ci capability is present, this determines if
|
||||
* settings such as brightness, contrast or others should be set
|
||||
* using DDC/CI.
|
||||
* @param allowed 1 if allowed, 0 if disabled
|
||||
* @since 14
|
||||
*/
|
||||
void (*ddc_ci_allowed)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t allowed);
|
||||
/**
|
||||
* override max bpc
|
||||
*
|
||||
* This limits the amount of bits per color that are sent to the
|
||||
* display.
|
||||
* @param max_bpc 0 for the default / automatic
|
||||
* @since 15
|
||||
*/
|
||||
void (*max_bits_per_color)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t max_bpc);
|
||||
/**
|
||||
* range of max bits per color value
|
||||
*
|
||||
*
|
||||
* @param min_value the minimum supported by the driver
|
||||
* @param max_value the maximum supported by the driver
|
||||
* @since 15
|
||||
*/
|
||||
void (*max_bits_per_color_range)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t min_value,
|
||||
uint32_t max_value);
|
||||
/**
|
||||
* if and to what value automatic max bpc is limited
|
||||
*
|
||||
*
|
||||
* @param max_bpc_limit which value automatic bpc gets limited to. 0 if not limited
|
||||
* @since 15
|
||||
*/
|
||||
void (*automatic_max_bits_per_color_limit)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t max_bpc_limit);
|
||||
/**
|
||||
* when the compositor may apply EDR
|
||||
*
|
||||
* When EDR is enabled, the compositor may increase the backlight
|
||||
* beyond the user-specified setting, in order to present HDR
|
||||
* content on displays without native HDR support. This will
|
||||
* usually result in better visuals, but also increases battery
|
||||
* usage.
|
||||
* @since 16
|
||||
*/
|
||||
void (*edr_policy)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t policy);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -779,6 +895,30 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_REPLICATION_SOURCE_SINCE_VERSION 13
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_DDC_CI_ALLOWED_SINCE_VERSION 14
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_RANGE_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_AUTOMATIC_MAX_BITS_PER_COLOR_LIMIT_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16
|
||||
|
||||
|
||||
/** @ingroup iface_kde_output_device_v2 */
|
||||
|
||||
@@ -60,12 +60,18 @@ static const struct wl_message kde_output_device_v2_events[] = {
|
||||
{ "brightness", "8u", kde_output_device_v2_types + 0 },
|
||||
{ "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 },
|
||||
{ "dimming", "11u", kde_output_device_v2_types + 0 },
|
||||
{ "replication_source", "13s", kde_output_device_v2_types + 0 },
|
||||
{ "ddc_ci_allowed", "14u", kde_output_device_v2_types + 0 },
|
||||
{ "max_bits_per_color", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 },
|
||||
{ "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "edr_policy", "16u", kde_output_device_v2_types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
|
||||
"kde_output_device_v2", 11,
|
||||
"kde_output_device_v2", 16,
|
||||
0, NULL,
|
||||
27, kde_output_device_v2_events,
|
||||
33, kde_output_device_v2_events,
|
||||
};
|
||||
|
||||
static const struct wl_message kde_output_device_mode_v2_events[] = {
|
||||
|
||||
@@ -137,6 +137,12 @@ static void waylandKdeHdrListener(void *data, FF_MAYBE_UNUSED struct kde_output_
|
||||
display->hdrEnabled = !!hdr_enabled;
|
||||
}
|
||||
|
||||
static void waylandKdeMaxBitsPerColorListener(void *data, FF_MAYBE_UNUSED struct kde_output_device_v2 *kde_output_device_v2, uint32_t max_bpc)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
display->bitDepth = (uint8_t) max_bpc;
|
||||
}
|
||||
|
||||
static struct kde_output_device_v2_listener outputListener = {
|
||||
.geometry = waylandKdeGeometryListener,
|
||||
.current_mode = waylandKdeCurrentModeListener,
|
||||
@@ -165,6 +171,12 @@ static struct kde_output_device_v2_listener outputListener = {
|
||||
.brightness = (void*) stubListener,
|
||||
.color_power_tradeoff = (void*) stubListener,
|
||||
.dimming = (void*) stubListener,
|
||||
.replication_source = (void*) stubListener,
|
||||
.ddc_ci_allowed = (void*) stubListener,
|
||||
.max_bits_per_color = (void*) waylandKdeMaxBitsPerColorListener,
|
||||
.max_bits_per_color_range = (void*) stubListener,
|
||||
.automatic_max_bits_per_color_limit = (void*) stubListener,
|
||||
.edr_policy = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
|
||||
@@ -237,6 +249,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
|
||||
item->manufactureYear = display.myear;
|
||||
item->manufactureWeek = display.mweek;
|
||||
item->serial = display.serial;
|
||||
item->bitDepth = display.bitDepth;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&display.description);
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef struct WaylandData
|
||||
typedef struct WaylandDisplay
|
||||
{
|
||||
WaylandData* parent;
|
||||
void* internal;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t refreshRate;
|
||||
@@ -55,7 +56,7 @@ typedef struct WaylandDisplay
|
||||
uint16_t myear;
|
||||
uint16_t mweek;
|
||||
uint32_t serial;
|
||||
void* internal;
|
||||
uint8_t bitDepth;
|
||||
} WaylandDisplay;
|
||||
|
||||
inline static void stubListener(void* data, ...)
|
||||
|
||||
@@ -335,6 +335,7 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xcbRandr, "dlopen libxcb-randr failed", "libxcb-randr" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connect)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connection_has_error)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_get_setup)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_setup_roots_iterator)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_screen_next)
|
||||
@@ -368,8 +369,11 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
|
||||
|
||||
data.connection = ffxcb_connect(NULL, NULL);
|
||||
if(data.connection == NULL)
|
||||
if(ffxcb_connection_has_error(data.connection) > 0)
|
||||
{
|
||||
ffxcb_disconnect(data.connection);
|
||||
return "xcb_connect() failed";
|
||||
}
|
||||
|
||||
|
||||
data.result = result;
|
||||
|
||||
@@ -20,9 +20,6 @@ extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iA
|
||||
// Function to retrieve memory information from the adapter. Version 2
|
||||
extern int ADL2_Adapter_MemoryInfo2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLMemoryInfo2* lpMemoryInfo2);
|
||||
|
||||
// This function retrieves the VRAM usage of given adapter.
|
||||
extern int ADL2_Adapter_VRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
|
||||
|
||||
// This function retrieves the Dedicated VRAM usage of given adapter.
|
||||
extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+12
-2
@@ -15,6 +15,11 @@ const char* FF_GPU_VENDOR_NAME_PARALLEL = "Parallel";
|
||||
const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
|
||||
const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat";
|
||||
const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle";
|
||||
const char* FF_GPU_VENDOR_NAME_BROADCOM = "Broadcom";
|
||||
const char* FF_GPU_VENDOR_NAME_LOONGSON = "Loongson";
|
||||
const char* FF_GPU_VENDOR_NAME_JINGJIA_MICRO = "Jingjia Micro";
|
||||
const char* FF_GPU_VENDOR_NAME_HUAWEI = "Huawei";
|
||||
const char* FF_GPU_VENDOR_NAME_ZHAOXIN = "Zhaoxin";
|
||||
|
||||
const char* ffGPUGetVendorString(unsigned vendorId)
|
||||
{
|
||||
@@ -22,17 +27,22 @@ const char* ffGPUGetVendorString(unsigned vendorId)
|
||||
switch (vendorId)
|
||||
{
|
||||
case 0x106b: return FF_GPU_VENDOR_NAME_APPLE;
|
||||
case 0x1002: case 0x1022: return FF_GPU_VENDOR_NAME_AMD;
|
||||
case 0x1002: case 0x1022: case 0x1dd8: return FF_GPU_VENDOR_NAME_AMD;
|
||||
case 0x8086: case 0x8087: case 0x03e7: return FF_GPU_VENDOR_NAME_INTEL;
|
||||
case 0x0955: case 0x10de: case 0x12d2: return FF_GPU_VENDOR_NAME_NVIDIA;
|
||||
case 0x1ed5: return FF_GPU_VENDOR_NAME_MTHREADS;
|
||||
case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
|
||||
case 0x17cb: case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
|
||||
case 0x14c3: return FF_GPU_VENDOR_NAME_MTK;
|
||||
case 0x15ad: return FF_GPU_VENDOR_NAME_VMWARE;
|
||||
case 0x1af4: return FF_GPU_VENDOR_NAME_REDHAT;
|
||||
case 0x1ab8: return FF_GPU_VENDOR_NAME_PARALLEL;
|
||||
case 0x1414: return FF_GPU_VENDOR_NAME_MICROSOFT;
|
||||
case 0x108e: return FF_GPU_VENDOR_NAME_ORACLE;
|
||||
case 0x182f: case 0x14e4: return FF_GPU_VENDOR_NAME_BROADCOM;
|
||||
case 0x0014: return FF_GPU_VENDOR_NAME_LOONGSON;
|
||||
case 0x0731: return FF_GPU_VENDOR_NAME_JINGJIA_MICRO;
|
||||
case 0x19e5: return FF_GPU_VENDOR_NAME_HUAWEI;
|
||||
case 0x1d17: return FF_GPU_VENDOR_NAME_ZHAOXIN;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -49,7 +49,25 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus);
|
||||
|
||||
const char* ffGPUGetVendorString(unsigned vendorId);
|
||||
|
||||
typedef struct FFGpuDriverPciBusId
|
||||
{
|
||||
uint32_t domain;
|
||||
uint32_t bus;
|
||||
uint32_t device;
|
||||
uint32_t func;
|
||||
} FFGpuDriverPciBusId;
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||||
void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu);
|
||||
void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu);
|
||||
#endif
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
|
||||
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
|
||||
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd);
|
||||
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd);
|
||||
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd);
|
||||
#endif // FF_HAVE_DRM
|
||||
|
||||
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId);
|
||||
#endif // defined(XXX)
|
||||
|
||||
@@ -49,7 +49,6 @@ struct FFAdlData {
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_Graphic_Core_Info_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_VRAMUsage_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps)
|
||||
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get)
|
||||
@@ -91,7 +90,6 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_Graphic_Core_Info_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_VRAMUsage_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get)
|
||||
@@ -188,29 +186,12 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
|
||||
FF_DEBUG("ADL2_Adapter_DedicatedVRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
if (status == ADL_OK && vramUsage >= 0) {
|
||||
result.memory->used = (uint64_t) vramUsage * 1024 * 1024;
|
||||
FF_DEBUG("Dedicated VRAM usage: %llu bytes (%d MB)", result.memory->used, vramUsage);
|
||||
} else {
|
||||
FF_DEBUG("Failed to get dedicated VRAM usage");
|
||||
}
|
||||
|
||||
if (result.sharedMemory)
|
||||
{
|
||||
vramUsage = 0;
|
||||
status = adlData.ffADL2_Adapter_VRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage);
|
||||
FF_DEBUG("ADL2_Adapter_VRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
uint64_t totalUsage = (uint64_t) vramUsage * 1024 * 1024;
|
||||
result.sharedMemory->used = totalUsage - result.memory->used;
|
||||
FF_DEBUG("Total VRAM usage: %llu bytes, Shared VRAM usage: %llu bytes (%llu MB)",
|
||||
totalUsage, result.sharedMemory->used, result.sharedMemory->used / (1024 * 1024));
|
||||
} else {
|
||||
FF_DEBUG("Failed to get total VRAM usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.memoryType)
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#import <Metal/MTLDevice.h>
|
||||
#import <IOKit/kext/KextManager.h>
|
||||
|
||||
#ifndef MAC_OS_VERSION_26_0
|
||||
#define MTLGPUFamilyMetal4 ((MTLGPUFamily) 5002)
|
||||
#endif
|
||||
#ifndef MAC_OS_VERSION_13_0
|
||||
#define MTLGPUFamilyMetal3 ((MTLGPUFamily) 5001)
|
||||
#endif
|
||||
@@ -57,7 +60,9 @@ const char* ffGpuDetectMetal(FFlist* gpus)
|
||||
else if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1");
|
||||
#else // MAC_OS_X_VERSION_10_15
|
||||
if ([device supportsFamily:MTLGPUFamilyMetal3])
|
||||
if ([device supportsFamily:MTLGPUFamilyMetal4])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal 4");
|
||||
else if ([device supportsFamily:MTLGPUFamilyMetal3])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon3])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
|
||||
@@ -66,7 +71,7 @@ const char* ffGpuDetectMetal(FFlist* gpus)
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon1])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
|
||||
|
||||
gpu->type = device.location == MTLDeviceLocationBuiltIn ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
gpu->index = (uint32_t) device.locationNumber;
|
||||
|
||||
if (device.hasUnifiedMemory && device.recommendedMaxWorkingSetSize > 0)
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#if __aarch64__ && FF_HAVE_DRM
|
||||
|
||||
#include <drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if __has_include(<drm/asahi_drm.h>)
|
||||
|
||||
#include <drm/asahi_drm.h>
|
||||
|
||||
#else
|
||||
|
||||
// https://github.com/AsahiLinux/linux/blob/asahi/include/uapi/drm/asahi_drm.h
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/* Copyright (C) The Asahi Linux Contributors */
|
||||
|
||||
#define DRM_ASAHI_UNSTABLE_UABI_VERSION 10011
|
||||
|
||||
#define DRM_ASAHI_GET_PARAMS 0x00
|
||||
#define DRM_ASAHI_MAX_CLUSTERS 32
|
||||
struct drm_asahi_params_global
|
||||
{
|
||||
__u32 unstable_uabi_version;
|
||||
__u32 pad0;
|
||||
|
||||
__u64 feat_compat;
|
||||
__u64 feat_incompat;
|
||||
|
||||
__u32 gpu_generation;
|
||||
__u32 gpu_variant;
|
||||
__u32 gpu_revision;
|
||||
__u32 chip_id;
|
||||
|
||||
__u32 num_dies;
|
||||
__u32 num_clusters_total;
|
||||
__u32 num_cores_per_cluster;
|
||||
__u32 num_frags_per_cluster;
|
||||
__u32 num_gps_per_cluster;
|
||||
__u32 num_cores_total_active;
|
||||
__u64 core_masks[DRM_ASAHI_MAX_CLUSTERS];
|
||||
|
||||
__u32 vm_page_size;
|
||||
__u32 pad1;
|
||||
__u64 vm_user_start;
|
||||
__u64 vm_user_end;
|
||||
__u64 vm_usc_start;
|
||||
__u64 vm_usc_end;
|
||||
__u64 vm_kernel_min_size;
|
||||
|
||||
__u32 max_syncs_per_submission;
|
||||
__u32 max_commands_per_submission;
|
||||
__u32 max_commands_in_flight;
|
||||
__u32 max_attachments;
|
||||
|
||||
__u32 timer_frequency_hz;
|
||||
__u32 min_frequency_khz;
|
||||
__u32 max_frequency_khz;
|
||||
__u32 max_power_mw;
|
||||
|
||||
__u32 result_render_size;
|
||||
__u32 result_compute_size;
|
||||
|
||||
__u32 firmware_version[4];
|
||||
};
|
||||
|
||||
struct drm_asahi_get_params
|
||||
{
|
||||
/** @extensions: Pointer to the first extension struct, if any */
|
||||
__u64 extensions;
|
||||
|
||||
/** @param: Parameter group to fetch (MBZ) */
|
||||
__u32 param_group;
|
||||
|
||||
/** @pad: MBZ */
|
||||
__u32 pad;
|
||||
|
||||
/** @value: User pointer to write parameter struct */
|
||||
__u64 pointer;
|
||||
|
||||
/** @value: Size of user buffer, max size supported on return */
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOWR(DRM_COMMAND_BASE + DRM_ASAHI_GET_PARAMS, struct drm_asahi_get_params),
|
||||
};
|
||||
|
||||
#endif // __has_include
|
||||
|
||||
#endif // FF_HAVE_DRM
|
||||
+158
-44
@@ -1,6 +1,7 @@
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <sys/pciio.h>
|
||||
#include <fcntl.h>
|
||||
@@ -10,11 +11,145 @@
|
||||
#include <bus/pci/pcireg.h> // DragonFly
|
||||
#endif
|
||||
|
||||
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
static void fillGPUTypeGeneric(FFGPUResult* gpu)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0);
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
|
||||
{
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
|
||||
{
|
||||
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
|
||||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
|
||||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
}
|
||||
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
|
||||
{
|
||||
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
#include "common/library.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <xf86drm.h>
|
||||
|
||||
static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm" FF_LIBRARY_EXTENSION " failed", "libdrm" FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices)
|
||||
|
||||
drmDevicePtr devices[64];
|
||||
int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices));
|
||||
if (nDevices < 0)
|
||||
return "drmGetDevices() failed";
|
||||
|
||||
for (int iDev = 0; iDev < nDevices; ++iDev)
|
||||
{
|
||||
drmDevice* dev = devices[iDev];
|
||||
|
||||
if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY)))
|
||||
continue;
|
||||
|
||||
const char* path = dev->nodes[DRM_NODE_PRIMARY];
|
||||
|
||||
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
||||
ffStrbufInit(&gpu->vendor);
|
||||
ffStrbufInit(&gpu->name);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInitS(&gpu->platformApi, path);
|
||||
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 = 0;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
switch (dev->bustype)
|
||||
{
|
||||
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;
|
||||
break;
|
||||
case DRM_BUS_HOST1X:
|
||||
ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]);
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
break;
|
||||
case DRM_BUS_PLATFORM:
|
||||
ffStrbufSetS(&gpu->name, dev->deviceinfo.platform->compatible[0]);
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
break;
|
||||
case DRM_BUS_USB:
|
||||
ffStrbufSetF(&gpu->name, "USB Device (%u-%u)", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product);
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
break;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) continue;
|
||||
|
||||
char driverName[64];
|
||||
driverName[0] = '\0';
|
||||
struct drm_version ver = {
|
||||
.name = driverName,
|
||||
.name_len = ARRAY_SIZE(driverName),
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0)
|
||||
ffStrbufSetF(&gpu->driver, "%*s %d.%d.%d", (int) ver.name_len, ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel);
|
||||
|
||||
if (ffStrStartsWith(driverName, "i915"))
|
||||
ffDrmDetectI915(gpu, fd);
|
||||
else if (ffStrStartsWith(driverName, "amdgpu"))
|
||||
ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]);
|
||||
else if (ffStrStartsWith(driverName, "radeon"))
|
||||
ffDrmDetectRadeon(options, gpu, dev->nodes[DRM_NODE_RENDER]);
|
||||
else if (ffStrStartsWith(driverName, "xe"))
|
||||
ffDrmDetectXe(gpu, fd);
|
||||
else if (ffStrStartsWith(driverName, "asahi"))
|
||||
ffDrmDetectAsahi(gpu, fd);
|
||||
else if (dev->bustype == DRM_BUS_PCI)
|
||||
{
|
||||
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
|
||||
.domain = (uint32_t) dev->businfo.pci->domain,
|
||||
.bus = dev->businfo.pci->bus,
|
||||
.device = dev->businfo.pci->dev,
|
||||
.func = dev->businfo.pci->func,
|
||||
});
|
||||
}
|
||||
|
||||
if (gpu->name.length == 0)
|
||||
{
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
|
||||
ffGPUQueryAmdGpuName(dev->deviceinfo.pci->device_id, dev->deviceinfo.pci->revision_id, gpu);
|
||||
if (gpu->name.length == 0)
|
||||
ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, gpu);
|
||||
}
|
||||
|
||||
fillGPUTypeGeneric(gpu);
|
||||
}
|
||||
|
||||
ffdrmFreeDevices(devices, nDevices);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return "open(\"/dev/pci\", O_RDONLY, 0) failed";
|
||||
return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed";
|
||||
|
||||
struct pci_conf confs[128];
|
||||
struct pci_match_conf match = {
|
||||
@@ -54,27 +189,12 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
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->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
|
||||
{
|
||||
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
|
||||
.pciBusId = {
|
||||
.domain = (uint32_t) pc->pc_sel.pc_domain,
|
||||
.bus = pc->pc_sel.pc_bus,
|
||||
.device = pc->pc_sel.pc_dev,
|
||||
.func = pc->pc_sel.pc_func,
|
||||
},
|
||||
}, (FFGpuDriverResult) {
|
||||
.index = &gpu->index,
|
||||
.temp = options->temp ? &gpu->temperature : NULL,
|
||||
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.type = &gpu->type,
|
||||
.frequency = &gpu->frequency,
|
||||
.coreUsage = &gpu->coreUsage,
|
||||
.name = &gpu->name,
|
||||
}, "libnvidia-ml.so");
|
||||
}
|
||||
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
|
||||
.domain = (uint32_t) pc->pc_sel.pc_domain,
|
||||
.bus = pc->pc_sel.pc_bus,
|
||||
.device = pc->pc_sel.pc_dev,
|
||||
.func = pc->pc_sel.pc_func,
|
||||
});
|
||||
|
||||
if (gpu->name.length == 0)
|
||||
{
|
||||
@@ -84,27 +204,21 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
ffGPUFillVendorAndName(pc->pc_subclass, pc->pc_vendor, pc->pc_device, gpu);
|
||||
}
|
||||
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
|
||||
{
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
|
||||
{
|
||||
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
|
||||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
|
||||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
}
|
||||
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS)
|
||||
{
|
||||
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT "))
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
fillGPUTypeGeneric(gpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
#if FF_HAVE_DRM
|
||||
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO)
|
||||
{
|
||||
detectByDrm(options, gpus);
|
||||
if (gpus->length > 0) return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return detectByPci(options, gpus);
|
||||
}
|
||||
|
||||
@@ -10,14 +10,6 @@ typedef enum __attribute__((__packed__)) FFGpuDriverConditionType
|
||||
FF_GPU_DRIVER_CONDITION_TYPE_FORCE_UNSIGNED = UINT8_MAX,
|
||||
} FFGpuDriverConditionType;
|
||||
|
||||
typedef struct FFGpuDriverPciBusId
|
||||
{
|
||||
uint32_t domain;
|
||||
uint32_t bus;
|
||||
uint32_t device;
|
||||
uint32_t func;
|
||||
} FFGpuDriverPciBusId;
|
||||
|
||||
typedef struct FFGpuDriverPciDeviceId
|
||||
{
|
||||
uint32_t deviceId;
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
#include "gpu.h"
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
#include <drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "common/library.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include "intel_drm.h"
|
||||
#include "asahi_drm.h"
|
||||
#include <radeon_drm.h>
|
||||
|
||||
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "Failed to open DRM render device";
|
||||
|
||||
uint32_t value;
|
||||
|
||||
// https://github.com/torvalds/linux/blob/fb4d33ab452ea254e2c319bac5703d1b56d895bf/drivers/gpu/drm/radeon/radeon_kms.c#L231
|
||||
|
||||
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
|
||||
.request = RADEON_INFO_ACTIVE_CU_COUNT,
|
||||
.value = (uintptr_t) &value,
|
||||
}) >= 0)
|
||||
gpu->coreCount = (int32_t) value;
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
|
||||
.request = RADEON_INFO_CURRENT_GPU_TEMP, // millidegrees C
|
||||
.value = (uintptr_t) &value,
|
||||
}) >= 0 && value != 0) // 0 means unavailable
|
||||
gpu->temperature = (double) value / 1000.0;
|
||||
}
|
||||
|
||||
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
|
||||
.request = RADEON_INFO_MAX_SCLK, // MHz
|
||||
.value = (uintptr_t) &value,
|
||||
}) >= 0)
|
||||
gpu->frequency = (uint32_t) (value / 1000u);
|
||||
|
||||
if (options->driverSpecific)
|
||||
{
|
||||
struct drm_radeon_gem_info gemInfo;
|
||||
if (ioctl(fd, DRM_IOCTL_RADEON_GEM_INFO, &gemInfo) >= 0)
|
||||
{
|
||||
// vram_usage can be bigger than vram_usage, so we use vram_size here
|
||||
gpu->dedicated.total = gemInfo.vram_size;
|
||||
gpu->shared.total = gemInfo.gart_size;
|
||||
|
||||
uint64_t memSize;
|
||||
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
|
||||
.request = RADEON_INFO_VRAM_USAGE, // uint64_t
|
||||
.value = (uintptr_t) &memSize,
|
||||
}) >= 0)
|
||||
gpu->dedicated.used = memSize;
|
||||
|
||||
if (ioctl(fd, DRM_IOCTL_RADEON_INFO, &(struct drm_radeon_info) {
|
||||
.request = RADEON_INFO_GTT_USAGE, // uint64_t
|
||||
.value = (uintptr_t) &memSize,
|
||||
}) >= 0)
|
||||
gpu->shared.used = memSize;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef FF_HAVE_DRM_AMDGPU
|
||||
#include <amdgpu.h>
|
||||
#include <amdgpu_drm.h>
|
||||
|
||||
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath)
|
||||
{
|
||||
#if FF_HAVE_DRM_AMDGPU
|
||||
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
|
||||
|
||||
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "Failed to open DRM render device";
|
||||
|
||||
amdgpu_device_handle handle;
|
||||
uint32_t majorVersion, minorVersion;
|
||||
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0)
|
||||
return "Failed to initialize AMDGPU device";
|
||||
|
||||
uint32_t value;
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0)
|
||||
gpu->temperature = value / 1000.;
|
||||
}
|
||||
|
||||
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
|
||||
|
||||
struct amdgpu_gpu_info gpuInfo;
|
||||
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0)
|
||||
{
|
||||
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
|
||||
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break
|
||||
switch (gpuInfo.vram_type)
|
||||
{
|
||||
FF_VRAM_CASE(UNKNOWN, 0);
|
||||
FF_VRAM_CASE(GDDR1, 1);
|
||||
FF_VRAM_CASE(DDR2, 2);
|
||||
FF_VRAM_CASE(GDDR3, 3);
|
||||
FF_VRAM_CASE(GDDR4, 4);
|
||||
FF_VRAM_CASE(GDDR5, 5);
|
||||
FF_VRAM_CASE(HBM, 6);
|
||||
FF_VRAM_CASE(DDR3, 7);
|
||||
FF_VRAM_CASE(DDR4, 8);
|
||||
FF_VRAM_CASE(GDDR6, 9);
|
||||
FF_VRAM_CASE(DDR5, 10);
|
||||
FF_VRAM_CASE(LPDDR4, 11);
|
||||
FF_VRAM_CASE(LPDDR5, 12);
|
||||
default:
|
||||
ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type);
|
||||
break;
|
||||
}
|
||||
|
||||
struct amdgpu_heap_info heapInfo;
|
||||
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
|
||||
{
|
||||
gpu->dedicated.total = heapInfo.heap_size;
|
||||
gpu->dedicated.used = heapInfo.heap_usage;
|
||||
}
|
||||
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_GTT, 0, &heapInfo) >= 0)
|
||||
{
|
||||
gpu->shared.total = heapInfo.heap_size;
|
||||
gpu->shared.used = heapInfo.heap_usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0)
|
||||
gpu->coreUsage = value;
|
||||
|
||||
ffamdgpu_device_deinitialize(handle);
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
FF_UNUSED(gpu, renderPath);
|
||||
return "Fastfetch is compiled without libdrm support";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd)
|
||||
{
|
||||
{
|
||||
int value;
|
||||
drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value };
|
||||
if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0)
|
||||
gpu->coreCount = value;
|
||||
}
|
||||
{
|
||||
struct drm_i915_query_item queryItem = {
|
||||
.query_id = DRM_I915_QUERY_MEMORY_REGIONS,
|
||||
};
|
||||
struct drm_i915_query query = {
|
||||
.items_ptr = (uintptr_t) &queryItem,
|
||||
.num_items = 1,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 )
|
||||
{
|
||||
FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length);
|
||||
queryItem.data_ptr = (uintptr_t) buffer;
|
||||
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0)
|
||||
{
|
||||
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
|
||||
struct drm_i915_query_memory_regions* regionInfo = (void*) buffer;
|
||||
for (uint32_t i = 0; i < regionInfo->num_regions; i++)
|
||||
{
|
||||
struct drm_i915_memory_region_info* region = regionInfo->regions + i;
|
||||
switch (region->region.memory_class)
|
||||
{
|
||||
case I915_MEMORY_CLASS_SYSTEM:
|
||||
gpu->shared.total += region->probed_size;
|
||||
gpu->shared.used += region->probed_size - region->unallocated_size;
|
||||
break;
|
||||
case I915_MEMORY_CLASS_DEVICE:
|
||||
gpu->dedicated.total += region->probed_size;
|
||||
gpu->dedicated.used += region->probed_size - region->unallocated_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
|
||||
{
|
||||
int count = 0;
|
||||
while (length >= 8)
|
||||
{
|
||||
count += __builtin_popcountll(*(uint64_t*) bytes);
|
||||
bytes += 8;
|
||||
length -= 8;
|
||||
}
|
||||
if (length >= 4)
|
||||
{
|
||||
count += __builtin_popcountl(*(uint32_t*) bytes);
|
||||
bytes += 4;
|
||||
length -= 4;
|
||||
}
|
||||
if (length >= 2)
|
||||
{
|
||||
count += __builtin_popcountl(*(uint16_t*) bytes);
|
||||
bytes += 2;
|
||||
length -= 2;
|
||||
}
|
||||
if (length)
|
||||
{
|
||||
count += __builtin_popcountl(*(uint8_t*) bytes);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd)
|
||||
{
|
||||
bool flag = false;
|
||||
{
|
||||
struct drm_xe_device_query query = {
|
||||
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
|
||||
query.data = (uintptr_t) buffer;
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
int dssCount = 0, euPerDssCount = 0;
|
||||
for (struct drm_xe_query_topology_mask* topo = (void*) buffer;
|
||||
(uint8_t*) topo < buffer + query.size;
|
||||
topo = (void*) (topo->mask + topo->num_bytes)
|
||||
) {
|
||||
switch (topo->type)
|
||||
{
|
||||
case DRM_XE_TOPO_DSS_COMPUTE:
|
||||
case DRM_XE_TOPO_DSS_GEOMETRY:
|
||||
dssCount += popcountBytes(topo->mask, topo->num_bytes);
|
||||
break;
|
||||
case DRM_XE_TOPO_EU_PER_DSS:
|
||||
euPerDssCount += popcountBytes(topo->mask, topo->num_bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gpu->coreCount = dssCount * euPerDssCount;
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct drm_xe_device_query query = {
|
||||
.query = DRM_XE_DEVICE_QUERY_MEM_REGIONS,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
|
||||
query.data = (uintptr_t) buffer;
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
|
||||
struct drm_xe_query_mem_regions* regionInfo = (void*) buffer;
|
||||
for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++)
|
||||
{
|
||||
struct drm_xe_mem_region* region = regionInfo->mem_regions + i;
|
||||
switch (region->mem_class)
|
||||
{
|
||||
case DRM_XE_MEM_REGION_CLASS_SYSMEM:
|
||||
gpu->shared.total += region->total_size;
|
||||
gpu->shared.used += region->used;
|
||||
break;
|
||||
case DRM_XE_MEM_REGION_CLASS_VRAM:
|
||||
gpu->dedicated.total += region->total_size;
|
||||
gpu->dedicated.used += region->used;
|
||||
break;
|
||||
}
|
||||
}
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag ? NULL : "Failed to query Xe GPU information";
|
||||
}
|
||||
|
||||
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd)
|
||||
{
|
||||
struct drm_asahi_params_global paramsGlobal = {};
|
||||
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
|
||||
.param_group = DRM_ASAHI_GET_PARAMS,
|
||||
.pointer = (uintptr_t) ¶msGlobal,
|
||||
.size = sizeof(paramsGlobal),
|
||||
}) >= 0)
|
||||
{
|
||||
// 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;
|
||||
|
||||
if (!gpu->name.length)
|
||||
{
|
||||
const char* variant = " Unknown";
|
||||
switch (paramsGlobal.gpu_variant) {
|
||||
case 'G':
|
||||
variant = "";
|
||||
break;
|
||||
case 'S':
|
||||
variant = " Pro";
|
||||
break;
|
||||
case 'C':
|
||||
variant = " Max";
|
||||
break;
|
||||
case 'D':
|
||||
variant = " Ultra";
|
||||
break;
|
||||
}
|
||||
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
|
||||
paramsGlobal.gpu_generation - 12, variant,
|
||||
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
|
||||
paramsGlobal.gpu_revision + 0xA0);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "Failed to query Asahi GPU information";
|
||||
}
|
||||
|
||||
#endif // FF_HAVE_DRM
|
||||
|
||||
#include "gpu_driver_specific.h"
|
||||
|
||||
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId)
|
||||
{
|
||||
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
|
||||
const char* soName;
|
||||
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific))
|
||||
{
|
||||
return detectFn(&(FFGpuDriverCondition) {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
|
||||
.pciBusId = pciBusId,
|
||||
}, (FFGpuDriverResult) {
|
||||
.index = &gpu->index,
|
||||
.temp = options->temp ? &gpu->temperature : NULL,
|
||||
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
|
||||
.type = &gpu->type,
|
||||
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
|
||||
.name = &gpu->name,
|
||||
}, soName);
|
||||
}
|
||||
|
||||
return "No driver-specific detection function found for the GPU vendor";
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR);
|
||||
FF_AUTO_CLOSE_FD int pokefd = open(POKE_DEVICE_FULLNAME, O_RDWR | O_CLOEXEC);
|
||||
if (pokefd < 0) return "open(POKE_DEVICE_FULLNAME) failed";
|
||||
|
||||
pci_info dev;
|
||||
|
||||
@@ -89,19 +89,19 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
|
||||
if (properties.device_type != CTL_DEVICE_TYPE_GRAPHICS)
|
||||
continue;
|
||||
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
|
||||
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
|
||||
{
|
||||
if (cond->luid == deviceId)
|
||||
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
|
||||
cond->pciBusId.device == properties.adapter_bdf.device &&
|
||||
cond->pciBusId.func == properties.adapter_bdf.function)
|
||||
{
|
||||
device = devices[iDev];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
|
||||
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
|
||||
{
|
||||
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
|
||||
cond->pciBusId.device == properties.adapter_bdf.device &&
|
||||
cond->pciBusId.func == properties.adapter_bdf.function)
|
||||
if (cond->luid == deviceId)
|
||||
{
|
||||
device = devices[iDev];
|
||||
break;
|
||||
|
||||
+100
-295
@@ -21,10 +21,16 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "gpu_asahi.h"
|
||||
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
#if defined(FF_HAVE_DRM) && defined(__aarch64__)
|
||||
// https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h
|
||||
// Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
|
||||
#if __has_include(<drm/asahi_drm.h>)
|
||||
#include <drm/asahi_drm.h>
|
||||
#else
|
||||
#include "asahi_drm.h"
|
||||
#endif
|
||||
#define FF_HAVE_DRM_ASAHI 1
|
||||
#endif
|
||||
|
||||
static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
|
||||
{
|
||||
@@ -99,73 +105,23 @@ FF_MAYBE_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey,
|
||||
|
||||
static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
|
||||
{
|
||||
#if FF_HAVE_DRM_AMDGPU
|
||||
|
||||
FF_LIBRARY_LOAD(libdrm, "dlopen libdrm_amdgpu" FF_LIBRARY_EXTENSION " failed", "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
const char* error = drmFindRenderFromCard(drmKey, buffer);
|
||||
if (error) return error;
|
||||
if (ffStrbufEqualS(&gpu->driver, "radeon"))
|
||||
return ffDrmDetectRadeon(options, gpu, buffer->chars);
|
||||
else
|
||||
{
|
||||
const char* error = drmFindRenderFromCard(drmKey, buffer);
|
||||
if (error) return error;
|
||||
#if FF_HAVE_DRM_AMDGPU
|
||||
return ffDrmDetectAmdgpu(options, gpu, buffer->chars);
|
||||
#else
|
||||
FF_UNUSED(options, gpu, drmKey, buffer);
|
||||
return "Fastfetch is not compiled with libdrm_amdgpu support";
|
||||
#endif
|
||||
}
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
|
||||
if (fd < 0) return "Failed to open DRM device";
|
||||
|
||||
amdgpu_device_handle handle;
|
||||
uint32_t majorVersion, minorVersion;
|
||||
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0)
|
||||
return "Failed to initialize AMDGPU device";
|
||||
|
||||
ffStrbufAppendF(&gpu->driver, " %u.%u", (unsigned) majorVersion, (unsigned) minorVersion);
|
||||
|
||||
uint32_t value;
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0)
|
||||
gpu->temperature = value / 1000.;
|
||||
}
|
||||
|
||||
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
|
||||
|
||||
struct amdgpu_gpu_info gpuInfo;
|
||||
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0)
|
||||
{
|
||||
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
|
||||
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
|
||||
struct amdgpu_heap_info heapInfo;
|
||||
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
|
||||
{
|
||||
if (gpu->type == FF_GPU_TYPE_DISCRETE)
|
||||
{
|
||||
gpu->dedicated.total = heapInfo.heap_size;
|
||||
gpu->dedicated.used = heapInfo.heap_usage;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpu->shared.total = heapInfo.heap_size;
|
||||
gpu->shared.used = heapInfo.heap_usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0)
|
||||
gpu->coreUsage = value;
|
||||
|
||||
ffamdgpu_device_deinitialize(handle);
|
||||
|
||||
return NULL;
|
||||
#else
|
||||
FF_UNUSED(options, gpu, drmKey, buffer);
|
||||
return "Fastfetch is compiled without libdrm support";
|
||||
FF_UNUSED(gpu, drmKey, buffer);
|
||||
return "Fastfetch is not compiled with drm support";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -189,46 +145,54 @@ static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu,
|
||||
ffStrbufAppendC(pciDir, '/');
|
||||
|
||||
const uint32_t hwmonLen = pciDir->length;
|
||||
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
|
||||
if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY))
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
else
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
|
||||
uint64_t value = 0;
|
||||
if (options->temp)
|
||||
{
|
||||
ffStrbufSubstrBefore(pciDir, hwmonLen);
|
||||
ffStrbufAppendS(pciDir, "temp1_input"); // The on die GPU temperature in millidegrees Celsius
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
gpu->temperature = (double) value / 1000;
|
||||
}
|
||||
|
||||
if (options->driverSpecific)
|
||||
if (ffStrbufEqualS(&gpu->driver, "amdgpu")) // Ancient radeon drivers don't have these files
|
||||
{
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
{
|
||||
if (gpu->type == FF_GPU_TYPE_DISCRETE)
|
||||
gpu->dedicated.total = value;
|
||||
else
|
||||
gpu->shared.total = value;
|
||||
ffStrbufSubstrBefore(pciDir, hwmonLen);
|
||||
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
|
||||
if (ffPathExists(pciDir->chars, FF_PATHTYPE_ANY))
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
else
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
|
||||
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
|
||||
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used");
|
||||
if (options->driverSpecific)
|
||||
{
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
{
|
||||
if (gpu->type == FF_GPU_TYPE_DISCRETE)
|
||||
gpu->dedicated.used = value;
|
||||
gpu->dedicated.total = value;
|
||||
else
|
||||
gpu->shared.used = value;
|
||||
gpu->shared.total = value;
|
||||
|
||||
ffStrbufSubstrBefore(pciDir, pciDir->length - (uint32_t) strlen("/mem_info_vis_vram_total"));
|
||||
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_used");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
{
|
||||
if (gpu->type == FF_GPU_TYPE_DISCRETE)
|
||||
gpu->dedicated.used = value;
|
||||
else
|
||||
gpu->shared.used = value;
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
ffStrbufAppendS(pciDir, "/gpu_busy_percent");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
gpu->coreUsage = (double) value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer, const char* drmKey)
|
||||
static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer, const char* drmKey)
|
||||
{
|
||||
// Works for Intel GPUs
|
||||
// https://patchwork.kernel.org/project/intel-gfx/patch/1422039866-11572-3-git-send-email-ville.syrjala@linux.intel.com/
|
||||
@@ -238,40 +202,46 @@ static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf*
|
||||
|
||||
if (!drmKey) return;
|
||||
|
||||
if (ffStrbufEqualS(&gpu->driver, "xe"))
|
||||
const uint32_t pciDirLen = pciDir->length;
|
||||
|
||||
bool isXE = ffStrbufEqualS(&gpu->driver, "xe");
|
||||
if (isXE)
|
||||
ffStrbufAppendS(pciDir, "/tile0/gt0/freq0/max_freq");
|
||||
else
|
||||
ffStrbufAppendF(pciDir, "/drm/%s/gt_max_freq_mhz", drmKey);
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer))
|
||||
gpu->frequency = (uint32_t) ffStrbufToUInt(buffer, 0);
|
||||
}
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
|
||||
static inline int popcountBytes(uint8_t* bytes, uint32_t length)
|
||||
{
|
||||
int count = 0;
|
||||
while (length >= 8)
|
||||
if (options->temp)
|
||||
{
|
||||
count += __builtin_popcountll(*(uint64_t*) bytes);
|
||||
bytes += 8;
|
||||
length -= 8;
|
||||
ffStrbufAppendS(pciDir, "/hwmon/");
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDir->chars);
|
||||
if (dirp)
|
||||
{
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen + strlen("/hwmon/"));
|
||||
ffStrbufAppendS(pciDir, entry->d_name);
|
||||
// https://github.com/Syllo/nvtop/blob/73291884d926445e499d6b9b71cb7a9bdbc7c393/src/extract_gpuinfo_intel.c#L279-L281
|
||||
ffStrbufAppendS(pciDir, isXE ? "/temp2_input" : "/temp1_input");
|
||||
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer))
|
||||
{
|
||||
uint64_t value = ffStrbufToUInt(buffer, 0);
|
||||
if (value > 0)
|
||||
{
|
||||
gpu->temperature = (double) value / 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
}
|
||||
if (length >= 4)
|
||||
{
|
||||
count += __builtin_popcountl(*(uint32_t*) bytes);
|
||||
bytes += 4;
|
||||
length -= 4;
|
||||
}
|
||||
if (length >= 2)
|
||||
{
|
||||
count += __builtin_popcountl(*(uint16_t*) bytes);
|
||||
bytes += 2;
|
||||
length -= 2;
|
||||
}
|
||||
if (length)
|
||||
{
|
||||
count += __builtin_popcountl(*(uint8_t*) bytes);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
|
||||
@@ -279,120 +249,14 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey,
|
||||
#if FF_HAVE_DRM
|
||||
ffStrbufSetS(buffer, "/dev/dri/");
|
||||
ffStrbufAppendS(buffer, drmKey);
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "Failed to open drm device";
|
||||
|
||||
if (ffStrbufEqualS(&gpu->driver, "xe"))
|
||||
{
|
||||
{
|
||||
struct drm_xe_device_query query = {
|
||||
.extensions = 0,
|
||||
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
|
||||
.size = 0,
|
||||
.data = 0,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
|
||||
query.data = (uintptr_t) buffer;
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
int dssCount = 0, euPerDssCount = 0;
|
||||
for (struct drm_xe_query_topology_mask* topo = (void*) buffer;
|
||||
(uint8_t*) topo < buffer + query.size;
|
||||
topo = (void*) (topo->mask + topo->num_bytes)
|
||||
) {
|
||||
switch (topo->type)
|
||||
{
|
||||
case DRM_XE_TOPO_DSS_COMPUTE:
|
||||
case DRM_XE_TOPO_DSS_GEOMETRY:
|
||||
dssCount += popcountBytes(topo->mask, topo->num_bytes);
|
||||
break;
|
||||
case DRM_XE_TOPO_EU_PER_DSS:
|
||||
euPerDssCount += popcountBytes(topo->mask, topo->num_bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
gpu->coreCount = dssCount * euPerDssCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct drm_xe_device_query query = {
|
||||
.query = DRM_XE_DEVICE_QUERY_MEM_REGIONS,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
FF_AUTO_FREE uint8_t* buffer = malloc(query.size);
|
||||
query.data = (uintptr_t) buffer;
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
|
||||
struct drm_xe_query_mem_regions* regionInfo = (void*) buffer;
|
||||
for (uint32_t i = 0; i < regionInfo->num_mem_regions; i++)
|
||||
{
|
||||
struct drm_xe_mem_region* region = regionInfo->mem_regions + i;
|
||||
switch (region->mem_class)
|
||||
{
|
||||
case DRM_XE_MEM_REGION_CLASS_SYSMEM:
|
||||
gpu->shared.total += region->total_size;
|
||||
gpu->shared.used += region->used;
|
||||
break;
|
||||
case DRM_XE_MEM_REGION_CLASS_VRAM:
|
||||
gpu->dedicated.total += region->total_size;
|
||||
gpu->dedicated.used += region->used;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ffDrmDetectXe(gpu, fd);
|
||||
else if (ffStrbufEqualS(&gpu->driver, "i915"))
|
||||
{
|
||||
{
|
||||
int value;
|
||||
drm_i915_getparam_t getparam = { .param = I915_PARAM_EU_TOTAL, .value = &value };
|
||||
if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &getparam) >= 0)
|
||||
gpu->coreCount = value;
|
||||
}
|
||||
{
|
||||
struct drm_i915_query_item queryItem = {
|
||||
.query_id = DRM_I915_QUERY_MEMORY_REGIONS,
|
||||
};
|
||||
struct drm_i915_query query = {
|
||||
.items_ptr = (uintptr_t) &queryItem,
|
||||
.num_items = 1,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0 )
|
||||
{
|
||||
FF_AUTO_FREE uint8_t* buffer = calloc(1, (size_t) queryItem.length);
|
||||
queryItem.data_ptr = (uintptr_t) buffer;
|
||||
if (ioctl(fd, DRM_IOCTL_I915_QUERY, &query) >= 0)
|
||||
{
|
||||
gpu->dedicated.total = gpu->shared.total = gpu->dedicated.used = gpu->shared.used = 0;
|
||||
struct drm_i915_query_memory_regions* regionInfo = (void*) buffer;
|
||||
for (uint32_t i = 0; i < regionInfo->num_regions; i++)
|
||||
{
|
||||
struct drm_i915_memory_region_info* region = regionInfo->regions + i;
|
||||
switch (region->region.memory_class)
|
||||
{
|
||||
case I915_MEMORY_CLASS_SYSTEM:
|
||||
gpu->shared.total += region->probed_size;
|
||||
gpu->shared.used += region->probed_size - region->unallocated_size;
|
||||
break;
|
||||
case I915_MEMORY_CLASS_DEVICE:
|
||||
gpu->dedicated.total += region->probed_size;
|
||||
gpu->dedicated.used += region->probed_size - region->unallocated_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return ffDrmDetectI915(gpu, fd);
|
||||
return "Unknown Intel GPU driver";
|
||||
#else
|
||||
FF_UNUSED(gpu, drmKey, buffer);
|
||||
return "Fastfetch is not compiled with drm support";
|
||||
@@ -500,36 +364,19 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
}
|
||||
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
|
||||
{
|
||||
pciDetectIntelSpecific(gpu, deviceDir, buffer, drmKey);
|
||||
pciDetectIntelSpecific(options, gpu, deviceDir, buffer, drmKey);
|
||||
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
|
||||
if (options->driverSpecific && drmKey)
|
||||
drmDetectIntelSpecific(gpu, drmKey, buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
|
||||
const char* soName;
|
||||
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific))
|
||||
{
|
||||
detectFn(&(FFGpuDriverCondition) {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
|
||||
.pciBusId = {
|
||||
.domain = pciDomain,
|
||||
.bus = pciBus,
|
||||
.device = pciDevice,
|
||||
.func = pciFunc,
|
||||
},
|
||||
}, (FFGpuDriverResult) {
|
||||
.index = &gpu->index,
|
||||
.temp = options->temp ? &gpu->temperature : NULL,
|
||||
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
|
||||
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
|
||||
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
|
||||
.type = &gpu->type,
|
||||
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
|
||||
.name = &gpu->name,
|
||||
}, soName);
|
||||
}
|
||||
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
|
||||
.domain = pciDomain,
|
||||
.bus = pciBus,
|
||||
.device = pciDevice,
|
||||
.func = pciFunc,
|
||||
});
|
||||
}
|
||||
|
||||
if (gpu->name.length == 0)
|
||||
@@ -556,60 +403,18 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
|
||||
#if __aarch64__
|
||||
|
||||
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FFstrbuf* buffer, const char* drmKey)
|
||||
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_MAYBE_UNUSED FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
|
||||
{
|
||||
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1)
|
||||
ffStrbufSetStatic(&gpu->name, ffCPUAppleCodeToName((uint32_t) gpu->deviceId));
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
#if FF_HAVE_DRM_ASAHI
|
||||
ffStrbufSetS(buffer, "/dev/dri/");
|
||||
ffStrbufAppendS(buffer, drmKey);
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
|
||||
if (fd >= 0)
|
||||
{
|
||||
struct drm_asahi_params_global paramsGlobal = {};
|
||||
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
|
||||
.param_group = DRM_ASAHI_GET_PARAMS,
|
||||
.pointer = (uint64_t) ¶msGlobal,
|
||||
.size = sizeof(paramsGlobal),
|
||||
}) >= 0)
|
||||
{
|
||||
ffStrbufAppendF(&gpu->driver, " %u", paramsGlobal.unstable_uabi_version);
|
||||
|
||||
// FIXME: They will introduce ABI breaking changes. Always check the latest version
|
||||
// https://www.reddit.com/r/AsahiLinux/comments/1ei2qiv/comment/lgm0v5s/
|
||||
if (paramsGlobal.unstable_uabi_version == DRM_ASAHI_UNSTABLE_UABI_VERSION)
|
||||
{
|
||||
gpu->coreCount = (int) paramsGlobal.num_cores_total_active;
|
||||
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
|
||||
gpu->deviceId = paramsGlobal.chip_id;
|
||||
|
||||
if (!gpu->name.length)
|
||||
{
|
||||
const char* variant = " Unknown";
|
||||
switch (paramsGlobal.gpu_variant) {
|
||||
case 'G':
|
||||
variant = "";
|
||||
break;
|
||||
case 'S':
|
||||
variant = " Pro";
|
||||
break;
|
||||
case 'C':
|
||||
variant = " Max";
|
||||
break;
|
||||
case 'D':
|
||||
variant = " Ultra";
|
||||
break;
|
||||
}
|
||||
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
|
||||
paramsGlobal.gpu_generation - 12, variant,
|
||||
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
|
||||
paramsGlobal.gpu_revision + 0xA0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ffDrmDetectAsahi(gpu, fd);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -29,11 +29,12 @@ struct FFNvapiData {
|
||||
FF_LIBRARY_SYMBOL(nvapi_Unload)
|
||||
FF_LIBRARY_SYMBOL(nvapi_EnumPhysicalGPUs)
|
||||
FF_LIBRARY_SYMBOL(nvapi_GPU_GetRamType)
|
||||
FF_LIBRARY_SYMBOL(nvapi_GPU_GetGPUType)
|
||||
|
||||
bool inited;
|
||||
} nvapiData;
|
||||
|
||||
static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
|
||||
static const char* detectMoreByNvapi(FFGpuDriverResult* result)
|
||||
{
|
||||
if (!nvapiData.inited)
|
||||
{
|
||||
@@ -55,6 +56,7 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
|
||||
FF_NVAPI_INTERFACE(nvapi_Unload, NVAPI_INTERFACE_OFFSET_UNLOAD)
|
||||
FF_NVAPI_INTERFACE(nvapi_EnumPhysicalGPUs, NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS)
|
||||
FF_NVAPI_INTERFACE(nvapi_GPU_GetRamType, NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE)
|
||||
FF_NVAPI_INTERFACE(nvapi_GPU_GetGPUType, NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE)
|
||||
#undef FF_NVAPI_INTERFACE
|
||||
|
||||
if (ffnvapi_Initialize() < 0)
|
||||
@@ -62,6 +64,7 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
|
||||
|
||||
nvapiData.ffnvapi_EnumPhysicalGPUs = ffnvapi_EnumPhysicalGPUs;
|
||||
nvapiData.ffnvapi_GPU_GetRamType = ffnvapi_GPU_GetRamType;
|
||||
nvapiData.ffnvapi_GPU_GetGPUType = ffnvapi_GPU_GetGPUType;
|
||||
nvapiData.ffnvapi_Unload = ffnvapi_Unload;
|
||||
|
||||
atexit((void*) ffnvapi_Unload);
|
||||
@@ -86,36 +89,53 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
|
||||
NvPhysicalGpuHandle gpuHandle = handles[gpuIndex];
|
||||
|
||||
NvApiGPUMemoryType memType;
|
||||
if (nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) < 0)
|
||||
return "NvAPI_GPU_GetRamType() failed";
|
||||
|
||||
switch (memType)
|
||||
if (result->memoryType && nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) == 0)
|
||||
{
|
||||
#define FF_NVAPI_MEMORY_TYPE(type) \
|
||||
case NVAPI_GPU_MEMORY_TYPE_##type: \
|
||||
ffStrbufSetStatic(result->memoryType, #type); \
|
||||
switch (memType)
|
||||
{
|
||||
#define FF_NVAPI_MEMORY_TYPE(type) \
|
||||
case NVAPI_GPU_MEMORY_TYPE_##type: \
|
||||
ffStrbufSetStatic(result->memoryType, #type); \
|
||||
break;
|
||||
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
|
||||
FF_NVAPI_MEMORY_TYPE(SDRAM)
|
||||
FF_NVAPI_MEMORY_TYPE(DDR1)
|
||||
FF_NVAPI_MEMORY_TYPE(DDR2)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR2)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR3)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR4)
|
||||
FF_NVAPI_MEMORY_TYPE(DDR3)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR5)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR2)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR5X)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR3)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR4)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR5)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR6)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR6X)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR7)
|
||||
#undef FF_NVAPI_MEMORY_TYPE
|
||||
default:
|
||||
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
|
||||
break;
|
||||
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
|
||||
FF_NVAPI_MEMORY_TYPE(SDRAM)
|
||||
FF_NVAPI_MEMORY_TYPE(DDR1)
|
||||
FF_NVAPI_MEMORY_TYPE(DDR2)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR2)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR3)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR4)
|
||||
FF_NVAPI_MEMORY_TYPE(DDR3)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR5)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR2)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR5X)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR3)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR4)
|
||||
FF_NVAPI_MEMORY_TYPE(LPDDR5)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR6)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR6X)
|
||||
FF_NVAPI_MEMORY_TYPE(GDDR7)
|
||||
#undef FF_NVAPI_MEMORY_TYPE
|
||||
default:
|
||||
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NvApiGPUType gpuType;
|
||||
if (result->type && nvapiData.ffnvapi_GPU_GetGPUType(gpuHandle, &gpuType) == 0)
|
||||
{
|
||||
switch (gpuType)
|
||||
{
|
||||
case NV_SYSTEM_TYPE_IGPU:
|
||||
*result->type = FF_GPU_TYPE_INTEGRATED;
|
||||
break;
|
||||
case NV_SYSTEM_TYPE_DGPU:
|
||||
*result->type = FF_GPU_TYPE_DISCRETE;
|
||||
break;
|
||||
default:
|
||||
*result->type = FF_GPU_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -222,13 +242,13 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
|
||||
{
|
||||
*result.index = value;
|
||||
#ifdef _WIN32
|
||||
// Don't bother loading nvapi for GPU type detection only
|
||||
if (result.memoryType)
|
||||
detectMemTypeByNvapi(&result);
|
||||
detectMoreByNvapi(&result);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (result.temp)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
@@ -45,8 +45,10 @@ static const FFstrbuf* loadPciIds()
|
||||
if (pciids.length == 0)
|
||||
ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/local/share/hwdata/pci.ids", &pciids);
|
||||
}
|
||||
#elif __FreeBSD__ || __OpenBSD__ || __NetBSD__
|
||||
#elif __FreeBSD__ || __NetBSD__
|
||||
ffReadFileBuffer(_PATH_LOCALBASE "/share/pciids/pci.ids", &pciids);
|
||||
#elif __OpenBSD__
|
||||
ffReadFileBuffer(_PATH_LOCALBASE "/share/hwdata/pci.ids", &pciids);
|
||||
#elif __sun
|
||||
ffReadFileBuffer(FASTFETCH_TARGET_DIR_ROOT "/usr/share/hwdata/pci.ids", &pciids);
|
||||
#elif __HAIKU__
|
||||
|
||||
@@ -1,83 +1,57 @@
|
||||
#include "gpu.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
#include <libdevinfo.h>
|
||||
|
||||
static int walkDevTree(di_node_t node, FF_MAYBE_UNUSED di_minor_t minor, FFlist* gpus)
|
||||
{
|
||||
// SunOS requires root permission to query PCI device list, except `/usr/bin/scanpci`
|
||||
// Same behavior can be observed with `cp $(which scanpci) /tmp/ && /tmp/scanpci`
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/scanpci",
|
||||
"-v",
|
||||
NULL,
|
||||
});
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!ffStrbufStartsWithS(&buffer, "\npci "))
|
||||
return "Invalid scanpci result";
|
||||
|
||||
// pci bus 0x0000 cardnum 0x00 function 0x00: vendor 0x1414 device 0x008e
|
||||
// Device unknown
|
||||
// CardVendor 0x0000 card 0x0000 (Card unknown)
|
||||
// STATUS 0x0010 COMMAND 0x0007
|
||||
// CLASS 0x03 0x02 0x00 REVISION 0x00
|
||||
// BIST 0x00 HEADER 0x00 LATENCY 0x00 CACHE 0x00
|
||||
// MAX_LAT 0x00 MIN_GNT 0x00 INT_PIN 0x00 INT_LINE 0x00
|
||||
|
||||
for (
|
||||
const char* pclass = strstr(buffer.chars, "\n CLASS 0x03 ");
|
||||
pclass;
|
||||
pclass = strstr(pclass, "\n CLASS 0x03 ")
|
||||
)
|
||||
int* vendorId;
|
||||
int* deviceId;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "vendor-id", &vendorId) > 0
|
||||
&& di_prop_lookup_ints(DDI_DEV_T_ANY, node, "device-id", &deviceId) > 0)
|
||||
{
|
||||
// find the start of device entry
|
||||
const char* pstart = memrchr(buffer.chars, '\n', (size_t) (pclass - buffer.chars));
|
||||
if (pstart == NULL)
|
||||
return "PCI info not found, invalid scanpci result";
|
||||
while (pstart[1] != 'p')
|
||||
{
|
||||
pstart = memrchr(buffer.chars, '\n', (size_t) (pstart - buffer.chars - 1));
|
||||
if (pstart == NULL)
|
||||
return "PCI info not found, invalid scanpci result";
|
||||
}
|
||||
++pstart;
|
||||
|
||||
uint32_t vendorId, deviceId;
|
||||
if (sscanf(pstart, "pci %*[^:]: vendor %x device %x",
|
||||
&vendorId, &deviceId) != 2)
|
||||
return "PCI info not found, invalid scanpci result";
|
||||
|
||||
pclass += strlen("\n CLASS 0x03 ");
|
||||
uint32_t subclass = (uint32_t) strtoul(pclass, NULL, 16);
|
||||
pclass += strlen("0x02 0x00 REVISION ");
|
||||
uint32_t revision = (uint32_t) strtoul(pclass, NULL, 16);
|
||||
|
||||
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
||||
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
ffStrbufInit(&gpu->memoryType);
|
||||
ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString((uint16_t) *vendorId));
|
||||
ffStrbufInit(&gpu->name);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "/usr/bin/scanpci");
|
||||
ffStrbufInitS(&gpu->driver, di_driver_name(node));
|
||||
ffStrbufInitStatic(&gpu->platformApi, "libdevinfo");
|
||||
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 = 0;
|
||||
gpu->deviceId = strtoul(di_bus_addr(node), NULL, 16);
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
|
||||
ffGPUQueryAmdGpuName((uint16_t) deviceId, (uint8_t) revision, gpu);
|
||||
{
|
||||
int* revId;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "revision-id", &revId) > 0)
|
||||
ffGPUQueryAmdGpuName((uint16_t) *deviceId, (uint8_t) *revId, gpu);
|
||||
}
|
||||
|
||||
if (gpu->name.length == 0)
|
||||
{
|
||||
ffGPUFillVendorAndName((uint8_t) subclass, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
|
||||
uint8_t subclass = 0; // assume VGA
|
||||
int* classCode;
|
||||
if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "class-code", &classCode) > 0)
|
||||
subclass = (uint8_t) (*classCode & 0xFFFF);
|
||||
ffGPUFillVendorAndName(subclass, (uint16_t) *vendorId, (uint16_t) *deviceId, gpu);
|
||||
}
|
||||
}
|
||||
|
||||
return DI_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
di_node_t rootNode = di_init("/", DINFOCPYALL);
|
||||
if (rootNode == DI_NODE_NIL)
|
||||
return "di_init() failed";
|
||||
di_walk_minor(rootNode, DDI_NT_DISPLAY, DI_WALK_CLDFIRST, gpus, (void*) walkDevTree);
|
||||
di_fini(rootNode);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+193
-84
@@ -1,18 +1,15 @@
|
||||
#include "gpu.h"
|
||||
#include "common/library.h"
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#define INITGUID
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <devguid.h>
|
||||
|
||||
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
|
||||
{
|
||||
if(*hdev)
|
||||
SetupDiDestroyDeviceInfoList(*hdev);
|
||||
}
|
||||
#include <cfgmgr32.h>
|
||||
#include <ntddvdeo.h>
|
||||
#include <devpkey.h>
|
||||
#include "util/windows/nt.h"
|
||||
|
||||
#define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}"
|
||||
enum { FF_GUID_STRLEN = sizeof(FF_EMPTY_GUID_STR) / sizeof(wchar_t) - 1 };
|
||||
@@ -24,21 +21,38 @@ const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\C
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
|
||||
SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
|
||||
ULONG devInfListSize = 0;
|
||||
if (CM_Get_Device_Interface_List_SizeW(&devInfListSize, (LPGUID)&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS || devInfListSize <= 1)
|
||||
return "No display devices found";
|
||||
|
||||
if(hdev == INVALID_HANDLE_VALUE)
|
||||
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY) failed";
|
||||
FF_AUTO_FREE DEVINSTID_W devInfList = malloc(devInfListSize * sizeof(*devInfList));
|
||||
|
||||
SP_DEVINFO_DATA did = { .cbSize = sizeof(did) };
|
||||
for (DWORD idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); ++idev)
|
||||
if (CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, devInfList, devInfListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS)
|
||||
return "CM_Get_Device_Interface_ListW failed";
|
||||
|
||||
for (wchar_t* devInf = devInfList; *devInf; devInf += wcslen(devInf) + 1)
|
||||
{
|
||||
if (wcsncmp(devInf, L"\\\\?\\ROOT#BasicDisplay#", 22) == 0)
|
||||
continue; // Skip Microsoft Basic Display Adapter
|
||||
|
||||
DEVINST devInst = 0;
|
||||
wchar_t buffer[256];
|
||||
ULONG bufferLen = 0;
|
||||
|
||||
{
|
||||
DEVPROPTYPE propertyType;
|
||||
bufferLen = sizeof(buffer);
|
||||
if (CM_Get_Device_Interface_PropertyW(devInf, &DEVPKEY_Device_InstanceId, &propertyType, (PBYTE) buffer, &bufferLen, 0) != CR_SUCCESS ||
|
||||
CM_Locate_DevNodeW(&devInst, buffer, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS)
|
||||
continue;
|
||||
}
|
||||
|
||||
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
|
||||
ffStrbufInit(&gpu->vendor);
|
||||
ffStrbufInit(&gpu->name);
|
||||
ffStrbufInit(&gpu->driver);
|
||||
ffStrbufInit(&gpu->memoryType);
|
||||
ffStrbufInitStatic(&gpu->platformApi, "SetupAPI");
|
||||
ffStrbufInitStatic(&gpu->platformApi, "CM API");
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
|
||||
@@ -48,86 +62,91 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
gpu->deviceId = 0;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
|
||||
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_BUSNUMBER, NULL, (PBYTE) &pciBus, sizeof(pciBus), NULL) &&
|
||||
SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_ADDRESS, NULL, (PBYTE) &pciAddr, sizeof(pciAddr), NULL))
|
||||
{
|
||||
pciDev = (pciAddr >> 16) & 0xFFFF;
|
||||
pciFunc = pciAddr & 0xFFFF;
|
||||
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
|
||||
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
|
||||
}
|
||||
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
|
||||
if (swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4)
|
||||
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
|
||||
wchar_t buffer[256];
|
||||
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
|
||||
|
||||
ULONG pciBufLen = sizeof(pciBus);
|
||||
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS)
|
||||
{
|
||||
pciBufLen = sizeof(pciAddr);
|
||||
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS)
|
||||
{
|
||||
pciDev = (pciAddr >> 16) & 0xFFFF;
|
||||
pciFunc = pciAddr & 0xFFFF;
|
||||
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
|
||||
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t adapterLuid = 0;
|
||||
|
||||
FF_HKEY_AUTO_DESTROY hVideoIdKey = SetupDiOpenDevRegKey(hdev, &did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
||||
if (!hVideoIdKey) continue;
|
||||
DWORD bufferLen = sizeof(buffer);
|
||||
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS &&
|
||||
bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
|
||||
FF_HKEY_AUTO_DESTROY hVideoIdKey = NULL;
|
||||
if (CM_Open_DevNode_Key(devInst, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hVideoIdKey, CM_REGISTRY_HARDWARE) == CR_SUCCESS)
|
||||
{
|
||||
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
|
||||
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
|
||||
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
|
||||
bufferLen = sizeof(buffer);
|
||||
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS &&
|
||||
bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
|
||||
{
|
||||
uint32_t vendorId = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
|
||||
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
|
||||
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
|
||||
uint64_t dedicatedVideoMemory = 0;
|
||||
if(ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, NULL))
|
||||
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
|
||||
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
|
||||
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
|
||||
{
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
|
||||
gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
if (gpu->vendor.length == 0)
|
||||
{
|
||||
uint32_t vendorId = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
|
||||
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
}
|
||||
|
||||
uint64_t dedicatedSystemMemory, sharedSystemMemory;
|
||||
if(ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &dedicatedSystemMemory, NULL) &&
|
||||
ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
|
||||
{
|
||||
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
|
||||
gpu->shared.total = sharedSystemMemory;
|
||||
}
|
||||
ffRegReadStrbuf(hDirectxKey, L"Description", &gpu->name, NULL);
|
||||
|
||||
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
|
||||
{
|
||||
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
|
||||
}
|
||||
ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &gpu->dedicated.total, NULL);
|
||||
if (ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &gpu->shared.total, NULL))
|
||||
{
|
||||
uint64_t sharedSystemMemory = 0;
|
||||
if (ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
|
||||
gpu->shared.total += sharedSystemMemory;
|
||||
}
|
||||
|
||||
uint32_t featureLevel = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
|
||||
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
|
||||
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
|
||||
{
|
||||
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
|
||||
}
|
||||
|
||||
uint64_t driverVersion = 0;
|
||||
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
|
||||
{
|
||||
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
|
||||
(unsigned) (driverVersion >> 48) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 32) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 16) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 0) & 0xFFFF
|
||||
);
|
||||
uint32_t featureLevel = 0;
|
||||
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
|
||||
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
|
||||
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
|
||||
|
||||
uint64_t driverVersion = 0;
|
||||
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
|
||||
{
|
||||
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
|
||||
(unsigned) (driverVersion >> 48) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 32) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 16) & 0xFFFF,
|
||||
(unsigned) (driverVersion >> 0) & 0xFFFF
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gpu->vendor.length == 0)
|
||||
if (gpu->vendor.length == 0 || gpu->name.length == 0)
|
||||
{
|
||||
bufferLen = sizeof(buffer);
|
||||
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DRIVER, NULL, (PBYTE) buffer, sizeof(buffer), &bufferLen) && bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
|
||||
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DRIVER, NULL, buffer, &bufferLen, 0) == CR_SUCCESS &&
|
||||
bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
|
||||
{
|
||||
wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000"));
|
||||
FF_HKEY_AUTO_DESTROY hRegDriverKey = NULL;
|
||||
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL))
|
||||
{
|
||||
if (ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
|
||||
if (gpu->vendor.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
|
||||
{
|
||||
if (ffStrbufContainS(&gpu->vendor, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
@@ -136,6 +155,19 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
else if (ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
||||
}
|
||||
if (gpu->name.length == 0)
|
||||
ffRegReadStrbuf(hRegDriverKey, L"DriverDesc", &gpu->name, NULL);
|
||||
if (gpu->driver.length == 0)
|
||||
ffRegReadStrbuf(hRegDriverKey, L"DriverVersion", &gpu->driver, NULL);
|
||||
if (gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET)
|
||||
{
|
||||
if (!ffRegReadUint64(hRegDriverKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
|
||||
{
|
||||
uint32_t memorySize = 0;
|
||||
if (ffRegReadUint(hRegDriverKey, L"HardwareInformation.MemorySize", &memorySize, NULL))
|
||||
gpu->dedicated.total = memorySize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,18 +175,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
|
||||
const char* dllName;
|
||||
|
||||
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName) && (options->temp || options->driverSpecific))
|
||||
if (options->driverSpecific && getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName))
|
||||
{
|
||||
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
|
||||
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_HARDWAREID, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
|
||||
{
|
||||
swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
|
||||
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
|
||||
}
|
||||
|
||||
detectFn(
|
||||
&(FFGpuDriverCondition) {
|
||||
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID
|
||||
.type = (deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0)
|
||||
| (adapterLuid > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_LUID : 0)
|
||||
| (pciAddr > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID : 0),
|
||||
.pciDeviceId = {
|
||||
@@ -189,9 +214,93 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
|
||||
if (!gpu->name.length)
|
||||
{
|
||||
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DEVICEDESC, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
|
||||
bufferLen = sizeof(buffer);
|
||||
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DEVICEDESC, NULL, buffer, &bufferLen, 0) == CR_SUCCESS)
|
||||
ffStrbufSetWS(&gpu->name, buffer);
|
||||
}
|
||||
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN && adapterLuid > 0)
|
||||
{
|
||||
HMODULE hgdi32 = GetModuleHandleW(L"gdi32.dll");
|
||||
if (hgdi32)
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(hgdi32, D3DKMTOpenAdapterFromLuid);
|
||||
if (ffD3DKMTOpenAdapterFromLuid) // Windows 8 and later
|
||||
{
|
||||
D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*)&adapterLuid };
|
||||
if (NT_SUCCESS(ffD3DKMTOpenAdapterFromLuid(&openAdapterFromLuid)))
|
||||
{
|
||||
D3DKMT_ADAPTERTYPE adapterType = {};
|
||||
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
|
||||
.hAdapter = openAdapterFromLuid.hAdapter,
|
||||
.Type = KMTQAITYPE_ADAPTERTYPE,
|
||||
.pPrivateDriverData = &adapterType,
|
||||
.PrivateDriverDataSize = sizeof(adapterType),
|
||||
};
|
||||
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) // Vista and later
|
||||
{
|
||||
if (adapterType.HybridDiscrete)
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
else if (adapterType.HybridIntegrated)
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
|
||||
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET)
|
||||
{
|
||||
for (ULONG nodeIdx = 0; ; nodeIdx++)
|
||||
{
|
||||
D3DKMT_NODEMETADATA nodeMetadata = {
|
||||
.NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx,
|
||||
};
|
||||
queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) {
|
||||
.hAdapter = openAdapterFromLuid.hAdapter,
|
||||
.Type = KMTQAITYPE_NODEMETADATA,
|
||||
.pPrivateDriverData = &nodeMetadata,
|
||||
.PrivateDriverDataSize = sizeof(nodeMetadata),
|
||||
};
|
||||
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) break; // Windows 10 and later
|
||||
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) continue;
|
||||
|
||||
D3DKMT_QUERYSTATISTICS queryStatistics = {
|
||||
.Type = D3DKMT_QUERYSTATISTICS_NODE2,
|
||||
.AdapterLuid = *(LUID*)&adapterLuid,
|
||||
.QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx },
|
||||
};
|
||||
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) // Windows 11 (22H2) and later
|
||||
{
|
||||
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter };
|
||||
(void) D3DKMTCloseAdapter(&closeAdapter);
|
||||
openAdapterFromLuid.hAdapter = 0;
|
||||
}
|
||||
|
||||
if (options->temp && gpu->temperature != gpu->temperature)
|
||||
{
|
||||
D3DKMT_QUERYSTATISTICS queryStatistics = {
|
||||
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER,
|
||||
.AdapterLuid = *(LUID*)&adapterLuid,
|
||||
.QueryPhysAdapter = { .PhysicalAdapterIndex = 0 },
|
||||
};
|
||||
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) &&
|
||||
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
|
||||
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
|
||||
{
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
|
||||
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
else if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
|
||||
gpu->type = gpu->dedicated.total >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -23,6 +23,13 @@ typedef enum NvApiGPUMemoryType
|
||||
NVAPI_GPU_MEMORY_TYPE_GDDR7,
|
||||
} NvApiGPUMemoryType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NV_SYSTEM_TYPE_GPU_UNKNOWN = 0,
|
||||
NV_SYSTEM_TYPE_IGPU = 1, // Integrated
|
||||
NV_SYSTEM_TYPE_DGPU = 2, // Discrete
|
||||
} NvApiGPUType;
|
||||
|
||||
typedef int NvAPI_Status; // 0 = success; < 0 = error
|
||||
typedef struct NvPhysicalGpuHandle* NvPhysicalGpuHandle;
|
||||
|
||||
@@ -32,6 +39,7 @@ typedef enum
|
||||
NVAPI_INTERFACE_OFFSET_UNLOAD = 0xD22BDD7E,
|
||||
NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS = 0xE5AC921F,
|
||||
NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE = 0x57F7CAAC,
|
||||
NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE = 0xC33BAEB1,
|
||||
|
||||
NVAPI_INTERFACE_OFFSET_FORCE_UINT32 = 0xFFFFFFFF
|
||||
} NvApiInterfaceOffsets;
|
||||
@@ -42,3 +50,4 @@ extern NvAPI_Status nvapi_Initialize(void);
|
||||
extern NvAPI_Status nvapi_Unload(void);
|
||||
extern NvAPI_Status nvapi_EnumPhysicalGPUs(NvPhysicalGpuHandle* handles, int* count);
|
||||
extern NvAPI_Status nvapi_GPU_GetRamType(NvPhysicalGpuHandle handle, NvApiGPUMemoryType* memtype);
|
||||
extern NvAPI_Status nvapi_GPU_GetGPUType(NvPhysicalGpuHandle handle, NvApiGPUType* gpuType);
|
||||
|
||||
@@ -12,6 +12,7 @@ const char* ffDetectHost(FFHostResult* host)
|
||||
|| ffSettingsGetAndroidProperty("ro.vivo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.vendor.oplus.market.enname", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name)
|
||||
|
||||
@@ -36,6 +36,10 @@ const char* getOthersByIokit(FFHostResult* host)
|
||||
if (manufacturer)
|
||||
ffCfStrGetString(manufacturer, &host->vendor);
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef version = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (version)
|
||||
ffCfStrGetString(version, &host->version);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,11 @@ const char* ffDetectHost(FFHostResult* host)
|
||||
//On WSL, the real host can't be detected. Instead use WSL as host.
|
||||
if(wslDistroName != NULL || getenv("WSL_DISTRO") != NULL || getenv("WSL_INTEROP") != NULL)
|
||||
{
|
||||
ffStrbufAppendS(&host->name, "Windows Subsystem for Linux");
|
||||
ffStrbufSetStatic(&host->name, "Windows Subsystem for Linux");
|
||||
if (wslDistroName)
|
||||
ffStrbufAppendF(&host->name, " - %s", wslDistroName);
|
||||
ffStrbufAppendS(&host->family, "WSL");
|
||||
ffStrbufSetStatic(&host->family, "WSL");
|
||||
ffStrbufSetStatic(&host->vendor, "Microsoft Corporation");
|
||||
|
||||
if (instance.config.general.detectVersion)
|
||||
{
|
||||
@@ -92,6 +93,17 @@ const char* ffDetectHost(FFHostResult* host)
|
||||
}); // supported in 2.2.3 and later
|
||||
}
|
||||
}
|
||||
else if (ffStrbufStartsWithS(&instance.state.platform.sysinfo.version, "FreeBSD "))
|
||||
{
|
||||
ffStrbufSetStatic(&host->name, "Linux Binary Compatibility on FreeBSD");
|
||||
ffStrbufSetStatic(&host->family, "FreeBSD");
|
||||
ffStrbufSetStatic(&host->vendor, "FreeBSD Foundation");
|
||||
if (instance.config.general.detectVersion)
|
||||
{
|
||||
ffStrbufSetS(&host->version, instance.state.platform.sysinfo.version.chars + strlen("FreeBSD "));
|
||||
ffStrbufSubstrBeforeFirstC(&host->version, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -121,7 +121,7 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
|
||||
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 5 ports)";
|
||||
if(ffStrEquals(version, "15,14")) return "Mac Studio (M3 Ultra, 2025)";
|
||||
if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,2")) return "MacBook Air (13-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,12")) return "MacBook Air (13-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,3")) return "MacBook Pro (14-inch, Nov 2023, Two Thunderbolt / USB 4 ports)";
|
||||
if(ffStrEquals(version, "15,4")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports)";
|
||||
if(ffStrEquals(version, "15,5")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports, Two USB 3 ports)";
|
||||
|
||||
@@ -1,48 +1,35 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/media/media.h"
|
||||
#include "common/library.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/apple/osascript.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreFoundation/CoreFoundation.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));
|
||||
extern void MRMediaRemoteGetNowPlayingClient(dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import));
|
||||
extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribute__((weak_import));
|
||||
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
|
||||
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
|
||||
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* getMedia(FFMediaResult* result)
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result)
|
||||
{
|
||||
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingClient);
|
||||
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetBundleIdentifier);
|
||||
FF_TEST_FN_EXISTANCE(MRNowPlayingClientGetParentAppBundleIdentifier);
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingApplicationIsPlaying);
|
||||
#undef FF_TEST_FN_EXISTANCE
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
||||
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
|
||||
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
dispatch_group_enter(group);
|
||||
__block const char* error = NULL;
|
||||
MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) {
|
||||
if(info != nil)
|
||||
{
|
||||
error = ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
|
||||
if(!error)
|
||||
{
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
|
||||
}
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
|
||||
}
|
||||
else
|
||||
error = "MRMediaRemoteGetNowPlayingInfo() failed";
|
||||
@@ -51,36 +38,104 @@ static const char* getMedia(FFMediaResult* result)
|
||||
});
|
||||
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingClient(queue, ^(_Nullable id clientObj) {
|
||||
if (clientObj != nil)
|
||||
{
|
||||
CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier(clientObj);
|
||||
if (identifier == nil)
|
||||
identifier = MRNowPlayingClientGetParentAppBundleIdentifier(clientObj);
|
||||
if (identifier != nil)
|
||||
ffCfStrGetString(identifier, &result->playerId);
|
||||
}
|
||||
MRMediaRemoteGetNowPlayingApplicationIsPlaying(queue, ^(BOOL playing) {
|
||||
ffStrbufSetStatic(&result->status, playing ? "Playing" : "Paused");
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayID)
|
||||
{
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationDisplayID(queue, ^(_Nullable CFStringRef displayID) {
|
||||
ffCfStrGetString(displayID, &result->playerId);
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
}
|
||||
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayName)
|
||||
{
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationDisplayName(0, queue, ^(_Nullable CFStringRef name) {
|
||||
ffCfStrGetString(name, &result->player);
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
}
|
||||
|
||||
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
||||
// Don't dispatch_release because we are using ARC
|
||||
|
||||
if(result->playerId.length > 0)
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, ARRAY_SIZE(buf), "name of app id \"%s\"", result->playerId.chars);
|
||||
ffOsascript(buf, &result->player);
|
||||
}
|
||||
|
||||
if(result->song.length > 0)
|
||||
return NULL;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"), used))
|
||||
int ffPrintMediaByMediaRemote(void)
|
||||
{
|
||||
FFMediaResult media = {
|
||||
.status = ffStrbufCreate(),
|
||||
.song = ffStrbufCreate(),
|
||||
.artist = ffStrbufCreate(),
|
||||
.album = ffStrbufCreate(),
|
||||
.playerId = ffStrbufCreate(),
|
||||
.player = ffStrbufCreate(),
|
||||
};
|
||||
if (getMediaByMediaRemote(&media) != NULL)
|
||||
return 1;
|
||||
ffStrbufPutTo(&media.status, stdout);
|
||||
ffStrbufPutTo(&media.song, stdout);
|
||||
ffStrbufPutTo(&media.artist, stdout);
|
||||
ffStrbufPutTo(&media.album, stdout);
|
||||
ffStrbufPutTo(&media.playerId, stdout);
|
||||
ffStrbufPutTo(&media.player, stdout);
|
||||
ffStrbufDestroy(&media.status);
|
||||
ffStrbufDestroy(&media.song);
|
||||
ffStrbufDestroy(&media.artist);
|
||||
ffStrbufDestroy(&media.album);
|
||||
ffStrbufDestroy(&media.playerId);
|
||||
ffStrbufDestroy(&media.player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* getMediaByAuthorizedProcess(FFMediaResult* result)
|
||||
{
|
||||
// #1737
|
||||
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote()", instance.state.platform.exePath.chars);
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
|
||||
"-c",
|
||||
script.chars,
|
||||
nil
|
||||
});
|
||||
if (error) return error;
|
||||
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 };
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
|
||||
ffStrbufSetS(varList[i], line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
{
|
||||
const char* error = getMedia(media);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
const char* error;
|
||||
if (@available(macOS 15.4, *))
|
||||
error = getMediaByAuthorizedProcess(media);
|
||||
else
|
||||
error = getMediaByMediaRemote(media);
|
||||
if (error)
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
else if (media->player.length == 0 && media->playerId.length > 0)
|
||||
{
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufStartsWithIgnCaseS(&media->player, "com."))
|
||||
ffStrbufSubstrAfter(&media->player, strlen("com.") - 1);
|
||||
ffStrbufReplaceAllC(&media->player, '.', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
|
||||
ffStrbufClear(&result->artist);
|
||||
ffStrbufClear(&result->album);
|
||||
ffStrbufClear(&result->url);
|
||||
ffStrbufClear(&result->status);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,16 @@ static const char* getMedia(FFMediaResult* media)
|
||||
}
|
||||
|
||||
ffStrbufSetWS(&media->playerId, result.playerId);
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
if (result.playerName[0])
|
||||
{
|
||||
ffStrbufSetWS(&media->player, result.playerName);
|
||||
}
|
||||
else
|
||||
ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID
|
||||
{
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
}
|
||||
ffStrbufSetWS(&media->song, result.song);
|
||||
ffStrbufSetWS(&media->artist, result.artist);
|
||||
ffStrbufSetWS(&media->album, result.album);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user