mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
256 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba8a21142f | |||
| eca3625165 | |||
| 677e920dc8 | |||
| 38c0b24daa | |||
| 4e05502d7a | |||
| d0928a63bf | |||
| aa0bbd5aee | |||
| ce554dbdd0 | |||
| a0174e8666 | |||
| 8be419cfd6 | |||
| ca79bae36e | |||
| b1f0248fb3 | |||
| 77dd18466b | |||
| 5bb6e22679 | |||
| 9ea9291ab8 | |||
| 6ec73863ab | |||
| 8c2f93151d | |||
| 71ddc4ffc6 | |||
| 4909d693e3 | |||
| fe76bbe68a | |||
| d1f20822f1 | |||
| 1ed804db52 | |||
| 0e8b9bec2d | |||
| a3182c31cb | |||
| d2f2c76dfc | |||
| 2d1ae1b4c5 | |||
| 316409ecc3 | |||
| f0fc38bcb5 | |||
| e7a6b84107 | |||
| 02c3254961 | |||
| a90e1d7ccf | |||
| 6cdd64ac55 | |||
| aa1201ffb8 | |||
| 9b491c2f49 | |||
| be3e2ba521 | |||
| ccbb9e90ea | |||
| d07fe997a9 | |||
| b60996bcd1 | |||
| 272c0aad9c | |||
| 7566f10bb6 | |||
| 847b76b863 | |||
| 5c0ad030cc | |||
| 02aafbd7f4 | |||
| 72da8150bd | |||
| aca2b5336d | |||
| c79b67efc1 | |||
| 30af91ce8e | |||
| 6c56348e54 | |||
| 531b25dc2f | |||
| 8c6dc34654 | |||
| cf2034b93e | |||
| f7db03b8c4 | |||
| 8647e366f9 | |||
| 1bf41d68f9 | |||
| 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 |
+130
-10
@@ -383,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
|
||||
@@ -408,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
|
||||
@@ -426,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
|
||||
@@ -452,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:
|
||||
@@ -505,7 +552,7 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '14.2'
|
||||
version: '14.3'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
@@ -542,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
|
||||
@@ -581,7 +628,7 @@ jobs:
|
||||
version: '10.1'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick opencl-headers ocl-icd
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -597,6 +644,77 @@ 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: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
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
|
||||
@@ -734,11 +852,13 @@ 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:
|
||||
|
||||
+214
@@ -1,3 +1,217 @@
|
||||
# 2.49.0
|
||||
|
||||
Deprecation Notice:
|
||||
* In fastfetch v2, the JSONC configuration format has been introduced, while command line configuration flags are kept for compatibility. Although they have the same effects, they use two different code paths, and as the number of flags grows, the codebase is becoming increasingly difficult to maintain.
|
||||
* Removal of module config flags is planned for **v2.50.0**, which will also fix a long-standing issue #1477.
|
||||
* Removal of most other config flags is also planned for later versions.
|
||||
* Keys of JSON configuration files will be all case-sensitive. Currently they are inconsistent. Planned for **v2.50.0**.
|
||||
|
||||
Changes:
|
||||
* Due to more restrictive permissions in macOS Tahoe, SSID detection on macOS 26+ requires root privileges. `<redacted>` will be displayed otherwise.
|
||||
|
||||
Features:
|
||||
* Improve `nouveau` driver support for `--gpu-driver-specific` (GPU, Linux)
|
||||
* VRAM size detection
|
||||
* GPU temperature detection
|
||||
* Core count detection (when available)
|
||||
* Improve Scoop package manager detection (Packages, Windows)
|
||||
* Support [`scoop-global`](https://github.com/ScoopInstaller/Install?tab=readme-ov-file#advanced-installation)
|
||||
* Read Scoop's config file to find the installation path of Scoop
|
||||
* Improve ARM SoC detection (CPU, Android)
|
||||
* Make SoC detection more lenient. Higher chance to match at the cost of accuracy.
|
||||
* Add more Snapdragon SoC names
|
||||
* Support labwc WM version detection, used for XFCE4 on Wayland (WM, Linux)
|
||||
* Improve accuracy of GPU temperature detection for Intel dedicated GPUs on Windows (GPU, Windows)
|
||||
* Parse unicode escaped strings generated by qt5ct (#1864, Font, Linux)
|
||||
* Add `--{duration,percent,size,freq,temp}-space-before-unit [always|never]` options to add a space before the unit when printing duration, percent, size, frequency and temperature values
|
||||
* Add `--duration-abbreviation` to abbreviate duration values in custom format
|
||||
* For example: `1 day, 2 hours, 3 mins` will be displayed as `1d 2h 3m`
|
||||
* Add `--percent-with` to pad the percent value with spaces to a fixed width
|
||||
* For example: `--percent-with 3` will display ` 50%` instead of `50%`; useful for aligning percent values in custom format
|
||||
|
||||
Bugfixes:
|
||||
* Improve accuracy of Flatpak count detection (#1856, Packages, Linux)
|
||||
* Remove qi package manager support (#1858, Packages, Linux)
|
||||
* Fix LocalIP module on Windows (LocalIP, Windows)
|
||||
* Fix default route detection when multiple network interfaces are connected
|
||||
* Fix link speed calculation
|
||||
* Fix interface status when the interface is up but not connected (Wifi, Linux)
|
||||
* Fix variable names in custom format (#1861)
|
||||
* `full-path` to `path` (Editor)
|
||||
* `session` to `session-name` (Users)
|
||||
* `name` to `project-name` (Version)
|
||||
* Fix wrong /s assignment in custom format (#1871, DiskIO)
|
||||
|
||||
Logos:
|
||||
* Add `Aeon`
|
||||
* Remove `Evolinx`
|
||||
|
||||
# 2.48.1
|
||||
|
||||
Features:
|
||||
* Add support for detecting Openbox WM version (WM, Linux)
|
||||
* Improve reliability of child process spawning on Windows (Windows)
|
||||
* Add a new option `--packages-combined`, which combines related package managers into single counts (#1851, Packages)
|
||||
* For example: if you have both `flatpak-system` and `flatpak-user` packages installed, they will be combined into a single `flatpak` count with `--packages-combined` enabled.
|
||||
* Add `modules[n].condition` to conditionally enable modules on different platforms
|
||||
* Useful when sharing configuration files across platforms
|
||||
* For example:
|
||||
```jsonc
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "This string will be printed on Intel macOS only",
|
||||
"condition": {
|
||||
"system": "macOS", // Can be an array, optional
|
||||
"arch": "x86_64" // Can be an array, optional too
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bugfixes:
|
||||
* Revert the change of `posix_spawn` in v2.48.0 for Android and OpenBSD (Android / OpenBSD)
|
||||
* Fix completion for Android 7 (Required by Termux)
|
||||
|
||||
# 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:
|
||||
|
||||
+36
-32
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.43.0
|
||||
VERSION 2.49.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)
|
||||
@@ -326,11 +326,6 @@ endif()
|
||||
fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP)
|
||||
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
|
||||
|
||||
if(APPLE)
|
||||
# See src/detection/media/media_apple.m
|
||||
fastfetch_load_text(src/data/nowPlaying.scptd DATATEXT_NOWPLAYING)
|
||||
endif()
|
||||
|
||||
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
|
||||
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
|
||||
if(APPLE)
|
||||
@@ -341,7 +336,7 @@ 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)
|
||||
@@ -356,10 +351,11 @@ file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
|
||||
#######################
|
||||
|
||||
set(LIBFASTFETCH_SRC
|
||||
src/common/percent.c
|
||||
src/common/commandoption.c
|
||||
src/common/duration.c
|
||||
src/common/font.c
|
||||
src/common/format.c
|
||||
src/common/frequency.c
|
||||
src/common/init.c
|
||||
src/common/jsonconfig.c
|
||||
src/common/library.c
|
||||
@@ -368,9 +364,11 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/networking/networking_common.c
|
||||
src/common/option.c
|
||||
src/common/parsing.c
|
||||
src/common/percent.c
|
||||
src/common/printing.c
|
||||
src/common/properties.c
|
||||
src/common/settings.c
|
||||
src/common/size.c
|
||||
src/common/temps.c
|
||||
src/detection/bluetoothradio/bluetoothradio.c
|
||||
src/detection/bootmgr/bootmgr.c
|
||||
@@ -529,6 +527,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
|
||||
@@ -676,6 +675,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
|
||||
@@ -787,7 +787,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
|
||||
@@ -802,7 +802,7 @@ elseif(NetBSD)
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nbsd.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
|
||||
@@ -884,7 +884,7 @@ elseif(OpenBSD)
|
||||
src/detection/users/users_obsd.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_obsd.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
|
||||
@@ -1060,7 +1060,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 +1100,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,7 +1585,6 @@ elseif(WIN32)
|
||||
PRIVATE "ws2_32"
|
||||
PRIVATE "ntdll"
|
||||
PRIVATE "version"
|
||||
PRIVATE "setupapi"
|
||||
PRIVATE "hid"
|
||||
PRIVATE "wtsapi32"
|
||||
PRIVATE "imagehlp"
|
||||
@@ -1593,7 +1592,6 @@ elseif(WIN32)
|
||||
PRIVATE "winbrand"
|
||||
PRIVATE "propsys"
|
||||
PRIVATE "secur32"
|
||||
PRIVATE "pdh"
|
||||
)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
# WoA only works on Windows 10 or higher
|
||||
@@ -1636,6 +1634,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)
|
||||
@@ -1925,17 +1924,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)
|
||||
@@ -1961,12 +1960,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,6 +10,7 @@
|
||||
[](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 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.
|
||||
|
||||
@@ -21,6 +22,8 @@ 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
|
||||
@@ -67,13 +70,12 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
|
||||
|
||||
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`
|
||||
|
||||
### NetBSD
|
||||
|
||||
* `pkgin in fastfetch`
|
||||
* FreeBSD: `pkg install fastfetch`
|
||||
* NetBSD: `pkgin in fastfetch`
|
||||
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
|
||||
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
|
||||
|
||||
### Android (Termux)
|
||||
|
||||
@@ -91,7 +93,7 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
|
||||
* 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 <module> --format json`
|
||||
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
|
||||
* Display help messages: `fastfetch --help`
|
||||
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
|
||||
|
||||
|
||||
@@ -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
+36
@@ -1,3 +1,39 @@
|
||||
fastfetch (2.48.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.48.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 17 Jul 2025 16:16:52 +0800
|
||||
|
||||
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
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.42.0_source.buildinfo universe/utils optional
|
||||
fastfetch_2.48.0_source.buildinfo universe/utils optional
|
||||
|
||||
+500
-15
File diff suppressed because it is too large
Load Diff
+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",
|
||||
|
||||
+94
-20
@@ -6,11 +6,13 @@
|
||||
"keys": "blue"
|
||||
},
|
||||
"separator": "",
|
||||
// Constants are reusable strings referenced by {$1}, {$2}, etc.
|
||||
// These contain ANSI escape codes for cursor positioning
|
||||
"constants": [
|
||||
"──────────────────────────────────────────────",
|
||||
"\u001b[47D",
|
||||
"\u001b[47C",
|
||||
"\u001b[46C"
|
||||
"──────────────────────────────────────────────", // {$1} - horizontal line for borders
|
||||
"\u001b[47D", // {$2} - move cursor left 47 columns
|
||||
"\u001b[47C", // {$3} - move cursor right 47 columns
|
||||
"\u001b[46C" // {$4} - move cursor right 46 columns
|
||||
],
|
||||
"brightColor": false
|
||||
},
|
||||
@@ -22,6 +24,24 @@
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
// Key format breakdown for OS module:
|
||||
// "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
//
|
||||
// │ - Left border of key block
|
||||
// {icon} - OS icon (defined internally by fastfetch)
|
||||
// \u001b[s - ANSI escape: save cursor position (ESC[s)
|
||||
// {sysname} - Format variable: system name (e.g., "Linux", "Darwin")
|
||||
// \u001b[u - ANSI escape: restore cursor to saved position (ESC[u)
|
||||
// Necessary because the length of `{sysname}` differs between different platforms
|
||||
// \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C)
|
||||
// │ - Right border of key block (always 10 columns from left border)
|
||||
// {$3} - Reference to constants[2]: move cursor right 47 columns
|
||||
// │ - Right border of value block
|
||||
// {$2} - Reference to constants[1]: move cursor left 47 columns
|
||||
//
|
||||
// This creates a fixed-width layout where the key block is exactly 10 columns wide,
|
||||
// regardless of the actual content length. The cursor manipulation ensures proper
|
||||
// alignment for the table-like structure.
|
||||
"key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
},
|
||||
{
|
||||
@@ -34,7 +54,7 @@
|
||||
"key": "│ {icon} Locale │{$3}│{$2}"
|
||||
},
|
||||
|
||||
// Hardware
|
||||
// Hardware section with cyan color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
@@ -42,6 +62,11 @@
|
||||
},
|
||||
{
|
||||
"type": "chassis",
|
||||
// Similar structure but with cyan color formatting:
|
||||
// │{#cyan}│ - Left border with cyan color
|
||||
// {icon} - Chassis icon
|
||||
// Chassis - Fixed label text
|
||||
// │{$4}│{#keys}│{$2} - Positioning and borders for value area
|
||||
"key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
@@ -76,7 +101,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Desktop
|
||||
// Desktop section with green color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
@@ -106,7 +131,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Terminal
|
||||
// Terminal section with yellow color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
@@ -138,7 +163,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Development
|
||||
// Development section with red color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D",
|
||||
@@ -146,31 +171,44 @@
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"keyIcon": "", // Custom icon override
|
||||
"key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}",
|
||||
"text": "rustc --version | cut -d' ' -f2",
|
||||
"format": "rustc {}"
|
||||
"text": "rustc --version",
|
||||
"format": "rustc {~6,13}" // Print 6th to 13th characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"condition": {
|
||||
"!system": "Windows" // Posix version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"text": "clang --version | head -1 | awk '{print $NF}'",
|
||||
"format": "clang {}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"condition": {
|
||||
"system": "Windows" // Windows version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"text": "clang --version | findstr version", // Finds the line with "version"
|
||||
"format": "clang {~-6}" // Prints the last 6 characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}",
|
||||
"text": "node --version",
|
||||
"format": "node {~1}"
|
||||
"format": "node {~1}" // {~1} removes first character (v)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}",
|
||||
"text": "go version | cut -d' ' -f3",
|
||||
"format": "go {~2}"
|
||||
"format": "go {~2}" // {~2} removes first 2 characters (go)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
@@ -200,7 +238,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Uptime
|
||||
// Uptime section with magenta color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D",
|
||||
@@ -212,15 +250,28 @@
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"myselfOnly": true,
|
||||
"myselfOnly": true, // Only show current user
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on non-macOS
|
||||
"!system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/", // On macOS, "/System/Volumes/VM" works for me
|
||||
"folders": "/", // Check root filesystem
|
||||
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on macOS
|
||||
"system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
},
|
||||
{
|
||||
@@ -230,12 +281,35 @@
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "└─────────────────{$1}┘",
|
||||
"key": "└─────────────────{$1}┘", // Bottom border of the entire layout
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// End
|
||||
"break",
|
||||
"colors"
|
||||
// End with color palette and line break
|
||||
"break", // Add a blank line
|
||||
"colors" // Display color palette
|
||||
]
|
||||
}
|
||||
|
||||
/*
|
||||
Key Format Structure Explanation:
|
||||
|
||||
The key format uses a combination of:
|
||||
1. Unicode box drawing characters (│ ┌ ┐ └ ┘ ┬ ┴) for borders
|
||||
2. ANSI escape codes for cursor positioning (\u001b[...)
|
||||
3. Format variables ({icon}, {sysname}, etc.)
|
||||
4. Constant references ({$1}, {$2}, etc.)
|
||||
5. Color formatting ({#color})
|
||||
|
||||
ANSI Escape Codes Used:
|
||||
- \u001b[s - Save cursor position (ESC[s)
|
||||
- \u001b[u - Restore cursor position (ESC[u)
|
||||
- \u001b[nC - Move cursor right n columns (ESC[nC)
|
||||
- \u001b[nD - Move cursor left n columns (ESC[nD)
|
||||
|
||||
This creates a table-like layout with fixed column widths and proper alignment,
|
||||
regardless of the actual content length in each field.
|
||||
|
||||
For more ANSI escape code reference, see:
|
||||
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#cursor-controls
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
@@ -16,7 +16,10 @@
|
||||
"format": "{release}"
|
||||
},
|
||||
"uptime",
|
||||
"packages",
|
||||
{
|
||||
"type": "packages",
|
||||
"combined": true
|
||||
},
|
||||
"shell",
|
||||
{
|
||||
"type": "display",
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "duration.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
|
||||
const char* space = instance.config.display.durationSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER ? " " : "";
|
||||
|
||||
if(totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendF(result, options->durationAbbreviation ? "%u%ssec" : "%u%ssecond", (unsigned) totalSeconds, space);
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if(options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u%sd", days, space);
|
||||
|
||||
if(hours > 0 || minutes > 0)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendF(result, "%u%sday", days, space);
|
||||
|
||||
if(days > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
|
||||
if(days >= 100)
|
||||
ffStrbufAppendS(result, "(!)");
|
||||
|
||||
if(hours > 0 || minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
if(hours > 0)
|
||||
{
|
||||
if(options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u%sh", hours, space);
|
||||
|
||||
if (minutes > 0)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendF(result, "%u%shour", hours, space);
|
||||
|
||||
if(hours > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
|
||||
if(minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
if(minutes > 0)
|
||||
{
|
||||
if(options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u%sm", minutes, space);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendF(result, "%u%smin", minutes, space);
|
||||
|
||||
if(minutes > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
|
||||
+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)) ||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "frequency.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
|
||||
{
|
||||
if (mhz == 0)
|
||||
return false;
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
const char* space = options->freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ";
|
||||
int8_t ndigits = options->freqNdigits;
|
||||
|
||||
if (ndigits >= 0)
|
||||
ffStrbufAppendF(result, "%.*f%sGHz", ndigits, mhz / 1000., space);
|
||||
else
|
||||
ffStrbufAppendF(result, "%u%sMHz", (unsigned) mhz, space);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
|
||||
@@ -105,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
|
||||
|
||||
+22
-3
@@ -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)
|
||||
@@ -32,6 +31,7 @@ static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(3)
|
||||
static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
@@ -42,18 +42,22 @@ static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* dat
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content)
|
||||
{
|
||||
return ffWriteFDData(fd, content->length, content->chars);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer)
|
||||
{
|
||||
return ffWriteFileData(fileName, buffer->length, buffer->chars);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(3)
|
||||
static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
@@ -67,26 +71,32 @@ static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
|
||||
FF_C_NONNULL(2, 4)
|
||||
ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data);
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
|
||||
FF_C_NONNULL(1, 2)
|
||||
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
|
||||
FF_C_NONNULL(2, 3)
|
||||
bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer);
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFileBuffer(fileName, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 3)
|
||||
static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFileBufferRelative(dfd, fileName, buffer);
|
||||
}
|
||||
|
||||
//Bit flags, combine with |
|
||||
typedef enum __attribute__((__packed__)) FFPathType
|
||||
{
|
||||
FF_PATHTYPE_FILE = 1 << 0,
|
||||
@@ -95,6 +105,7 @@ typedef enum __attribute__((__packed__)) FFPathType
|
||||
FF_PATHTYPE_FORCE_UNSIGNED = UINT8_MAX,
|
||||
} FFPathType;
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -137,11 +148,13 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out);
|
||||
|
||||
#define FF_IO_TERM_RESP_WAIT_MS 100 // #554
|
||||
|
||||
FF_C_SCANF(3, 4)
|
||||
FF_C_NONNULL(1, 3)
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
|
||||
|
||||
// Not thread safe!
|
||||
@@ -158,6 +171,7 @@ static inline void ffUnsuppressIO(bool* suppressed)
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty);
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapClose(FFNativeFD* pfd)
|
||||
{
|
||||
assert(pfd);
|
||||
@@ -177,6 +191,7 @@ static inline bool wrapClose(FFNativeFD* pfd)
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapFclose(FILE** pfile)
|
||||
{
|
||||
assert(pfile);
|
||||
@@ -187,6 +202,7 @@ static inline bool wrapFclose(FILE** pfile)
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FILE __attribute__((__cleanup__(wrapFclose)))
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
#ifndef _WIN32
|
||||
static inline bool wrapClosedir(DIR** pdir)
|
||||
{
|
||||
@@ -208,6 +224,7 @@ static inline bool wrapClosedir(HANDLE* pdir)
|
||||
#endif
|
||||
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
|
||||
|
||||
FF_C_NONNULL(1, 2, 3)
|
||||
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
|
||||
{
|
||||
// configDirs is a list of FFstrbufs include the trailing slash
|
||||
@@ -223,6 +240,8 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
|
||||
return false;
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Only O_RDONLY is supported
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
|
||||
|
||||
+10
-1
@@ -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;
|
||||
|
||||
@@ -358,3 +358,12 @@ void ffListFilesRecursively(const char* path, bool pretty)
|
||||
ffStrbufEnsureEndsWithC(&folder, '/');
|
||||
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
static FFNativeFD hNullFile = -1;
|
||||
if (hNullFile != -1)
|
||||
return hNullFile;
|
||||
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ bool ffSuppressIO(bool suppress)
|
||||
static bool init = false;
|
||||
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hOrigErr = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hNullFile = INVALID_HANDLE_VALUE;
|
||||
HANDLE hNullFile = ffGetNullFD();
|
||||
static int fOrigOut = -1;
|
||||
static int fOrigErr = -1;
|
||||
static int fNullFile = -1;
|
||||
@@ -187,7 +187,6 @@ bool ffSuppressIO(bool suppress)
|
||||
|
||||
hOrigOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hOrigErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
hNullFile = CreateFileW(L"NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
|
||||
fOrigOut = _dup(STDOUT_FILENO);
|
||||
fOrigErr = _dup(STDERR_FILENO);
|
||||
fNullFile = _open_osfhandle((intptr_t) hNullFile, 0);
|
||||
@@ -352,3 +351,23 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
static FFNativeFD hNullFile = INVALID_HANDLE_VALUE;
|
||||
if (hNullFile != INVALID_HANDLE_VALUE)
|
||||
return hNullFile;
|
||||
hNullFile = CreateFileW(
|
||||
L"NUL",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
&(SECURITY_ATTRIBUTES){
|
||||
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
||||
.lpSecurityDescriptor = NULL,
|
||||
.bInheritHandle = TRUE,
|
||||
});
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
+44
-1
@@ -4,6 +4,7 @@
|
||||
#include "common/printing.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/time.h"
|
||||
#include "detection/version/version.h"
|
||||
#include "modules/modules.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
@@ -170,6 +171,25 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
}
|
||||
}
|
||||
|
||||
static bool matchesJsonArray(const char* str, yyjson_val* val)
|
||||
{
|
||||
assert(val);
|
||||
|
||||
if (unsafe_yyjson_is_str(val))
|
||||
return ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(val));
|
||||
|
||||
if (!unsafe_yyjson_is_arr(val)) return false;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val* item;
|
||||
yyjson_arr_foreach(val, idx, max, item)
|
||||
{
|
||||
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
|
||||
@@ -197,6 +217,29 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
module = NULL;
|
||||
else if (yyjson_is_obj(module))
|
||||
{
|
||||
yyjson_val* conditions = yyjson_obj_get(module, "condition");
|
||||
if (conditions)
|
||||
{
|
||||
if (!yyjson_is_obj(conditions))
|
||||
return "Property 'conditions' must be an object";
|
||||
|
||||
yyjson_val* system = yyjson_obj_get(conditions, "system");
|
||||
if (system && !matchesJsonArray(ffVersionResult.sysName, system))
|
||||
continue;
|
||||
|
||||
system = yyjson_obj_get(conditions, "!system");
|
||||
if (system && matchesJsonArray(ffVersionResult.sysName, system))
|
||||
continue;
|
||||
|
||||
yyjson_val* arch = yyjson_obj_get(conditions, "arch");
|
||||
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
continue;
|
||||
|
||||
arch = yyjson_obj_get(conditions, "!arch");
|
||||
if (arch && matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
continue;
|
||||
}
|
||||
|
||||
type = yyjson_get_str(yyjson_obj_get(module, "type"));
|
||||
if (!type) return "module object must contain a \"type\" key ( case sensitive )";
|
||||
if (yyjson_obj_size(module) == 1) // contains only Property type
|
||||
@@ -224,7 +267,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);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#else
|
||||
#define IF_NAMESIZE 0
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex);
|
||||
|
||||
@@ -2,8 +2,5 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
const char* ffNetifGetDefaultRouteIfName();
|
||||
#endif
|
||||
|
||||
uint32_t ffNetifGetDefaultRouteIfIndex();
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
|
||||
#include <iphlpapi.h>
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(FF_MAYBE_UNUSED char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
DWORD result = GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable);
|
||||
|
||||
if (result != NO_ERROR)
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
|
||||
return false;
|
||||
|
||||
bool foundDefault = false;
|
||||
uint32_t smallestMetric = UINT32_MAX;
|
||||
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
@@ -24,9 +24,31 @@ bool ffNetifGetDefaultRouteImpl(FF_MAYBE_UNUSED char iface[IF_NAMESIZE + 1], uin
|
||||
(row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))))
|
||||
{
|
||||
*ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
break;
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) &&
|
||||
ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = (row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET) ? AF_INET : AF_INET6,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
|
||||
uint32_t realMetric = row->Metric /* Metric offset */;
|
||||
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
|
||||
realMetric += ipInterfaceRow.Metric /* Interface metric */;
|
||||
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
smallestMetric = realMetric;
|
||||
*ifIndex = row->InterfaceIndex;
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, ifRow.Alias, -1, iface, IF_NAMESIZE, NULL, NULL) > 0)
|
||||
iface[IF_NAMESIZE] = '\0';
|
||||
foundDefault = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "common/parsing.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic push
|
||||
@@ -60,56 +59,6 @@ void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
|
||||
ffStrbufAppendF(pretty, ".%u", version->patch);
|
||||
}
|
||||
|
||||
static void parseSize(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
|
||||
{
|
||||
double size = (double) bytes;
|
||||
uint8_t counter = 0;
|
||||
|
||||
while(size >= base && counter < instance.config.display.sizeMaxPrefix && prefixes[counter + 1])
|
||||
{
|
||||
size /= base;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if(counter == 0)
|
||||
ffStrbufAppendF(result, "%" PRIu64 " %s", bytes, prefixes[0]);
|
||||
else
|
||||
ffStrbufAppendF(result, "%.*f %s", instance.config.display.sizeNdigits, size, prefixes[counter]);
|
||||
}
|
||||
|
||||
void ffParseSize(uint64_t bytes, FFstrbuf* result)
|
||||
{
|
||||
switch (instance.config.display.sizeBinaryPrefix)
|
||||
{
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
|
||||
parseSize(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
|
||||
parseSize(result, bytes, 1000, (const char*[]) {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
|
||||
parseSize(result, bytes, 1024, (const char*[]) {"B", "KB", "MB", "GB", "TB", NULL});
|
||||
break;
|
||||
default:
|
||||
parseSize(result, bytes, 1024, (const char*[]) {"B", NULL});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result)
|
||||
{
|
||||
if (mhz == 0)
|
||||
return false;
|
||||
|
||||
int8_t ndigits = instance.config.display.freqNdigits;
|
||||
|
||||
if (ndigits >= 0)
|
||||
ffStrbufAppendF(result, "%.*f GHz", ndigits, mhz / 1000.);
|
||||
else
|
||||
ffStrbufAppendF(result, "%u MHz", (unsigned) mhz);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
|
||||
{
|
||||
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
|
||||
@@ -190,61 +139,6 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
}
|
||||
}
|
||||
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
if(totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u day", days);
|
||||
|
||||
if(days > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
|
||||
if(days >= 100)
|
||||
ffStrbufAppendS(result, "(!)");
|
||||
|
||||
if(hours > 0 || minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
if(hours > 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u hour", hours);
|
||||
|
||||
if(hours > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
|
||||
if(minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
if(minutes > 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u min", minutes);
|
||||
|
||||
if(minutes > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,3 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
|
||||
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
|
||||
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(uint64_t totalSeconds, FFstrbuf* result);
|
||||
|
||||
@@ -175,7 +175,6 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -187,7 +186,8 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
}
|
||||
}
|
||||
ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent);
|
||||
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent,
|
||||
options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
|
||||
if (colored && !options->pipe)
|
||||
{
|
||||
|
||||
+106
-14
@@ -12,6 +12,10 @@
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
#include <spawn.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
@@ -33,6 +37,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 +56,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,7 +66,77 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
if(ffPipe2(pipes, O_CLOEXEC) == -1)
|
||||
return "pipe() failed";
|
||||
|
||||
pid_t childPid = fork();
|
||||
pid_t childPid = -1;
|
||||
int nullFile = ffGetNullFD();
|
||||
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
|
||||
// NetBSD / Darwin: native syscall
|
||||
// Linux (glibc): clone3-execve
|
||||
// FreeBSD: vfork-execve
|
||||
// illumos: vforkx-execve
|
||||
// OpenBSD / Android (bionic): fork-execve
|
||||
|
||||
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_adddup2(&file_actions, nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
|
||||
|
||||
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);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
return "posix_spawnp() failed";
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// https://github.com/termux/termux-packages/issues/25369
|
||||
childPid = fork();
|
||||
if(childPid == -1)
|
||||
{
|
||||
close(pipes[0]);
|
||||
@@ -64,18 +144,18 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
return "fork() failed";
|
||||
}
|
||||
|
||||
//Child
|
||||
if(childPid == 0)
|
||||
{
|
||||
int nullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
//Child
|
||||
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
|
||||
setenv("LANG", "C", 1);
|
||||
putenv("LANG=C.UTF-8");
|
||||
execvp(argv[0], argv);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
//Parent
|
||||
#endif
|
||||
|
||||
close(pipes[1]);
|
||||
|
||||
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
|
||||
@@ -86,20 +166,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 +369,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)
|
||||
|
||||
@@ -81,7 +81,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
if (hChildPipeWrite == INVALID_HANDLE_VALUE)
|
||||
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
|
||||
|
||||
PROCESS_INFORMATION piProcInfo = {0};
|
||||
PROCESS_INFORMATION piProcInfo = {};
|
||||
|
||||
BOOL success;
|
||||
|
||||
@@ -91,9 +91,15 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
};
|
||||
if (useStdErr)
|
||||
{
|
||||
siStartInfo.hStdOutput = ffGetNullFD();
|
||||
siStartInfo.hStdError = hChildPipeWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
siStartInfo.hStdOutput = hChildPipeWrite;
|
||||
siStartInfo.hStdError = ffGetNullFD();
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
|
||||
argvToCmdline(argv, &cmdline);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "size.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
double size = (double) bytes;
|
||||
uint8_t counter = 0;
|
||||
|
||||
while(size >= base && counter < options->sizeMaxPrefix && prefixes[counter + 1])
|
||||
{
|
||||
size /= base;
|
||||
counter++;
|
||||
}
|
||||
|
||||
const char* space = options->sizeSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ";
|
||||
if(counter == 0)
|
||||
ffStrbufAppendF(result, "%" PRIu64 "%s%s", bytes, space, prefixes[0]);
|
||||
else
|
||||
ffStrbufAppendF(result, "%.*f%s%s", options->sizeNdigits, size, space, prefixes[counter]);
|
||||
}
|
||||
|
||||
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
switch (options->sizeBinaryPrefix)
|
||||
{
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
|
||||
appendNum(result, bytes, 1000, (const char*[]) {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", "KB", "MB", "GB", "TB", NULL});
|
||||
break;
|
||||
default:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", NULL});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result);
|
||||
+6
-3
@@ -41,13 +41,16 @@ void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig confi
|
||||
{
|
||||
case FF_TEMPERATURE_UNIT_DEFAULT:
|
||||
case FF_TEMPERATURE_UNIT_CELSIUS:
|
||||
ffStrbufAppendF(buffer, "%.*f°C", options->tempNdigits, celsius);
|
||||
ffStrbufAppendF(buffer, "%.*f%s°C", options->tempNdigits, celsius,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
break;
|
||||
case FF_TEMPERATURE_UNIT_FAHRENHEIT:
|
||||
ffStrbufAppendF(buffer, "%.*f°F", options->tempNdigits, celsius * 1.8 + 32);
|
||||
ffStrbufAppendF(buffer, "%.*f%s°F", options->tempNdigits, celsius * 1.8 + 32,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
break;
|
||||
case FF_TEMPERATURE_UNIT_KELVIN:
|
||||
ffStrbufAppendF(buffer, "%.*f K", options->tempNdigits, celsius + 273.15);
|
||||
ffStrbufAppendF(buffer, "%.*f%sK", options->tempNdigits, celsius + 273.15,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
|
||||
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;
|
||||
}
|
||||
|
||||
+118
-3
@@ -454,7 +454,8 @@
|
||||
"remark": "Auto-detected based on isatty(1) by default",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -500,6 +501,28 @@
|
||||
"type": "color"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "duration-abbreviation",
|
||||
"desc": "Specify whether to abbreviate duration values",
|
||||
"remark": "If true, the output will be in the form of \"1h 2m\" instead of \"1 hour, 2 mins\"",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "duration-space-before-unit",
|
||||
"desc": "Specify whether to put a space before the unit in duration values",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"default": "Use the default behavior of the module",
|
||||
"always": "Always put a space before the unit",
|
||||
"never": "Never put a space before the unit"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "key-width",
|
||||
"desc": "Align the width of keys to <num> characters",
|
||||
@@ -623,6 +646,27 @@
|
||||
"default": "light_red"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "percent-space-before-unit",
|
||||
"desc": "Specify whether to put a space before the percentage symbol",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"default": "Use the default behavior of the module",
|
||||
"always": "Always put a space before the unit",
|
||||
"never": "Never put a space before the unit"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "percent-width",
|
||||
"desc": "Specify the width of the percentage number, in number of characters",
|
||||
"remark": "This option affects only percentage numbers, not bars",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "bar-char-elapsed",
|
||||
"desc": "Set the character to use in the elapsed part of percentage bars",
|
||||
@@ -711,6 +755,18 @@
|
||||
"default": "YB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "size-space-before-unit",
|
||||
"desc": "Specify whether to put a space before the unit",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"default": "Use the default behavior of the module",
|
||||
"always": "Always put a space before the unit",
|
||||
"never": "Never put a space before the unit"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "freq-ndigits",
|
||||
"desc": "Set the number of digits to keep after the decimal point when printing CPU/GPU frequency in GHz",
|
||||
@@ -719,6 +775,27 @@
|
||||
"default": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "freq-space-before-unit",
|
||||
"desc": "Specify whether to put a space before the unit",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"default": "Use the default behavior of the module",
|
||||
"always": "Always put a space before the unit",
|
||||
"never": "Never put a space before the unit"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "fraction-ndigits",
|
||||
"desc": "Set the number of digits to keep after the decimal point when printing ordinary fraction numbers",
|
||||
"remark": "If negative, the number of digits will be automatically determined based on the value",
|
||||
"arg": {
|
||||
"type": "num",
|
||||
"default": -1
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "temp-unit",
|
||||
"desc": "Set the temperature unit",
|
||||
@@ -767,6 +844,18 @@
|
||||
"type": "color",
|
||||
"default": "light_red"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "temp-space-before-unit",
|
||||
"desc": "Specify whether to put a space before the unit",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"default": "Use the default behavior of the module",
|
||||
"always": "Always put a space before the unit",
|
||||
"never": "Never put a space before the unit"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Module specific": [
|
||||
@@ -840,6 +929,22 @@
|
||||
"default": "Auto detection using mount-points"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-folders",
|
||||
"desc": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"default": "/efi:/boot:/boot/efi:/boot/firmware"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-fs",
|
||||
"desc": "A colon separated list of file systems to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-regular",
|
||||
"desc": "Specify whether regular volumes should be displayed",
|
||||
@@ -965,6 +1070,16 @@
|
||||
"default": "winget"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "packages-combined",
|
||||
"desc": "Whether to combine related package managers into single counts",
|
||||
"remark": "e.g., nix-system + nix-user = nix",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "display-compact-type",
|
||||
"desc": "Specify whether all displays should be printed in one line",
|
||||
@@ -1128,11 +1243,11 @@
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Not supported on BSDs",
|
||||
"auto": "Query platform-specific graphics APIs. Requires proper GPU drivers to be installed. Supported on Linux, FreeBSD, Windows and macOS",
|
||||
"pci": "Search PCI devices, which does not require GPU drivers to be installed. Not supported on Windows and macOS",
|
||||
"vulkan": "Use Vulkan API. Slow and requires proper Vulkan drivers to be installed. Used for Android",
|
||||
"opencl": "Use OpenCL API. Slow and requires proper OpenCL drivers to be installed",
|
||||
"opengl": "Use OpenGL API. Slow and only detects one GPU"
|
||||
"opengl": "Use OpenGL API. Slow and only detects one GPU. Used for OpenBSD"
|
||||
},
|
||||
"default": "auto"
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
use scripting additions
|
||||
use framework "/System/Library/PrivateFrameworks/MediaRemote.framework"
|
||||
|
||||
set MRNowPlayingRequest to current application's NSClassFromString("MRNowPlayingRequest")
|
||||
|
||||
if MRNowPlayingRequest's localNowPlayingItem() is missing value then
|
||||
return
|
||||
end if
|
||||
|
||||
if MRNowPlayingRequest's localIsPlaying() then
|
||||
set status to "Playing"
|
||||
else
|
||||
set status to "Paused"
|
||||
end if
|
||||
|
||||
set infoDict to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo()
|
||||
set bundleObj to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client()
|
||||
|
||||
return status & "
|
||||
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle" as text) & "
|
||||
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist" as text) & "
|
||||
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum" as text) & "
|
||||
" & (bundleObj's bundleIdentifier() as text) & "
|
||||
" & (bundleObj's displayName() as text)
|
||||
@@ -15,7 +15,7 @@ typedef struct FFBatteryResult
|
||||
double capacity;
|
||||
double temperature;
|
||||
uint32_t cycleCount;
|
||||
int32_t timeRemaining;
|
||||
int32_t timeRemaining; // in seconds, -1 if unknown
|
||||
} FFBatteryResult;
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -20,7 +20,7 @@ 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)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
|
||||
@@ -100,85 +100,75 @@ static void detectQualcomm(FFCPUResult* cpu)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips
|
||||
|
||||
if (ffStrbufEqualS(&cpu->name, "SM8750-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite for Galaxy [SM8750-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8750-3"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750-3]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8750"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8635"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8s Gen 3 [SM8635]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8650-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 3 for Galaxy [SM8650-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8650"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 3 [SM8650]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8550-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 2 for Galaxy [SM8550-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8550"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 2 [SM8550]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8475"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8+ Gen 1 [SM8475]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 1 [SM8450]");
|
||||
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 2, NULL, 10);
|
||||
const char* name = NULL;
|
||||
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7675"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7+ Gen 3 [SM7675]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7635"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7s Gen 3 [SM7635]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7550"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7 Gen 3 [SM7550]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7475"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7+ Gen 2 [SM7550]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7435"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7s Gen 2 [SM7435]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7 Gen 1 [SM7450]");
|
||||
switch (code)
|
||||
{
|
||||
case 8735: name = "8s Gen 4"; break;
|
||||
case 8750: name = "8 Elite"; break;
|
||||
case 8635: name = "8s Gen 3"; break;
|
||||
case 8650: name = "8 Gen 3"; break;
|
||||
case 8550: name = "8 Gen 2"; break;
|
||||
case 8475: name = "8+ Gen 1"; break;
|
||||
case 8450: name = "8 Gen 1"; break;
|
||||
case 7750: name = "7 Gen 4"; break;
|
||||
case 7675: name = "7+ Gen 3"; break;
|
||||
case 7635: name = "7s Gen 3"; break;
|
||||
case 7550: name = "7 Gen 3"; break;
|
||||
case 7475: name = "7+ Gen 2"; break;
|
||||
case 7435: name = "7s Gen 2"; break;
|
||||
case 7450: name = "7 Gen 1"; break;
|
||||
case 6650: name = "6 Gen 4"; break;
|
||||
case 6375: name = "6s Gen 3"; break;
|
||||
case 6475: name = "6 Gen 3"; break;
|
||||
case 6115: name = "6s Gen 1"; break;
|
||||
case 6450: name = "6 Gen 1"; break;
|
||||
case 4635: name = "4s Gen 2"; break;
|
||||
case 4450: name = "4 Gen 2"; break;
|
||||
case 4375: name = "4 Gen 1"; break;
|
||||
}
|
||||
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6375-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6s Gen 3 [SM6375-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6475"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6 Gen 3 [SM6475]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6115"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6s Gen 1 [SM6115]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6 Gen 1 [SM6450]");
|
||||
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM4635"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4s Gen 2 [SM4635]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM4450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 2 [SM4450]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM4375"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 1 [SM4375]");
|
||||
if (name)
|
||||
{
|
||||
char str[32];
|
||||
ffStrCopy(str, cpu->name.chars, sizeof(str));
|
||||
ffStrbufSetF(&cpu->name, "Qualcomm Snapdragon %s [%s]", name, str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void detectMediaTek(FFCPUResult* cpu)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/List_of_MediaTek_systems_on_chips
|
||||
|
||||
if (ffStrbufEqualS(&cpu->name, "MT6991"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6991Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6989Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT6989Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8796Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT8796Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6989"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT6989]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8796"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT8796]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6985W"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200+ [MT6985W]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6985"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200 [MT6985]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6983W"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT6983W]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/T"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT8798Z/T]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6983Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT6983Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/C"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT8798Z/C]");
|
||||
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 2, NULL, 10);
|
||||
const char* name = NULL;
|
||||
|
||||
switch (code) // The SOC code of MTK Dimensity series is full of mess
|
||||
{
|
||||
case 6991: name = "9400"; break;
|
||||
case 6989:
|
||||
case 8796: name = "9300"; break;
|
||||
case 6985: name = "9200"; break;
|
||||
case 6983:
|
||||
case 8798: name = "9000"; break;
|
||||
|
||||
case 6899: name = "8400"; break;
|
||||
case 6897:
|
||||
case 8792: name = "8300"; break;
|
||||
case 6896: name = "8200"; break;
|
||||
case 8795: name = "8100"; break;
|
||||
case 6895: name = "8000"; break;
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
char str[32];
|
||||
ffStrCopy(str, cpu->name.chars, sizeof(str));
|
||||
ffStrbufSetF(&cpu->name, "MediaTek Dimensity %s [%s]", name, str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void detectAndroid(FFCPUResult* cpu)
|
||||
@@ -474,7 +464,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
|
||||
|
||||
static const char* detectPhysicalCores(FFCPUResult* cpu)
|
||||
{
|
||||
int dfd = open("/sys/devices/system/cpu/", O_RDONLY | O_DIRECTORY);
|
||||
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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -4,42 +4,116 @@
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
#include <pdh.h>
|
||||
#include <windows.h>
|
||||
#include "util/windows/perflib_.h"
|
||||
#include <wchar.h>
|
||||
|
||||
static void ffPdhOpenCloseQuery(HQUERY* query)
|
||||
static inline void ffPerfCloseQueryHandle(HANDLE* phQuery)
|
||||
{
|
||||
assert(query);
|
||||
if (*query)
|
||||
if (*phQuery != NULL)
|
||||
{
|
||||
PdhCloseQuery(*query);
|
||||
*query = NULL;
|
||||
PerfCloseQueryHandle(*phQuery);
|
||||
*phQuery = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* detectThermalTemp(double* result)
|
||||
const char* detectThermalTemp(double* result)
|
||||
{
|
||||
// typeperf.exe -sc 1 "\Thermal Zone Information(*)\Temperature"
|
||||
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
|
||||
};
|
||||
|
||||
__attribute__((__cleanup__(ffPdhOpenCloseQuery))) HQUERY query = NULL;
|
||||
DWORD dataSize = 0;
|
||||
if (PerfEnumerateCounterSetInstances(NULL, &querySpec.Identifier.CounterSetGuid, NULL, 0, &dataSize) != ERROR_NOT_ENOUGH_MEMORY)
|
||||
return "PerfEnumerateCounterSetInstances() failed";
|
||||
|
||||
if (PdhOpenQueryW(NULL, 0, &query) != ERROR_SUCCESS)
|
||||
return "Failed to open PDH query";
|
||||
if (dataSize <= sizeof(PERF_INSTANCE_HEADER))
|
||||
return "No `Thermal Zone Information` instances found";
|
||||
|
||||
HCOUNTER counter = NULL;
|
||||
if (PdhAddEnglishCounterW(query,
|
||||
L"\\Thermal Zone Information(*)\\Temperature",
|
||||
0,
|
||||
&counter) != ERROR_SUCCESS)
|
||||
return "Failed to add TZI temperature counter";
|
||||
{
|
||||
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";
|
||||
|
||||
if (PdhCollectQueryData(query) != ERROR_SUCCESS)
|
||||
return "Failed to collect query data";
|
||||
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;
|
||||
|
||||
PDH_FMT_COUNTERVALUE value;
|
||||
if (PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, NULL, &value) != ERROR_SUCCESS)
|
||||
return "Failed to format counter value";
|
||||
dataSize -= pInstanceHeader->Size;
|
||||
if (dataSize == 0)
|
||||
break;
|
||||
pInstanceHeader = (PERF_INSTANCE_HEADER*)((BYTE*)pInstanceHeader + pInstanceHeader->Size);
|
||||
}
|
||||
|
||||
*result = value.doubleValue - 273;
|
||||
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;
|
||||
}
|
||||
@@ -151,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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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, ...)
|
||||
|
||||
+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;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -49,7 +49,26 @@ 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);
|
||||
const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd);
|
||||
#endif // FF_HAVE_DRM
|
||||
|
||||
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId);
|
||||
#endif // defined(XXX)
|
||||
|
||||
@@ -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,8 +60,13 @@ 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])
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
||||
if ([device supportsFamily:MTLGPUFamilyMetal4])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal 4");
|
||||
else if ([device supportsFamily:MTLGPUFamilyMetal3])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
|
||||
#pragma clang diagnostic pop
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon3])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon2])
|
||||
@@ -66,7 +74,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)
|
||||
|
||||
+160
-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,147 @@
|
||||
#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 (ffStrStartsWith(driverName, "nouveau"))
|
||||
ffDrmDetectNouveau(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 +191,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 +206,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,396 @@
|
||||
#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>
|
||||
#include <nouveau_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";
|
||||
}
|
||||
|
||||
#ifndef DRM_IOCTL_NOUVEAU_GETPARAM
|
||||
#define DRM_IOCTL_NOUVEAU_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_GETPARAM, struct drm_nouveau_getparam)
|
||||
#endif
|
||||
|
||||
const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd)
|
||||
{
|
||||
struct drm_nouveau_getparam getparam = { };
|
||||
|
||||
getparam.param = NOUVEAU_GETPARAM_FB_SIZE;
|
||||
if (ioctl(fd, DRM_IOCTL_NOUVEAU_GETPARAM, &getparam) == 0)
|
||||
gpu->dedicated.total = getparam.value;
|
||||
|
||||
getparam.param = NOUVEAU_GETPARAM_AGP_SIZE;
|
||||
if (ioctl(fd, DRM_IOCTL_NOUVEAU_GETPARAM, &getparam) == 0)
|
||||
gpu->shared.total = getparam.value;
|
||||
|
||||
getparam.param = NOUVEAU_GETPARAM_GRAPH_UNITS;
|
||||
if (ioctl(fd, DRM_IOCTL_NOUVEAU_GETPARAM, &getparam) == 0 && getparam.value < INT32_MAX)
|
||||
gpu->coreCount = (int32_t) getparam.value;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#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;
|
||||
|
||||
@@ -10,7 +10,7 @@ struct FFIgclData {
|
||||
FF_LIBRARY_SYMBOL(ctlEnumerateDevices)
|
||||
FF_LIBRARY_SYMBOL(ctlGetDeviceProperties)
|
||||
FF_LIBRARY_SYMBOL(ctlEnumTemperatureSensors)
|
||||
FF_LIBRARY_SYMBOL(ctlTemperatureGetState)
|
||||
FF_LIBRARY_SYMBOL(ctlTemperatureGetProperties)
|
||||
FF_LIBRARY_SYMBOL(ctlEnumMemoryModules)
|
||||
FF_LIBRARY_SYMBOL(ctlMemoryGetProperties)
|
||||
FF_LIBRARY_SYMBOL(ctlMemoryGetState)
|
||||
@@ -41,7 +41,7 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumerateDevices)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlGetDeviceProperties)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumTemperatureSensors)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlTemperatureGetState)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlTemperatureGetProperties)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumMemoryModules)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetProperties)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState)
|
||||
@@ -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;
|
||||
@@ -204,19 +204,20 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
|
||||
uint32_t sensorCount = ARRAY_SIZE(sensors);
|
||||
if (igclData.ffctlEnumTemperatureSensors(device, &sensorCount, sensors) == CTL_RESULT_SUCCESS && sensorCount > 0)
|
||||
{
|
||||
double sumValue = 0;
|
||||
uint32_t availableCount = 0;
|
||||
for (uint32_t iSensor = 0; iSensor < sensorCount; iSensor++)
|
||||
{
|
||||
double value;
|
||||
if (igclData.ffctlTemperatureGetState(sensors[iSensor], &value) == CTL_RESULT_SUCCESS)
|
||||
ctl_temp_properties_t props = { .Size = sizeof(props) };
|
||||
// The official sample code does not set Version
|
||||
// https://github.com/intel/drivers.gpu.control-library/blob/1bbacbf3814f2fd0d2b930cdf42fad83f3628db9/Samples/Telemetry_Samples/Sample_TelemetryAPP.cpp#L256
|
||||
if (igclData.ffctlTemperatureGetProperties(sensors[iSensor], &props) == CTL_RESULT_SUCCESS)
|
||||
{
|
||||
sumValue += value;
|
||||
availableCount++;
|
||||
if (props.type == CTL_TEMP_SENSORS_GPU)
|
||||
{
|
||||
*result.temp = props.maxTemperature;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (availableCount > 0)
|
||||
*result.temp = sumValue / availableCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+95
-300
@@ -105,93 +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;
|
||||
#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)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
@@ -215,47 +145,50 @@ 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, pciDirLen);
|
||||
ffStrbufAppendS(pciDir, "/gpu_busy_percent");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
gpu->coreUsage = (double) 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,153 +244,62 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
|
||||
{
|
||||
#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"))
|
||||
return ffDrmDetectI915(gpu, fd);
|
||||
return "Unknown Intel GPU driver";
|
||||
#else
|
||||
FF_UNUSED(gpu, drmKey, buffer);
|
||||
return "Fastfetch is not compiled with drm support";
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char* pciDetectNouveauSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
|
||||
{
|
||||
if (options->temp)
|
||||
{
|
||||
const uint32_t pciDirLen = pciDir->length;
|
||||
ffStrbufAppendS(pciDir, "/hwmon/");
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDir->chars);
|
||||
if (dirp)
|
||||
{
|
||||
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 )
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)))
|
||||
{
|
||||
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)
|
||||
if (entry->d_name[0] == '.') continue;
|
||||
ffStrbufAppendS(pciDir, entry->d_name);
|
||||
ffStrbufAppendS(pciDir, "/temp1_input");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
uint64_t value = ffStrbufToUInt(buffer, 0);
|
||||
if (value > 0) gpu->temperature = (double) value / 1000.0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* drmDetectNouveauSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer)
|
||||
{
|
||||
#if FF_HAVE_DRM
|
||||
ffStrbufSetS(buffer, "/dev/dri/");
|
||||
ffStrbufAppendS(buffer, drmKey);
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "Failed to open drm device";
|
||||
|
||||
return ffDrmDetectNouveau(gpu, fd);
|
||||
#else
|
||||
FF_UNUSED(gpu, drmKey, buffer);
|
||||
return "Fastfetch is not compiled with drm support";
|
||||
@@ -570,31 +412,20 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
if (options->driverSpecific && drmKey)
|
||||
drmDetectIntelSpecific(gpu, drmKey, buffer);
|
||||
}
|
||||
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && ffStrbufEqualS(&gpu->driver, "nouveau"))
|
||||
{
|
||||
pciDetectNouveauSpecific(options, gpu, deviceDir, buffer);
|
||||
if (options->driverSpecific && drmKey)
|
||||
drmDetectNouveauSpecific(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)
|
||||
@@ -630,45 +461,9 @@ FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, cons
|
||||
#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)
|
||||
{
|
||||
// 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 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;
|
||||
|
||||
@@ -120,8 +120,28 @@ typedef struct ctl_temp_handle_t* ctl_temp_handle_t;
|
||||
|
||||
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctlenumtemperaturesensors
|
||||
extern ctl_result_t ctlEnumTemperatureSensors(ctl_device_adapter_handle_t hDAhandle, uint32_t* pCount, ctl_temp_handle_t* phTemperature);
|
||||
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctltemperaturegetstate
|
||||
extern ctl_result_t ctlTemperatureGetState(ctl_temp_handle_t hTemperature, double* pTemperature);
|
||||
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv427ctlTemperatureGetProperties17ctl_temp_handle_tP21ctl_temp_properties_t
|
||||
|
||||
typedef enum ctl_temp_sensors_t
|
||||
{
|
||||
CTL_TEMP_SENSORS_GLOBAL = 0,
|
||||
CTL_TEMP_SENSORS_GPU = 1,
|
||||
CTL_TEMP_SENSORS_MEMORY = 2,
|
||||
CTL_TEMP_SENSORS_GLOBAL_MIN = 3,
|
||||
CTL_TEMP_SENSORS_GPU_MIN = 4,
|
||||
CTL_TEMP_SENSORS_MEMORY_MIN = 5,
|
||||
CTL_TEMP_SENSORS_MAX
|
||||
} ctl_temp_sensors_t;
|
||||
|
||||
typedef struct _ctl_temp_properties_t
|
||||
{
|
||||
uint32_t Size;
|
||||
uint8_t Version;
|
||||
ctl_temp_sensors_t type;
|
||||
double maxTemperature;
|
||||
} ctl_temp_properties_t;
|
||||
|
||||
extern ctl_result_t ctlTemperatureGetProperties(ctl_temp_handle_t hTemperature, ctl_temp_properties_t* pTemperature);
|
||||
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv420ctlEnumMemoryModules27ctl_device_adapter_handle_tP8uint32_tP16ctl_mem_handle_t
|
||||
|
||||
typedef struct ctl_mem_handle_t* ctl_mem_handle_t;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -140,18 +140,45 @@ static void detectQtCt(char qver, FFQtResult* result)
|
||||
// by the same author and qt6ct understands qt5ct in qt6 applications as well.
|
||||
char file[] = "qtXct/qtXct.conf";
|
||||
file[2] = file[8] = qver;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate();
|
||||
|
||||
ffParsePropFileConfigValues(file, 3, (FFpropquery[]) {
|
||||
{"style=", &result->widgetStyle},
|
||||
{"icon_theme=", &result->icons},
|
||||
{"general=", &result->font}
|
||||
{"general=", &font}
|
||||
});
|
||||
|
||||
if (ffStrbufStartsWithC(&result->font, '@'))
|
||||
if (ffStrbufStartsWithC(&font, '@'))
|
||||
{
|
||||
// See QVariant notes on https://doc.qt.io/qt-5/qsettings.html and
|
||||
// https://github.com/fastfetch-cli/fastfetch/issues/1053#issuecomment-2197254769
|
||||
// Thankfully, newer versions use the more common font encoding.
|
||||
ffStrbufSetNS(&result->font, 5, file);
|
||||
ffStrbufSetNS(&font, 5, file);
|
||||
}
|
||||
else if (qver == '5')
|
||||
{
|
||||
// #1864
|
||||
const char *p = font.chars;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (p[0] == '\\' && p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3]) && isxdigit(p[4]) && isxdigit(p[5]))
|
||||
{
|
||||
uint32_t codepoint = (uint32_t)strtoul((char[]) { p[2], p[3], p[4], p[5], '\0' }, NULL, 16);
|
||||
ffStrbufAppendUtf32CodePoint(&result->font, codepoint);
|
||||
p += 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendC(&result->font, *p++);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufDestroy(&result->font);
|
||||
ffStrbufInitMove(&result->font, &font);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,14 +205,17 @@ const FFQtResult* ffDetectQt(void)
|
||||
ffStrbufInit(&result.wallpaper);
|
||||
|
||||
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
|
||||
const char *qplatformtheme = getenv("QT_QPA_PLATFORMTHEME");
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA))
|
||||
detectPlasma(&result);
|
||||
else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT))
|
||||
detectLXQt(&result);
|
||||
else if(ffStrSet(qplatformtheme) && (ffStrEquals(qplatformtheme, "qt5ct") || ffStrEquals(qplatformtheme, "qt6ct")))
|
||||
detectQtCt(qplatformtheme[2], &result);
|
||||
else
|
||||
{
|
||||
const char *qPlatformTheme = getenv("QT_QPA_PLATFORMTHEME");
|
||||
if(qPlatformTheme && (ffStrEquals(qPlatformTheme, "qt5ct") || ffStrEquals(qPlatformTheme, "qt6ct")))
|
||||
detectQtCt(qPlatformTheme[2], &result);
|
||||
}
|
||||
|
||||
if(ffStrbufEqualS(&result.widgetStyle, "kvantum") || ffStrbufEqualS(&result.widgetStyle, "kvantum-dark"))
|
||||
{
|
||||
|
||||
@@ -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)";
|
||||
|
||||
@@ -10,7 +10,7 @@ typedef struct FFLocalIpResult
|
||||
FFstrbuf mac;
|
||||
FFstrbuf flags;
|
||||
int32_t mtu;
|
||||
int32_t speed;
|
||||
int32_t speed; // in Mbps
|
||||
bool defaultRoute;
|
||||
} FFLocalIpResult;
|
||||
|
||||
|
||||
@@ -95,6 +95,9 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
// Iterate through all of the adapters
|
||||
for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)
|
||||
{
|
||||
if (adapter->OperStatus != IfOperStatusUp)
|
||||
continue;
|
||||
|
||||
bool isDefaultRoute = adapter->IfIndex == defaultRouteIfIndex;
|
||||
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
|
||||
continue;
|
||||
@@ -170,7 +173,7 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
|
||||
{
|
||||
FFLocalIpResult* result = FF_LIST_GET(FFLocalIpResult, *results, results->length - 1);
|
||||
if (options->showType & FF_LOCALIP_TYPE_SPEED_BIT)
|
||||
result->speed = (int32_t) (adapter->ReceiveLinkSpeed / 1000);
|
||||
result->speed = (int32_t) (adapter->ReceiveLinkSpeed / 1000000);
|
||||
if (options->showType & FF_LOCALIP_TYPE_MTU_BIT)
|
||||
result->mtu = (int32_t) adapter->Mtu;
|
||||
if (options->showType & FF_LOCALIP_TYPE_FLAGS_BIT)
|
||||
|
||||
@@ -1,50 +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"
|
||||
#include "fastfetch_datatext.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* 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";
|
||||
@@ -53,42 +38,76 @@ static const char* getMediaByMediaRemote(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;
|
||||
}
|
||||
|
||||
static const char* getMediaByOsascript(FFMediaResult* result)
|
||||
__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();
|
||||
// The script must be executed by `/usr/bin/osascript`. `ffOsascript` doesn't work here
|
||||
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/osascript",
|
||||
"-e",
|
||||
FASTFETCH_DATATEXT_NOWPLAYING,
|
||||
"/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
|
||||
"-c",
|
||||
script.chars,
|
||||
nil
|
||||
});
|
||||
if (error) return error;
|
||||
@@ -107,8 +126,16 @@ void ffDetectMediaImpl(FFMediaResult* media)
|
||||
{
|
||||
const char* error;
|
||||
if (@available(macOS 15.4, *))
|
||||
error = getMediaByOsascript(media);
|
||||
error = getMediaByAuthorizedProcess(media);
|
||||
else
|
||||
error = getMediaByMediaRemote(media);
|
||||
if (error) ffStrbufAppendS(&media->error, error);
|
||||
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, '.', ' ');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ const char* ffDetectMemory(FFMemoryResult* ram)
|
||||
if (get_system_info(&info) != B_OK)
|
||||
return "Error getting system info";
|
||||
|
||||
ram->bytesTotal = B_PAGE_SIZE * info.max_pages;
|
||||
ram->bytesUsed = B_PAGE_SIZE * info.used_pages;
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
ram->bytesTotal = pageSize * info.max_pages;
|
||||
ram->bytesUsed = pageSize * info.used_pages;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,11 @@ static void parseSystemVersion(FFOSResult* os)
|
||||
ffStrbufInitS(&os->version, value.UTF8String);
|
||||
if((value = dict[@"ProductBuildVersion"]))
|
||||
ffStrbufInitS(&os->buildID, value.UTF8String);
|
||||
if (ffStrbufStartsWithS(&os->version, "16."))
|
||||
{
|
||||
// macOS 26 Tahoe. #1809
|
||||
os->version.chars[0] = '2';
|
||||
}
|
||||
}
|
||||
|
||||
static bool detectOSCodeName(FFOSResult* os)
|
||||
@@ -37,6 +42,8 @@ static bool detectOSCodeName(FFOSResult* os)
|
||||
|
||||
switch (num)
|
||||
{
|
||||
case 26:
|
||||
case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true;
|
||||
case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true;
|
||||
case 14: ffStrbufSetStatic(&os->codename, "Sonoma"); return true;
|
||||
case 13: ffStrbufSetStatic(&os->codename, "Ventura"); return true;
|
||||
@@ -62,7 +69,7 @@ static bool detectOSCodeName(FFOSResult* os)
|
||||
case 6: ffStrbufSetStatic(&os->codename, "Snow Leopard"); return true;
|
||||
case 5: ffStrbufSetStatic(&os->codename, "Leopard"); return true;
|
||||
case 4: ffStrbufSetStatic(&os->codename, "Tiger"); return true;
|
||||
case 3: ffStrbufSetStatic(&os->codename, "Panther"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
|
||||
case 3: ffStrbufSetStatic(&os->codename, "Panther"); return true;
|
||||
case 2: ffStrbufSetStatic(&os->codename, "Jaguar"); return true;
|
||||
case 1: ffStrbufSetStatic(&os->codename, "Puma"); return true;
|
||||
case 0: ffStrbufSetStatic(&os->codename, "Cheetah"); return true;
|
||||
|
||||
+125
-62
@@ -47,7 +47,7 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
|
||||
// - `Armbian_Security` for images with kali repo added
|
||||
// - `Armbian-unofficial` for an unofficial image built from source, e.g. during development and testing
|
||||
if (ffStrbufStartsWithS(&result->prettyName, "Armbian"))
|
||||
ffStrbufSetS(&result->name, "Armbian");
|
||||
ffStrbufSetStatic(&result->name, "Armbian");
|
||||
else
|
||||
return false;
|
||||
ffStrbufSet(&result->idLike, &result->id);
|
||||
@@ -69,113 +69,113 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
|
||||
return;
|
||||
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Linux Lite");
|
||||
ffStrbufSetS(&result->id, "linuxlite");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Linux Lite");
|
||||
ffStrbufSetStatic(&result->id, "linuxlite");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Linux Lite "));
|
||||
return;
|
||||
}
|
||||
else if(ffStrbufStartsWithS(&result->prettyName, "Rhino Linux "))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Rhino Linux");
|
||||
ffStrbufSetS(&result->id, "rhinolinux");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Rhino Linux");
|
||||
ffStrbufSetStatic(&result->id, "rhinolinux");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Rhino Linux "));
|
||||
return;
|
||||
}
|
||||
else if(ffStrbufStartsWithS(&result->prettyName, "VanillaOS "))
|
||||
{
|
||||
ffStrbufSetS(&result->id, "vanilla");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->id, "vanilla");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Kubuntu");
|
||||
ffStrbufSetS(&result->prettyName, "Kubuntu");
|
||||
ffStrbufSetS(&result->id, "kubuntu");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Kubuntu");
|
||||
ffStrbufSetF(&result->prettyName, "Kubuntu %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "kubuntu");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "xfce") || ffStrContains(xdgConfigDirs, "xubuntu"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Xubuntu");
|
||||
ffStrbufSetS(&result->prettyName, "Xubuntu");
|
||||
ffStrbufSetS(&result->id, "xubuntu");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Xubuntu");
|
||||
ffStrbufSetF(&result->prettyName, "Xubuntu %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "xubuntu");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "lxqt") || ffStrContains(xdgConfigDirs, "lubuntu"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Lubuntu");
|
||||
ffStrbufSetS(&result->prettyName, "Lubuntu");
|
||||
ffStrbufSetS(&result->id, "lubuntu");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Lubuntu");
|
||||
ffStrbufSetF(&result->prettyName, "Lubuntu %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "lubuntu");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "budgie"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Budgie");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Budgie");
|
||||
ffStrbufSetS(&result->id, "ubuntu-budgie");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Budgie");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Budgie %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-budgie");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "cinnamon"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Cinnamon");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Cinnamon");
|
||||
ffStrbufSetS(&result->id, "ubuntu-cinnamon");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Cinnamon");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Cinnamon %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-cinnamon");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "mate"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu MATE");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu MATE");
|
||||
ffStrbufSetS(&result->id, "ubuntu-mate");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu MATE");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu MATE %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-mate");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "studio"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Studio");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Studio");
|
||||
ffStrbufSetS(&result->id, "ubuntu-studio");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Studio %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-studio");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "sway"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Sway");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Sway");
|
||||
ffStrbufSetS(&result->id, "ubuntu-sway");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Sway");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Sway %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-sway");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "touch"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "Ubuntu Touch");
|
||||
ffStrbufSetS(&result->prettyName, "Ubuntu Touch");
|
||||
ffStrbufSetS(&result->id, "ubuntu-touch");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Touch");
|
||||
ffStrbufSetF(&result->prettyName, "Ubuntu Touch %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-touch");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ffStrContains(xdgConfigDirs, "lliurex"))
|
||||
{
|
||||
ffStrbufSetS(&result->name, "LliureX");
|
||||
ffStrbufSetS(&result->prettyName, "LliureX");
|
||||
ffStrbufSetS(&result->id, "lliurex");
|
||||
ffStrbufSetS(&result->idLike, "ubuntu");
|
||||
ffStrbufSetStatic(&result->name, "LliureX");
|
||||
ffStrbufSetF(&result->prettyName, "LliureX %s", result->version.chars);
|
||||
ffStrbufSetStatic(&result->id, "lliurex");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -196,8 +196,8 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
return true;
|
||||
else if (ffStrbufStartsWithS(&result->name, "Loc-OS"))
|
||||
{
|
||||
ffStrbufSetS(&result->id, "locos");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->id, "locos");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
return true;
|
||||
}
|
||||
else if (ffStrbufEqualS(&result->name, "Parrot Security"))
|
||||
@@ -210,15 +210,15 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
else if (ffStrbufStartsWithS(&result->name, "Lilidog GNU/Linux"))
|
||||
{
|
||||
// https://github.com/fastfetch-cli/fastfetch/issues/1373
|
||||
ffStrbufSetS(&result->id, "lilidog");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->id, "lilidog");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
return true;
|
||||
}
|
||||
else if (access("/usr/bin/pveversion", X_OK) == 0)
|
||||
{
|
||||
ffStrbufSetS(&result->id, "pve");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetS(&result->name, "Proxmox VE");
|
||||
ffStrbufSetStatic(&result->id, "pve");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "Proxmox VE");
|
||||
ffStrbufClear(&result->versionID);
|
||||
if (ffProcessAppendStdOut(&result->versionID, (char* const[]) {
|
||||
"/usr/bin/dpkg-query",
|
||||
@@ -231,15 +231,50 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars);
|
||||
return true;
|
||||
}
|
||||
else if (ffPathExists("/etc/rpi-issue", FF_PATHTYPE_FILE))
|
||||
{
|
||||
// Raspberry Pi OS
|
||||
ffStrbufSetStatic(&result->id, "raspbian");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "Raspberry Pi OS");
|
||||
ffStrbufSetStatic(&result->prettyName, "Raspberry Pi OS");
|
||||
return true;
|
||||
}
|
||||
else if (ffPathExists("/boot/dietpi/.version", FF_PATHTYPE_FILE))
|
||||
{
|
||||
// DietPi
|
||||
ffStrbufSetStatic(&result->id, "dietpi");
|
||||
ffStrbufSetStatic(&result->name, "DietPi");
|
||||
ffStrbufSetStatic(&result->prettyName, "DietPi");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
FF_STRBUF_AUTO_DESTROY core = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY sub = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY rc = ffStrbufCreate();
|
||||
if (ffParsePropFileValues("/boot/dietpi/.version", 3, (FFpropquery[]) {
|
||||
{"G_DIETPI_VERSION_CORE=", &core},
|
||||
{"G_DIETPI_VERSION_SUB=", &sub},
|
||||
{"G_DIETPI_VERSION_RC=", &rc},
|
||||
})) ffStrbufAppendF(&result->prettyName, " %s.%s.%s", core.chars, sub.chars, rc.chars);
|
||||
return true;
|
||||
}
|
||||
else if (ffStrbufEndsWithS(&instance.state.platform.sysinfo.release, "+truenas"))
|
||||
{
|
||||
// TrueNAS Scale
|
||||
ffStrbufSetStatic(&result->id, "truenas-scale");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "TrueNAS Scale");
|
||||
ffStrbufSetStatic(&result->prettyName, "TrueNAS Scale");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hack for MX Linux. See #847
|
||||
FF_STRBUF_AUTO_DESTROY lsbRelease = ffStrbufCreate();
|
||||
if (ffAppendFileBuffer("/etc/lsb-release", &lsbRelease) && ffStrbufContainS(&lsbRelease, "DISTRIB_ID=MX"))
|
||||
{
|
||||
ffStrbufSetS(&result->id, "mx");
|
||||
ffStrbufSetS(&result->idLike, "debian");
|
||||
ffStrbufSetS(&result->name, "MX");
|
||||
ffStrbufSetStatic(&result->id, "mx");
|
||||
ffStrbufSetStatic(&result->idLike, "debian");
|
||||
ffStrbufSetStatic(&result->name, "MX");
|
||||
|
||||
ffStrbufClear(&result->version);
|
||||
ffParsePropLines(lsbRelease.chars, "DISTRIB_RELEASE=", &result->version);
|
||||
@@ -256,6 +291,21 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static bool detectFedoraVariant(FFOSResult* result)
|
||||
{
|
||||
if (ffStrbufEqualS(&result->variantID, "coreos")
|
||||
|| ffStrbufEqualS(&result->variantID, "kinoite")
|
||||
|| ffStrbufEqualS(&result->variantID, "sericea")
|
||||
|| ffStrbufEqualS(&result->variantID, "silverblue"))
|
||||
{
|
||||
ffStrbufAppendC(&result->id, '-');
|
||||
ffStrbufAppend(&result->id, &result->variantID);
|
||||
ffStrbufSetStatic(&result->idLike, "fedora");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void detectOS(FFOSResult* os)
|
||||
{
|
||||
#ifdef FF_CUSTOM_OS_RELEASE_PATH
|
||||
@@ -286,8 +336,19 @@ static void detectOS(FFOSResult* os)
|
||||
parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os);
|
||||
if (os->id.length == 0 || os->version.length == 0 || os->prettyName.length == 0 || os->codename.length == 0)
|
||||
parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os);
|
||||
if (os->id.length == 0 || os->name.length > 0 || os->prettyName.length > 0)
|
||||
if (os->id.length == 0 || os->name.length == 0 || os->prettyName.length == 0)
|
||||
parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os);
|
||||
if (os->id.length == 0 && os->name.length == 0 && os->prettyName.length == 0)
|
||||
{
|
||||
// HarmonyOS has no os-release file
|
||||
if (ffStrbufEqualS(&instance.state.platform.sysinfo.name, "HarmonyOS"))
|
||||
{
|
||||
ffStrbufSetS(&os->id, "harmonyos");
|
||||
ffStrbufSetS(&os->idLike, "harmonyos");
|
||||
ffStrbufSetS(&os->name, "HarmonyOS");
|
||||
ffStrbufSetS(&os->prettyName, "HarmonyOS");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ffDetectOSImpl(FFOSResult* os)
|
||||
@@ -295,13 +356,15 @@ void ffDetectOSImpl(FFOSResult* os)
|
||||
detectOS(os);
|
||||
|
||||
#ifdef __linux__
|
||||
if(ffStrbufIgnCaseEqualS(&os->id, "ubuntu"))
|
||||
if(ffStrbufEqualS(&os->id, "ubuntu"))
|
||||
getUbuntuFlavour(os);
|
||||
else if(ffStrbufIgnCaseEqualS(&os->id, "debian"))
|
||||
else if(ffStrbufEqualS(&os->id, "debian"))
|
||||
{
|
||||
if (!detectDebianDerived(os))
|
||||
getDebianVersion(os);
|
||||
}
|
||||
else if(ffStrbufEqualS(&os->id, "fedora"))
|
||||
detectFedoraVariant(os);
|
||||
else if(ffStrbufEqualS(&os->id, "linuxmint"))
|
||||
{
|
||||
if (ffStrbufEqualS(&os->name, "LMDE"))
|
||||
|
||||
@@ -100,22 +100,23 @@ uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
#if !defined(__sun) && !defined(__HAIKU__)
|
||||
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
|
||||
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
|
||||
else
|
||||
#endif
|
||||
if (entry->d_name[0] != '.')
|
||||
{
|
||||
struct stat stbuf;
|
||||
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
|
||||
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
|
||||
#if !defined(__sun) && !defined(__HAIKU__)
|
||||
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
|
||||
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct stat stbuf;
|
||||
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
|
||||
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
if(ok) ++num_elements;
|
||||
}
|
||||
|
||||
if(isdir && num_elements >= 2)
|
||||
num_elements -= 2; // accounting for . and ..
|
||||
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,9 @@ typedef struct FFPackagesResult
|
||||
uint32_t pkg;
|
||||
uint32_t pkgsrc;
|
||||
uint32_t pkgtool;
|
||||
uint32_t qi;
|
||||
uint32_t rpm;
|
||||
uint32_t scoop;
|
||||
uint32_t scoopUser;
|
||||
uint32_t scoopGlobal;
|
||||
uint32_t snap;
|
||||
uint32_t soar;
|
||||
uint32_t sorcery;
|
||||
|
||||
@@ -519,6 +519,31 @@ static inline uint32_t getFlatpakRuntimePackages(FFstrbuf* baseDir)
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
static inline uint32_t getFlatpakAppPackages(FFstrbuf* baseDir)
|
||||
{
|
||||
ffStrbufAppendS(baseDir, "app/");
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
|
||||
if (dirp == NULL)
|
||||
return 0;
|
||||
|
||||
uint32_t appDirLength = baseDir->length;
|
||||
uint32_t num_elements = 0;
|
||||
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
|
||||
{
|
||||
ffStrbufAppendS(baseDir, entry->d_name);
|
||||
ffStrbufAppendS(baseDir, "/current");
|
||||
if (ffPathExists(baseDir->chars, FF_PATHTYPE_ANY)) // Exclude deleted apps, #1856
|
||||
++num_elements;
|
||||
ffStrbufSubstrBefore(baseDir, appDirLength);
|
||||
}
|
||||
}
|
||||
return num_elements;
|
||||
}
|
||||
|
||||
static uint32_t getFlatpakPackages(FFstrbuf* baseDir, const char* dirname)
|
||||
{
|
||||
uint32_t num_elements = 0;
|
||||
@@ -527,8 +552,7 @@ static uint32_t getFlatpakPackages(FFstrbuf* baseDir, const char* dirname)
|
||||
ffStrbufAppendS(baseDir, "/flatpak/");
|
||||
uint32_t flatpakDirLength = baseDir->length;
|
||||
|
||||
ffStrbufAppendS(baseDir, "app");
|
||||
num_elements += ffPackagesGetNumElements(baseDir->chars, true);
|
||||
num_elements += getFlatpakAppPackages(baseDir);
|
||||
ffStrbufSubstrBefore(baseDir, flatpakDirLength);
|
||||
|
||||
num_elements += getFlatpakRuntimePackages(baseDir);
|
||||
@@ -554,7 +578,11 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages", "rpm");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT))
|
||||
{
|
||||
// `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
|
||||
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
|
||||
@@ -572,7 +600,6 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT)) packageCounts->linglong += getNumElements(baseDir, "/var/lib/linglong/repo/refs/heads/main", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT)) packageCounts->pacstall += getNumElements(baseDir, "/var/lib/pacstall/metadata", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_QI_BIT)) packageCounts->qi += getNumStrings(baseDir, "/var/qi/installed_packages.list", "\n", "qi");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PISI_BIT)) packageCounts->pisi += getNumElements(baseDir, "/var/lib/pisi/package", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT)) packageCounts->pkgsrc += getNumElements(baseDir, "/usr/pkg/pkgdb", DT_DIR);
|
||||
}
|
||||
@@ -642,33 +669,30 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
#endif
|
||||
|
||||
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
|
||||
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
|
||||
{
|
||||
// check if ~/.nix-profile exists
|
||||
FF_STRBUF_AUTO_DESTROY profilePath = ffStrbufCreateCopy(&baseDir);
|
||||
ffStrbufAppendS(&profilePath, ".nix-profile");
|
||||
if (ffPathExists(profilePath.chars, FF_PATHTYPE_DIRECTORY))
|
||||
{
|
||||
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
|
||||
}
|
||||
// Count packages from $HOME/.nix-profile
|
||||
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
|
||||
|
||||
// check if $XDG_STATE_HOME/nix/profile exists
|
||||
FF_STRBUF_AUTO_DESTROY stateDir = ffStrbufCreate();
|
||||
const char* stateHome = getenv("XDG_STATE_HOME");
|
||||
if(ffStrSet(stateHome))
|
||||
// Check in $XDG_STATE_HOME/nix/profile
|
||||
FF_STRBUF_AUTO_DESTROY stateHome = ffStrbufCreate();
|
||||
const char* stateHomeEnv = getenv("XDG_STATE_HOME");
|
||||
if (ffStrSet(stateHomeEnv))
|
||||
{
|
||||
ffStrbufSetS(&stateDir, stateHome);
|
||||
ffStrbufEnsureEndsWithC(&stateDir, '/');
|
||||
ffStrbufSetS(&stateHome, stateHomeEnv);
|
||||
ffStrbufEnsureEndsWithC(&stateHome, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSet(&stateDir, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&stateDir, ".local/state/");
|
||||
ffStrbufSet(&stateHome, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&stateHome, ".local/state/");
|
||||
}
|
||||
result->nixUser += getNixPackages(&stateHome, "nix/profile");
|
||||
|
||||
ffStrbufSet(&profilePath, &stateDir);
|
||||
ffStrbufAppendS(&profilePath, "nix/profile");
|
||||
result->nixUser += getNixPackages(&stateDir, "nix/profile");
|
||||
// Check in /etc/profiles/per-user/$USER
|
||||
FF_STRBUF_AUTO_DESTROY userPkgsDir = ffStrbufCreateStatic("/etc/profiles/per-user/");
|
||||
result->nixUser += getNixPackages(&userPkgsDir, instance.state.platform.userName.chars);
|
||||
}
|
||||
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "packages.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
|
||||
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
{
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
|
||||
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user