Compare commits

...

172 Commits

Author SHA1 Message Date
Carter Li 855fd6edee Merge pull request #890 from fastfetch-cli/dev
Release v2.11.4
2024-05-06 20:06:58 +08:00
李通洲 d4bd4401a8 Release: v2.11.4 2024-05-06 19:45:45 +08:00
李通洲 689feb39a4 OS (Linux): don't detect debian version on debian derived distros 2024-05-06 18:42:19 +08:00
Carter Li 0f64e2830a OS (Linux): detect pve & armbian 2024-05-06 16:46:27 +08:00
Carter Li 3e24cdc752 CMake: add option CUSTOM_OS_RELEASE_PATH
And remove `--os-file`
2024-05-06 16:25:08 +08:00
李通洲 dc9c285a0b Doc: update README
Who cares how people install a package...

Close #883
2024-05-06 15:56:46 +08:00
李通洲 1d03c9c85e Logo (Builtin): add armbian
Fix #842
2024-05-06 15:22:43 +08:00
李通洲 4eae11df64 Presets: fix neofetch 2024-05-06 15:09:12 +08:00
李通洲 eba13d5485 JsonConfig: fix setting size.ndigits doesn't work
Silly copy & paste error
2024-05-06 15:08:58 +08:00
apocelipes 16b875ef5a Fastfetch: fix memory leaks when passing informative options
Informative options (e.g. "--help", "--list-module") make fastfetch
exit before calling ffDestroyInstance. Using "atexit" to avoid this
kind of leak.
2024-05-06 14:40:27 +08:00
李通洲 366138e1bd CI: try fixing Linux armv7 2024-05-06 14:08:29 +08:00
李通洲 7fe18a5b7c CI: build armv7 package using ubuntu22.04
Hopefully make it usable on RaspberryPi

Fix #884
2024-05-06 09:33:58 +08:00
李通洲 39cd8cfb4c Camera: fix deprecation warning for macOS 14.0 hopefully
Fix #860
2024-05-06 09:25:06 +08:00
李通洲 8b441c85e5 Logo (Builtin): update ubuntu 2024-05-05 23:31:23 +08:00
李通洲 f66e901c44 Presets: remove unsupported format placeholders 2024-05-05 22:12:33 +08:00
李通洲 3815823a20 CMake: enforce glibc version 2024-05-05 21:29:49 +08:00
李通洲 33ff4870dc Fastfetch: enable pipe mode if $NO_COLOR is set 2024-05-05 20:16:43 +08:00
李通洲 479731f076 Custom: don't print ANSI escape code in pipe mode 2024-05-05 20:14:24 +08:00
李通洲 d2f3f47457 Colors: print non-colored blocks in pipe mode 2024-05-05 20:14:24 +08:00
李通洲 5ea89ecba5 Fastfetch: print non-colored logo in pipe mode 2024-05-05 20:14:23 +08:00
Carter Li 865f57bd76 Revert "FFstrbuf: avoid redundant checks (#881)" (#882)
This reverts commit e98e2a3d52.
2024-05-05 18:46:22 +08:00
Nour1248 e98e2a3d52 FFstrbuf: avoid redundant checks (#881) 2024-05-05 18:40:59 +08:00
Carter Li 6bb748869e Terminal (macOS): fix Apple Terminal detection
Fix #878
2024-05-05 13:36:14 +08:00
李通洲 654721b8c5 Doc: remove (kind of) outdated information
Fix #867
2024-05-05 08:39:51 +08:00
Carter Li 0542eac1b9 Doc: metion ANSI 256 colors
Fix #869
2024-05-05 07:33:32 +08:00
apocelipes b9faf8d77f fastfetch: fix #868 (#871)
Fix #868.
2024-05-05 07:10:51 +08:00
Carter Li 61f848146a Merge pull request #862 from fastfetch-cli/dev
Release: v2.11.3
2024-05-04 20:47:54 +08:00
李通洲 4175dfdc3a Doc: update changelog (ci skip) 2024-05-04 20:27:26 +08:00
李通洲 861d9006d7 Release: v2.11.3 2024-05-04 20:11:30 +08:00
李通洲 7ba07bd2e0 Logo (Image): partially revert 71cba24
Images in SSH session and tmux do work for me

Fix #861
2024-05-04 19:43:41 +08:00
李通洲 9fee36a286 Logo (Image): ensure line ending is printed when printing errors 2024-05-04 19:14:45 +08:00
李通洲 2fc9230b29 Disk (Windows): use sub thread to check accessiblity of remote volumes. 2024-05-04 15:15:00 +08:00
李通洲 5fb1286e15 Battery (Windows): simplify code 2024-05-04 12:11:42 +08:00
李通洲 a4cace4765 CMake: add CUSTOM_AMDGPU_IDS_PATH 2024-05-04 10:06:49 +08:00
李通洲 c6d2467a83 Merge remote-tracking branch 'upstream/master' into dev 2024-05-04 10:06:40 +08:00
AxeldeWater db0d38202e Update README.md again for same reason different location (#857)
Oversaw a place where it wasn't updated either
2024-05-04 07:13:38 +08:00
AxeldeWater 9fbb23b135 Update README.md about installing fastfetch on Debian/Ubuntu (#856)
Apparently the file naming standard was changed over time but this was not updated in the README
2024-05-04 00:00:44 +08:00
李通洲 3a990e495b PhysicalDisk: fix temp output in custom formation
I hate `void *`
2024-05-03 20:48:51 +08:00
李通洲 648530ee8f PhysicalDisk: fix doubled output in custom formation
Fix #852
2024-05-03 20:42:39 +08:00
Carter Li b12a59cdaf Merge pull request #851 from fastfetch-cli/dev
Release: v2.11.2
2024-05-03 14:36:04 +08:00
李通洲 83c1fe26e6 Doc: update changelog 2024-05-03 14:14:13 +08:00
李通洲 217f98a36c Global: tidy json result formats 2024-05-03 13:56:19 +08:00
李通洲 1011e21ba8 Processing: trim \r on Windows 2024-05-03 13:46:28 +08:00
李通洲 08c6a6e4cb OS (macOS): don't print build id
Remove special handling
2024-05-03 13:20:23 +08:00
李通洲 5e9fcaf7ca OS (Linux): don't use rolling as os version 2024-05-03 13:09:14 +08:00
李通洲 8b838cef61 OS (Linux): fix name detection for MX
Fix #847
2024-05-03 12:57:51 +08:00
李通洲 22d9d8e196 OS (Linux): fix OS detection for MX Linux (2nd attempt)
Ref: #847
2024-05-03 11:28:59 +08:00
李通洲 a789b8330a Doc: update logo_request.md 2024-05-03 10:10:13 +08:00
李通洲 903ecf37f7 Chore: silience some warnings 2024-05-03 10:07:16 +08:00
李通洲 c4a876f6aa OS (Linux): Prioritize lsb-release over os-release
Fix #847
2024-05-03 10:00:18 +08:00
李通洲 82285ebeb4 Release: 2.11.2 2024-05-03 10:00:18 +08:00
李通洲 36dadcdc7f Logo (Builtin): add MX2 & fix mx distro detection
Fix: #847
2024-05-03 09:11:59 +08:00
李通洲 030c05429a Logo (Builtin): add missing FF_LOGO_LINE_TYPE_SMALL_BIT flags 2024-05-03 09:11:59 +08:00
李通洲 a462a12370 Logo (Builtin): fix distro name of DraugerOS 2024-05-03 09:11:59 +08:00
李通洲 b386365d95 Logo (Builtin): fix ascii file name 2024-05-03 09:11:59 +08:00
李通洲 158db9d7c7 Logo (Builtin): add KernelOS
Fix #848
2024-05-03 09:11:59 +08:00
李通洲 407bfa8c95 Shell: don't try detecting version of raw sh shell
Fix #849
2024-05-03 09:11:59 +08:00
李通洲 1449290e9e GPU (Linux): check NULL returned by opendir
Fix #845
2024-05-03 09:11:59 +08:00
李通洲 4c0ea7354d Logo (Image): only print error if --show-error is specified 2024-05-03 09:11:59 +08:00
李通洲 71cba2451a Logo: disable image logos in ssh and tmux sessions 2024-05-03 01:10:04 +08:00
李通洲 ef3b5df048 Doc: update man page 2024-05-03 01:10:04 +08:00
Juan 3e98034e55 Packages (Linux): check xdg state home for nix user packages (#844)
Check $XDG_STATE_HOME/nix/profile if ~/.nix-profile is not found as addressed in #837.

Fix #837
2024-05-02 22:55:50 +08:00
李通洲 1c89101522 Doc: update changelog 2024-05-02 20:45:46 +08:00
Carter Li 757e6271ff Merge pull request #840 from fastfetch-cli/dev
Release: v2.11.1
2024-05-02 20:23:35 +08:00
李通洲 c5c846aa22 CI: try build for Linux armv7 2024-05-02 20:03:40 +08:00
李通洲 23a59a15ec Release: v2.11.1 2024-05-02 19:48:17 +08:00
李通洲 4798c619d0 Battery (Android): fix uninitialized variables
Fix #760 and #838
2024-05-02 19:29:13 +08:00
李通洲 023e767237 Shell (Windows): ignore hyfetch 2024-05-02 16:27:13 +08:00
李通洲 688d9b00ab Shell (Linux): don't detect hyfetch as shell 2024-05-02 15:19:43 +08:00
李通洲 c2fe2f70dc DisplayServer (Linux): silence compiler warnings 2024-05-02 15:19:43 +08:00
李通洲 3430c10ec2 Doc: clarify --disk-folders overrides other disk options 2024-05-02 14:09:56 +08:00
李通洲 9afcc00201 Disk (Windows): don't rely on env vars 2024-05-01 19:32:15 +08:00
李通洲 cd783d1267 Presets: add a new example 2024-05-01 16:00:31 +08:00
李通洲 81480532e2 Custom: make --custom-format optional 2024-05-01 15:54:30 +08:00
李通洲 982e8a0117 Disk (Windows): make / an alias of C:\ for --disk-folders 2024-05-01 15:52:38 +08:00
李通洲 8af88a3376 Doc: fix incorrect man page
Fix #828
2024-05-01 11:55:26 +08:00
Val V 9ed2f13c78 Packages (Linux): Extended Source Mage support (#825)
* Extended Source Mage support

* Fix packages format args num

* Correct spelling
2024-05-01 11:25:04 +08:00
李通洲 d7ea774d71 CI: fix release script 2024-04-30 21:42:31 +08:00
Carter Li a4b9784c48 Merge pull request #823 from fastfetch-cli/dev
Release v2.11.0
2024-04-30 20:40:40 +08:00
Carter Li 3fe2d8091a Release: v2.11.0 2024-04-30 19:43:26 +08:00
Carter Li 78c903c403 Camera (macOS): fix building on old xcode 2024-04-30 19:22:45 +08:00
Carter Li c42711ee26 Camera (macOS): try silence system deprecation warnings 2024-04-30 18:56:45 +08:00
李通洲 367264e549 Disk: only detect folders that specified by --disk-folders
Can be used to improve performance by ignoring network disks
2024-04-30 15:42:44 +08:00
李通洲 36a0c273f9 Processing: suggest increasing --processing-timeout when child process timeouts 2024-04-30 14:52:47 +08:00
李通洲 418106c485 Revert "Disk: init variables"
This reverts commit 0576d4ca26.
2024-04-30 14:46:54 +08:00
李通洲 1058e876a7 Revert "Disk (Windows): add --disk-ignore-remote"
This reverts commit c71b04ba93.
2024-04-30 14:46:26 +08:00
李通洲 8721cc1ab5 CPU (Windows): silence compiler warnings 2024-04-30 14:43:12 +08:00
李通洲 e12642e0b9 Fastfetch: make config in jsonc overridable
Fix #821
2024-04-30 09:16:59 +08:00
李通洲 315bbb3020 GPU (Linux): constantly use *_vis_* 2024-04-30 09:16:59 +08:00
李通洲 0576d4ca26 Disk: init variables 2024-04-29 23:33:18 +08:00
李通洲 c309dbb844 Doc: update bug report template 2024-04-29 23:30:55 +08:00
李通洲 c71b04ba93 Disk (Windows): add --disk-ignore-remote 2024-04-29 23:28:20 +08:00
Carter Li f3417b1b05 Merge pull request #818 from fastfetch-cli/dev
Release: v2.10.3
2024-04-29 22:49:37 +08:00
李通洲 c597b7ec3a Release: v2.10.3 2024-04-29 21:47:39 +08:00
李通洲 8b4586b914 Packages: update help messages 2024-04-29 21:47:39 +08:00
李通洲 b65a0e2543 GPU (Linux): fix copy & paste error 2024-04-29 20:43:19 +08:00
李通洲 6e15a44168 GPU (Linux): ignore . when enumerating directories 2024-04-29 20:28:50 +08:00
李通洲 6bd3d2c434 GPU (Linux): greatly improve detection for AMD cards
Completely untested
2024-04-29 20:05:50 +08:00
李通洲 29644ef904 GPU (Linux): disable vmem detection
Ref #816
2024-04-29 13:27:57 +08:00
李通洲 39dfcb6f10 Packages (Linux): optimise nix detection code 2024-04-29 10:04:20 +08:00
Juan Llamas 882b17834c Packages (nix): use hash to cache count and process count manually (#817) 2024-04-29 09:59:05 +08:00
李通洲 bdd2908e6a Doc: update changelog 2024-04-28 10:46:08 +08:00
李通洲 d4a402f4dd Common: slience compiler warnings 2024-04-28 10:34:28 +08:00
李通洲 115b293ff5 CPU (Windows): fix silly bug... 2024-04-27 23:27:16 +08:00
李通洲 6831c095ec TerminalShell (Linux): actually fix #814 2024-04-27 23:12:45 +08:00
李通洲 81fb146869 CPU (Windows): detect max CPU freq with CPUID instruction
Note this only works when Hyper-V is not enabled

Ultimately fixes #800 #812 #815
2024-04-27 23:07:12 +08:00
李通洲 35b54fd064 Separator: add fast path for ascii strings 2024-04-27 17:30:42 +08:00
李通洲 866e65749e Init: tweaks 2024-04-27 16:36:33 +08:00
李通洲 e157b9a51f TerminalShell (Linux): fix nixos wrapped process name
Fix #814
2024-04-27 16:31:39 +08:00
李通洲 74c89cc03f Wifi (Linux): try fixing #811 2024-04-26 19:26:58 +08:00
李通洲 229c6674a4 CMake: fix #810 2024-04-25 15:48:39 +08:00
李通洲 ab8ad7ffc0 Fastfetch: default hideCursor to false
It doesn't make much difference but make user's terminal unusable if fastfetch is not exited correctly
2024-04-25 14:18:25 +08:00
Carter Li 6805cb16fb Packages: support printing total number of nix / flatpak / brew packages
Ref: https://github.com/fastfetch-cli/fastfetch/issues/436#issuecomment-2075469683
2024-04-25 09:16:12 +08:00
Carter Li e596d76430 Display (Linux): don't use *-unknown as name 2024-04-25 09:08:21 +08:00
李通洲 de4afb6507 CI: test with no dependencies installed 2024-04-24 19:40:31 +08:00
李通洲 beb5f479d9 CI: build Linux binaries with Ubuntu 20.04 again...
Ref: #808
2024-04-24 19:03:44 +08:00
李通洲 e660e61027 Swap (Windows): fix x86-32 (v2) 2024-04-24 11:04:03 +08:00
halperyon e3cdecdb14 bedrock version (#809) 2024-04-24 07:45:45 +08:00
李通洲 40320e5efa Swap (Windows): fix detection in i686 build 2024-04-23 23:29:26 +08:00
李通洲 c2fd057126 CI (macOS): revert back to macos 12 before we know what was happening 2024-04-23 22:51:22 +08:00
李通洲 ea1ef0f347 JsonSchema: add missing modules 2024-04-23 22:51:22 +08:00
Guiorgy 04456d9807 allow generation of either deb or rpm package only (#807) 2024-04-23 19:05:55 +08:00
李通洲 18240524dc DisplayServer (Linux): basic support for ukui 2024-04-23 15:32:49 +08:00
Carter Li 42b7d567a1 Merge pull request #806 from fastfetch-cli/dev
Release: v2.10.2
2024-04-23 13:46:23 +08:00
李通洲 2790493cba Release: v2.10.2 2024-04-23 13:43:16 +08:00
李通洲 8eabc49e12 DisplayServer (Linux): fix silly bug that detect x11 as wayland
Fix #805
2024-04-23 13:39:49 +08:00
Carter Li 3252812699 Merge pull request #803 from fastfetch-cli/dev
Release v2.10.1
2024-04-22 23:49:18 +08:00
李通洲 3fa308386f Release: v2.10.1 2024-04-22 23:44:21 +08:00
李通洲 84ee7cef7c DE (Linux): silence warnings 2024-04-22 23:38:43 +08:00
Carter Li 57f6aff2de Merge pull request #802 from ceamac/fix/dbus
fix/dbus
2024-04-22 23:33:51 +08:00
Viorel d745d7afef Fix build with ENABLE_DBUS=OFF 2024-04-22 18:23:27 +03:00
Carter Li 510a1f57f8 Merge pull request #801 from fastfetch-cli/dev
Release: v2.10.0
2024-04-22 22:34:25 +08:00
李通洲 a1c9b24755 Release: v2.10.0 2024-04-22 21:22:50 +08:00
李通洲 75e6f48dfd Doc: update changelog 2024-04-22 19:44:16 +08:00
李通洲 ed7b12e733 DisplayServer (Linux): fix compiling for old wayland version 2024-04-22 19:24:48 +08:00
李通洲 9c56839c97 DisplayServer (Linux): fix crash 2024-04-22 19:06:13 +08:00
李通洲 6647980ce3 DisplayServer (Linux): refactor & support wlroots protocol 2024-04-22 16:41:30 +08:00
李通洲 80f8b086ca Doc: update changelog 2024-04-21 20:13:22 +08:00
李通洲 8c2dd1aeac IO: don't print ANSI escape codes in --pipe mode 2024-04-21 20:12:42 +08:00
李通洲 ae3c6f1e63 GPU: detect max freq instead of current freq 2024-04-21 19:37:30 +08:00
李通洲 7cc381339c 3rdparty: update 2024-04-21 19:37:30 +08:00
李通洲 aa58a0999d CPU (Windows): try detecting invalid data in SMBIOS
Work around #800
2024-04-21 17:59:14 +08:00
李通洲 4580f3fd54 Disk (Linux): hide drivers folder in WSL 2024-04-21 17:35:47 +08:00
李通洲 6c0c4fa2cf Host (Linux): improve performance of WSL version detection 2024-04-21 17:28:40 +08:00
李通洲 526324be38 Terminal (FreeBSD): implement kitty version fast path for FreeBSD 2024-04-19 15:19:46 +08:00
李通洲 efb0f335e1 Chore: silence compiler warnings 2024-04-19 08:48:22 +08:00
李通洲 9b23ce94ab Chore: oops... 2024-04-18 23:34:27 +08:00
李通洲 47000f2aaf GPU (Linux): fix freq detection
oops...
2024-04-18 23:20:58 +08:00
李通洲 cb3ca73f60 Doc: update changelog 2024-04-18 22:55:04 +08:00
李通洲 fd0b35f21a Display: add option --ts-version to hide terminal and shell version 2024-04-18 22:53:31 +08:00
李通洲 0e7dda4043 Shell: remove unused vars 2024-04-18 22:38:22 +08:00
李通洲 5f7b9d2473 GPU (Linux): bring back pciDetectGPUs 2024-04-18 21:00:47 +08:00
Carter Li f8cbe4c008 GPU (Linux): improve detection performance of Apple Silicon 2024-04-18 19:58:38 +08:00
Carter Li 41df915f29 Terminal (Linux): make fast path of kitty version detection actually work 2024-04-18 15:22:13 +08:00
Carter Li ef440a015d Display (Linux): don't display (null) 2024-04-18 15:18:37 +08:00
李通洲 180cbce3a2 Doc: update changelog 2024-04-18 14:16:08 +08:00
李通洲 64ec76f5a6 Display (Linux): detect refresh rate for DRM method 2024-04-18 04:28:38 +00:00
李通洲 9860fb67d4 TerminalShell (Linux): if /bin/sh is set to default shell, use it
Fix #798
2024-04-18 09:22:08 +08:00
李通洲 08cbba1d9d Terminal (Linux): optimise kitty version detection 2024-04-18 08:53:53 +08:00
李通洲 095149a4e9 TerminalShell (Windows): fix compiling 2024-04-17 23:18:32 +08:00
李通洲 a561a96a5f Display (Linux): wlr-randr for hyprland
which support reporting fractional scale factors
2024-04-17 22:16:19 +08:00
李通洲 073d6a9337 DE (Linux): improve kde version detection performance
KDE6 uses wayland only
2024-04-17 21:02:32 +08:00
李通洲 6851c9cc1a DE (Linux): tag gnome-shell --version a slow operation 2024-04-17 20:58:49 +08:00
李通洲 2862f466f3 Terminal (Linux): improve performance of kitty version detection 2024-04-17 20:28:13 +08:00
李通洲 5e3fdc6c33 DE (Linux): better Gnome version detection 2024-04-17 19:00:45 +08:00
李通洲 03fe5803de common/properties: we don't use threads any more 2024-04-17 19:00:06 +08:00
Carter Li 6d36ec55c5 GPU (Linux): try detecting vmem with gpu kernel module 2024-04-17 14:32:11 +08:00
李通洲 f098cdbf69 CI: update artifact name for musl builds 2024-04-16 22:58:06 +08:00
李通洲 07d3fe3044 CI: add musl build 2024-04-16 22:29:01 +08:00
Carter Li 636b6fc43d Packaging: update debian stuff 2024-04-16 16:34:18 +08:00
李通洲 ccfba6786c README: metion linuxbrew 2024-04-16 16:24:30 +08:00
李通洲 7c2c631807 README: remove AUR as it's very outdated 2024-04-16 16:19:53 +08:00
110 changed files with 4834 additions and 1193 deletions
+4
View File
@@ -59,6 +59,10 @@ strace /path/to/fastfetch --multithreading false -s {MODULE} --pipe
If you cannot do the instructions above, please upload the core dump file:
## If fastfetch is slow
Use `time fastfetch --stat` to show time usage for each module.
## If my image logo didn't show / work
<!-- Please make sure the terminal does support the image protocol you used. Note Gnome terminal doesn't support any image protocols -->
+1 -1
View File
@@ -11,7 +11,7 @@ Tip: A logo can be displayed by fastfetch without getting into fastfetch's offic
# OS
```
Paste content of /etc/os-release here. If this file doesn't exist, describe a way to identify the distro.
Paste content of /etc/os-release and /etc/lsb-release here. If none of these files exist, describe a way to identify the distro
```
# Ascii
+131 -88
View File
@@ -14,66 +14,16 @@ jobs:
- name: Install codespell
shell: bash
run: sudo apt update && sudo apt install -y codespell
run: |
sudo apt-get update || true
sudo apt-get install -y codespell
- name: Run Spellchecker
run: codespell
linux-buildtest:
name: Linux build test
permissions:
contents: read
strategy:
fail-fast: false
matrix:
compiler: [
{ cc: gcc, cxx: "g++" },
{ cc: clang, cxx: "clang++" },
{ cc: "musl-gcc", cxx: "musl-g++" }
]
enableFeatures: [ON, OFF]
exclude:
# The feature libraries are all build against glibc, so they can't be used with musl
- compiler: { cc: "musl-gcc", cxx: "musl-g++" }
enableFeatures: ON
runs-on: ubuntu-22.04
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: uname -a
run: uname -a
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y musl-dev musl-tools linux-headers-generic libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libddcutil-dev libchafa-dev libdrm-dev directx-headers-dev
- name: configure project
env:
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
run: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_VULKAN=${{ matrix.enableFeatures }} -DENABLE_WAYLAND=${{ matrix.enableFeatures }} -DENABLE_XCB_RANDR=${{ matrix.enableFeatures }} -DENABLE_XCB=${{ matrix.enableFeatures }} -DENABLE_XRANDR=${{ matrix.enableFeatures }} -DENABLE_X11=${{ matrix.enableFeatures }} -DENABLE_GIO=${{ matrix.enableFeatures }} -DENABLE_DCONF=${{ matrix.enableFeatures }} -DENABLE_DBUS=${{ matrix.enableFeatures }} -DENABLE_XFCONF=${{ matrix.enableFeatures }} -DENABLE_SQLITE3=${{ matrix.enableFeatures }} -DENABLE_RPM=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK7=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK6=${{ matrix.enableFeatures }} -DENABLE_CHAFA=${{ matrix.enableFeatures }} -DENABLE_ZLIB=${{ matrix.enableFeatures }} -DENABLE_EGL=${{ matrix.enableFeatures }} -DENABLE_GLX=${{ matrix.enableFeatures }} -DENABLE_OSMESA=${{ matrix.enableFeatures }} -DENABLE_OPENCL=${{ matrix.enableFeatures }} -DENABLE_LIBNM=${{ matrix.enableFeatures }} -DENABLE_PULSE=${{ matrix.enableFeatures }} -DENABLE_DIRECTX_HEADERS=${{ matrix.enableFeatures }} -DENABLE_DRM=${{ matrix.enableFeatures }} -DENABLE_DDCUTIL=${{ matrix.enableFeatures }} -DENABLE_CHAFA=${{ matrix.enableFeatures }} .
- name: build project
run: cmake --build . --verbose -j4
- name: run tests
run: ctest
- name: run fastfetch --list-features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
Linux-old-amd64:
name: Linux-old-amd64
runs-on: ubuntu-20.04
no-features-test:
name: No-features-test
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
@@ -84,28 +34,12 @@ jobs:
- name: uname -a
run: uname -a
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev directx-headers-dev
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa ddcutil --ignore-dependencies
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: c
- name: configure project
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OSMESA=OFF -DENABLE_OPENCL=OFF -DENABLE_LIBNM=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
- name: build project
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v3
- name: list features
run: ./fastfetch --list-features
@@ -124,15 +58,9 @@ jobs:
- name: run tests
run: ctest
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-old-amd64
path: ./fastfetch-*.*
linux-amd64:
name: Linux-amd64
runs-on: ubuntu-22.04 # Ubuntu 22.04 uses Glibc 2.35. Should be fine with Debian 12, which uses Glibc 2.36 (https://packages.debian.org/source/bookworm/glibc)
runs-on: ubuntu-20.04
permissions:
security-events: write
contents: read
@@ -146,12 +74,12 @@ jobs:
run: uname -a
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev directx-headers-dev
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev directx-headers-dev
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa ddcutil --ignore-dependencies
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
@@ -230,9 +158,126 @@ jobs:
name: fastfetch-linux-aarch64
path: ./fastfetch-*.*
linux-armv7:
name: Linux-armv7
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: uraimo/run-on-arch-action@v2
id: runcmd
with:
arch: armv7
distro: ubuntu20.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y wget
# CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments`
wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb}
dpkg -i *.deb
apt-get install -y make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-armv7
path: ./fastfetch-*.*
musl-amd64:
name: Musl-amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: setup alpine linux
uses: jirutka/setup-alpine@master
- name: install dependencies
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 gcc g++
shell: alpine.sh --root {0}
- name: build
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr -DIS_MUSL=ON -GNinja .
cmake --build . --target package --verbose -j4
shell: alpine.sh {0}
- name: run
run: |
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest
shell: alpine.sh {0}
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
musl-aarch64:
name: Musl-aarch64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: setup alpine linux
uses: jirutka/setup-alpine@master
with:
arch: aarch64
- name: install dependencies
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 gcc g++
shell: alpine.sh --root {0}
- name: build
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr -DIS_MUSL=ON -GNinja .
cmake --build . --target package --verbose -j4
shell: alpine.sh {0}
- name: run
run: |
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest
shell: alpine.sh {0}
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-musl-aarch64
path: ./fastfetch-*.*
macos-universal:
name: macOS-universal
runs-on: macos-latest
runs-on: macos-12
permissions:
security-events: write
contents: read
@@ -495,6 +540,9 @@ jobs:
needs:
- linux-amd64
- linux-aarch64
- linux-armv7
- musl-amd64
- musl-aarch64
- macos-universal
- freebsd-amd64
- freebsd-aarch64
@@ -513,11 +561,6 @@ jobs:
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v4
- name: rm old artifacts
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
run: |
rm -rf fastfetch-*-old-*
- name: create release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
+140
View File
@@ -1,3 +1,143 @@
# 2.11.4
Changes:
* Fastfetch will print a colorless ascii logo in `--pipe` mode for better `lolcat` compatibility. `fastfetch | lolcat` should work and no `--pipe false` needed.
* Previously the logo would be disabled in `--pipe` mode.
* `--os-file` was removed and CMake option `-DCUSTOM_OS_RELEASE_PATH=/path/to/os-release` was added. This option should not used in most cases.
Bugfixes:
* Fix possible out-of-bound memory access (#868)
* Fix Apple Terminal detection (macOS, Terminal)
* Fix doubled output in custom formation (#852)
* Fix deprecation warning for macOS 14.0 hopefully (#860, macOS, Camera)
* Fix memory leaks when passing informative options
* Fix JSON config `size.ndigits` doesn't work
Features:
* Enable `--pipe` mode if environment variable `$NO_COLOR` is set
* Support Armbian and Proxmox distro detection (OS, Linux)
Logo:
* Add Armbian
# 2.11.3
Hotfix for nix (https://github.com/NixOS/nixpkgs/issues/308849#issuecomment-2093962376)
Features:
* Add cmake option `CUSTOM_AMDGPU_IDS_PATH` for specifying custom path of `amdgpu.ids`
Bugfixes:
* Fix hanging when detecting disconnected network drive (Disk, Windows)
* Ensure line ending is printed when printing image logo errors (Logo)
* Revert image logo limitation change in 2.11.2; allow image logo in SSH session and tmux again (#861, Logo)
* Fix doubled output in custom formation (PhysicalDisk, Windows)
# 2.11.2
Hotfix for Debian 11
Changes:
* Error messages when trying to print image logo will only be printed with `--show-errors`
* When generating JSON output, fastfetch will generate an empty array when no result is detected, instead of an error.
Bugfixes:
* Fix segfault in Debian 11 and some old kernels. Regression introduced in 2.11.0 (#845, GPU, Linux)
* Don't try detecting version of raw `sh` shell (#849, Shell, Linux)
* Trim `\r` on Windows
Features:
* Check xdg state home for nix user packages (#837, Packages, Linux)
* Disable image logos in ssh and tmux sessions (#839)
* Support MX Linux distro detection (#847, OS, Linux)
Logo:
* Add KernelOS
* Fix name of DraugerOS
* Add missing `FF_LOGO_LINE_TYPE_SMALL_BIT` flags
* Add MX2
# 2.11.1
Hotfix for Android
Bugfixes:
* Fix uninitialized variables which can cause crashes (#760 #838, Battery, Android)
* Don't detect hyfetch as shell when used as backend of [hyfetch](https://github.com/hykilpikonna/hyfetch)
* Fix incorrect information in man page (#828)
Features:
* Support sorcery package manager detection (Packages, Linux)
* Make `--custom-format` optional (Custom)
* Make `/` an alias of `C:\` for `--disk-folders` (Disk, Windows)
* Build for Linux armv7
Logo:
* Fix colors of Source Mage logo
# 2.11.0
Changes:
* Default `hideCursor` to false. It doesn't make much difference but makes user's terminal unusable if fastfetch is not exited correctly.
* Linux amd64 binaries are built with Ubuntu 20.04 again (#808)
Bugfixes:
* Fix swap usage detection in x86-32 build (Windows, Swap)
* Fix minimum cmake version support (#810)
* Fix wifi detection on platforms that don't use NetworkManager (#811, Wifi, Linux)
* Fix NixOS wrapped process name (#814, Terminal, Linux)
* Fix GPU type detection for AMD cards (#816, GPU, Linux)
* Silence system deprecation warnings (#822, Camera, macOS)
Features:
* Add basic support DE detection support for UKUI (DE, Linux)
* Support printing total number of nix / flatpak / brew packages (Packages)
* See `fastfetch -h packages-format` for detail
* Better max CPU frequency detection support with `CPUID / 16H` instruction (CPU, Windows)
* This requires Intel Core I Gen 6 or newer, and with `Virtual Machine Platform` Windows feature disabled. X86 only.
* Improve performance of nix packages detection (Packages, Linux)
* Make config specified in JSONC overridable by command line flags
* Note this change only make global config overridable; module configs are still not
* Suggest increasing `--processing-timeout` when child process timeouts
* Only detect folders that specified by `--disk-folders`
* Previously `--disk-folders` only omits unmatched disks from output
* This option can be used to improve detection performance by ignoring slow network drives
# 2.10.2
Bugfixes:
* Fix a regression that detect x11 as wayland (#805, WM, Linux)
# 2.10.1
Bugfixes:
* Fix build with `-DENABLE_DBUS=OFF` (Linux)
# 2.10.0
Changes:
* We now always detect max frequency of GPUs for consistent, instead of current frequency
Features:
* Improve display detection for wlroots based WMs. Fastfetch now correctly reports fractional scale factors in hyprland (Display, Linux)
* Improve GPU detection on Linux (GPU, Linux)
* Support GPU memory usage detection for AMD GPUs
* Support GPU frequency detection for Intel GPUs
* Improve performance of Gnome version detection (DE, Linux)
* Improve performance of kitty version detection (Terminal, Linux)
* Detect refresh rate when using `--ds-force-drm sysfs-only` (Display, Linux)
* Add option `--ts-version` to disable terminal and shell version detection. Mainly for benchmarking purposes
* Improve performance of detecting WSL version (Host, Linux)
Bugfixes:
* Correctly detect `/bin/sh` as current shell if it's used as default shell (#798, Shell, Linux)
* Work around an issue which CPU module reports incorrect CPU frequency that is too high (#800, CPU, Linux)
* Don't print ANSI escape codes in `--pipe` mode
# 2.9.2
Changes:
+47 -14
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.9.2
VERSION 2.11.4
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -75,9 +75,12 @@ option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
option(ENABLE_PROPRIETARY_GPU_DRIVER_API "Enable proprietary GPU driver API (NVML, IGCL and AGS)" ON)
option(BUILD_TESTS "Build tests" OFF) # Also create test executables
option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds
option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions
if (LINUX)
set(CUSTOM_PCI_IDS_PATH "" CACHE STRING "Custom path to file pci.ids, defaults to `/usr/share/hwdata/pci.ids`")
set(CUSTOM_AMDGPU_IDS_PATH "" CACHE STRING "Custom path to file amdgpu.ids, defaults to `/usr/share/libdrm/amdgpu.ids`")
set(CUSTOM_OS_RELEASE_PATH "" CACHE STRING "Custom path to file os-release, defaults to `/etc/os-release`")
endif()
####################
@@ -254,7 +257,7 @@ file(GLOB LOGO_FILES "src/logo/ascii/*.txt")
set(LOGO_BUILTIN_H "#pragma once\n#pragma GCC diagnostic ignored \"-Wtrigraphs\"\n\n")
foreach(file ${LOGO_FILES})
fastfetch_load_text("${file}" content)
get_filename_component(file "${file}" NAME_WLE)
get_filename_component(file "${file}" NAME_WE)
string(TOUPPER "${file}" file)
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
@@ -399,7 +402,10 @@ if(LINUX)
src/detection/diskio/diskio_linux.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
@@ -517,7 +523,10 @@ elseif(BSD)
src/detection/diskio/diskio_bsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
@@ -777,6 +786,14 @@ if(NOT "${CUSTOM_PCI_IDS_PATH}" STREQUAL "")
message(STATUS "Custom file path of pci.ids: ${CUSTOM_PCI_IDS_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_PCI_IDS_PATH=${CUSTOM_PCI_IDS_PATH})
endif()
if(NOT "${CUSTOM_AMDGPU_IDS_PATH}" STREQUAL "")
message(STATUS "Custom file path of amdgpu.ids: ${CUSTOM_AMDGPU_IDS_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_AMDGPU_IDS_PATH=${CUSTOM_AMDGPU_IDS_PATH})
endif()
if(NOT "${CUSTOM_OS_RELEASE_PATH}" STREQUAL "")
message(STATUS "Custom file path of os_release: ${CUSTOM_OS_RELEASE_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_OS_RELEASE_PATH=${CUSTOM_OS_RELEASE_PATH})
endif()
function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME)
if(NOT ENABLE_${VARNAME})
@@ -926,10 +943,6 @@ if(ENABLE_THREADS)
endif()
endif()
if(ENABLE_PCI_MEMORY)
target_compile_definitions(libfastfetch PRIVATE FF_USE_PCI_MEMORY)
endif()
if(LINUX)
target_link_libraries(libfastfetch
PRIVATE "m"
@@ -1131,17 +1144,37 @@ else() # We don't use this in Windows
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
endif()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
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()
endif()
if(LINUX)
set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB;RPM")
find_program(HAVE_DPKG "dpkg")
if(HAVE_DPKG)
set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB")
set(CPACK_DEBIAN_PACKAGE_SECTION, "utils")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
set(CPACK_DEBIAN_PACKAGE_SECTION, "utils")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
if(NOT IS_MUSL)
EXECUTE_PROCESS (
COMMAND getconf GNU_LIBC_VERSION
OUTPUT_VARIABLE GLIBC_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE)
STRING (REPLACE "glibc " "" GLIBC_VERSION ${GLIBC_VERSION})
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= ${GLIBC_VERSION})")
endif()
endif()
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
endif()
endif()
set(CPACK_SET_DESTDIR ON)
-34
View File
@@ -1,34 +0,0 @@
# Development help
This file is not an official documentation!
Here i just add things that are easy to forget.
## Features i am planning to implement
### Specific
- [ ] Split the project in different libs / executables, all linking static by default:
- `libffdetect`: contains all the detection stuff. To be used by anything that needs system information
- `libffprint`: contains the printing functions, logos, format etc
- `fastfetch` and `flashfetch`: Executables, that initialize the config of libffprint. Fist one at runtime, second one at compile time
- [ ] Make LocalIP module more configurable
- [ ] Automatic migrate old config files to newer versions
- [ ] ZSH completions
- [ ] Fish completions
- [ ] Make CPU usage detection much faster and more accurate
- [ ] Detect CPU usage in a common detection method and expose it both to the cpuUsage module and the cpu format string
- [ ] Per session caching
### General
- More presets
- More logos
- More package managers
- More DE detections
- More WM theme detections
- More terminal font detections
- Performance optimizations
- More module specific options
- Better error handling, especially the messages shown when using --show-errors
- Using package managers libraries for package count detection instead own. E.g. using libalpm instead of counting files in /var/lib/pacman/local
- Better documentation (especially default config file and the various --help options. Colored output?)
- General feature parity with neofetch, to demonstrate supremity of c
+7 -5
View File
@@ -27,11 +27,11 @@ There are [screenshots on different platforms](https://github.com/fastfetch-cli/
### Linux
Some distros packaged a outdated fastfetch version. Older version is not supported, please always ensure that the latest version is used.
Some distros packaged an outdated fastfetch version. Older version is not supported, please always ensure that the latest version is used.
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or above)
* Debian / Ubuntu: Download `fastfetch-<version>-Linux.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and `dpkg -i fastfetch-<version>-Linux.deb` (for Ubuntu 22.04 or above and Debian 12 or above).
* Arch Linux: `sudo pacman -S fastfetch`. You can also find fastfetch [on the AUR](https://aur.archlinux.org/packages/fastfetch-git).
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or newer)
* Debian / Ubuntu: Download `fastfetch-linux-<proper architecture>.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and double-click it (for Ubuntu 20.04 or newer and Debian 11 or newer).
* Arch Linux: `sudo pacman -S fastfetch`
* Fedora: `sudo dnf install fastfetch`
* Gentoo: `sudo emerge --ask app-misc/fastfetch`
* Alpine: `apk add --upgrade fastfetch`
@@ -41,7 +41,9 @@ Some distros packaged a outdated fastfetch version. Older version is not support
Replace sudo with doas depending on what you use.
[See also if fastfetch has been packaged for your favorite Linux distro](#Packaging)
[See also if fastfetch has been packaged for your favorite Linux distro](#Packaging).
If fastfetch is not packaged for your distro or an outdated version is packaged, [linuxbrew](https://brew.sh/) is a good alternate: `brew install fastfetch`
### macOS
+12
View File
@@ -1,3 +1,15 @@
fastfetch (2.9.2) jammy; urgency=medium
* Update to 2.9.2
-- Carter Li <zhangsongcui@live.cn> Tue, 16 Apr 2024 16:32:40 +0800
fastfetch (2.9.1) jammy; urgency=medium
* Update to 2.9.1
-- Carter Li <zhangsongcui@live.cn> Mon, 08 Apr 2024 09:34:30 +0800
fastfetch (2.8.10) jammy; urgency=medium
* Update to 2.8.10
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.8.10_source.buildinfo universe/utils optional
fastfetch_2.9.2_source.buildinfo universe/utils optional
+5 -8
View File
@@ -107,12 +107,12 @@ To list all available modules, use \fB \-\-list\-modules \fR
.SS "Config Files"
fastfetch supports two types of config files. The legacy
configuration files and a JSONC based format.
Fastfetch uses JSONC based format for configuration. Fastfetch doesn't generate
config file automatically; it should be generated manually by \fB \-\-gen\-config\fR.
The config file will be saved in \fB~/.config/fastfetch/config.jsonc\fR by default.
A JSONC config file is a JSON file that also supports comments with (//). Those
files must have the extension '.jsonc'. You can migrate a legacy config
file to the JSONC format by using \fB\-\-gen\-config\fR.
files must have the extension '.jsonc'.
The specified configuration/preset files are searched in the following order:
@@ -122,10 +122,7 @@ The specified configuration/preset files are searched in the following order:
3. relative to /usr/share/fastfetch/presets/
When both a '.jsonc' and a '.conf' file with the same name is found,
the '.jsonc' file is preferred.
Fastfetch provides some default presets. List them with \fB \-\-print\-available\-presets\fR.
Fastfetch provides some default presets. List them with \fB\-\-list\-presets\fR.
.SH "SEE ALSO"
.BR neofetch (1)
+15 -9
View File
@@ -294,10 +294,6 @@
"type": "string",
"description": "The name of the player to use for module Media and Player. Linux only"
},
"osFile": {
"type": "string",
"description": "Set the path to the file containing OS information. Linux only"
},
"dsForceDrm": {
"description": "Force display detection to use DRM. Linux only",
"oneOf": [
@@ -549,6 +545,11 @@
"type": "boolean",
"description": "Whether to disable the stdout application buffer",
"default": false
},
"tsVersion": {
"type": "boolean",
"description": "Whether to detect and display the version of terminal and shell. Mainly for benchmarking",
"default": true
}
}
},
@@ -674,6 +675,7 @@
"board",
"break",
"brightness",
"camera",
"chassis",
"cpu",
"cpuusage",
@@ -767,6 +769,10 @@
"const": "board",
"description": "Print mather board name and other info"
},
{
"const": "camera",
"description": "Print available cameras"
},
{
"const": "cursor",
"description": "Print cursor style name"
@@ -1107,6 +1113,9 @@
"maxItems": 2
}
}
},
"key": {
"$ref": "#/$defs/key"
}
}
},
@@ -1164,10 +1173,7 @@
"description": "Text to print",
"type": "string"
}
},
"required": [
"format"
]
}
},
{
"title": "Display",
@@ -1228,7 +1234,7 @@
},
"folders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points"
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
},
"showExternal": {
"type": "boolean",
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "file:///C:/msys64/home/zhang/fastfetch/doc/json_schema.json",
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small"
},
+85
View File
@@ -0,0 +1,85 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small",
"padding": {
"top": 1
}
},
"display": {
"separator": "",
"keyWidth": 15
},
"modules": [
{
"key": "╭───────────╮",
"type": "custom"
},
{
// draw borders first to make colors of left and right border consistant
"key": "│ │\u001b[11D\u001b[31m user",
"type": "title",
"format": "{1}"
},
{
"key": "│ │\u001b[11D\u001b[32m󰇅 hname",
"type": "title",
"format": "{2}"
},
{
"key": "│ │\u001b[11D\u001b[33m󰅐 uptime",
"type": "uptime"
},
{
"key": "│ │\u001b[11D\u001b[34m󰟾 distro",
"type": "os"
},
{
"key": "│ │\u001b[11D\u001b[35m kernel",
"type": "kernel"
},
{
"key": "│ │\u001b[11D\u001b[36m󰇄 desktop",
"type": "de"
},
{
"key": "│ │\u001b[11D\u001b[31m term",
"type": "terminal"
},
{
"key": "│ │\u001b[11D\u001b[32m shell",
"type": "shell"
},
{
"key": "│ │\u001b[11D\u001b[33m󰍛 cpu",
"type": "cpu"
},
{
"key": "│ │\u001b[11D\u001b[34m󰉉 disk",
"type": "disk",
"folders": "/"
},
{
"key": "│ │\u001b[11D\u001b[35m memory",
"type": "memory"
},
{
"key": "│ │\u001b[11D\u001b[36m󰩟 network",
"type": "localip",
"format": "{1} ({4})"
},
{
"key": "├───────────┤",
"type": "custom"
},
{
"key": "│ │\u001b[11D\u001b[m colors",
"type": "colors",
"symbol": "circle"
},
{
"key": "╰───────────╯",
"type": "custom"
}
]
}
+1 -2
View File
@@ -9,8 +9,7 @@
"modules": [
{
"type": "theme",
"key": "T",
"format": "{7}"
"key": "T"
},
{
"type": "icons",
+9 -12
View File
@@ -1,16 +1,16 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"display": {
"size": {
"maxPrefix": "MB",
"ndigits": 0
}
},
"modules": [
"title",
"separator",
{
"type": "os",
"format": "{3} {12}"
},
{
"type": "host",
"format": "{/2}{-}{/}{2}{?3} {3}{?}"
},
"os",
"host",
"kernel",
"uptime",
"packages",
@@ -23,10 +23,7 @@
"de",
"wm",
"wmtheme",
{
"type": "theme",
"format": "{?1}{1}{?3} {3}{?} [Plasma], {?}{7}"
},
"theme",
"icons",
"terminal",
{
+257
View File
@@ -1229,6 +1229,18 @@ typedef struct _ctl_lda_args_t ctl_lda_args_t;
/// @brief Forward-declare ctl_dce_args_t
typedef struct _ctl_dce_args_t ctl_dce_args_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_wire_format_t
typedef struct _ctl_wire_format_t ctl_wire_format_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_get_set_wire_format_config_t
typedef struct _ctl_get_set_wire_format_config_t ctl_get_set_wire_format_config_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_display_settings_t
typedef struct _ctl_display_settings_t ctl_display_settings_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Forward-declare ctl_engine_properties_t
typedef struct _ctl_engine_properties_t ctl_engine_properties_t;
@@ -2029,6 +2041,8 @@ typedef enum _ctl_std_display_feature_flag_t
CTL_STD_DISPLAY_FEATURE_FLAG_VESA_COMPRESSION = CTL_BIT(4), ///< [out] Is display compression (VESA DSC) supported
CTL_STD_DISPLAY_FEATURE_FLAG_HDR = CTL_BIT(5), ///< [out] Is HDR supported
CTL_STD_DISPLAY_FEATURE_FLAG_HDMI_QMS = CTL_BIT(6), ///< [out] Is HDMI QMS supported
CTL_STD_DISPLAY_FEATURE_FLAG_HDR10_PLUS_CERTIFIED = CTL_BIT(7), ///< [out] Is HDR10+ certified
CTL_STD_DISPLAY_FEATURE_FLAG_VESA_HDR_CERTIFIED = CTL_BIT(8), ///< [out] Is VESA HDR certified - for future use
CTL_STD_DISPLAY_FEATURE_FLAG_MAX = 0x80000000
} ctl_std_display_feature_flag_t;
@@ -2042,6 +2056,7 @@ typedef enum _ctl_intel_display_feature_flag_t
CTL_INTEL_DISPLAY_FEATURE_FLAG_DPST = CTL_BIT(0), ///< [out] Is DPST supported
CTL_INTEL_DISPLAY_FEATURE_FLAG_LACE = CTL_BIT(1), ///< [out] Is LACE supported
CTL_INTEL_DISPLAY_FEATURE_FLAG_DRRS = CTL_BIT(2), ///< [out] Is DRRS supported
CTL_INTEL_DISPLAY_FEATURE_FLAG_ARC_ADAPTIVE_SYNC_CERTIFIED = CTL_BIT(3),///< [out] Is Intel Arc certified adaptive sync display
CTL_INTEL_DISPLAY_FEATURE_FLAG_MAX = 0x80000000
} ctl_intel_display_feature_flag_t;
@@ -4398,6 +4413,232 @@ ctlGetSetDynamicContrastEnhancement(
ctl_dce_args_t* pDceArgs ///< [in,out] Dynamic Contrast Enhancement arguments
);
///////////////////////////////////////////////////////////////////////////////
/// @brief Color model
typedef enum _ctl_wire_format_color_model_t
{
CTL_WIRE_FORMAT_COLOR_MODEL_RGB = 0, ///< Color model RGB
CTL_WIRE_FORMAT_COLOR_MODEL_YCBCR_420 = 1, ///< Color model YCBCR 420
CTL_WIRE_FORMAT_COLOR_MODEL_YCBCR_422 = 2, ///< Color model YCBCR 422
CTL_WIRE_FORMAT_COLOR_MODEL_YCBCR_444 = 3, ///< Color model YCBCR 444
CTL_WIRE_FORMAT_COLOR_MODEL_MAX
} ctl_wire_format_color_model_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Operation type
typedef enum _ctl_wire_format_operation_type_t
{
CTL_WIRE_FORMAT_OPERATION_TYPE_GET = 0, ///< Get request
CTL_WIRE_FORMAT_OPERATION_TYPE_SET = 1, ///< Set request
CTL_WIRE_FORMAT_OPERATION_TYPE_RESTORE_DEFAULT = 2, ///< Restore to default values
CTL_WIRE_FORMAT_OPERATION_TYPE_MAX
} ctl_wire_format_operation_type_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Wire Format
typedef struct _ctl_wire_format_t
{
uint32_t Size; ///< [in] size of this structure
uint8_t Version; ///< [in] version of this structure
ctl_wire_format_color_model_t ColorModel; ///< [in,out] Color model
ctl_output_bpc_flags_t ColorDepth; ///< [in,out] Color Depth
} ctl_wire_format_t;
///////////////////////////////////////////////////////////////////////////////
#ifndef CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED
/// @brief Maximum Wire Formats Supported
#define CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED 4
#endif // CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED
///////////////////////////////////////////////////////////////////////////////
/// @brief Get Set Wire Format
typedef struct _ctl_get_set_wire_format_config_t
{
uint32_t Size; ///< [in] size of this structure
uint8_t Version; ///< [in] version of this structure
ctl_wire_format_operation_type_t Operation; ///< [in] Get/Set Operation
ctl_wire_format_t SupportedWireFormat[CTL_MAX_WIREFORMAT_COLOR_MODELS_SUPPORTED]; ///< [out] Array of WireFormats supported
ctl_wire_format_t WireFormat; ///< [in,out] Current/Requested WireFormat based on Operation. During SET
///< Operation, if multiple bpc is set, the MIN bpc will be applied
} ctl_get_set_wire_format_config_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Get/Set Color Format and Color Depth
///
/// @details
/// - Get and Set the Color Format and Color Depth of a target
///
/// @returns
/// - CTL_RESULT_SUCCESS
/// - CTL_RESULT_ERROR_UNINITIALIZED
/// - CTL_RESULT_ERROR_DEVICE_LOST
/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
/// + `nullptr == hDisplayOutput`
/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
/// + `nullptr == pGetSetWireFormatSetting`
/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
/// - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid data passed as argument, WireFormat is not supported"
/// - ::CTL_RESULT_ERROR_DISPLAY_NOT_ACTIVE - "Display not active"
/// - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
CTL_APIEXPORT ctl_result_t CTL_APICALL
ctlGetSetWireFormat(
ctl_display_output_handle_t hDisplayOutput, ///< [in][release] Handle to display output
ctl_get_set_wire_format_config_t* pGetSetWireFormatSetting ///< [in][release] Get/Set Wire Format settings to be fetched/applied
);
///////////////////////////////////////////////////////////////////////////////
/// @brief Various display settings
typedef uint32_t ctl_display_setting_flags_t;
typedef enum _ctl_display_setting_flag_t
{
CTL_DISPLAY_SETTING_FLAG_LOW_LATENCY = CTL_BIT(0), ///< Low latency
CTL_DISPLAY_SETTING_FLAG_SOURCE_TM = CTL_BIT(1),///< Source tone mapping
CTL_DISPLAY_SETTING_FLAG_CONTENT_TYPE = CTL_BIT(2), ///< Content type
CTL_DISPLAY_SETTING_FLAG_QUANTIZATION_RANGE = CTL_BIT(3), ///< Quantization range, full range or limited range
CTL_DISPLAY_SETTING_FLAG_PICTURE_AR = CTL_BIT(4), ///< Picture aspect ratio
CTL_DISPLAY_SETTING_FLAG_AUDIO = CTL_BIT(5), ///< Audio settings
CTL_DISPLAY_SETTING_FLAG_MAX = 0x80000000
} ctl_display_setting_flag_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Low latency setting
typedef enum _ctl_display_setting_low_latency_t
{
CTL_DISPLAY_SETTING_LOW_LATENCY_DEFAULT = 0, ///< Default
CTL_DISPLAY_SETTING_LOW_LATENCY_DISABLED = 1, ///< Disabled
CTL_DISPLAY_SETTING_LOW_LATENCY_ENABLED = 2, ///< Enabled
CTL_DISPLAY_SETTING_LOW_LATENCY_MAX
} ctl_display_setting_low_latency_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Source tone mapping setting
typedef enum _ctl_display_setting_sourcetm_t
{
CTL_DISPLAY_SETTING_SOURCETM_DEFAULT = 0, ///< Default
CTL_DISPLAY_SETTING_SOURCETM_DISABLED = 1, ///< Disabled
CTL_DISPLAY_SETTING_SOURCETM_ENABLED = 2, ///< Enabled
CTL_DISPLAY_SETTING_SOURCETM_MAX
} ctl_display_setting_sourcetm_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Content type settings
typedef enum _ctl_display_setting_content_type_t
{
CTL_DISPLAY_SETTING_CONTENT_TYPE_DEFAULT = 0, ///< Default content type used by driver. Driver will use internal
///< techniques to determine content type and indicate to panel
CTL_DISPLAY_SETTING_CONTENT_TYPE_DISABLED = 1, ///< Content type indication is disabled
CTL_DISPLAY_SETTING_CONTENT_TYPE_DESKTOP = 2, ///< Typical desktop with a mix of text and graphics
CTL_DISPLAY_SETTING_CONTENT_TYPE_MEDIA = 3, ///< Video or media content
CTL_DISPLAY_SETTING_CONTENT_TYPE_GAMING = 4, ///< Gaming content
CTL_DISPLAY_SETTING_CONTENT_TYPE_MAX
} ctl_display_setting_content_type_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Quantization range
typedef enum _ctl_display_setting_quantization_range_t
{
CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_DEFAULT = 0, ///< Default based on video format
CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_LIMITED_RANGE = 1, ///< Limited range
CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_FULL_RANGE = 2, ///< Full range
CTL_DISPLAY_SETTING_QUANTIZATION_RANGE_MAX
} ctl_display_setting_quantization_range_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Picture aspect ratio
typedef uint32_t ctl_display_setting_picture_ar_flags_t;
typedef enum _ctl_display_setting_picture_ar_flag_t
{
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_DEFAULT = CTL_BIT(0), ///< Default picture aspect ratio
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_DISABLED = CTL_BIT(1), ///< Picture aspect ratio indication is explicitly disabled
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_4_3 = CTL_BIT(2),///< Aspect ratio of 4:3
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_16_9 = CTL_BIT(3), ///< Aspect ratio of 16:9
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_64_27 = CTL_BIT(4), ///< Aspect ratio of 64:27 or 21:9 anamorphic
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_AR_256_135 = CTL_BIT(5),///< Aspect ratio of 256:135
CTL_DISPLAY_SETTING_PICTURE_AR_FLAG_MAX = 0x80000000
} ctl_display_setting_picture_ar_flag_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Audio settings
typedef enum _ctl_display_setting_audio_t
{
CTL_DISPLAY_SETTING_AUDIO_DEFAULT = 0, ///< Default audio settings, always enumerated and enabled if display
///< supports it
CTL_DISPLAY_SETTING_AUDIO_DISABLED = 1, ///< Forcefully disable display audio end point enumeration to OS
CTL_DISPLAY_SETTING_AUDIO_MAX
} ctl_display_setting_audio_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Get/Set end display settings
typedef struct _ctl_display_settings_t
{
uint32_t Size; ///< [in] size of this structure
uint8_t Version; ///< [in] version of this structure
bool Set; ///< [in] Flag to indicate Set or Get operation. Default option for all
///< features are reserved for Set=true calls, which will reset the setting
///< to driver defaults.
ctl_display_setting_flags_t SupportedFlags; ///< [out] Display setting flags supported by the display.
ctl_display_setting_flags_t ControllableFlags; ///< [out] Display setting flags which can be controlled by the caller.
///< Features which doesn't have this flag set cannot be changed by caller.
ctl_display_setting_flags_t ValidFlags; ///< [in,out] Display setting flags which caller can use to indicate the
///< features it's interested in. This cannot have a bit set which is not
///< supported by SupportedFlags and ControllableFlags.
ctl_display_setting_low_latency_t LowLatency; ///< [in,out] Low latency state of panel. For HDR10+ Gaming this need to be
///< in ENABLED state.
ctl_display_setting_sourcetm_t SourceTM; ///< [in,out] Source tone mapping state known to panel. For HDR10+ Gaming
///< this need to be in ENABLED state.
ctl_display_setting_content_type_t ContentType; ///< [in,out] Source content type known to panel.
ctl_display_setting_quantization_range_t QuantizationRange; ///< [in,out] Quantization range
ctl_display_setting_picture_ar_flags_t SupportedPictureAR; ///< [out] Supported Picture aspect ratios
ctl_display_setting_picture_ar_flag_t PictureAR;///< [in,out] Picture aspect ratio
ctl_display_setting_audio_t AudioSettings; ///< [in,out] Audio settings
uint32_t Reserved[25]; ///< [out] Reserved fields for future enumerations
} ctl_display_settings_t;
///////////////////////////////////////////////////////////////////////////////
/// @brief Get/Set Display settings
///
/// @details
/// - To get/set end display settings like low latency, HDR10+ signaling
/// etc. which are controlled via info-frames/secondary data packets
///
/// @returns
/// - CTL_RESULT_SUCCESS
/// - CTL_RESULT_ERROR_UNINITIALIZED
/// - CTL_RESULT_ERROR_DEVICE_LOST
/// - CTL_RESULT_ERROR_INVALID_NULL_HANDLE
/// + `nullptr == hDisplayOutput`
/// - CTL_RESULT_ERROR_INVALID_NULL_POINTER
/// + `nullptr == pDisplaySettings`
/// - ::CTL_RESULT_ERROR_UNSUPPORTED_VERSION - "Unsupported version"
/// - ::CTL_RESULT_ERROR_NULL_OS_DISPLAY_OUTPUT_HANDLE - "Null OS display output handle"
/// - ::CTL_RESULT_ERROR_NULL_OS_INTERFACE - "Null OS interface"
/// - ::CTL_RESULT_ERROR_NULL_OS_ADAPATER_HANDLE - "Null OS adapter handle"
/// - ::CTL_RESULT_ERROR_KMD_CALL - "Kernel mode driver call failure"
/// - ::CTL_RESULT_ERROR_INVALID_NULL_HANDLE - "Invalid or Null handle passed"
/// - ::CTL_RESULT_ERROR_INVALID_NULL_POINTER - "Invalid null pointer"
/// - ::CTL_RESULT_ERROR_INVALID_OPERATION_TYPE - "Invalid operation type"
/// - ::CTL_RESULT_ERROR_INVALID_ARGUMENT - "Invalid combination of parameters"
CTL_APIEXPORT ctl_result_t CTL_APICALL
ctlGetSetDisplaySettings(
ctl_display_output_handle_t hDisplayOutput, ///< [in] Handle to display output
ctl_display_settings_t* pDisplaySettings ///< [in,out] End display capabilities
);
#if !defined(__GNUC__)
#pragma endregion // display
@@ -7229,6 +7470,22 @@ typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetDynamicContrastEnhancement_t)(
);
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlGetSetWireFormat
typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetWireFormat_t)(
ctl_display_output_handle_t,
ctl_get_set_wire_format_config_t*
);
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlGetSetDisplaySettings
typedef ctl_result_t (CTL_APICALL *ctl_pfnGetSetDisplaySettings_t)(
ctl_display_output_handle_t,
ctl_display_settings_t*
);
///////////////////////////////////////////////////////////////////////////////
/// @brief Function-pointer for ctlEnumEngineGroups
typedef ctl_result_t (CTL_APICALL *ctl_pfnEnumEngineGroups_t)(
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/intel/drivers.gpu.control-library",
"license": "./LICENSE",
"version": "e1776b7be2ceead1296204371447b27860d25a66",
"version": "v184",
"author": "Intel Corporation"
}
+740 -25
View File
@@ -153,6 +153,27 @@ typedef struct nvmlDevice_st* nvmlDevice_t;
*/
#define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE 16
/**
* PCI information about a GPU device.
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff
unsigned int bus; //!< The bus on which the device resides, 0 to 0xff
unsigned int device; //!< The device's id on the bus, 0 to 31
unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id
unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID
unsigned int baseClass; //!< The 8-bit PCI base class code
unsigned int subClass; //!< The 8-bit PCI sub class code
char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (&amp; NULL terminator)
} nvmlPciInfoExt_v1_t;
typedef nvmlPciInfoExt_v1_t nvmlPciInfoExt_t;
#define nvmlPciInfoExt_v1 NVML_STRUCT_VERSION(PciInfoExt, 1)
/**
* PCI information about a GPU device.
*/
@@ -482,11 +503,16 @@ typedef enum nvmlGpuP2PStatus_enum
typedef enum nvmlGpuP2PCapsIndex_enum
{
NVML_P2P_CAPS_INDEX_READ = 0,
NVML_P2P_CAPS_INDEX_WRITE,
NVML_P2P_CAPS_INDEX_NVLINK,
NVML_P2P_CAPS_INDEX_ATOMICS,
NVML_P2P_CAPS_INDEX_PROP,
NVML_P2P_CAPS_INDEX_UNKNOWN
NVML_P2P_CAPS_INDEX_WRITE = 1,
NVML_P2P_CAPS_INDEX_NVLINK = 2,
NVML_P2P_CAPS_INDEX_ATOMICS = 3,
NVML_P2P_CAPS_INDEX_PCI = 4,
/*
* DO NOT USE! NVML_P2P_CAPS_INDEX_PROP is deprecated.
* Use NVML_P2P_CAPS_INDEX_PCI instead.
*/
NVML_P2P_CAPS_INDEX_PROP = NVML_P2P_CAPS_INDEX_PCI,
NVML_P2P_CAPS_INDEX_UNKNOWN = 5,
}nvmlGpuP2PCapsIndex_t;
/**
@@ -526,6 +552,8 @@ typedef enum nvmlSamplingType_enum
NVML_PROCESSOR_CLK_SAMPLES = 5, //!< To represent processor clock samples
NVML_MEMORY_CLK_SAMPLES = 6, //!< To represent memory clock samples
NVML_MODULE_POWER_SAMPLES = 7, //!< To represent module power samples for total module starting Grace Hopper
NVML_JPG_UTILIZATION_SAMPLES = 8, //!< To represent percent of time during which NVJPG remains busy
NVML_OFA_UTILIZATION_SAMPLES = 9, //!< To represent percent of time during which NVOFA remains busy
// Keep this last
NVML_SAMPLINGTYPE_COUNT
@@ -1005,6 +1033,7 @@ typedef enum nvmlReturn_enum
NVML_ERROR_DEPRECATED = 26, //!< The requested functionality has been deprecated
NVML_ERROR_NOT_READY = 27, //!< The system is not ready for the request
NVML_ERROR_GPU_NOT_FOUND = 28, //!< No GPUs were found
NVML_ERROR_INVALID_STATE = 29, //!< Resource not in correct state to perform requested operation
NVML_ERROR_UNKNOWN = 999 //!< An internal driver error occurred
} nvmlReturn_t;
@@ -1150,11 +1179,14 @@ typedef enum nvmlVgpuDriverCapability_enum
*/
typedef enum nvmlDeviceVgpuCapability_enum
{
NVML_DEVICE_VGPU_CAP_FRACTIONAL_MULTI_VGPU = 0, //!< Fractional vGPU profiles on this GPU can be used in multi-vGPU configurations
NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_PROFILES = 1, //!< Supports concurrent execution of timesliced vGPU profiles of differing types
NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_SIZES = 2, //!< Supports concurrent execution of timesliced vGPU profiles of differing framebuffer sizes
NVML_DEVICE_VGPU_CAP_READ_DEVICE_BUFFER_BW = 3, //!< GPU device's read_device_buffer expected bandwidth capacity in megabytes per second
NVML_DEVICE_VGPU_CAP_WRITE_DEVICE_BUFFER_BW = 4, //!< GPU device's write_device_buffer expected bandwidth capacity in megabytes per second
NVML_DEVICE_VGPU_CAP_FRACTIONAL_MULTI_VGPU = 0, //!< Query if the fractional vGPU profiles on this GPU can be used in multi-vGPU configurations
NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_PROFILES = 1, //!< Query if the GPU support concurrent execution of timesliced vGPU profiles of differing types
NVML_DEVICE_VGPU_CAP_HETEROGENEOUS_TIMESLICE_SIZES = 2, //!< Query if the GPU support concurrent execution of timesliced vGPU profiles of differing framebuffer sizes
NVML_DEVICE_VGPU_CAP_READ_DEVICE_BUFFER_BW = 3, //!< Query the GPU's read_device_buffer expected bandwidth capacity in megabytes per second
NVML_DEVICE_VGPU_CAP_WRITE_DEVICE_BUFFER_BW = 4, //!< Query the GPU's write_device_buffer expected bandwidth capacity in megabytes per second
NVML_DEVICE_VGPU_CAP_DEVICE_STREAMING = 5, //!< Query if vGPU profiles on the GPU supports migration data streaming
NVML_DEVICE_VGPU_CAP_MINI_QUARTER_GPU = 6, //!< Set/Get support for mini-quarter vGPU profiles
NVML_DEVICE_VGPU_CAP_COMPUTE_MEDIA_ENGINE_GPU = 7, //!< Set/Get support for compute media engine vGPU profiles
// Keep this last
NVML_DEVICE_VGPU_CAP_COUNT
} nvmlDeviceVgpuCapability_t;
@@ -1181,6 +1213,8 @@ typedef enum nvmlDeviceVgpuCapability_enum
#define INVALID_GPU_INSTANCE_ID 0xFFFFFFFF
#define NVML_INVALID_VGPU_PLACEMENT_ID 0xFFFF
/*!
* Macros for vGPU instance's virtualization capabilities bitfield.
*/
@@ -1207,6 +1241,41 @@ typedef unsigned int nvmlVgpuTypeId_t;
typedef unsigned int nvmlVgpuInstance_t;
/**
* Structure to store the vGPU heterogeneous mode of device -- version 1
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
unsigned int mode; //!< The vGPU heterogeneous mode
} nvmlVgpuHeterogeneousMode_v1_t;
typedef nvmlVgpuHeterogeneousMode_v1_t nvmlVgpuHeterogeneousMode_t;
#define nvmlVgpuHeterogeneousMode_v1 NVML_STRUCT_VERSION(VgpuHeterogeneousMode, 1)
/**
* Structure to store the placement ID of vGPU instance -- version 1
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
unsigned int placementId; //!< Placement ID of the active vGPU instance
} nvmlVgpuPlacementId_v1_t;
typedef nvmlVgpuPlacementId_v1_t nvmlVgpuPlacementId_t;
#define nvmlVgpuPlacementId_v1 NVML_STRUCT_VERSION(VgpuPlacementId, 1)
/**
* Structure to store the list of vGPU placements -- version 1
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
unsigned int placementSize; //!< The number of slots occupied by the vGPU type
unsigned int count; //!< Count of placement IDs fetched
unsigned int *placementIds; //!< Placement IDs for the vGPU type
} nvmlVgpuPlacementList_v1_t;
typedef nvmlVgpuPlacementList_v1_t nvmlVgpuPlacementList_t;
#define nvmlVgpuPlacementList_v1 NVML_STRUCT_VERSION(VgpuPlacementList, 1)
/**
* Structure to store Utilization Value and vgpuInstance
*/
@@ -1220,6 +1289,35 @@ typedef struct nvmlVgpuInstanceUtilizationSample_st
nvmlValue_t decUtil; //!< Decoder Util Value
} nvmlVgpuInstanceUtilizationSample_t;
/**
* Structure to store Utilization Value and vgpuInstance Info -- Version 1
*/
typedef struct
{
unsigned long long timeStamp; //!< CPU Timestamp in microseconds
nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance
nvmlValue_t smUtil; //!< SM (3D/Compute) Util Value
nvmlValue_t memUtil; //!< Frame Buffer Memory Util Value
nvmlValue_t encUtil; //!< Encoder Util Value
nvmlValue_t decUtil; //!< Decoder Util Value
nvmlValue_t jpgUtil; //!< Jpeg Util Value
nvmlValue_t ofaUtil; //!< Ofa Util Value
} nvmlVgpuInstanceUtilizationInfo_v1_t;
/**
* Structure to store recent utilization for vGPU instances running on a device -- version 1
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
nvmlValueType_t sampleValType; //!< Hold the type of returned sample values
unsigned int vgpuInstanceCount; //!< Hold the number of vGPU instances
unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp
nvmlVgpuInstanceUtilizationInfo_v1_t *vgpuUtilArray; //!< The array (allocated by caller) in which vGPU utilization are returned
} nvmlVgpuInstancesUtilizationInfo_v1_t;
typedef nvmlVgpuInstancesUtilizationInfo_v1_t nvmlVgpuInstancesUtilizationInfo_t;
#define nvmlVgpuInstancesUtilizationInfo_v1 NVML_STRUCT_VERSION(VgpuInstancesUtilizationInfo, 1)
/**
* Structure to store Utilization Value, vgpuInstance and subprocess information
*/
@@ -1235,6 +1333,36 @@ typedef struct nvmlVgpuProcessUtilizationSample_st
unsigned int decUtil; //!< Decoder Util Value
} nvmlVgpuProcessUtilizationSample_t;
/**
* Structure to store Utilization Value, vgpuInstance and subprocess information for process running on vGPU instance -- version 1
*/
typedef struct
{
char processName[NVML_VGPU_NAME_BUFFER_SIZE]; //!< Name of process running within the vGPU VM
unsigned long long timeStamp; //!< CPU Timestamp in microseconds
nvmlVgpuInstance_t vgpuInstance; //!< vGPU Instance
unsigned int pid; //!< PID of process running within the vGPU VM
unsigned int smUtil; //!< SM (3D/Compute) Util Value
unsigned int memUtil; //!< Frame Buffer Memory Util Value
unsigned int encUtil; //!< Encoder Util Value
unsigned int decUtil; //!< Decoder Util Value
unsigned int jpgUtil; //!< Jpeg Util Value
unsigned int ofaUtil; //!< Ofa Util Value
} nvmlVgpuProcessUtilizationInfo_v1_t;
/**
* Structure to store recent utilization, vgpuInstance and subprocess information for processes running on vGPU instances active on a device -- version 1
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
unsigned int vgpuProcessCount; //!< Hold the number of processes running on vGPU instances
unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp
nvmlVgpuProcessUtilizationInfo_v1_t *vgpuProcUtilArray; //!< The array (allocated by caller) in which utilization of processes running on vGPU instances are returned
} nvmlVgpuProcessesUtilizationInfo_v1_t;
typedef nvmlVgpuProcessesUtilizationInfo_v1_t nvmlVgpuProcessesUtilizationInfo_t;
#define nvmlVgpuProcessesUtilizationInfo_v1 NVML_STRUCT_VERSION(VgpuProcessesUtilizationInfo, 1)
/**
* vGPU scheduler policies
*/
@@ -1392,6 +1520,34 @@ typedef struct nvmlProcessUtilizationSample_st
unsigned int decUtil; //!< Decoder Util Value
} nvmlProcessUtilizationSample_t;
/**
* Structure to store utilization value and process Id -- version 1
*/
typedef struct
{
unsigned long long timeStamp; //!< CPU Timestamp in microseconds
unsigned int pid; //!< PID of process
unsigned int smUtil; //!< SM (3D/Compute) Util Value
unsigned int memUtil; //!< Frame Buffer Memory Util Value
unsigned int encUtil; //!< Encoder Util Value
unsigned int decUtil; //!< Decoder Util Value
unsigned int jpgUtil; //!< Jpeg Util Value
unsigned int ofaUtil; //!< Ofa Util Value
} nvmlProcessUtilizationInfo_v1_t;
/**
* Structure to store utilization and process ID for each running process -- version 1
*/
typedef struct
{
unsigned int version; //!< The version number of this struct
unsigned int processSamplesCount; //!< Caller-supplied array size, and returns number of processes running
unsigned long long lastSeenTimeStamp; //!< Return only samples with timestamp greater than lastSeenTimeStamp
nvmlProcessUtilizationInfo_v1_t *procUtilArray; //!< The array (allocated by caller) of the utilization of GPU SM, framebuffer, video encoder, video decoder, JPEG, and OFA
} nvmlProcessesUtilizationInfo_v1_t;
typedef nvmlProcessesUtilizationInfo_v1_t nvmlProcessesUtilizationInfo_t;
#define nvmlProcessesUtilizationInfo_v1 NVML_STRUCT_VERSION(ProcessesUtilizationInfo, 1)
/**
* Structure to store license expiry date and time values
*/
@@ -1429,6 +1585,29 @@ typedef struct nvmlGridLicensableFeatures_st
nvmlGridLicensableFeature_t gridLicensableFeatures[NVML_GRID_LICENSE_FEATURE_MAX_COUNT]; //!< Array of vGPU software licensable features.
} nvmlGridLicensableFeatures_t;
/**
* Structure to store SRAM uncorrectable error counters
*/
typedef struct
{
unsigned int version; //!< the API version number
unsigned long long aggregateUncParity; //!< aggregate uncorrectable parity error count
unsigned long long aggregateUncSecDed; //!< aggregate uncorrectable SEC-DED error count
unsigned long long aggregateCor; //!< aggregate correctable error count
unsigned long long volatileUncParity; //!< volatile uncorrectable parity error count
unsigned long long volatileUncSecDed; //!< volatile uncorrectable SEC-DED error count
unsigned long long volatileCor; //!< volatile correctable error count
unsigned long long aggregateUncBucketL2; //!< aggregate uncorrectable error count for L2 cache bucket
unsigned long long aggregateUncBucketSm; //!< aggregate uncorrectable error count for SM bucket
unsigned long long aggregateUncBucketPcie; //!< aggregate uncorrectable error count for PCIE bucket
unsigned long long aggregateUncBucketMcu; //!< aggregate uncorrectable error count for Microcontroller bucket
unsigned long long aggregateUncBucketOther; //!< aggregate uncorrectable error count for Other bucket
unsigned int bThresholdExceeded; //!< if the error threshold of field diag is exceeded
} nvmlEccSramErrorStatus_v1_t;
typedef nvmlEccSramErrorStatus_v1_t nvmlEccSramErrorStatus_t;
#define nvmlEccSramErrorStatus_v1 NVML_STRUCT_VERSION(EccSramErrorStatus, 1)
/**
* GSP firmware
*/
@@ -1837,7 +2016,9 @@ typedef struct nvmlGpuDynamicPstatesInfo_st
#define NVML_FI_DEV_TEMPERATURE_MEM_MAX_TLIMIT 195 //!< T.Limit temperature after which GPU may begin SW slowdown due to memory temperature
#define NVML_FI_DEV_TEMPERATURE_GPU_MAX_TLIMIT 196 //!< T.Limit temperature after which GPU may be throttled below base clock
#define NVML_FI_MAX 197 //!< One greater than the largest field ID defined above
#define NVML_FI_DEV_IS_MIG_MODE_INDEPENDENT_MIG_QUERY_CAPABLE 199 //!< MIG mode independent, MIG query capable device. 1=yes. 0=no.
#define NVML_FI_MAX 200 //!< One greater than the largest field ID defined above
/**
* Information for a Field Value Sample
@@ -2248,9 +2429,10 @@ typedef struct nvmlAccountingStats_st {
*/
typedef enum nvmlEncoderQueryType_enum
{
NVML_ENCODER_QUERY_H264 = 0, //!< H264 encoder
NVML_ENCODER_QUERY_HEVC = 1, //!< HEVC encoder
NVML_ENCODER_QUERY_AV1 = 2 //!< AV1 encoder
NVML_ENCODER_QUERY_H264 = 0x00, //!< H264 encoder
NVML_ENCODER_QUERY_HEVC = 0x01, //!< HEVC encoder
NVML_ENCODER_QUERY_AV1 = 0x02, //!< AV1 encoder
NVML_ENCODER_QUERY_UNKNOWN = 0xFF //!< Unknown encoder
}nvmlEncoderType_t;
/**
@@ -2399,6 +2581,26 @@ typedef struct nvmlConfComputeSystemState_st {
unsigned int devToolsMode;
} nvmlConfComputeSystemState_t;
/**
* Confidential Compute Multigpu mode values
*/
#define NVML_CC_SYSTEM_MULTIGPU_NONE 0
#define NVML_CC_SYSTEM_MULTIGPU_PROTECTED_PCIE 1
/**
* Confidential Compute System settings
*/
typedef struct {
unsigned int version;
unsigned int environment;
unsigned int ccFeature;
unsigned int devToolsMode;
unsigned int multiGpuMode;
} nvmlSystemConfComputeSettings_v1_t;
typedef nvmlSystemConfComputeSettings_v1_t nvmlSystemConfComputeSettings_t;
#define nvmlSystemConfComputeSettings_v1 NVML_STRUCT_VERSION(SystemConfComputeSettings, 1)
/**
* Protected memory size
*/
@@ -2436,6 +2638,8 @@ typedef struct nvmlConfComputeGpuCertificate_st {
#define NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE 0x1000
#define NVML_CC_CEC_ATTESTATION_REPORT_NOT_PRESENT 0
#define NVML_CC_CEC_ATTESTATION_REPORT_PRESENT 1
#define NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MIN 50
#define NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MAX 75
typedef struct nvmlConfComputeGpuAttestationReport_st {
unsigned int isCecAttestationReportPresent;
@@ -2446,6 +2650,24 @@ typedef struct nvmlConfComputeGpuAttestationReport_st {
unsigned char cecAttestationReport[NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE];
} nvmlConfComputeGpuAttestationReport_t;
typedef struct nvmlConfComputeSetKeyRotationThresholdInfo_st {
unsigned int version;
unsigned long long maxAttackerAdvantage;
} nvmlConfComputeSetKeyRotationThresholdInfo_v1_t;
typedef nvmlConfComputeSetKeyRotationThresholdInfo_v1_t nvmlConfComputeSetKeyRotationThresholdInfo_t;
#define nvmlConfComputeSetKeyRotationThresholdInfo_v1 \
NVML_STRUCT_VERSION(ConfComputeSetKeyRotationThresholdInfo, 1)
typedef struct nvmlConfComputeGetKeyRotationThresholdInfo_st {
unsigned int version;
unsigned long long attackerAdvantage;
} nvmlConfComputeGetKeyRotationThresholdInfo_v1_t;
typedef nvmlConfComputeGetKeyRotationThresholdInfo_v1_t nvmlConfComputeGetKeyRotationThresholdInfo_t;
#define nvmlConfComputeGetKeyRotationThresholdInfo_v1 \
NVML_STRUCT_VERSION(ConfComputeGetKeyRotationThresholdInfo, 1)
/** @} */
#define NVML_GPU_FABRIC_UUID_LEN 16
@@ -2464,6 +2686,55 @@ typedef struct {
nvmlGpuFabricState_t state; //!< Current state of GPU registration process
} nvmlGpuFabricInfo_t;
#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_NOT_SUPPORTED 0
#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_TRUE 1
#define NVML_GPU_FABRIC_HEALTH_MASK_DEGRADED_BW_FALSE 2
#define NVML_GPU_FABRIC_HEALTH_MASK_SHIFT_DEGRADED_BW 0
#define NVML_GPU_FABRIC_HEALTH_MASK_WIDTH_DEGRADED_BW 0x11
/**
* GPU Fabric Health Status Mask for various fields can be obtained
* using the below macro.
* Ex - NVML_GPU_FABRIC_HEALTH_GET(var, _DEGRADED_BW)
*/
#define NVML_GPU_FABRIC_HEALTH_GET(var, type) \
(((var) >> NVML_GPU_FABRIC_HEALTH_MASK_SHIFT##type) & \
(NVML_GPU_FABRIC_HEALTH_MASK_WIDTH##type))
/**
* GPU Fabric Health Status Mask for various fields can be tested
* using the below macro.
* Ex - NVML_GPU_FABRIC_HEALTH_TEST(var, _DEGRADED_BW, _TRUE)
*/
#define NVML_GPU_FABRIC_HEALTH_TEST(var, type, val) \
(NVML_GPU_FABRIC_HEALTH_GET(var, type) == \
NVML_GPU_FABRIC_HEALTH_MASK##type##val)
/**
* GPU Fabric information (v2).
*
* Version 2 adds the \ref nvmlGpuFabricInfo_v2_t.version field
* to the start of the structure, and the \ref nvmlGpuFabricInfo_v2_t.healthMask
* field to the end. This structure is not backwards-compatible with
* \ref nvmlGpuFabricInfo_t.
*/
typedef struct {
unsigned int version; //!< Structure version identifier (set to \ref nvmlGpuFabricInfo_v2)
unsigned char clusterUuid[NVML_GPU_FABRIC_UUID_LEN]; //!< Uuid of the cluster to which this GPU belongs
nvmlReturn_t status; //!< Error status, if any. Must be checked only if state returns "complete".
unsigned int cliqueId; //!< ID of the fabric clique to which this GPU belongs
nvmlGpuFabricState_t state; //!< Current state of GPU registration process
unsigned int healthMask; //!< GPU Fabric health Status Mask
} nvmlGpuFabricInfo_v2_t;
typedef nvmlGpuFabricInfo_v2_t nvmlGpuFabricInfoV_t;
/**
* Version identifier value for \ref nvmlGpuFabricInfo_v2_t.version.
*/
#define nvmlGpuFabricInfo_v2 NVML_STRUCT_VERSION(GpuFabricInfo, 2)
/**
* Device Scope - This is useful to retrieve the telemetry at GPU and module (e.g. GPU + CPU) level
*/
@@ -3414,6 +3685,19 @@ nvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device);
*/
nvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device);
/**
* Get the NUMA node of the given GPU device.
* This only applies to platforms where the GPUs are NUMA nodes.
*
* @param[in] device The device handle
* @param[out] node NUMA node ID of the device
*
* @returns
* - \ref NVML_SUCCESS if the NUMA node is retrieved successfully
* - \ref NVML_ERROR_NOT_SUPPORTED if request is not supported on the current platform
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device \a node is invalid
*/
nvmlReturn_t DECLDIR nvmlDeviceGetNumaNodeId(nvmlDevice_t device, unsigned int *node);
/**
* Retrieve the common ancestor for two devices
* For all products.
@@ -3726,6 +4010,25 @@ nvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableS
*/
nvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode);
/**
* Retrieves PCI attributes of this device.
*
* For all products.
*
* See \ref nvmlPciInfoExt_t for details on the available PCI info.
*
* @param device The identifier of the target device
* @param pci Reference in which to return the PCI info
*
* @return
* - \ref NVML_SUCCESS if \a pci has been populated
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetPciInfoExt(nvmlDevice_t device, nvmlPciInfoExt_t *pci);
/**
* Retrieves the PCI attributes of this device.
*
@@ -5423,7 +5726,7 @@ nvmlReturn_t DECLDIR nvmlDeviceGetMPSComputeRunningProcesses_v3(nvmlDevice_t dev
*
* To determine the size of the @ref plist->procArray array to allocate, call the function with
* @ref plist->numProcArrayEntries set to zero and @ref plist->procArray set to NULL. The return
* code will be either NVML_ERROR_INSUFFICIENT_SIZE (if there are valid processes of type
* code will be either NVML_ERROR_INSUFFICIENT_SIZE (if there are valid processes of type
* @ref plist->mode to report on, in which case the @ref plist->numProcArrayEntries field will
* indicate the required number of entries in the array) or NVML_SUCCESS (if no processes of type
* @ref plist->mode exist).
@@ -5708,7 +6011,7 @@ nvmlReturn_t DECLDIR nvmlDeviceGetPcieSpeed(nvmlDevice_t device, unsigned int *p
*
* @param device The identifier of the target device
* @param adaptiveClockStatus The current adaptive clocking status, either
* @ref NVML_ADAPTIVE_CLOCKING_INFO_STATUS_DISABLED
* @ref NVML_ADAPTIVE_CLOCKING_INFO_STATUS_DISABLED
* or @ref NVML_ADAPTIVE_CLOCKING_INFO_STATUS_ENABLED
*
* @return
@@ -5735,7 +6038,10 @@ nvmlReturn_t DECLDIR nvmlDeviceGetAdaptiveClockInfoStatus(nvmlDevice_t device, u
*/
nvmlReturn_t DECLDIR nvmlDeviceGetBusType(nvmlDevice_t device, nvmlBusType_t *type);
/**
/**
* Deprecated: Will be deprecated in a future release. Use \ref nvmlDeviceGetGpuFabricInfoV instead
*
* Get fabric information associated with the device.
*
* %HOPPER_OR_NEWER%
@@ -5746,6 +6052,7 @@ nvmlReturn_t DECLDIR nvmlDeviceGetBusType(nvmlDevice_t device, nvmlBusType_t *ty
* This API reports the current state of the GPU in the NVLink fabric
* along with other useful information.
*
*
* @param device The identifier of the target device
* @param gpuFabricInfo Information about GPU fabric state
*
@@ -5755,6 +6062,30 @@ nvmlReturn_t DECLDIR nvmlDeviceGetBusType(nvmlDevice_t device, nvmlBusType_t *ty
*/
nvmlReturn_t DECLDIR nvmlDeviceGetGpuFabricInfo(nvmlDevice_t device, nvmlGpuFabricInfo_t *gpuFabricInfo);
/**
* Versioned wrapper around \ref nvmlDeviceGetGpuFabricInfo that accepts a versioned
* \ref nvmlGpuFabricInfo_v2_t or later output structure.
*
* @note The caller must set the \ref nvmlGpuFabricInfoV_t.version field to the
* appropriate version prior to calling this function. For example:
* \code
* nvmlGpuFabricInfoV_t fabricInfo =
* { .version = nvmlGpuFabricInfo_v2 };
* nvmlReturn_t result = nvmlDeviceGetGpuFabricInfoV(device,&fabricInfo);
* \endcode
*
* %HOPPER_OR_NEWER%
*
* @param device The identifier of the target device
* @param gpuFabricInfo Information about GPU fabric state
*
* @return
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support gpu fabric
*/
nvmlReturn_t DECLDIR nvmlDeviceGetGpuFabricInfoV(nvmlDevice_t device,
nvmlGpuFabricInfoV_t *gpuFabricInfo);
/**
* Get Conf Computing System capabilities.
*
@@ -5877,6 +6208,42 @@ nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeGpuCertificate(nvmlDevice_t device,
*/
nvmlReturn_t DECLDIR nvmlDeviceGetConfComputeGpuAttestationReport(nvmlDevice_t device,
nvmlConfComputeGpuAttestationReport_t *gpuAtstReport);
/**
* Get Conf Computing key rotation threshold detail.
*
* %HOPPER_OR_NEWER%
* Supported on Linux, Windows TCC.
*
* @param pKeyRotationThrInfo Reference in which to return the key rotation threshold data
*
* @return
* - \ref NVML_SUCCESS if \a gpu key rotation threshold info has been populated
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlSystemGetConfComputeKeyRotationThresholdInfo(
nvmlConfComputeGetKeyRotationThresholdInfo_t *pKeyRotationThrInfo);
/**
* Get Conf Computing System Settings.
*
* %HOPPER_OR_NEWER%
* Supported on Linux, Windows TCC.
*
* @param settings System CC settings
*
* @return
* - \ref NVML_SUCCESS if the query is success
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counters is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_ARGUMENT_VERSION_MISMATCH if the provided version is invalid/unsupported
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlSystemGetConfComputeSettings(nvmlSystemConfComputeSettings_t *settings);
/**
* Retrieve GSP firmware version.
@@ -6241,6 +6608,52 @@ nvmlReturn_t DECLDIR nvmlDeviceGetClkMonStatus(nvmlDevice_t device, nvmlClkMonSt
nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization,
unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp);
/**
* Retrieves the recent utilization and process ID for all running processes
*
* For Maxwell &tm; or newer fully supported devices.
*
* Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder, jpeg decoder, OFA (Optical Flow Accelerator)
* for all running processes. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at
* by \a procesesUtilInfo->procUtilArray. One utilization sample structure is returned per process running, that had some non-zero utilization
* during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values
* are returned as "unsigned int" values.
*
* The caller should allocate a buffer of size processSamplesCount * sizeof(nvmlProcessUtilizationInfo_t). If the buffer is too small, the API will
* return \a NVML_ERROR_INSUFFICIENT_SIZE, with the recommended minimal buffer size at \a procesesUtilInfo->processSamplesCount. The caller should
* invoke the function again with the allocated buffer passed in \a procesesUtilInfo->procUtilArray, and \a procesesUtilInfo->processSamplesCount
* set to the number no less than the recommended value by the previous API return.
*
* On successful return, the function updates \a procesesUtilInfo->processSamplesCount with the number of process utilization info structures
* that were actually written. This may differ from a previously read value as instances are created or destroyed.
*
* \a procesesUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0
* to read utilization based on all the samples maintained by the driver's internal sample buffer. Set \a procesesUtilInfo->lastSeenTimeStamp
* to a timeStamp retrieved from a previous query to read utilization since the previous query.
*
* \a procesesUtilInfo->version is the version number of the structure nvmlProcessesUtilizationInfo_t, the caller should set the correct version
* number to retrieve the specific version of processes utilization information.
*
* @note On MIG-enabled GPUs, querying process utilization is not currently supported.
*
* @param device The identifier of the target device
* @param procesesUtilInfo Pointer to the caller-provided structure of nvmlProcessesUtilizationInfo_t.
* @return
* - \ref NVML_SUCCESS if \a procesesUtilInfo->procUtilArray has been populated
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a procesesUtilInfo is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature
* - \ref NVML_ERROR_NOT_FOUND if sample entries are not found
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_VERSION_MISMATCH if the version of \a procesesUtilInfo is invalid
* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a procesesUtilInfo->procUtilArray is NULL, or the buffer size of procesesUtilInfo->procUtilArray is too small.
* The caller should check the minimul array size from the returned procesesUtilInfo->processSamplesCount, and call
* the function again with a buffer no smaller than procesesUtilInfo->processSamplesCount * sizeof(nvmlProcessUtilizationInfo_t)
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetProcessesUtilizationInfo(nvmlDevice_t device, nvmlProcessesUtilizationInfo_t *procesesUtilInfo);
/** @} */
/***************************************************************************************************/
@@ -6960,6 +7373,30 @@ nvmlReturn_t DECLDIR nvmlDeviceSetConfComputeUnprotectedMemSize(nvmlDevice_t dev
*/
nvmlReturn_t DECLDIR nvmlSystemSetConfComputeGpusReadyState(unsigned int isAcceptingWork);
/**
* Set Conf Computing key rotation threshold.
*
* %HOPPER_OR_NEWER%
* Supported on Linux, Windows TCC.
*
* This function is to set the confidential compute key rotation threshold parameters.
* @ref pKeyRotationThrInfo->maxAttackerAdvantage should be in the range from
* NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MIN to NVML_CC_KEY_ROTATION_THRESHOLD_ATTACKER_ADVANTAGE_MAX.
* Default value is 60.
*
* @param pKeyRotationThrInfo Reference to the key rotation threshold data
*
* @return
* - \ref NVML_SUCCESS if \a key rotation threashold max attacker advantage has been set
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL
* - \ref NVML_ERROR_INVALID_STATE if confidential compute GPU ready state is enabled
* - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlSystemSetConfComputeKeyRotationThresholdInfo(
nvmlConfComputeSetKeyRotationThresholdInfo_t *pKeyRotationThrInfo);
/**
* @}
*/
@@ -7648,15 +8085,180 @@ nvmlReturn_t DECLDIR nvmlDeviceGetHostVgpuMode(nvmlDevice_t device, nvmlHostVgpu
* @param virtualMode virtualization mode. One of NVML_GPU_VIRTUALIZATION_?
*
* @return
* - \ref NVML_SUCCESS if \a pVirtualMode is set
* - \ref NVML_SUCCESS if \a virtualMode is set
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a virtualMode is NULL
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_NOT_SUPPORTED if setting of virtualization mode is not supported.
* - \ref NVML_ERROR_NO_PERMISSION if setting of virtualization mode is not allowed for this client.
*/
nvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode);
/**
* Get the vGPU heterogeneous mode for the device.
*
* When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes.
*
* On successful return, the function returns \a pHeterogeneousMode->mode with the current vGPU heterogeneous mode.
* \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should
* set the correct version number to retrieve the vGPU heterogeneous mode.
* \a pHeterogeneousMode->mode can either be \ref NVML_FEATURE_ENABLED or \ref NVML_FEATURE_DISABLED.
*
* @param device The identifier of the target device
* @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t
*
* @return
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid or \a pHeterogeneousMode is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support this feature
* - \ref NVML_ERROR_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetVgpuHeterogeneousMode(nvmlDevice_t device, nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode);
/**
* Enable or disable vGPU heterogeneous mode for the device.
*
* When in heterogeneous mode, a vGPU can concurrently host timesliced vGPUs with differing framebuffer sizes.
*
* API would return an appropriate error code upon unsuccessful activation. For example, the heterogeneous mode
* set will fail with error \ref NVML_ERROR_IN_USE if any vGPU instance is active on the device. The caller of this API
* is expected to shutdown the vGPU VMs and retry setting the \a mode.
* On successful return, the function updates the vGPU heterogeneous mode with the user provided \a pHeterogeneousMode->mode.
* \a pHeterogeneousMode->version is the version number of the structure nvmlVgpuHeterogeneousMode_t, the caller should
* set the correct version number to set the vGPU heterogeneous mode.
*
* @param device Identifier of the target device
* @param pHeterogeneousMode Pointer to the caller-provided structure of nvmlVgpuHeterogeneousMode_t
*
* @return
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a pHeterogeneousMode is NULL or \a pHeterogeneousMode->mode is invalid
* - \ref NVML_ERROR_IN_USE If the \a device is in use
* - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation
* - \ref NVML_ERROR_NOT_SUPPORTED If MIG is enabled or \a device doesn't support this feature
* - \ref NVML_ERROR_VERSION_MISMATCH If the version of \a pHeterogeneousMode is invalid
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceSetVgpuHeterogeneousMode(nvmlDevice_t device, const nvmlVgpuHeterogeneousMode_t *pHeterogeneousMode);
/**
* Query the placement ID of active vGPU instance.
*
* When in vGPU heterogeneous mode, this function returns a valid placement ID as \a pPlacement->placementId
* else NVML_INVALID_VGPU_PLACEMENT_ID is returned.
* \a pPlacement->version is the version number of the structure nvmlVgpuPlacementId_t, the caller should
* set the correct version number to get placement id of the vGPU instance \a vgpuInstance.
*
* @param vgpuInstance Identifier of the target vGPU instance
* @param pPlacement Pointer to vGPU placement ID structure \a nvmlVgpuPlacementId_t
*
* @return
* - \ref NVML_SUCCESS If information is successfully retrieved
* - \ref NVML_ERROR_NOT_FOUND If \a vgpuInstance does not match a valid active vGPU instance
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuInstance is invalid or \a pPlacement is NULL
* - \ref NVML_ERROR_VERSION_MISMATCH If the version of \a pPlacement is invalid
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlVgpuInstanceGetPlacementId(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuPlacementId_t *pPlacement);
/**
* Query the supported vGPU placement ID of the vGPU type.
*
* An array of supported vGPU placement IDs for the vGPU type ID indicated by \a vgpuTypeId is returned in the
* caller-supplied buffer of \a pPlacementList->placementIds. Memory needed for the placementIds array should be
* allocated based on maximum instances of a vGPU type which can be queried via \ref nvmlVgpuTypeGetMaxInstances().
*
* This function will return supported placement IDs even if GPU is not in vGPU heterogeneous mode.
*
* @param device Identifier of the target device
* @param vgpuTypeId Handle to vGPU type. The vGPU type ID
* @param pPlacementList Pointer to the vGPU placement structure \a nvmlVgpuPlacementList_t
*
* @return
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a vgpuTypeId is invalid or \a pPlacementList is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device or \a vgpuTypeId isn't supported
* - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation
* - \ref NVML_ERROR_VERSION_MISMATCH If the version of \a pPlacementList is invalid
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetVgpuTypeSupportedPlacements(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuPlacementList_t *pPlacementList);
/**
* Query the creatable vGPU placement ID of the vGPU type.
*
* An array of creatable vGPU placement IDs for the vGPU type ID indicated by \a vgpuTypeId is returned in the
* caller-supplied buffer of \a pPlacementList->placementIds. Memory needed for the placementIds array should be
* allocated based on maximum instances of a vGPU type which can be queried via \ref nvmlVgpuTypeGetMaxInstances().
* The creatable vGPU placement IDs may differ over time, as there may be restrictions on what type of vGPU the
* vGPU instance is running.
*
* The function will return \ref NVML_ERROR_NOT_SUPPORTED if the \a device is not in vGPU heterogeneous mode.
*
* @param device The identifier of the target device
* @param vgpuTypeId Handle to vGPU type. The vGPU type ID
* @param pPlacementList Pointer to the list of vGPU placement structure \a nvmlVgpuPlacementList_t
*
* @return
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device or \a vgpuTypeId is invalid or \a pPlacementList is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device or \a vgpuTypeId isn't supported
* - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation
* - \ref NVML_ERROR_VERSION_MISMATCH If the version of \a pPlacementList is invalid
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetVgpuTypeCreatablePlacements(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, nvmlVgpuPlacementList_t *pPlacementList);
/**
* Retrieve the static GSP heap size of the vGPU type in bytes
*
* @param vgpuTypeId Handle to vGPU type
* @param gspHeapSize Reference to return the GSP heap size value
* @return
* - \ref NVML_SUCCESS Successful completion
* - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuTypeId is invalid, or \a gspHeapSize is NULL
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlVgpuTypeGetGspHeapSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *gspHeapSize);
/**
* Retrieve the static framebuffer reservation of the vGPU type in bytes
*
* @param vgpuTypeId Handle to vGPU type
* @param fbReservation Reference to return the framebuffer reservation
* @return
* - \ref NVML_SUCCESS Successful completion
* - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a vgpuTypeId is invalid, or \a fbReservation is NULL
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlVgpuTypeGetFbReservation(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbReservation);
/**
* Set the desirable vGPU capability of a device
*
* Refer to the \a nvmlDeviceVgpuCapability_t structure for the specific capabilities that can be set.
* See \ref nvmlEnableState_t for available state.
*
* @param device The identifier of the target device
* @param capability Specifies the \a nvmlDeviceVgpuCapability_t to be set
* @param state The target capability mode
*
* @return
* - \ref NVML_SUCCESS Successful completion
* - \ref NVML_ERROR_UNINITIALIZED If the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device is invalid, or \a capability is invalid, or \a state is invalid
* - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported in current state, or \a device not in vGPU mode
* - \ref NVML_ERROR_UNKNOWN On any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceSetVgpuCapabilities(nvmlDevice_t device, nvmlDeviceVgpuCapability_t capability, nvmlEnableState_t state);
/**
* Retrieve the vGPU Software licensable features.
*
@@ -8774,6 +9376,52 @@ nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned
nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount,
nvmlVgpuInstanceUtilizationSample_t *utilizationSamples);
/**
* Retrieves recent utilization for vGPU instances running on a physical GPU (device).
*
* For Kepler &tm; or newer fully supported devices.
*
* Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, video decoder, jpeg decoder, and OFA for vGPU
* instances running on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied
* buffer pointed at by \a vgpuUtilInfo->vgpuUtilArray. One utilization sample structure is returned per vGPU instance, and includes the
* CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values
* in nvmlValue_t unions. The function sets the caller-supplied \a vgpuUtilInfo->sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to
* indicate the returned value type.
*
* To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with
* \a vgpuUtilInfo->vgpuUtilArray set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance
* count in \a vgpuUtilInfo->vgpuInstanceCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate
* a buffer of size vgpuUtilInfo->vgpuInstanceCount * sizeof(nvmlVgpuInstanceUtilizationInfo_t). Invoke the function again with
* the allocated buffer passed in \a vgpuUtilInfo->vgpuUtilArray, and \a vgpuUtilInfo->vgpuInstanceCount set to the number of entries the
* buffer is sized for.
*
* On successful return, the function updates \a vgpuUtilInfo->vgpuInstanceCount with the number of vGPU utilization sample
* structures that were actually written. This may differ from a previously read value as vGPU instances are created or
* destroyed.
*
* \a vgpuUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0
* to read utilization based on all the samples maintained by the driver's internal sample buffer. Set \a vgpuUtilInfo->lastSeenTimeStamp
* to a timeStamp retrieved from a previous query to read utilization since the previous query.
*
* @param device The identifier for the target device
* @param vgpuUtilInfo Pointer to the caller-provided structure of nvmlVgpuInstancesUtilizationInfo_t
* @return
* - \ref NVML_SUCCESS if utilization samples are successfully retrieved
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuUtilInfo is NULL, or \a vgpuUtilInfo->vgpuInstanceCount is 0
* - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_VERSION_MISMATCH if the version of \a vgpuUtilInfo is invalid
* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a vgpuUtilInfo->vgpuUtilArray is NULL, or the buffer size of vgpuUtilInfo->vgpuInstanceCount is too small.
* The caller should check the current vGPU instance count from the returned vgpuUtilInfo->vgpuInstanceCount, and call
* the function again with a buffer of size vgpuUtilInfo->vgpuInstanceCount * sizeof(nvmlVgpuInstanceUtilizationInfo_t)
* - \ref NVML_ERROR_NOT_FOUND if sample entries are not found
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetVgpuInstancesUtilizationInfo(nvmlDevice_t device,
nvmlVgpuInstancesUtilizationInfo_t *vgpuUtilInfo);
/**
* Retrieves current utilization for processes running on vGPUs on a physical GPU (device).
*
@@ -8820,6 +9468,52 @@ nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned
nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp,
unsigned int *vgpuProcessSamplesCount,
nvmlVgpuProcessUtilizationSample_t *utilizationSamples);
/**
* Retrieves recent utilization for processes running on vGPU instances on a physical GPU (device).
*
* For Maxwell &tm; or newer fully supported devices.
*
* Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, video decoder, jpeg decoder, and OFA for processes running
* on vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied
* buffer pointed at by \a vgpuProcUtilInfo->vgpuProcUtilArray. One utilization sample structure is returned per process running
* on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which
* the samples were recorded. Individual utilization values are returned as "unsigned int" values.
*
* To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with
* \a vgpuProcUtilInfo->vgpuProcUtilArray set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current processes' count
* running on vGPU instances in \a vgpuProcUtilInfo->vgpuProcessCount. The caller should allocate a buffer of size
* vgpuProcUtilInfo->vgpuProcessCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed
* in \a vgpuProcUtilInfo->vgpuProcUtilArray, and \a vgpuProcUtilInfo->vgpuProcessCount set to the number of entries the buffer is sized for.
*
* On successful return, the function updates \a vgpuProcUtilInfo->vgpuProcessCount with the number of vGPU sub process utilization sample
* structures that were actually written. This may differ from a previously read value depending on the number of processes that are active
* in any given sample period.
*
* vgpuProcUtilInfo->lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0
* to read utilization based on all the samples maintained by the driver's internal sample buffer. Set vgpuProcUtilInfo->lastSeenTimeStamp
* to a timeStamp retrieved from a previous query to read utilization since the previous query.
*
* @param device The identifier for the target device
* @param vgpuProcUtilInfo Pointer to the caller-provided structure of nvmlVgpuProcessesUtilizationInfo_t
* @return
* - \ref NVML_SUCCESS if utilization samples are successfully retrieved
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a vgpuProcUtilInfo is null
* - \ref NVML_ERROR_VERSION_MISMATCH if the version of \a vgpuProcUtilInfo is invalid
* - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a vgpuProcUtilInfo->vgpuProcUtilArray is null, or supplied \a vgpuProcUtilInfo->vgpuProcessCount
* is too small to return samples for all processes on vGPU instances currently executing on the device.
* The caller should check the current processes count from the returned \a vgpuProcUtilInfo->vgpuProcessCount,
* and call the function again with a buffer of size
* vgpuProcUtilInfo->vgpuProcessCount * sizeof(nvmlVgpuProcessUtilizationSample_t)
* - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_NOT_FOUND if sample entries are not found
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessesUtilizationInfo(nvmlDevice_t device, nvmlVgpuProcessesUtilizationInfo_t *vgpuProcUtilInfo);
/**
* Queries the state of per process accounting mode on vGPU.
*
@@ -9304,7 +9998,7 @@ nvmlReturn_t DECLDIR nvmlDeviceSetMigMode(nvmlDevice_t device, unsigned int mode
nvmlReturn_t DECLDIR nvmlDeviceGetMigMode(nvmlDevice_t device, unsigned int *currentMode, unsigned int *pendingMode);
/**
* Get GPU instance profile information.
* Get GPU instance profile information
*
* Information provided by this API is immutable throughout the lifetime of a MIG mode.
*
@@ -9319,7 +10013,7 @@ nvmlReturn_t DECLDIR nvmlDeviceGetMigMode(nvmlDevice_t device, unsigned int *cur
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profile or \a info are invalid
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profile isn't supported
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG or \a profile isn't supported
* - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation
*/
nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfo(nvmlDevice_t device, unsigned int profile,
@@ -9360,7 +10054,7 @@ nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfoV(nvmlDevice_t device, u
* Get GPU instance placements.
*
* A placement represents the location of a GPU instance within a device. This API only returns all the possible
* placements for the given profile.
* placements for the given profile regardless of whether MIG is enabled or not.
* A created GPU instance occupies memory slices described by its placement. Creation of new GPU instance will
* fail if there is overlap with the already occupied memory slices.
*
@@ -9379,7 +10073,7 @@ nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstanceProfileInfoV(nvmlDevice_t device, u
* - \ref NVML_SUCCESS Upon success
* - \ref NVML_ERROR_UNINITIALIZED If library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT If \a device, \a profileId or \a count are invalid
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't have MIG mode enabled or \a profileId isn't supported
* - \ref NVML_ERROR_NOT_SUPPORTED If \a device doesn't support MIG or \a profileId isn't supported
* - \ref NVML_ERROR_NO_PERMISSION If user doesn't have permission to perform the operation
*/
nvmlReturn_t DECLDIR nvmlDeviceGetGpuInstancePossiblePlacements_v2(nvmlDevice_t device, unsigned int profileId,
@@ -10287,7 +10981,7 @@ nvmlReturn_t DECLDIR nvmlSystemGetNvlinkBwMode(unsigned int *nvlinkBwMode);
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*
* @see NVML_FI_DEV_POWER_AVERAGE
* @see NVML_FI_DEV_POWER_AVERAGE
* @see NVML_FI_DEV_POWER_INSTANT
* @see NVML_FI_DEV_POWER_MIN_LIMIT
* @see NVML_FI_DEV_POWER_MAX_LIMIT
@@ -10295,7 +10989,28 @@ nvmlReturn_t DECLDIR nvmlSystemGetNvlinkBwMode(unsigned int *nvlinkBwMode);
*/
nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit_v2(nvmlDevice_t device, nvmlPowerValue_v2_t *powerValue);
/**
* Get SRAM ECC error status of this device.
*
* For Ampere &tm; or newer fully supported devices.
* Requires root/admin permissions.
*
* See \ref nvmlEccSramErrorStatus_v1_t for more information on the struct.
*
* @param device The identifier of the target device
* @param status Returns SRAM ECC error status
*
* @return
* - \ref NVML_SUCCESS if \a limit has been set
* - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized
* - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counters is NULL
* - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature
* - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible
* - \ref NVML_ERROR_VERSION_MISMATCH if the version of \a nvmlEccSramErrorStatus_t is invalid
* - \ref NVML_ERROR_UNKNOWN on any unexpected error
*/
nvmlReturn_t DECLDIR nvmlDeviceGetSramEccErrorStatus(nvmlDevice_t device,
nvmlEccSramErrorStatus_t *status);
/**
* NVML API versioning support
*/
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/NVIDIA/nvidia-settings/blob/main/src/nvml.h",
"license": "Embed in source",
"version": "545.23.06",
"version": "550.54.14",
"author": "NVIDIA Corporation"
}
+2 -2
View File
@@ -11,7 +11,7 @@
bool ffParseModuleOptions(const char* key, const char* value)
{
if (!ffStrStartsWith(key, "--") || !isalpha(key[2])) return false;
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
{
@@ -102,7 +102,7 @@ static void parseStructureCommand(
}
}
if(isalpha(line[0]))
if(ffCharIsEnglishAlphabet(line[0]))
{
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules)
{
+6 -4
View File
@@ -181,22 +181,24 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char
return reply;
}
void ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result)
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result)
{
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
if(reply == NULL)
return;
return false;
DBusMessageIter rootIterator;
if(!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator))
{
dbus->lib->ffdbus_message_unref(reply);
return;
return false;
}
ffDBusGetValue(dbus, &rootIterator, result);
bool ret = ffDBusGetValue(dbus, &rootIterator, result);
dbus->lib->ffdbus_message_unref(reply);
return ret;
}
#endif //FF_HAVE_DBUS
+1 -1
View File
@@ -48,6 +48,6 @@ bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
bool ffDBusGetByte(FFDBusData* dbus, DBusMessageIter* iter, uint8_t* result);
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method);
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
void ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
#endif // FF_HAVE_DBUS
+5 -5
View File
@@ -238,9 +238,6 @@ void ffListFeatures(void)
#ifdef FF_HAVE_DDCUTIL
"libddcutil\n"
#endif
#if __has_include(<linux/videodev2.h>)
"videodev2\n"
#endif
#ifdef FF_HAVE_DIRECTX_HEADERS
"Directx Headers\n"
#endif
@@ -250,8 +247,11 @@ void ffListFeatures(void)
#ifdef FF_USE_SYSTEM_YYJSON
"System yyjson\n"
#endif
#ifdef FF_USE_PCI_MEMORY
"PCI memory\n"
#if __has_include(<linux/videodev2.h>)
"linux/videodev2\n"
#endif
#if __has_include(<linux/wireless.h>)
"linux/wireless\n"
#endif
""
, stdout);
+4 -1
View File
@@ -1,6 +1,6 @@
#include "io.h"
#include "fastfetch.h"
#include "util/stringUtils.h"
#include "util/unused.h"
#include <fcntl.h>
#include <termios.h>
@@ -133,6 +133,9 @@ bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* o
const char* ffGetTerminalResponse(const char* request, const char* format, ...)
{
if (instance.config.display.pipe)
return "Not supported in --pipe mode";
struct termios oldTerm, newTerm;
if(tcgetattr(STDIN_FILENO, &oldTerm) == -1)
return "tcgetattr(STDIN_FILENO, &oldTerm) failed";
+4
View File
@@ -1,4 +1,5 @@
#include "io.h"
#include "fastfetch.h"
#include "util/stringUtils.h"
#include <windows.h>
@@ -174,6 +175,9 @@ void ffListFilesRecursively(const char* path, bool pretty)
const char* ffGetTerminalResponse(const char* request, const char* format, ...)
{
if (instance.config.display.pipe)
return "Not supported in --pipe mode";
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
DWORD prev_mode;
GetConsoleMode(hInput, &prev_mode);
+1 -1
View File
@@ -94,7 +94,7 @@ static inline void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_mut_doc* jsonDoc)
{
if(!isalpha(type[0])) return false;
if(!ffCharIsEnglishAlphabet(type[0])) return false;
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(type[0]) - 'A']; *modules; ++modules)
{
+1 -1
View File
@@ -4,7 +4,7 @@
#include <stdarg.h>
//Clang doesn't define __SANITIZE_ADDRESS__ but defines __has_feature(address_sanitizer)
#if defined(__has_feature)
#if !defined(__SANITIZE_ADDRESS__) && defined(__has_feature)
#if __has_feature(address_sanitizer)
#define __SANITIZE_ADDRESS__
#endif
+2 -8
View File
@@ -8,10 +8,7 @@ static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const ar
{
const char* error = ffProcessAppendOutput(buffer, argv, false);
if (!error)
{
ffStrbufTrimRight(buffer, '\n');
ffStrbufTrimRight(buffer, ' ');
}
ffStrbufTrimRightSpace(buffer);
return error;
}
@@ -19,9 +16,6 @@ static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const ar
{
const char* error = ffProcessAppendOutput(buffer, argv, true);
if (!error)
{
ffStrbufTrimRight(buffer, '\n');
ffStrbufTrimRight(buffer, ' ');
}
ffStrbufTrimRightSpace(buffer);
return error;
}
+1 -1
View File
@@ -68,7 +68,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) timeout";
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
}
else if (pollfd.revents & POLLERR)
{
+1 -1
View File
@@ -96,7 +96,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
{
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "WaitForSingleObject(hChildPipeRead) failed or timeout";
return "WaitForSingleObject(hChildPipeRead) failed or timeout (try increasing --processing-timeout)";
}
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
+29 -36
View File
@@ -1,5 +1,7 @@
#include "fastfetch.h"
#include "common/properties.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include <stdlib.h>
#ifdef _WIN32
@@ -95,50 +97,44 @@ bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer)
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
{
FILE* file = fopen(filename, "r");
if(file == NULL)
FF_AUTO_CLOSE_FILE FILE* file = fopen(filename, "r");
if (file == NULL)
return false;
bool valueStorage[4];
bool* unsetValues;
bool valueStorage[32];
bool* unsetValues = valueStorage;
if(numQueries > sizeof(valueStorage) / sizeof(valueStorage[0]))
if (numQueries > sizeof(valueStorage) / sizeof(valueStorage[0]))
unsetValues = malloc(sizeof(bool) * numQueries);
else
unsetValues = valueStorage;
bool allSet = true;
for(uint32_t i = 0; i < numQueries; i++)
for (uint32_t i = 0; i < numQueries; i++)
{
if((unsetValues[i] = queries[i].buffer->length == 0))
unsetValues[i] = queries[i].buffer->length == 0;
if (unsetValues[i])
allSet = false;
}
if(allSet)
goto done;
char* line = NULL;
size_t len = 0;
while (getline(&line, &len, file) != -1)
if (!allSet)
{
for(uint32_t i = 0; i < numQueries; i++)
{
if(!unsetValues[i])
continue;
FF_AUTO_FREE char* line = NULL;
size_t len = 0;
uint32_t currentLength = queries[i].buffer->length;
queries[i].buffer->length = 0;
if(!ffParsePropLine(line, queries[i].start, queries[i].buffer))
queries[i].buffer->length = currentLength;
while (getline(&line, &len, file) != -1)
{
for(uint32_t i = 0; i < numQueries; i++)
{
if(!unsetValues[i])
continue;
uint32_t currentLength = queries[i].buffer->length;
queries[i].buffer->length = 0;
if(!ffParsePropLine(line, queries[i].start, queries[i].buffer))
queries[i].buffer->length = currentLength;
}
}
}
if(line != NULL)
free(line);
done:
fclose(file);
if(unsetValues != valueStorage)
free(unsetValues);
return true;
@@ -154,16 +150,13 @@ bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uin
{
bool foundAFile = false;
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
FF_LIST_FOR_EACH(FFstrbuf, dirPrefix, *list)
{
//We need to copy the dir each time, because it used by multiple threads, so we can't directly write to it.
ffStrbufSet(&baseDir, dirPrefix);
ffStrbufAppendS(&baseDir, relativeFile);
if(ffParsePropFileValues(baseDir.chars, numQueries, queries))
const uint32_t dirPrefixLength = dirPrefix->length;
ffStrbufAppendS(dirPrefix, relativeFile);
if(ffParsePropFileValues(dirPrefix->chars, numQueries, queries))
foundAFile = true;
ffStrbufSubstrBefore(dirPrefix, dirPrefixLength);
bool allSet = true;
for(uint32_t k = 0; k < numQueries; k++)
+12 -1
View File
@@ -702,6 +702,16 @@
"type": "color",
"default": "light_red"
}
},
{
"long": "ts-version",
"desc": "Whether to detect and display the version of terminal and shell",
"remark": "Mainly for benchmarking",
"arg": {
"type": "bool",
"optional": true,
"default": true
}
}
],
"Library path": [
@@ -937,7 +947,8 @@
},
{
"long": "disk-folders",
"desc": "A colon (semicolon on Windows) separated list of folder paths for the disk output",
"desc": "A colon (semicolon on Windows) separated list of folder paths to be detected",
"remark": "On Windows, a drive latter must be upper cased and end with \"\\\". \"/\" is used as an alias of the system drive. This option overrides other disk-show-* options",
"arg": {
"type": "path",
"default": "Auto detection using mount-points"
+4 -3
View File
@@ -3,7 +3,8 @@ Usage: fastfetch --color <color>
<color> must be a color encoding as ANSI escape sequences. It is inserted between "ESC[" and "m".
Infos about them can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters.
Examples:
--color 35: sets the color to magenta. `--color magenta` is also supported
--color 4;92: sets the color to bright Green with underline
--color 5;104: blinking text on a blue background
--color 35: sets the color to magenta. `--color magenta` is also supported
--color 38;5;38: sets the color to 38th color of ANSI 256 colors
--color 4;92: sets the color to bright Green with underline
--color 5;104: blinking text on a blue background
If no color is set, the main color of the logo will be used.
+3
View File
@@ -40,6 +40,7 @@ static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results)
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->serial);
ffStrbufInit(&battery->manufactureDate);
battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage"));
@@ -77,6 +78,8 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->serial);
ffStrbufInit(&battery->manufactureDate);
if (ffParsePropLines(start, "AC powered: ", &temp) && ffStrbufEqualS(&temp, "true"))
ffStrbufAppendS(&battery->status, "AC powered");
-3
View File
@@ -170,8 +170,5 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
ffStrbufSubstrBefore(&baseDir, baseDirLength);
}
if(results->length == 0)
return "\"/sys/class/power_supply/\" doesn't contain any battery folder";
return NULL;
}
+3 -6
View File
@@ -1,4 +1,6 @@
#include "battery.h"
#include "common/io/io.h"
#include "util/windows/unicode.h"
#include "util/mallocHelper.h"
#include "util/smbiosHelper.h"
@@ -20,11 +22,6 @@ NtPowerInformation(
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength);
static inline void wrapCloseHandle(HANDLE* handle)
{
if(*handle)
CloseHandle(*handle);
}
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
{
if(*hdev)
@@ -52,7 +49,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
if(!SetupDiGetDeviceInterfaceDetailW(hdev, &did, pdidd, cbRequired, &cbRequired, NULL))
continue;
HANDLE __attribute__((__cleanup__(wrapCloseHandle))) hBattery =
HANDLE FF_AUTO_CLOSE_FD hBattery =
CreateFileW(pdidd->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hBattery == INVALID_HANDLE_VALUE)
+22 -1
View File
@@ -1,10 +1,31 @@
#include "camera.h"
#include "common/io/io.h"
#import <AVFoundation/AVCaptureDevice.h>
// warning: 'AVCaptureDeviceTypeExternalUnknown' is deprecated
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
const char* ffDetectCamera(FFlist* result)
{
AVCaptureDeviceDiscoverySession* session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
FF_SUPPRESS_IO(); // #822
AVCaptureDeviceType deviceType;
#ifdef MAC_OS_VERSION_14_0
if (@available(macOS 14.0, *))
{
deviceType = AVCaptureDeviceTypeExternal;
}
else
#endif
{
deviceType = AVCaptureDeviceTypeExternalUnknown;
}
AVCaptureDeviceDiscoverySession* session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, deviceType]
mediaType:AVMediaTypeVideo
position:AVCaptureDevicePositionUnspecified];
if (!session)
return "Failed to create AVCaptureDeviceDiscoverySession";
+21
View File
@@ -18,3 +18,24 @@ const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu)
ffStrbufTrimRight(&cpu->name, ' '); //If we removed the @ in previous step there was most likely a space before it
return NULL;
}
const char* ffCPUAppleCodeToName(uint32_t code)
{
// https://github.com/AsahiLinux/docs/wiki/Codenames
switch (code)
{
case 8103: return "Apple M1";
case 6000: return "Apple M1 Pro";
case 6001: return "Apple M1 Max";
case 6002: return "Apple M1 Ultra";
case 8112: return "Apple M2";
case 6020: return "Apple M2 Pro";
case 6021: return "Apple M2 Max";
case 6022: return "Apple M2 Ultra";
case 8122: return "Apple M3";
case 6030: return "Apple M3 Pro";
case 6031:
case 6034: return "Apple M3 Max";
default: return "Apple Silicon";
}
}
+1
View File
@@ -22,3 +22,4 @@ typedef struct FFCPUResult
const char* ffCPUDetectByCpuid(FFCPUResult* cpu);
const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu);
const char* ffCPUAppleCodeToName(uint32_t code);
+2 -17
View File
@@ -210,23 +210,8 @@ void detectAsahi(FFCPUResult* cpu)
char* modelName = memchr(content, '\0', (size_t) length) + 1;
if (modelName - content < length && ffStrStartsWith(modelName, "apple,t"))
{
// https://github.com/AsahiLinux/docs/wiki/Codenames
switch (strtoul(modelName + strlen("apple,t"), NULL, 10))
{
case 8103: ffStrbufSetStatic(&cpu->name, "Apple M1"); break;
case 6000: ffStrbufSetStatic(&cpu->name, "Apple M1 Pro"); break;
case 6001: ffStrbufSetStatic(&cpu->name, "Apple M1 Max"); break;
case 6002: ffStrbufSetStatic(&cpu->name, "Apple M1 Ultra"); break;
case 8112: ffStrbufSetStatic(&cpu->name, "Apple M2"); break;
case 6020: ffStrbufSetStatic(&cpu->name, "Apple M2 Pro"); break;
case 6021: ffStrbufSetStatic(&cpu->name, "Apple M2 Max"); break;
case 6022: ffStrbufSetStatic(&cpu->name, "Apple M2 Ultra"); break;
case 8122: ffStrbufSetStatic(&cpu->name, "Apple M3"); break;
case 6030: ffStrbufSetStatic(&cpu->name, "Apple M3 Pro"); break;
case 6031:
case 6034: ffStrbufSetStatic(&cpu->name, "Apple M3 Max"); break;
default: ffStrbufSetStatic(&cpu->name, "Apple Silicon"); break;
}
uint32_t deviceId = (uint32_t) strtoul(modelName + strlen("apple,t"), NULL, 10);
ffStrbufSetStatic(&cpu->name, ffCPUAppleCodeToName(deviceId));
}
}
}
+33 -7
View File
@@ -50,6 +50,31 @@ typedef struct FFSmbiosProcessorInfo
uint16_t ThreadEnabled; // varies
} FFSmbiosProcessorInfo;
#if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h>
inline static const char* detectSpeedByCpuid(FFCPUResult* cpu)
{
uint32_t base = 0, max = 0, bus = 0, unused = 0;
if (!__get_cpuid(0x16, &base, &max, &bus, &unused))
return "Unsupported instruction";
// cpuid returns 0 MHz when hyper-v is enabled
if (base) cpu->frequencyBase = base / 1000.0;
if (max) cpu->frequencyMax = max / 1000.0;
return NULL;
}
#else
inline static const char* detectSpeedByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu)
{
return "Unsupported platform";
}
#endif
static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu)
{
const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PROCESSOR_INFO];
@@ -64,13 +89,12 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu)
return "No active CPU is found in SMBIOS data";
}
if (data->MaxSpeed > 0 && data->MaxSpeed < 30000) // VMware reports weird values
{
double speed = data->MaxSpeed / 1000.0;
if (cpu->frequencyBase < speed)
cpu->frequencyMax = speed;
}
double speed = data->MaxSpeed / 1000.0;
// Sometimes SMBIOS reports invalid value. We assume that max speed is small than 2x of base
if (speed < cpu->frequencyBase || speed > cpu->frequencyBase * 2)
return "Possible invalid CPU max speed in SMBIOS data. See #800";
cpu->frequencyMax = speed;
return NULL;
}
@@ -115,6 +139,7 @@ static const char* detectByRegistry(FFCPUResult* cpu)
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL))
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
if (detectSpeedByCpuid(cpu) != NULL || cpu->frequencyBase != cpu->frequencyBase)
{
uint32_t mhz;
if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL))
@@ -142,7 +167,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
if (error)
return error;
detectMaxSpeedBySmbios(cpu);
if (cpu->frequencyMax != cpu->frequencyMax)
detectMaxSpeedBySmbios(cpu);
if(options->temp)
ffDetectSmbiosTemp(&cpu->temperature, NULL);
+25 -9
View File
@@ -1,5 +1,6 @@
#include "de.h"
#include "common/dbus.h"
#include "common/io/io.h"
#include "common/library.h"
#include "common/parsing.h"
@@ -12,19 +13,20 @@
static void getKDE(FFstrbuf* result, FFDEOptions* options)
{
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", 1, (FFpropquery[]) {
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
{"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}
});
}
if(result->length == 0)
ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
ffParsePropFileData("xsessions/plasma5.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
{
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
{"X-KDE-PluginInfo-Version =", result}
});
}
if(result->length == 0)
ffParsePropFileData("wayland-sessions/plasmawayland.desktop", "X-KDE-PluginInfo-Version =", result);
if(result->length == 0)
@@ -41,11 +43,25 @@ static void getKDE(FFstrbuf* result, FFDEOptions* options)
}
}
static const char* getGnomeByDbus(FF_MAYBE_UNUSED FFstrbuf* result)
{
#ifdef FF_HAVE_DBUS
FFDBusData dbus;
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return "ffDBusLoadData() failed";
ffDBusGetPropertyString(&dbus, "org.gnome.Shell", "/org/gnome/Shell", "org.gnome.Shell", "ShellVersion", result);
return NULL;
#else // FF_HAVE_DBUS
return "ffDBusLoadData() failed: dbus support not compiled in";
#endif // FF_HAVE_DBUS
}
static void getGnome(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
{
ffParsePropFileData("gnome-shell/org.gnome.Extensions", "version :", result);
getGnomeByDbus(result);
if (result->length == 0)
if (result->length == 0 && options->slowVersionDetection)
{
if (ffProcessAppendStdOut(result, (char* const[]){
"gnome-shell",
+25 -2
View File
@@ -1,6 +1,29 @@
#include "disk.h"
const char* ffDetectDisksImpl(FFlist* disks);
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
{
#ifdef _WIN32
const char separator = ';';
#else
const char separator = ':';
#endif
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
uint32_t startIndex = 0;
while(startIndex < options->folders.length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
static int compareDisks(const FFDisk* disk1, const FFDisk* disk2)
{
@@ -9,7 +32,7 @@ static int compareDisks(const FFDisk* disk1, const FFDisk* disk2)
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks)
{
const char* error = ffDetectDisksImpl(disks);
const char* error = ffDetectDisksImpl(options, disks);
if (error) return error;
if (disks->length == 0) return "No disks found";
+3
View File
@@ -26,3 +26,6 @@ typedef struct FFDisk
* If error is not set, disks contains at least one disk.
*/
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint);
+7 -2
View File
@@ -90,7 +90,7 @@ void detectFsInfo(struct statfs* fs, FFDisk* disk)
}
#endif
const char* ffDetectDisksImpl(FFlist* disks)
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
int size = getfsstat(NULL, 0, MNT_WAIT);
@@ -103,7 +103,12 @@ const char* ffDetectDisksImpl(FFlist* disks)
for(struct statfs* fs = buf; fs < buf + size; ++fs)
{
if(!ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
if(__builtin_expect(options->folders.length, 0))
{
if(!ffDiskMatchMountpoint(options, fs->f_mntonname))
continue;
}
else if(!ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
continue;
#ifdef __FreeBSD__
+8 -3
View File
@@ -31,7 +31,7 @@ static bool isPhysicalDevice(const struct mntent* device)
//DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
if(ffStrEquals(device->mnt_type, "9p"))
return true;
return ffStrContains(device->mnt_opts, "aname=drvfs");
//ZFS pool
if(ffStrEquals(device->mnt_type, "zfs"))
@@ -250,7 +250,7 @@ static void detectStats(FFDisk* disk)
#endif
}
const char* ffDetectDisksImpl(FFlist* disks)
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
FILE* mountsFile = setmntent("/proc/mounts", "r");
if(mountsFile == NULL)
@@ -260,7 +260,12 @@ const char* ffDetectDisksImpl(FFlist* disks)
while((device = getmntent(mountsFile)))
{
if(!isPhysicalDevice(device))
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(options, device->mnt_dir))
continue;
}
else if(!isPhysicalDevice(device))
continue;
//We have a valid device, add it to the list
+71 -41
View File
@@ -1,53 +1,102 @@
#include "disk.h"
#include "common/io/io.h"
#include "common/thread.h"
#include "util/windows/unicode.h"
#include <windows.h>
#include <winioctl.h>
#include <assert.h>
const char* ffDetectDisksImpl(FFlist* disks)
static unsigned __stdcall testRemoteVolumeAccessable(void* mountpoint)
{
FF_AUTO_CLOSE_FD HANDLE handle = CreateFileW(
(wchar_t*) mountpoint,
READ_CONTROL,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
return 0;
}
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
wchar_t buf[MAX_PATH + 1];
uint32_t length = GetLogicalDriveStringsW(sizeof(buf) / sizeof(*buf), buf);
if (length == 0 || length >= sizeof(buf) / sizeof(*buf))
return "GetLogicalDriveStringsW(sizeof(buf) / sizeof(*buf), buf) failed";
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
// For cross-platform portability; used by `presets/examples/13.jsonc`
if (__builtin_expect(options->folders.length == 1 && options->folders.chars[0] == '/', 0))
{
wchar_t path[MAX_PATH + 1];
GetSystemWindowsDirectoryW(path, sizeof(path) / sizeof(*path));
ffStrbufSetF(&options->folders, "%c:\\", (char) path[0]);
}
for(uint32_t i = 0; i < length; i++)
{
wchar_t* mountpoint = buf + i;
ffStrbufSetWS(&buffer, mountpoint);
i += buffer.length;
UINT driveType = GetDriveTypeW(mountpoint);
if(driveType == DRIVE_NO_ROOT_DIR)
if (__builtin_expect((long) options->folders.length, 0))
{
i += (uint32_t)wcslen(mountpoint);
continue;
if (!ffDiskMatchMountpoint(options, buffer.chars))
continue;
}
else if(driveType == DRIVE_NO_ROOT_DIR)
continue;
FFDisk* disk = ffListAdd(disks);
if(!GetDiskFreeSpaceExW(
disk->filesUsed = 0;
disk->filesTotal = 0;
disk->bytesTotal = 0;
disk->bytesFree = 0;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->bytesAvailable = 0;
disk->createTime = 0;
ffStrbufInit(&disk->filesystem);
ffStrbufInit(&disk->name);
ffStrbufInitMove(&disk->mountpoint, &buffer);
ffStrbufInit(&disk->mountFrom);
disk->type = driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM
? FF_DISK_VOLUME_TYPE_EXTERNAL_BIT
: driveType == DRIVE_FIXED
? FF_DISK_VOLUME_TYPE_REGULAR_BIT
: FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
if (mountpoint[2] == L'\\' && mountpoint[3] == L'\0')
{
wchar_t volumeName[MAX_PATH + 1];
mountpoint[2] = L'\0';
if(QueryDosDeviceW(mountpoint, volumeName, sizeof(volumeName) / sizeof(*volumeName)))
ffStrbufSetWS(&disk->mountFrom, volumeName);
mountpoint[2] = L'\\';
}
#ifdef FF_HAVE_THREADS
if (driveType == DRIVE_REMOTE)
{
FFThreadType thread = ffThreadCreate(testRemoteVolumeAccessable, mountpoint);
if (!ffThreadJoin(thread, 500))
continue;
}
#endif
GetDiskFreeSpaceExW(
mountpoint,
(PULARGE_INTEGER)&disk->bytesAvailable,
(PULARGE_INTEGER)&disk->bytesTotal,
(PULARGE_INTEGER)&disk->bytesFree
))
{
disk->bytesTotal = 0;
disk->bytesFree = 0;
disk->bytesAvailable = 0;
}
disk->bytesUsed = 0; // To be filled in ./disk.c
);
if(driveType == DRIVE_REMOVABLE || driveType == DRIVE_REMOTE || driveType == DRIVE_CDROM)
disk->type = FF_DISK_VOLUME_TYPE_EXTERNAL_BIT;
else if(driveType == DRIVE_FIXED)
disk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
else
disk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
ffStrbufInit(&disk->filesystem);
ffStrbufInit(&disk->name);
wchar_t diskName[MAX_PATH + 1], diskFileSystem[MAX_PATH + 1];
//https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationa#remarks
@@ -74,25 +123,6 @@ const char* ffDetectDisksImpl(FFlist* disks)
WIN32_FILE_ATTRIBUTE_DATA data;
if(GetFileAttributesExW(mountpoint, GetFileExInfoStandard, &data) && data.ftCreationTime.dwHighDateTime > 0)
disk->createTime = (*(uint64_t*) &data.ftCreationTime - 116444736000000000ull) / 10000ull;
else
disk->createTime = 0;
ffStrbufInitWS(&disk->mountpoint, mountpoint);
if (mountpoint[2] == L'\\' && mountpoint[3] == L'\0')
{
wchar_t volumeName[MAX_PATH + 1];
mountpoint[2] = L'\0';
if(QueryDosDeviceW(mountpoint, volumeName, sizeof(volumeName) / sizeof(*volumeName)))
ffStrbufInitWS(&disk->mountFrom, volumeName);
else
ffStrbufInit(&disk->mountFrom);
}
//Unsupported
disk->filesUsed = 0;
disk->filesTotal = 0;
i += disk->mountpoint.length;
}
return NULL;
@@ -13,6 +13,7 @@
#define FF_DE_PRETTY_BUDGIE "Budgie"
#define FF_DE_PRETTY_CDE "CDE"
#define FF_DE_PRETTY_UNITY "Unity"
#define FF_DE_PRETTY_UKUI "UKUI"
#define FF_WM_PRETTY_KWIN "KWin"
#define FF_WM_PRETTY_MUTTER "Mutter"
@@ -1,4 +1,7 @@
#include "displayserver_linux.h"
#include "common/io/io.h"
#include "util/edidHelper.h"
#include "util/stringUtils.h"
#ifdef __FreeBSD__
#include "common/settings.h"
@@ -57,3 +60,43 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
//This fills in missing information about WM / DE by using env vars and iterating processes
ffdsDetectWMDE(ds);
}
bool ffdsMatchDrmConnector(const char* connName, FFstrbuf* edidName)
{
// https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output-event-name
// The doc says that "do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc."
// However I can't find a better method to get the edid data
const char* drmDirPath = "/sys/class/drm/";
DIR* dirp = opendir(drmDirPath);
if(dirp == NULL)
return false;
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
const char* plainName = entry->d_name;
if (ffStrStartsWith(plainName, "card"))
{
const char* tmp = strchr(plainName + strlen("card"), '-');
if (tmp) plainName = tmp + 1;
}
if (ffStrEquals(plainName, connName))
{
ffStrbufAppendF(edidName, "%s%s/edid", drmDirPath, entry->d_name);
uint8_t edidData[128];
if(ffReadFileData(edidName->chars, sizeof(edidData), edidData) == sizeof(edidData))
{
ffStrbufClear(edidName);
ffEdidGetName(edidData, edidName);
closedir(dirp);
return true;
}
break;
}
}
ffStrbufClear(edidName);
closedir(dirp);
return false;
}
@@ -5,6 +5,9 @@
#include "detection/displayserver/displayserver.h"
bool ffdsMatchDrmConnector(const char* connName, FFstrbuf* edidName);
const char* ffdsConnectWlroots(FFDisplayServerResult* result);
void ffdsConnectWayland(FFDisplayServerResult* result);
void ffdsConnectXcbRandr(FFDisplayServerResult* result);
+29 -32
View File
@@ -36,31 +36,28 @@ static const char* drmParseSysfs(FFDisplayServerResult* result)
continue;
}
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
ffStrbufAppendS(&drmDir, "/modes");
char modes[32];
if (ffReadFileData(drmDir.chars, sizeof(modes), modes) < 3)
{
ffStrbufSubstrBefore(&drmDir, drmDirLength);
continue;
}
unsigned width = 0, height = 0;
double refreshRate = 0;
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
int scanned = sscanf(modes, "%ux%u", &width, &height);
if(scanned == 2 && width > 0 && height > 0)
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
ffStrbufAppendS(&drmDir, "/edid");
uint8_t edidData[128];
if(ffReadFileData(drmDir.chars, sizeof(edidData), edidData) == sizeof(edidData))
{
ffStrbufSubstrBefore(&drmDir, drmDirLength);
ffStrbufAppendS(&drmDir, entry->d_name);
ffStrbufAppendS(&drmDir, "/edid");
ffEdidGetName(edidData, &name);
ffEdidGetPreferredResolutionAndRefreshRate(edidData, &width, &height, &refreshRate);
}
else
{
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
ffStrbufAppendS(&drmDir, "/modes");
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
uint8_t edidData[128];
if(ffReadFileData(drmDir.chars, sizeof(edidData), edidData) == sizeof(edidData))
ffEdidGetName(edidData, &name);
else
char modes[32];
if (ffReadFileData(drmDir.chars, sizeof(modes), modes) >= 3)
{
sscanf(modes, "%ux%u", &width, &height);
const char* plainName = entry->d_name;
if (ffStrStartsWith(plainName, "card"))
{
@@ -69,20 +66,20 @@ static const char* drmParseSysfs(FFDisplayServerResult* result)
}
ffStrbufAppendS(&name, plainName);
}
ffdsAppendDisplay(
result,
width, height,
0,
0, 0,
0,
&name,
FF_DISPLAY_TYPE_UNKNOWN,
false,
0
);
}
ffdsAppendDisplay(
result,
width, height,
refreshRate,
0, 0,
0,
&name,
FF_DISPLAY_TYPE_UNKNOWN,
false,
0
);
ffStrbufSubstrBefore(&drmDir, drmDirLength);
}
-352
View File
@@ -1,352 +0,0 @@
#include "displayserver_linux.h"
#include "util/stringUtils.h"
#include <stdlib.h>
#include <string.h>
#ifdef FF_HAVE_WAYLAND
#include "common/library.h"
#include "common/io/io.h"
#include "common/thread.h"
#include "util/edidHelper.h"
#include <wayland-client.h>
#include <sys/socket.h>
#include <assert.h>
#include <dirent.h>
typedef struct WaylandData
{
FFDisplayServerResult* result;
FF_LIBRARY_SYMBOL(wl_proxy_marshal_constructor_versioned)
FF_LIBRARY_SYMBOL(wl_proxy_add_listener)
FF_LIBRARY_SYMBOL(wl_proxy_destroy)
FF_LIBRARY_SYMBOL(wl_display_roundtrip)
struct wl_display* display;
const struct wl_interface* ffwl_output_interface;
} WaylandData;
typedef struct WaylandDisplay
{
int32_t width;
int32_t height;
int32_t refreshRate;
int32_t scale;
enum wl_output_transform transform;
FFDisplayType type;
FFstrbuf name;
FFstrbuf description;
FFstrbuf vendorAndModelId;
FFstrbuf edidName;
} WaylandDisplay;
#ifndef __FreeBSD__
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
{
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
return;
FF_STRBUF_AUTO_DESTROY procPath = ffStrbufCreate();
ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); //We check the cmdline for the process name, because it is not trimmed.
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
ffStrbufTrimRightSpace(&result->wmProcessName);
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
}
#else
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
{
FF_UNUSED(fd, result);
}
#endif
static void stubListener(void* data, ...)
{
(void) data;
}
static void waylandOutputModeListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate)
{
if(!(flags & WL_OUTPUT_MODE_CURRENT))
return;
WaylandDisplay* display = data;
display->width = width;
display->height = height;
display->refreshRate = refreshRate;
}
static void waylandOutputScaleListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, int32_t scale)
{
WaylandDisplay* display = data;
display->scale = scale;
}
static void waylandOutputGeometryListener(void *data,
FF_MAYBE_UNUSED struct wl_output *output,
FF_MAYBE_UNUSED int32_t x,
FF_MAYBE_UNUSED int32_t y,
FF_MAYBE_UNUSED int32_t physical_width,
FF_MAYBE_UNUSED int32_t physical_height,
FF_MAYBE_UNUSED int32_t subpixel,
const char *make,
const char *model,
int32_t transform)
{
WaylandDisplay* display = data;
display->transform = (enum wl_output_transform) transform;
if (make && !ffStrEqualsIgnCase(make, "unknown") && model && !ffStrEqualsIgnCase(model, "unknown"))
{
ffStrbufAppendS(&display->vendorAndModelId, make);
ffStrbufAppendS(&display->vendorAndModelId, model);
}
}
static bool matchDrmConnector(const char* wlName, FFstrbuf* edidName)
{
// https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output-event-name
// The doc says that "do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc."
// However I can't find a better method to get the edid data
const char* drmDirPath = "/sys/class/drm/";
DIR* dirp = opendir(drmDirPath);
if(dirp == NULL)
return false;
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
const char* plainName = entry->d_name;
if (ffStrStartsWith(plainName, "card"))
{
const char* tmp = strchr(plainName + strlen("card"), '-');
if (tmp) plainName = tmp + 1;
}
if (ffStrEquals(plainName, wlName))
{
ffStrbufAppendF(edidName, "%s%s/edid", drmDirPath, entry->d_name);
uint8_t edidData[128];
if(ffReadFileData(edidName->chars, sizeof(edidData), edidData) == sizeof(edidData))
{
ffStrbufClear(edidName);
ffEdidGetName(edidData, edidName);
closedir(dirp);
return true;
}
break;
}
}
ffStrbufClear(edidName);
closedir(dirp);
return false;
}
static void waylandOutputNameListener(void *data, FF_MAYBE_UNUSED struct wl_output *output, const char *name)
{
WaylandDisplay* display = data;
if(ffStrStartsWith(name, "eDP-"))
display->type = FF_DISPLAY_TYPE_BUILTIN;
else if(ffStrStartsWith(name, "HDMI-"))
display->type = FF_DISPLAY_TYPE_EXTERNAL;
matchDrmConnector(name, &display->edidName);
ffStrbufAppendS(&display->name, name);
}
static void waylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED struct wl_output* wl_output, const char* description)
{
WaylandDisplay* display = data;
while (*description == ' ') ++description;
if (!ffStrEquals(description, "Unknown Display"))
ffStrbufAppendS(&display->description, description);
}
static void waylandOutputHandler(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
if(output == NULL)
return;
WaylandDisplay display = {
.width = 0,
.height = 0,
.refreshRate = 0,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
};
ffStrbufInit(&display.name);
ffStrbufInit(&display.description);
ffStrbufInit(&display.vendorAndModelId);
ffStrbufInit(&display.edidName);
// Dirty hack for #477
// The order of these callbacks MUST follow `struct wl_output_listener`
void* outputListener[] = {
waylandOutputGeometryListener, // geometry
waylandOutputModeListener, // mode
stubListener, // done
waylandOutputScaleListener, // scale
waylandOutputNameListener, // name
waylandOutputDescriptionListener, // description
};
static_assert(
sizeof(outputListener) >= sizeof(struct wl_output_listener),
"sizeof(outputListener) is too small. Please report it to fastfetch github issue"
);
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
wldata->ffwl_proxy_destroy(output);
if(display.width <= 0 || display.height <= 0)
return;
switch(display.transform)
{
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_270: {
int32_t temp = display.width;
display.width = display.height;
display.height = temp;
break;
}
default:
break;
}
uint32_t rotation;
switch(display.transform)
{
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_90:
rotation = 90;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_180:
rotation = 180;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
case WL_OUTPUT_TRANSFORM_270:
rotation = 270;
break;
default:
rotation = 0;
break;
}
ffdsAppendDisplay(wldata->result,
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale),
(uint32_t) (display.height / display.scale),
rotation,
display.edidName.length
? &display.edidName
: display.description.length
? &display.description
: display.vendorAndModelId.length
? &display.vendorAndModelId : &display.name,
display.type,
false,
0
);
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.vendorAndModelId);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
}
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
{
WaylandData* wldata = data;
if(ffStrEquals(interface, wldata->ffwl_output_interface->name))
waylandOutputHandler(wldata, registry, name, version);
}
bool detectWayland(FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(wayland, &instance.config.library.libWayland, false, "libwayland-client" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_get_fd, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_dispatch, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_proxy_marshal_constructor, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_disconnect, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_registry_interface, false)
WaylandData data;
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_marshal_constructor_versioned, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_add_listener, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_destroy, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_display_roundtrip, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_output_interface, false)
data.display = ffwl_display_connect(NULL);
if(data.display == NULL)
return false;
waylandDetectWM(ffwl_display_get_fd(data.display), result);
struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL);
if(registry == NULL)
{
ffwl_display_disconnect(data.display);
return false;
}
data.result = result;
struct wl_registry_listener registry_listener = {
.global = waylandGlobalAddListener,
.global_remove = (void*) stubListener
};
data.ffwl_proxy_add_listener(registry, (void(**)(void)) &registry_listener, &data);
ffwl_display_dispatch(data.display);
data.ffwl_display_roundtrip(data.display);
data.ffwl_proxy_destroy(registry);
ffwl_display_disconnect(data.display);
//We successfully connected to wayland and detected the display.
//So we can set set the session type to wayland.
//This is used as an indicator that we are running wayland by the x11 backends.
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
return true;
}
#endif
void ffdsConnectWayland(FFDisplayServerResult* result)
{
//Wayland requires this to be set
if(getenv("XDG_RUNTIME_DIR") == NULL)
return;
#ifdef FF_HAVE_WAYLAND
if(detectWayland(result))
return;
#endif
const char* xdgSessionType = getenv("XDG_SESSION_TYPE");
//If XDG_SESSION_TYPE is set, and doesn't contain "wayland", we are probably not running in a wayland session.
if(xdgSessionType != NULL && strcasecmp(xdgSessionType, "wayland") != 0)
return;
//If XDG_SESSION_TYPE is not set, check if WAYLAND_DISPLAY or WAYLAND_SOCKET is set.
//If not, there is no indicator for a wayland session
if(xdgSessionType == NULL && getenv("WAYLAND_DISPLAY") == NULL && getenv("WAYLAND_SOCKET") == NULL)
return;
//We are probably running a wayland compositor at this point,
//but fastfetch was compiled without the required library, or loading the library failed.
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
}
@@ -0,0 +1,134 @@
#ifdef FF_HAVE_WAYLAND
#include "wayland.h"
#include "util/stringUtils.h"
static void waylandOutputModeListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate)
{
if(!(flags & WL_OUTPUT_MODE_CURRENT))
return;
WaylandDisplay* display = data;
display->width = width;
display->height = height;
display->refreshRate = refreshRate;
}
static void waylandOutputScaleListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, int32_t scale)
{
WaylandDisplay* display = data;
display->scale = scale;
}
static void waylandOutputGeometryListener(void *data,
FF_MAYBE_UNUSED struct wl_output *output,
FF_MAYBE_UNUSED int32_t x,
FF_MAYBE_UNUSED int32_t y,
FF_MAYBE_UNUSED int32_t physical_width,
FF_MAYBE_UNUSED int32_t physical_height,
FF_MAYBE_UNUSED int32_t subpixel,
FF_MAYBE_UNUSED const char *make,
FF_MAYBE_UNUSED const char *model,
int32_t transform)
{
WaylandDisplay* display = data;
display->transform = (enum wl_output_transform) transform;
}
void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
if(output == NULL)
return;
WaylandDisplay display = {
.parent = wldata,
.width = 0,
.height = 0,
.refreshRate = 0,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
.description = ffStrbufCreate(),
.edidName = ffStrbufCreate(),
};
// Dirty hack for #477
// The order of these callbacks MUST follow `struct wl_output_listener`
void* outputListener[] = {
waylandOutputGeometryListener, // geometry
waylandOutputModeListener, // mode
stubListener, // done
waylandOutputScaleListener, // scale
ffWaylandOutputNameListener, // name
ffWaylandOutputDescriptionListener, // description
};
static_assert(
sizeof(outputListener) >= sizeof(struct wl_output_listener),
"sizeof(outputListener) is too small. Please report it to fastfetch github issue"
);
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
wldata->ffwl_proxy_destroy(output);
if(display.width <= 0 || display.height <= 0)
return;
uint32_t rotation;
switch(display.transform)
{
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_90:
rotation = 90;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_180:
rotation = 180;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
case WL_OUTPUT_TRANSFORM_270:
rotation = 270;
break;
default:
rotation = 0;
break;
}
switch(rotation)
{
case 90:
case 270: {
int32_t temp = display.width;
display.width = display.height;
display.height = temp;
break;
}
default:
break;
}
ffdsAppendDisplay(wldata->result,
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale),
(uint32_t) (display.height / display.scale),
rotation,
display.edidName.length
? &display.edidName
: display.description.length && !ffStrbufEndsWithS(&display.description, "-unknown")
? &display.description
: &display.name,
display.type,
false,
0
);
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
}
#endif
@@ -0,0 +1,149 @@
#include "../displayserver_linux.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include <stdlib.h>
#include <string.h>
#ifdef FF_HAVE_WAYLAND
#include <sys/socket.h>
#include "wayland.h"
#include "wlr-output-management-unstable-v1-client-protocol.h"
#ifndef __FreeBSD__
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
{
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
return;
FF_STRBUF_AUTO_DESTROY procPath = ffStrbufCreate();
ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); //We check the cmdline for the process name, because it is not trimmed.
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
ffStrbufTrimRightSpace(&result->wmProcessName);
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
}
#else
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
{
FF_UNUSED(fd, result);
}
#endif
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
{
WaylandData* wldata = data;
if((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wldata->ffwl_output_interface->name))
{
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_GLOBAL;
ffWaylandHandleGlobalOutput(wldata, registry, name, version);
}
else if((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_ZWLR) && ffStrEquals(interface, zwlr_output_manager_v1_interface.name))
{
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_ZWLR;
ffWaylandHandleZwlrOutput(wldata, registry, name, version);
}
}
bool detectWayland(FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(wayland, &instance.config.library.libWayland, false, "libwayland-client" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_get_fd, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_proxy_marshal_constructor, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_disconnect, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_registry_interface, false)
WaylandData data = {};
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_marshal_constructor_versioned, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_add_listener, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_destroy, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_display_roundtrip, false)
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_output_interface, false)
data.display = ffwl_display_connect(NULL);
if(data.display == NULL)
return false;
waylandDetectWM(ffwl_display_get_fd(data.display), result);
struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL);
if(registry == NULL)
{
ffwl_display_disconnect(data.display);
return false;
}
data.result = result;
struct wl_registry_listener registry_listener = {
.global = waylandGlobalAddListener,
.global_remove = (void*) stubListener
};
data.ffwl_proxy_add_listener(registry, (void(**)(void)) &registry_listener, &data);
data.ffwl_display_roundtrip(data.display);
data.ffwl_proxy_destroy(registry);
ffwl_display_disconnect(data.display);
//We successfully connected to wayland and detected the display.
//So we can set set the session type to wayland.
//This is used as an indicator that we are running wayland by the x11 backends.
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
return true;
}
void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const char *name)
{
WaylandDisplay* display = data;
if(ffStrStartsWith(name, "eDP-"))
display->type = FF_DISPLAY_TYPE_BUILTIN;
else if(ffStrStartsWith(name, "HDMI-"))
display->type = FF_DISPLAY_TYPE_EXTERNAL;
ffdsMatchDrmConnector(name, &display->edidName);
ffStrbufAppendS(&display->name, name);
}
void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output, const char* description)
{
WaylandDisplay* display = data;
while (*description == ' ') ++description;
if (!ffStrEquals(description, "Unknown Display") && !ffStrContains(description, "(null)"))
ffStrbufAppendS(&display->description, description);
}
#endif
void ffdsConnectWayland(FFDisplayServerResult* result)
{
//Wayland requires this to be set
if(getenv("XDG_RUNTIME_DIR") == NULL)
return;
#ifdef FF_HAVE_WAYLAND
if(detectWayland(result))
return;
#endif
const char* xdgSessionType = getenv("XDG_SESSION_TYPE");
//If XDG_SESSION_TYPE is set, and doesn't contain "wayland", we are probably not running in a wayland session.
if(xdgSessionType != NULL && !ffStrEqualsIgnCase(xdgSessionType, "wayland"))
return;
//If XDG_SESSION_TYPE is not set, check if WAYLAND_DISPLAY or WAYLAND_SOCKET is set.
//If not, there is no indicator for a wayland session
if(xdgSessionType == NULL && getenv("WAYLAND_DISPLAY") == NULL && getenv("WAYLAND_SOCKET") == NULL)
return;
//We are probably running a wayland compositor at this point,
//but fastfetch was compiled without the required library, or loading the library failed.
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
}
@@ -0,0 +1,57 @@
#pragma once
#ifdef FF_HAVE_WAYLAND
#include "common/library.h"
#include "util/stringUtils.h"
#include <wayland-client.h>
#include "../displayserver_linux.h"
typedef enum WaylandProtocolType
{
FF_WAYLAND_PROTOCOL_TYPE_NONE,
FF_WAYLAND_PROTOCOL_TYPE_GLOBAL,
FF_WAYLAND_PROTOCOL_TYPE_ZWLR,
} WaylandProtocolType;
typedef struct WaylandData
{
FFDisplayServerResult* result;
FF_LIBRARY_SYMBOL(wl_proxy_marshal_constructor_versioned)
FF_LIBRARY_SYMBOL(wl_proxy_add_listener)
FF_LIBRARY_SYMBOL(wl_proxy_destroy)
FF_LIBRARY_SYMBOL(wl_display_roundtrip)
struct wl_display* display;
const struct wl_interface* ffwl_output_interface;
WaylandProtocolType protocolType;
} WaylandData;
typedef struct WaylandDisplay
{
WaylandData* parent;
int32_t width;
int32_t height;
int32_t refreshRate;
double scale;
enum wl_output_transform transform;
FFDisplayType type;
FFstrbuf name;
FFstrbuf description;
FFstrbuf edidName;
void* internal;
} WaylandDisplay;
inline static void stubListener(void* data, ...)
{
(void) data;
}
void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const char *name);
void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output, const char* description);
void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
#endif
@@ -0,0 +1,160 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.22.0 */
/*
* Copyright © 2019 Purism SPC
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include <wayland-util.h>
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface zwlr_output_configuration_head_v1_interface;
extern const struct wl_interface zwlr_output_configuration_v1_interface;
extern const struct wl_interface zwlr_output_head_v1_interface;
extern const struct wl_interface zwlr_output_mode_v1_interface;
static const struct wl_interface *wlr_output_management_unstable_v1_types[] = {
NULL,
NULL,
NULL,
&zwlr_output_configuration_v1_interface,
NULL,
&zwlr_output_head_v1_interface,
&zwlr_output_mode_v1_interface,
&zwlr_output_mode_v1_interface,
&zwlr_output_configuration_head_v1_interface,
&zwlr_output_head_v1_interface,
&zwlr_output_head_v1_interface,
&zwlr_output_mode_v1_interface,
};
static const struct wl_message zwlr_output_manager_v1_requests[] = {
{ "create_configuration", "nu", wlr_output_management_unstable_v1_types + 3 },
{ "stop", "", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_manager_v1_events[] = {
{ "head", "n", wlr_output_management_unstable_v1_types + 5 },
{ "done", "u", wlr_output_management_unstable_v1_types + 0 },
{ "finished", "", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_manager_v1_interface = {
"zwlr_output_manager_v1", 4,
2, zwlr_output_manager_v1_requests,
3, zwlr_output_manager_v1_events,
};
static const struct wl_message zwlr_output_head_v1_requests[] = {
{ "release", "3", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_head_v1_events[] = {
{ "name", "s", wlr_output_management_unstable_v1_types + 0 },
{ "description", "s", wlr_output_management_unstable_v1_types + 0 },
{ "physical_size", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "mode", "n", wlr_output_management_unstable_v1_types + 6 },
{ "enabled", "i", wlr_output_management_unstable_v1_types + 0 },
{ "current_mode", "o", wlr_output_management_unstable_v1_types + 7 },
{ "position", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "transform", "i", wlr_output_management_unstable_v1_types + 0 },
{ "scale", "f", wlr_output_management_unstable_v1_types + 0 },
{ "finished", "", wlr_output_management_unstable_v1_types + 0 },
{ "make", "2s", wlr_output_management_unstable_v1_types + 0 },
{ "model", "2s", wlr_output_management_unstable_v1_types + 0 },
{ "serial_number", "2s", wlr_output_management_unstable_v1_types + 0 },
{ "adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_head_v1_interface = {
"zwlr_output_head_v1", 4,
1, zwlr_output_head_v1_requests,
14, zwlr_output_head_v1_events,
};
static const struct wl_message zwlr_output_mode_v1_requests[] = {
{ "release", "3", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_mode_v1_events[] = {
{ "size", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "refresh", "i", wlr_output_management_unstable_v1_types + 0 },
{ "preferred", "", wlr_output_management_unstable_v1_types + 0 },
{ "finished", "", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_mode_v1_interface = {
"zwlr_output_mode_v1", 3,
1, zwlr_output_mode_v1_requests,
4, zwlr_output_mode_v1_events,
};
static const struct wl_message zwlr_output_configuration_v1_requests[] = {
{ "enable_head", "no", wlr_output_management_unstable_v1_types + 8 },
{ "disable_head", "o", wlr_output_management_unstable_v1_types + 10 },
{ "apply", "", wlr_output_management_unstable_v1_types + 0 },
{ "test", "", wlr_output_management_unstable_v1_types + 0 },
{ "destroy", "", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_configuration_v1_events[] = {
{ "succeeded", "", wlr_output_management_unstable_v1_types + 0 },
{ "failed", "", wlr_output_management_unstable_v1_types + 0 },
{ "cancelled", "", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_configuration_v1_interface = {
"zwlr_output_configuration_v1", 4,
5, zwlr_output_configuration_v1_requests,
3, zwlr_output_configuration_v1_events,
};
static const struct wl_message zwlr_output_configuration_head_v1_requests[] = {
{ "set_mode", "o", wlr_output_management_unstable_v1_types + 11 },
{ "set_custom_mode", "iii", wlr_output_management_unstable_v1_types + 0 },
{ "set_position", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "set_transform", "i", wlr_output_management_unstable_v1_types + 0 },
{ "set_scale", "f", wlr_output_management_unstable_v1_types + 0 },
{ "set_adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_configuration_head_v1_interface = {
"zwlr_output_configuration_head_v1", 4,
6, zwlr_output_configuration_head_v1_requests,
0, NULL,
};
#endif
@@ -0,0 +1,193 @@
#ifdef FF_HAVE_WAYLAND
#include "wayland.h"
#include "wlr-output-management-unstable-v1-client-protocol.h"
static void waylandZwlrTransformListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, int32_t transform)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->transform = (enum wl_output_transform) transform;
}
static void waylandZwlrScaleListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, wl_fixed_t scale)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->scale = wl_fixed_to_double(scale);
}
typedef struct WaylandZwlrMode
{
int32_t width;
int32_t height;
int32_t refreshRate;
struct zwlr_output_mode_v1* pMode;
} WaylandZwlrMode;
static void waylandZwlrSizeListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_mode_v1 *zwlr_output_mode_v1, int32_t width, int32_t height)
{
WaylandZwlrMode* mode = (WaylandZwlrMode*) data;
mode->width = width;
mode->height = height;
}
static void waylandZwlrRefreshListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_mode_v1 *zwlr_output_mode_v1, int32_t rate)
{
WaylandZwlrMode* mode = (WaylandZwlrMode*) data;
mode->refreshRate = rate;
}
static const struct zwlr_output_mode_v1_listener modeListener = {
.size = waylandZwlrSizeListener,
.refresh = waylandZwlrRefreshListener,
.preferred = (void*) stubListener,
.finished = (void*) stubListener,
};
static void waylandZwlrModeListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, struct zwlr_output_mode_v1 *mode)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
WaylandZwlrMode* newMode = ffListAdd((FFlist*) wldata->internal);
newMode->pMode = mode;
// Strangely, the listener is called only in this function, but not in `waylandZwlrCurrentModeListener`
wldata->parent->ffwl_proxy_add_listener((struct wl_proxy *) mode, (void (**)(void)) &modeListener, newMode);
}
static void waylandZwlrCurrentModeListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, struct zwlr_output_mode_v1 *mode)
{
// waylandZwlrModeListener is always run before this
WaylandDisplay* wldata = (WaylandDisplay*) data;
WaylandZwlrMode* current = NULL;
FF_LIST_FOR_EACH(WaylandZwlrMode, m, *(FFlist*) wldata->internal)
{
if (m->pMode == mode)
{
current = m;
break;
}
}
wldata->width = current->width;
wldata->height = current->height;
wldata->refreshRate = current->refreshRate;
}
static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output_manager_v1 *zwlr_output_manager_v1, struct zwlr_output_head_v1 *head)
{
WaylandData* wldata = data;
const struct zwlr_output_head_v1_listener headListener = {
.name = (void*) ffWaylandOutputNameListener,
.description = (void*) ffWaylandOutputDescriptionListener,
.physical_size = (void*) stubListener,
.mode = waylandZwlrModeListener,
.enabled = (void*) stubListener,
.current_mode = waylandZwlrCurrentModeListener,
.position = (void*) stubListener,
.transform = waylandZwlrTransformListener,
.scale = waylandZwlrScaleListener,
.finished = (void*) stubListener,
.make = (void*) stubListener,
.model = (void*) stubListener,
.serial_number = (void*) stubListener,
.adaptive_sync = (void*) stubListener,
};
FF_LIST_AUTO_DESTROY modes = ffListCreate(sizeof(WaylandZwlrMode));
WaylandDisplay display = {
.parent = wldata,
.width = 0,
.height = 0,
.refreshRate = 0,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
.description = ffStrbufCreate(),
.edidName = ffStrbufCreate(),
.internal = &modes,
};
wldata->ffwl_proxy_add_listener((struct wl_proxy*) head, (void(**)(void)) &headListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
if(display.width <= 0 || display.height <= 0)
return;
uint32_t rotation;
switch(display.transform)
{
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_90:
rotation = 90;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
case WL_OUTPUT_TRANSFORM_180:
rotation = 180;
break;
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
case WL_OUTPUT_TRANSFORM_270:
rotation = 270;
break;
default:
rotation = 0;
break;
}
switch(rotation)
{
case 90:
case 270: {
int32_t temp = display.width;
display.width = display.height;
display.height = temp;
break;
}
default:
break;
}
ffdsAppendDisplay(wldata->result,
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale + 0.5),
(uint32_t) (display.height / display.scale + 0.5),
rotation,
display.edidName.length
? &display.edidName
: display.description.length
? &display.description
: &display.name,
display.type,
false,
0
);
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
// These must be released manually
FF_LIST_FOR_EACH(WaylandZwlrMode, m, modes)
wldata->ffwl_proxy_destroy((void*) m->pMode);
wldata->ffwl_proxy_destroy((void*) head);
}
void ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, version, name, zwlr_output_manager_v1_interface.name, version, NULL);
if(output == NULL)
return;
const struct zwlr_output_manager_v1_listener outputListener = {
.head = waylandHandleZwlrHead,
.done = (void*) stubListener,
.finished = (void*) stubListener,
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, wldata);
wldata->ffwl_display_roundtrip(wldata->display);
wldata->ffwl_proxy_destroy(output);
}
#endif
+10 -1
View File
@@ -75,7 +75,9 @@ static void applyPrettyNameIfWM(FFDisplayServerResult* result, const char* name)
ffStrEqualsIgnCase(name, "kwin_wayland_wrapper") ||
ffStrEqualsIgnCase(name, "kwin_x11") ||
ffStrEqualsIgnCase(name, "kwin_x11_wrapper") ||
ffStrEqualsIgnCase(name, "kwin")
ffStrEqualsIgnCase(name, "kwin") ||
ffStrEndsWithIgnCase(name, "-kwin_wayland") ||
ffStrEndsWithIgnCase(name, "-kwin_x11")
) ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_KWIN);
else if(
ffStrEqualsIgnCase(name, "gnome-shell") ||
@@ -231,6 +233,13 @@ static void applyPrettyNameIfDE(FFDisplayServerResult* result, const char* name)
ffStrbufSetS(&result->deProcessName, "dtsession");
ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_CDE);
}
else if(
ffStrEqualsIgnCase(name, "ukui-session")
) {
ffStrbufSetS(&result->deProcessName, "ukui-session");
ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_UKUI);
}
}
static void getWMProtocolNameFromEnv(FFDisplayServerResult* result)
+12 -13
View File
@@ -14,7 +14,7 @@ struct FFIgclData {
FF_LIBRARY_SYMBOL(ctlEnumMemoryModules)
FF_LIBRARY_SYMBOL(ctlMemoryGetState)
FF_LIBRARY_SYMBOL(ctlEnumFrequencyDomains)
FF_LIBRARY_SYMBOL(ctlFrequencyGetState)
FF_LIBRARY_SYMBOL(ctlFrequencyGetProperties)
bool inited;
ctl_api_handle_t apiHandle;
@@ -44,7 +44,7 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumMemoryModules)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumFrequencyDomains)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetState)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetProperties)
if (ffctlInit(&(ctl_init_args_t) {
.AppVersion = CTL_MAKE_VERSION(CTL_IMPL_MAJOR_VERSION, CTL_IMPL_MINOR_VERSION),
@@ -177,22 +177,21 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
if (result.frequency)
{
ctl_freq_handle_t freqs[16];
uint32_t freqCount = sizeof(freqs) / sizeof(freqs[0]);
if (igclData.ffctlEnumFrequencyDomains(device, &freqCount, freqs) == CTL_RESULT_SUCCESS && freqCount > 0)
ctl_freq_handle_t domains[16];
uint32_t domainCount = sizeof(domains) / sizeof(domains[0]);
if (igclData.ffctlEnumFrequencyDomains(device, &domainCount, domains) == CTL_RESULT_SUCCESS && domainCount > 0)
{
double sumValue = 0;
uint32_t availableCount = 0;
for (uint32_t iFreq = 0; iFreq < freqCount; iFreq++)
double maxValue = 0;
ctl_freq_properties_t props = { .Size = sizeof(props), .Version = 0 };
for (uint32_t iDomain = 0; iDomain < domainCount; iDomain++)
{
ctl_freq_state_t state = { .Size = sizeof(state), .Version = 0 };
if (igclData.ffctlFrequencyGetState(freqs[iFreq], &state) == CTL_RESULT_SUCCESS)
if (igclData.ffctlFrequencyGetProperties(domains[iDomain], &props) == CTL_RESULT_SUCCESS)
{
sumValue += state.actual;
availableCount++;
if (props.type == CTL_FREQ_DOMAIN_GPU && props.max > maxValue)
maxValue = props.max;
}
}
*result.frequency = (sumValue / availableCount) / 1000.;
*result.frequency = maxValue / 1000;
}
}
+269 -93
View File
@@ -1,6 +1,7 @@
#include "detection/gpu/gpu.h"
#include "detection/vulkan/vulkan.h"
#include "detection/temps/temps_linux.h"
#include "detection/cpu/cpu.h"
#include "common/io/io.h"
#include "common/properties.h"
#include "util/stringUtils.h"
@@ -14,22 +15,6 @@
#include <inttypes.h>
FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, uint32_t deviceClass)
{
const FFlist* tempsResult = ffDetectTemps();
FF_LIST_FOR_EACH(FFTempValue, tempValue, *tempsResult)
{
// FIXME: this code doesn't take multiGPUs into count
//The kernel exposes the device class multiplied by 256 for some reason
if(tempValue->deviceClass == deviceClass * 256)
{
gpu->temperature = tempValue->value;
return;
}
}
}
static void pciDetectDriver(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
{
ffStrbufAppendS(pciDir, "/driver");
@@ -54,12 +39,95 @@ static void pciDetectDriver(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer
}
}
static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
{
// https://www.kernel.org/doc/html/v5.10/gpu/amdgpu.html#mem-info-vis-vram-total
const uint32_t pciDirLen = pciDir->length;
ffStrbufAppendS(pciDir, "/hwmon/");
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDir->chars);
if (!dirp) return;
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_name[0] == '.') continue;
break;
}
if (!entry) return;
ffStrbufAppendS(pciDir, entry->d_name);
ffStrbufAppendC(pciDir, '/');
const uint32_t hwmonLen = pciDir->length;
ffStrbufAppendS(pciDir, "in1_input"); // Northbridge voltage in millivolts (APUs only)
if (ffPathExists(pciDir->chars, FF_PATHTYPE_FILE))
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;
}
ffStrbufSubstrBefore(pciDir, hwmonLen);
ffStrbufAppendS(pciDir, "freq1_input"); // The gfx/compute clock in hertz
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
gpu->frequency = (double) value / (1000 * 1000 * 1000);
if (options->driverSpecific)
{
ffStrbufSubstrBefore(pciDir, pciDirLen);
ffStrbufAppendS(pciDir, "/mem_info_vis_vram_total");
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
{
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;
}
}
}
}
static void pciDetectIntelSpecific(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
{
if (!ffStrbufEndsWithS(pciDir, "/device")) // Must be in `/sys/class/drm/cardN/device`
return;
// Works for Intel GPUs
// https://patchwork.kernel.org/project/intel-gfx/patch/1422039866-11572-3-git-send-email-ville.syrjala@linux.intel.com/
ffStrbufSetNS(buffer, pciDir->length - (uint32_t) strlen("device"), pciDir->chars);
ffStrbufAppendS(buffer, "gt_max_freq_mhz");
char str[16];
ssize_t len = ffReadFileData(buffer->chars, sizeof(str) - 1, str);
if (len > 1)
{
str[len] = '\0';
gpu->frequency = (double) strtoul(str, NULL, 10) / 1000.0;
}
if (ffStrbufStartsWithS(&gpu->name, "Intel "))
ffStrbufSubstrAfter(&gpu->name, (uint32_t) strlen("Intel "));
gpu->type = ffStrbufStartsWithIgnCaseS(&gpu->name, "Arc ") ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
static bool loadPciIds(FFstrbuf* pciids)
{
#ifdef FF_CUSTOM_PCI_IDS_PATH
ffReadFileBuffer(FF_STR(FF_CUSTOM_PCI_IDS_PATH), pciids);
if (pciids->length > 0) return true;
#endif
#else
ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/share/hwdata/pci.ids", pciids);
if (pciids->length > 0) return true;
@@ -70,95 +138,98 @@ static bool loadPciIds(FFstrbuf* pciids)
ffReadFileBuffer(FASTFETCH_TARGET_DIR_USR "/local/share/hwdata/pci.ids", pciids);
if (pciids->length > 0) return true;
#endif
return false;
}
static const char* pciDetectGPUs(const FFGPUOptions* options, FFlist* gpus)
static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf* buffer, FFstrbuf* drmDir)
{
//https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-pci
const char* pciDirPath = "/sys/bus/pci/devices/";
const uint32_t drmDirPathLength = drmDir->length;
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
uint8_t classId, subclassId;
if (sscanf(buffer->chars + strlen("pci:"), "v%8" SCNx32 "d%8" SCNx32 "sv%8" SCNx32 "sd%8" SCNx32 "bc%2" SCNx8 "sc%2" SCNx8, &vendorId, &deviceId, &subVendorId, &subDeviceId, &classId, &subclassId) != 6)
return "Invalid modalias string";
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDirPath);
if(dirp == NULL)
return "Failed to open `/sys/bus/pci/devices/`";
if (classId != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
return "Not a GPU device";
FF_STRBUF_AUTO_DESTROY pciDir = ffStrbufCreateA(64);
ffStrbufAppendS(&pciDir, pciDirPath);
char pciPath[PATH_MAX];
ssize_t pathLength = readlink(drmDir->chars, pciPath, sizeof(pciPath) - 1);
if (pathLength <= 0)
return "Unable to get PCI device path";
pciPath[pathLength] = '\0';
const char* pPciPath = strrchr(pciPath, '/');
if (pPciPath)
pPciPath++;
else
pPciPath = pciPath;
const uint32_t pciBaseDirLength = pciDir.length;
uint32_t pciDomain, pciBus, pciDevice, pciFunc;
if (sscanf(pPciPath, "%" SCNx32 ":%" SCNx32 ":%" SCNx32 ".%" SCNx32, &pciDomain, &pciBus, &pciDevice, &pciFunc) != 4)
return "Invalid PCI device path";
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY pciids = ffStrbufCreate();
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString((uint16_t) vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ((uint64_t) pciDomain << 6) | ((uint64_t) pciBus << 4) | (deviceId << 2) | pciFunc;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
{
if(entry->d_name[0] == '.')
continue;
ffStrbufSubstrBefore(&pciDir, pciBaseDirLength);
ffStrbufAppendS(&pciDir, entry->d_name);
const uint32_t pciDevDirLength = pciDir.length;
ffStrbufAppendS(&pciDir, "/modalias");
if (!ffReadFileBuffer(pciDir.chars, &buffer))
continue;
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
uint8_t classId, subclassId;
if (sscanf(buffer.chars, "pci:v%8" SCNx32 "d%8" SCNx32 "sv%8" SCNx32 "sd%8" SCNx32 "bc%2" SCNx8 "sc%2" SCNx8, &vendorId, &deviceId, &subVendorId, &subDeviceId, &classId, &subclassId) != 6)
continue;
if (classId != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
continue;
uint32_t pciDomain, pciBus, pciDevice, pciFunc;
if (sscanf(entry->d_name, "%" SCNx32 ":%" SCNx32 ":%" SCNx32 ".%" SCNx32, &pciDomain, &pciBus, &pciDevice, &pciFunc) != 4)
continue;
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString((uint16_t) vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ((uint64_t) pciDomain << 6) | ((uint64_t) pciBus << 4) | (deviceId << 2) | pciFunc;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
ffStrbufAppendS(drmDir, "/revision");
if (ffReadFileBuffer(drmDir->chars, buffer))
{
ffStrbufAppendS(&pciDir, "/revision");
if (ffReadFileBuffer(pciDir.chars, &buffer))
char* pend;
uint64_t revision = strtoul(buffer->chars, &pend, 16);
if (pend != buffer->chars)
{
char* pend;
uint64_t revision = strtoul(buffer.chars, &pend, 16);
if (pend != buffer.chars)
{
char query[32];
snprintf(query, sizeof(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision);
ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name);
}
char query[32];
snprintf(query, sizeof(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision);
#ifdef FF_CUSTOM_AMDGPU_IDS_PATH
ffParsePropFile(FF_STR(FF_CUSTOM_AMDGPU_IDS_PATH), query, &gpu->name);
#else
ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name);
#endif
}
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
}
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
}
if (gpu->name.length == 0)
if (gpu->name.length == 0)
{
static FFstrbuf pciids;
if (pciids.chars == NULL)
{
if (!pciids.length)
loadPciIds(&pciids);
ffGPUParsePciIds(&pciids, subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
ffStrbufInit(&pciids);
loadPciIds(&pciids);
}
ffGPUParsePciIds(&pciids, subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
}
pciDetectDriver(gpu, &pciDir, &buffer);
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
pciDetectDriver(gpu, drmDir, buffer);
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
{
pciDetectAmdSpecific(options, gpu, drmDir, buffer);
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
{
pciDetectIntelSpecific(gpu, drmDir, buffer);
ffStrbufSubstrBefore(drmDir, drmDirPathLength);
}
else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA)
{
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
if (options->temp || options->driverSpecific)
{
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
@@ -175,16 +246,118 @@ static const char* pciDetectGPUs(const FFGPUOptions* options, FFlist* gpus)
.type = &gpu->type,
.frequency = &gpu->frequency,
}, "libnvidia-ml.so");
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
#ifdef __linux__
if(options->temp && gpu->temperature != gpu->temperature)
pciDetectTemp(gpu, ((uint32_t) classId << 8) + subclassId);
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla"))
gpu->type = FF_GPU_TYPE_DISCRETE;
}
}
return NULL;
}
FF_MAYBE_UNUSED static const char* detectAsahi(FFlist* gpus, FFstrbuf* buffer, FFstrbuf* drmDir)
{
uint32_t index = ffStrbufFirstIndexS(buffer, "apple,agx-t");
if (index == buffer->length) return "display-subsystem?";
index += (uint32_t) strlen("apple,agx-t");
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
gpu->deviceId = strtoul(buffer->chars + index, NULL, 10);
ffStrbufInitStatic(&gpu->name, ffCPUAppleCodeToName((uint32_t) gpu->deviceId));
ffStrbufInitStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_INTEGRATED;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
pciDetectDriver(gpu, drmDir, buffer);
return NULL;
}
static const char* drmDetectGPUs(const FFGPUOptions* options, FFlist* gpus)
{
FF_STRBUF_AUTO_DESTROY drmDir = ffStrbufCreateA(64);
ffStrbufAppendS(&drmDir, "/sys/class/drm/");
const uint32_t drmDirLength = drmDir.length;
FF_AUTO_CLOSE_DIR DIR* dir = opendir(drmDir.chars);
if(dir == NULL)
return "Failed to open `/sys/class/drm/`";
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
struct dirent* entry;
while ((entry = readdir(dir)) != NULL)
{
if (!ffStrStartsWith(entry->d_name, "card") ||
strchr(entry->d_name + 4, '-') != NULL)
continue;
ffStrbufAppendS(&drmDir, entry->d_name);
ffStrbufAppendS(&drmDir, "/device/modalias");
if (!ffReadFileBuffer(drmDir.chars, &buffer))
continue;
ffStrbufSubstrBefore(&drmDir, drmDir.length - (uint32_t) strlen("/modalias"));
if (ffStrbufStartsWithS(&buffer, "pci:"))
detectPci(options, gpus, &buffer, &drmDir);
#ifdef __aarch64__
else if (ffStrbufStartsWithS(&buffer, "of:"))
detectAsahi(gpus, &buffer, &drmDir);
#endif
ffStrbufSubstrBefore(&drmDir, drmDirLength);
}
return NULL;
}
static const char* pciDetectGPUs(const FFGPUOptions* options, FFlist* gpus)
{
//https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-pci
const char* pciDirPath = "/sys/bus/pci/devices/";
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(pciDirPath);
if(dirp == NULL)
return "Failed to open `/sys/bus/pci/devices/`";
FF_STRBUF_AUTO_DESTROY pciDir = ffStrbufCreateA(64);
ffStrbufAppendS(&pciDir, pciDirPath);
const uint32_t pciBaseDirLength = pciDir.length;
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
if(entry->d_name[0] == '.')
continue;
ffStrbufSubstrBefore(&pciDir, pciBaseDirLength);
ffStrbufAppendS(&pciDir, entry->d_name);
const uint32_t pciDevDirLength = pciDir.length;
ffStrbufAppendS(&pciDir, "/modalias");
if (!ffReadFileBuffer(pciDir.chars, &buffer))
continue;
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
assert(ffStrbufStartsWithS(&buffer, "pci:"));
detectPci(options, gpus, &buffer, &pciDir);
ffStrbufSubstrBefore(&pciDir, pciBaseDirLength);
}
return NULL;
@@ -194,9 +367,12 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
#ifdef FF_HAVE_DIRECTX_HEADERS
const char* ffGPUDetectByDirectX(const FFGPUOptions* options, FFlist* gpus);
if (!ffGPUDetectByDirectX(options, gpus))
if (ffGPUDetectByDirectX(options, gpus) == NULL)
return NULL;
#endif
if (drmDetectGPUs(options, gpus) == NULL && gpus->length > 0)
return NULL;
return pciDetectGPUs(options, gpus);
}
+3 -3
View File
@@ -11,7 +11,7 @@ struct FFNvmlData {
FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperature)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores)
FF_LIBRARY_SYMBOL(nvmlDeviceGetClockInfo)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxClockInfo)
FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand)
bool inited;
@@ -32,7 +32,7 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperature)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetClockInfo)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxClockInfo)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand)
if (ffnvmlInit_v2() != NVML_SUCCESS)
@@ -122,7 +122,7 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
if (result.frequency)
{
uint32_t clockMHz;
if (nvmlData.ffnvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &clockMHz) == NVML_SUCCESS)
if (nvmlData.ffnvmlDeviceGetMaxClockInfo(device, NVML_CLOCK_GRAPHICS, &clockMHz) == NVML_SUCCESS)
*result.frequency = clockMHz / 1000.;
}
+6 -14
View File
@@ -78,20 +78,12 @@ const char* ffDetectHost(FFHostResult* host)
ffStrbufAppendF(&host->name, " - %s", wslDistroName);
ffStrbufAppendS(&host->family, "WSL");
FF_STRBUF_AUTO_DESTROY wslVer = ffStrbufCreate(); //Wide characters
if(!ffProcessAppendStdOut(&wslVer, (char* const[]){
"wsl.exe",
"--version",
NULL
}) && wslVer.length > 0)
{
ffStrbufSubstrBeforeFirstC(&wslVer, '\r'); //CRLF
ffStrbufSubstrAfterLastC(&wslVer, ' ');
for(uint32_t i = 0; i < wslVer.length; ++i) {
if(wslVer.chars[i]) //don't append \0
ffStrbufAppendC(&host->version, wslVer.chars[i]);
}
}
ffProcessAppendStdOut(&host->version, (char* const[]){
"wslinfo",
"--wsl-version",
"-n",
NULL,
}); // supported in 2.2.3 and later
}
}
+81 -21
View File
@@ -2,11 +2,15 @@
#include "common/properties.h"
#include "common/parsing.h"
#include "common/io/io.h"
#include "common/processing.h"
#include "util/stringUtils.h"
#include <string.h>
#include <stdlib.h>
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
static inline bool allRelevantValuesSet(const FFOSResult* result)
{
return result->id.length > 0
@@ -15,18 +19,25 @@ static inline bool allRelevantValuesSet(const FFOSResult* result)
;
}
static bool parseFile(const char* fileName, FFOSResult* result)
static bool parseLsbRelease(const char* fileName, FFOSResult* result)
{
return ffParsePropFileValues(fileName, 13, (FFpropquery[]) {
{"NAME =", &result->name},
{"DISTRIB_DESCRIPTION =", &result->prettyName},
{"PRETTY_NAME =", &result->prettyName},
return ffParsePropFileValues(fileName, 4, (FFpropquery[]) {
{"DISTRIB_ID =", &result->id},
{"DISTRIB_DESCRIPTION =", &result->prettyName},
{"DISTRIB_RELEASE =", &result->version},
{"DISTRIB_CODENAME =", &result->codename},
});
}
static bool parseOsRelease(const char* fileName, FFOSResult* result)
{
return ffParsePropFileValues(fileName, 10, (FFpropquery[]) {
{"PRETTY_NAME =", &result->prettyName},
{"NAME =", &result->name},
{"ID =", &result->id},
{"ID_LIKE =", &result->idLike},
{"VARIANT =", &result->variant},
{"VARIANT_ID =", &result->variantID},
{"DISTRIB_RELEASE =", &result->version},
{"VERSION =", &result->version},
{"VERSION_ID =", &result->versionID},
{"VERSION_CODENAME =", &result->codename},
@@ -132,15 +143,48 @@ static void getDebianVersion(FFOSResult* result)
ffStrbufSet(&result->versionID, &debianVersion);
}
static bool detectDebianDerived(FFOSResult* result)
{
if (ffStrbufStartsWithS(&result->prettyName, "Armbian ")) // Armbian 24.2.1 bookworm
{
ffStrbufSetS(&result->name, "Armbian");
ffStrbufSetS(&result->id, "armbian");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufClear(&result->versionID);
uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1;
uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' ');
ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart);
return true;
}
else if (ffPathExists("/usr/bin/pveversion", FF_PATHTYPE_FILE))
{
ffStrbufSetS(&result->id, "pve");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufSetS(&result->name, "Proxmox VE");
ffStrbufClear(&result->versionID);
if (ffProcessAppendStdOut(&result->versionID, (char* const[]) {
"/usr/bin/pveversion",
NULL,
}) == NULL) // pve-manager/8.2.2/9355359cd7afbae4 (running kernel: 6.8.4-2-pve)
{
ffStrbufSubstrBeforeLastC(&result->versionID, '/');
ffStrbufSubstrAfterFirstC(&result->versionID, '/');
}
ffStrbufSetF(&result->prettyName, "Proxmox VE %s", result->versionID.chars);
return true;
}
return false;
}
static void detectOS(FFOSResult* os)
{
if(instance.config.general.osFile.length > 0)
{
parseFile(instance.config.general.osFile.chars, os);
return;
}
#ifdef FF_CUSTOM_OS_RELEASE_PATH
parseOsRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
parseLsbRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
return;
#endif
if(instance.config.general.escapeBedrock && parseFile(FASTFETCH_TARGET_DIR_ROOT"/bedrock"FASTFETCH_TARGET_DIR_ETC"/bedrock-release", os))
if(instance.config.general.escapeBedrock && parseOsRelease(FASTFETCH_TARGET_DIR_ROOT "/bedrock" FASTFETCH_TARGET_DIR_ETC "/bedrock-release", os))
{
if(os->id.length == 0)
ffStrbufAppendS(&os->id, "bedrock");
@@ -151,18 +195,31 @@ static void detectOS(FFOSResult* os)
if(os->prettyName.length == 0)
ffStrbufAppendS(&os->prettyName, "Bedrock Linux");
return;
if(parseOsRelease("/bedrock" FASTFETCH_TARGET_DIR_ETC "/os-release", os) && allRelevantValuesSet(os))
return;
}
parseFile(FASTFETCH_TARGET_DIR_ETC"/os-release", os);
if(allRelevantValuesSet(os))
// Refer: https://gist.github.com/natefoo/814c5bf936922dad97ff
// Hack for MX Linux. See #847
if(parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os))
{
if (ffStrbufEqualS(&os->id, "MX"))
{
ffStrbufSetStatic(&os->name, "MX");
ffStrbufSetStatic(&os->idLike, "debian");
return;
}
// For archlinux
if (ffStrbufEqualS(&os->version, "rolling"))
ffStrbufClear(&os->version);
}
if(parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os) && allRelevantValuesSet(os))
return;
parseFile(FASTFETCH_TARGET_DIR_USR"/lib/os-release", os);
if(allRelevantValuesSet(os))
return;
parseFile(FASTFETCH_TARGET_DIR_ETC"/lsb-release", os);
parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os);
}
void ffDetectOSImpl(FFOSResult* os)
@@ -172,5 +229,8 @@ void ffDetectOSImpl(FFOSResult* os)
if(ffStrbufIgnCaseEqualS(&os->id, "ubuntu"))
getUbuntuFlavour(os);
else if(ffStrbufIgnCaseEqualS(&os->id, "debian"))
getDebianVersion(os);
{
if (!detectDebianDerived(os))
getDebianVersion(os);
}
}
+1
View File
@@ -26,6 +26,7 @@ typedef struct FFPackagesResult
uint32_t rpm;
uint32_t scoop;
uint32_t snap;
uint32_t sorcery;
uint32_t winget;
uint32_t xbps;
+160 -12
View File
@@ -118,28 +118,146 @@ static uint32_t countFilesRecursive(FFstrbuf* baseDir, const char* dirname, cons
return sum;
}
static bool isValidNixPkg(FFstrbuf* pkg)
{
if (!ffPathExists(pkg->chars, FF_PATHTYPE_DIRECTORY))
return false;
ffStrbufSubstrAfterLastC(pkg, '/');
if (
ffStrbufStartsWithS(pkg, "nixos-system-nixos-") ||
ffStrbufEndsWithS(pkg, "-doc") ||
ffStrbufEndsWithS(pkg, "-man") ||
ffStrbufEndsWithS(pkg, "-info") ||
ffStrbufEndsWithS(pkg, "-dev") ||
ffStrbufEndsWithS(pkg, "-bin")
) return false;
enum { START, DIGIT, DOT, MATCH } state = START;
for (uint32_t i = 0; i < pkg->length; i++)
{
char c = pkg->chars[i];
switch (state)
{
case START:
if (c >= '0' && c <= '9')
state = DIGIT;
break;
case DIGIT:
if (c >= '0' && c <= '9')
continue;
if (c == '.')
state = DOT;
else
state = START;
break;
case DOT:
if (c >= '0' && c <= '9')
state = MATCH;
else
state = START;
break;
case MATCH:
break;
}
}
return state == MATCH;
}
static bool checkNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t* count)
{
if (!ffPathExists(cacheDir->chars, FF_PATHTYPE_FILE))
return false;
FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreate();
if (!ffReadFileBuffer(cacheDir->chars, &cacheContent))
return false;
// Format: <hash>\n<count>
uint32_t split = ffStrbufFirstIndexC(&cacheContent, '\n');
if (split == cacheContent.length)
return false;
ffStrbufSetNS(hash, split, cacheContent.chars);
*count = (uint32_t)atoi(cacheContent.chars + split + 1);
return true;
}
static bool writeNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t count)
{
FF_STRBUF_AUTO_DESTROY cacheContent = ffStrbufCreateCopy(hash);
ffStrbufAppendF(&cacheContent, "\n%u", count);
return ffWriteFileBuffer(cacheDir->chars, &cacheContent);
}
static uint32_t getNixPackagesImpl(char* path)
{
//Nix detection is kinda slow, so we only do it if the dir exists
if(!ffPathExists(path, FF_PATHTYPE_DIRECTORY))
return 0;
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(128);
FF_STRBUF_AUTO_DESTROY cacheDir = ffStrbufCreateCopy(&instance.state.platform.cacheDir);
ffStrbufEnsureEndsWithC(&cacheDir, '/');
ffStrbufAppendS(&cacheDir, "fastfetch/packages/nix");
ffStrbufAppendS(&cacheDir, path);
//https://github.com/fastfetch-cli/fastfetch/issues/195#issuecomment-1191748222
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(255);
ffStrbufAppendS(&command, "for x in $(nix-store --query --requisites ");
ffStrbufAppendS(&command, path);
ffStrbufAppendS(&command, "); do if [ -d $x ]; then echo $x ; fi ; done | cut -d- -f2- | egrep '([0-9]{1,}\\.)+[0-9]{1,}' | egrep -v '\\-doc$|\\-man$|\\-info$|\\-dev$|\\-bin$|^nixos-system-nixos-' | uniq | wc -l");
//Check the hash first to determine if we need to recompute the count
FF_STRBUF_AUTO_DESTROY hash = ffStrbufCreateA(64);
FF_STRBUF_AUTO_DESTROY cacheHash = ffStrbufCreateA(64);
uint32_t count = 0;
ffProcessAppendStdOut(&output, (char* const[]) {
"sh",
"-c",
command.chars,
ffProcessAppendStdOut(&hash, (char* const[]) {
"nix-store",
"--query",
"--hash",
path,
NULL
});
return (uint32_t) strtol(output.chars, NULL, 10);
if (checkNixCache(&cacheDir, &cacheHash, &count) && ffStrbufEqual(&hash, &cacheHash))
return count;
//Cache is invalid, recompute the count
count = 0;
//Implementation based on bash script from here:
//https://github.com/fastfetch-cli/fastfetch/issues/195#issuecomment-1191748222
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(1024);
ffProcessAppendStdOut(&output, (char* const[]) {
"nix-store",
"--query",
"--requisites",
path,
NULL
});
uint32_t lineLength = 0;
for (uint32_t i = 0; i < output.length; i++)
{
if (output.chars[i] != '\n')
{
lineLength++;
continue;
}
output.chars[i] = '\0';
FFstrbuf line = {
.allocated = 0,
.length = lineLength,
.chars = output.chars + i - lineLength
};
if (isValidNixPkg(&line))
count++;
lineLength = 0;
}
writeNixCache(&cacheDir, &hash, count);
return count;
}
static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname)
@@ -315,6 +433,7 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
if (!(options->disabled & FF_PACKAGES_FLAG_PALUDIS_BIT)) packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2");
if (!(options->disabled & FF_PACKAGES_FLAG_OPKG_BIT)) packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:"); // openwrt
if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT)) packageCounts->am = getAM(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_SORCERY_BIT)) packageCounts->sorcery += getNumStrings(baseDir, "/var/state/sorcery/packages", ":installed:");
}
static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
@@ -383,7 +502,36 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
{
// 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");
}
// check if $XDG_STATE_HOME/nix/profile exists
else
{
FF_STRBUF_AUTO_DESTROY stateDir = ffStrbufCreate();
const char* stateHome = getenv("XDG_STATE_HOME");
if(ffStrSet(stateHome))
{
ffStrbufSetS(&stateDir, stateHome);
ffStrbufEnsureEndsWithC(&stateDir, '/');
}
else
{
ffStrbufSet(&stateDir, &instance.state.platform.homeDir);
ffStrbufAppendS(&stateDir, ".local/state/");
}
ffStrbufSet(&profilePath, &stateDir);
ffStrbufAppendS(&profilePath, "nix/profile");
result->nixUser = getNixPackages(&stateDir, "nix/profile");
}
}
if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT))
result->flatpakUser = getFlatpak(&baseDir, "/.local/share/flatpak");
}
+1 -1
View File
@@ -28,7 +28,7 @@ void ffPreparePublicIp(FFPublicIpOptions* options)
fputs("Error: only http: protocol is supported. Use `Command` module with `curl` if needed\n", stderr);
exit(1);
}
ffStrbufSubstrAfter(&host, hostStartIndex + (strlen("://") - 1));
ffStrbufSubstrAfter(&host, hostStartIndex + (uint32_t) (strlen("://") - 1));
}
uint32_t pathStartIndex = ffStrbufFirstIndexC(&host, '/');
+5 -14
View File
@@ -7,20 +7,11 @@
const char* ffDetectSwap(FFSwapResult* swap)
{
ULONG size = sizeof(SYSTEM_PAGEFILE_INFORMATION);
SYSTEM_PAGEFILE_INFORMATION* FF_AUTO_FREE pstart = (SYSTEM_PAGEFILE_INFORMATION*)malloc(size);
while(true)
{
NTSTATUS status = NtQuerySystemInformation(SystemPagefileInformation, pstart, size, &size);
if(status == STATUS_INFO_LENGTH_MISMATCH)
{
if(!(pstart = (SYSTEM_PAGEFILE_INFORMATION*)realloc(pstart, size)))
return "realloc(pstart, size) failed";
}
else if(!NT_SUCCESS(status))
return "NtQuerySystemInformation(SystemPagefileInformation, size) failed";
break;
}
uint8_t buffer[1024];
ULONG size = sizeof(buffer);
SYSTEM_PAGEFILE_INFORMATION* pstart = (SYSTEM_PAGEFILE_INFORMATION*) buffer;
if(!NT_SUCCESS(NtQuerySystemInformation(SystemPagefileInformation, pstart, size, &size)))
return "NtQuerySystemInformation(SystemPagefileInformation, size) failed";
uint32_t pageSize = instance.state.platform.pageSize;
swap->bytesUsed = (uint64_t)pstart->TotalUsed * pageSize;
+48 -2
View File
@@ -5,6 +5,9 @@
#include "util/stringUtils.h"
#include <ctype.h>
#ifdef __FreeBSD__
#include <paths.h>
#endif
#ifdef _WIN32
@@ -223,7 +226,12 @@ static bool getShellVersionGeneric(FFstrbuf* exe, const char* exeName, FFstrbuf*
bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
{
if(strcasecmp(exeName, "bash") == 0 || strcasecmp(exeName, "sh") == 0)
if (!instance.config.display.tsVersion) return false;
if(ffStrEqualsIgnCase(exeName, "sh")) // #849
return false;
if(strcasecmp(exeName, "bash") == 0)
return getShellVersionBash(exe, version);
if(strcasecmp(exeName, "zsh") == 0)
return getExeVersionGeneral(exe, version); //zsh 5.9 (arm-apple-darwin21.3.0)
@@ -469,6 +477,42 @@ static bool getTerminalVersionZellij(FFstrbuf* exe, FFstrbuf* version)
return version->length > 0;
}
#ifndef _WIN32
static bool getTerminalVersionKitty(FFstrbuf* exe, FFstrbuf* version)
{
#if defined(__linux__) || defined(__FreeBSD__)
// kitty is written in python. `kitty --version` can be expensive
char buffer[1024] = {};
if (
#ifdef __linux__
ffReadFileData(FASTFETCH_TARGET_DIR_USR "/lib64/kitty/kitty/constants.py", sizeof(buffer) - 1, buffer) ||
ffReadFileData(FASTFETCH_TARGET_DIR_USR "/lib/kitty/kitty/constants.py", sizeof(buffer) - 1, buffer)
#else
ffReadFileData(_PATH_LOCALBASE "/share/kitty/kitty/constants.py", sizeof(buffer) - 1, buffer)
#endif
)
{
// Starts from version 0.17.0
// https://github.com/kovidgoyal/kitty/blob/master/kitty/constants.py#L25
const char* p = memmem(buffer, sizeof(buffer) - 1, "version: Version = Version(", strlen("version: Version = Version("));
if (p)
{
p += strlen("version: Version = Version(");
int major, minor, patch;
if (sscanf(p, "%d,%d,%d", &major, &minor, &patch) == 3)
{
ffStrbufSetF(version, "%d.%d.%d", major, minor, patch);
return true;
}
}
}
#endif
//kitty 0.21.2 created by Kovid Goyal
return getExeVersionGeneral(exe, version);
}
#endif
#ifdef _WIN32
static bool getTerminalVersionWindowsTerminal(FFstrbuf* exe, FFstrbuf* version)
@@ -500,6 +544,8 @@ static bool getTerminalVersionConEmu(FFstrbuf* exe, FFstrbuf* version)
bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
{
if (!instance.config.display.tsVersion) return false;
#ifdef __ANDROID__
if(ffStrbufEqualS(processName, "com.termux"))
@@ -576,7 +622,7 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe
#ifndef _WIN32
if(ffStrbufIgnCaseEqualS(processName, "kitty"))
return getExeVersionGeneral(exe, version); //kitty 0.21.2 created by Kovid Goyal
return getTerminalVersionKitty(exe, version);
if (ffStrbufIgnCaseEqualS(processName, "Tabby") && getExeVersionRaw(exe, version))
return true;
@@ -214,31 +214,44 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
pid_t ppid = 0;
int32_t tty = -1;
const char* userShellName = NULL;
{
uint32_t index = ffStrbufLastIndexC(&instance.state.platform.userShell, '/');
if (index == instance.state.platform.userShell.length)
userShellName = instance.state.platform.userShell.chars;
else
userShellName = instance.state.platform.userShell.chars + index + 1;
}
while (getProcessNameAndPpid(pid, name, &ppid, &tty) == NULL)
{
//Common programs that are between terminal and own process, but are not the shell
if(
// tty < 0 || //A shell should connect to a tty
ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell
ffStrEquals(name, "sudo") ||
ffStrEquals(name, "su") ||
ffStrEquals(name, "strace") ||
ffStrEquals(name, "sshd") ||
ffStrEquals(name, "gdb") ||
ffStrEquals(name, "lldb") ||
ffStrEquals(name, "lldb-mi") ||
ffStrEquals(name, "login") ||
ffStrEquals(name, "ltrace") ||
ffStrEquals(name, "perf") ||
ffStrEquals(name, "guake-wrapped") ||
ffStrEquals(name, "time") ||
ffStrContainsIgnCase(name, "debug") ||
ffStrContainsIgnCase(name, "not-found") ||
ffStrEndsWith(name, ".sh")
)
if (!ffStrEquals(userShellName, name))
{
pid = ppid;
continue;
//Common programs that are between terminal and own process, but are not the shell
if(
// tty < 0 || //A shell should connect to a tty
ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell
ffStrEquals(name, "sudo") ||
ffStrEquals(name, "su") ||
ffStrEquals(name, "strace") ||
ffStrEquals(name, "sshd") ||
ffStrEquals(name, "gdb") ||
ffStrEquals(name, "lldb") ||
ffStrEquals(name, "lldb-mi") ||
ffStrEquals(name, "login") ||
ffStrEquals(name, "ltrace") ||
ffStrEquals(name, "perf") ||
ffStrEquals(name, "guake-wrapped") ||
ffStrEquals(name, "time") ||
ffStrEquals(name, "hyfetch") || //when hyfetch uses fastfetch as backend
ffStrContainsIgnCase(name, "debug") ||
ffStrContainsIgnCase(name, "not-found") ||
ffStrEndsWith(name, ".sh")
)
{
pid = ppid;
continue;
}
}
result->pid = (uint32_t) pid;
@@ -470,14 +483,12 @@ static void setShellInfoDetails(FFShellResult* result)
static void setTerminalInfoDetails(FFTerminalResult* result)
{
if(result->exeName[0] == '.' && ffStrEndsWith(result->exeName, "-wrapped"))
if(ffStrbufStartsWithC(&result->processName, '.') && ffStrbufEndsWithS(&result->processName, "-wrapped"))
{
// For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428
// We use processName when detecting version and font, overriding it for simplification
ffStrbufSetNS(
&result->processName,
(uint32_t) (strlen(result->exeName) - strlen(".-wrapped")),
result->exeName + 1);
ffStrbufSubstrBefore(&result->processName, result->processName.length - (uint32_t) strlen("-wrapped"));
ffStrbufSubstrAfter(&result->processName, 0);
}
if(ffStrbufEqualS(&result->processName, "wezterm-gui"))
@@ -508,6 +519,11 @@ static void setTerminalInfoDetails(FFTerminalResult* result)
else if(ffStrbufEqualS(&result->processName, "iTerm.app") || ffStrbufStartsWithS(&result->processName, "iTermServer-"))
ffStrbufInitStatic(&result->prettyName, "iTerm");
else if(ffStrbufEndsWithS(&result->exePath, "Terminal.app/Contents/MacOS/Terminal"))
{
ffStrbufSetStatic(&result->processName, "Apple_Terminal"); // for terminal font detection
ffStrbufInitStatic(&result->prettyName, "Apple Terminal");
}
else if(ffStrbufEqualS(&result->processName, "Apple_Terminal"))
ffStrbufInitStatic(&result->prettyName, "Apple Terminal");
else if(ffStrbufEqualS(&result->processName, "WarpTerminal"))
@@ -104,6 +104,7 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid)
ffStrbufIgnCaseEqualS(&result->prettyName, "python") || // python on windows generates shim executables
ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || // scoop warps the real binaries with a "shim" exe
ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "hyfetch") || // uses fastfetch as backend
ffStrbufContainIgnCaseS(&result->prettyName, "debug") ||
ffStrbufContainIgnCaseS(&result->prettyName, "time") ||
ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014
+2 -1
View File
@@ -337,7 +337,8 @@ static const char* detectWifiWithIoctls(FFlist* result)
const char* ffDetectWifi(FFlist* result)
{
#ifdef FF_HAVE_LIBNM
if(!detectWifiWithLibnm(result))
detectWifiWithLibnm(result);
if(result->length) // NetworkManager not enabled? #811
return NULL;
#endif
+32 -33
View File
@@ -249,7 +249,7 @@ static void printCommandHelp(const char* command)
puts(FASTFETCH_DATATEXT_HELP_COLOR);
else if(ffStrEqualsIgnCase(command, "format"))
puts(FASTFETCH_DATATEXT_HELP_FORMAT);
else if(isalpha(command[0]) && ffStrEndsWithIgnCase(command, "-format")) // <module>-format
else if(ffCharIsEnglishAlphabet(command[0]) && ffStrEndsWithIgnCase(command, "-format")) // <module>-format
printCommandFormatHelp(command);
else if(!printSpecificCommandHelp(command))
fprintf(stderr, "Error: No specific help for command '%s' provided\n", command);
@@ -321,21 +321,42 @@ static void parseOption(FFdata* data, const char* key, const char* value);
static bool parseJsoncFile(const char* path)
{
yyjson_read_err error;
yyjson_doc* doc = yyjson_read_file(path, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INF_AND_NAN, NULL, &error);
if (!doc)
assert(!instance.state.configDoc);
{
if (error.code != YYJSON_READ_ERROR_FILE_OPEN)
yyjson_read_err error;
instance.state.configDoc = yyjson_read_file(path, YYJSON_READ_ALLOW_COMMENTS | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_INF_AND_NAN, NULL, &error);
if (!instance.state.configDoc)
{
fprintf(stderr, "Error: failed to parse JSON config file `%s` at pos %zu: %s\n", path, error.pos, error.msg);
if (error.code != YYJSON_READ_ERROR_FILE_OPEN)
{
fprintf(stderr, "Error: failed to parse JSON config file `%s` at pos %zu: %s\n", path, error.pos, error.msg);
exit(477);
}
return false;
}
}
{
const char* error = NULL;
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
if (!yyjson_is_obj(root))
error = "Invalid JSON config format. Root value must be an object";
if (
error ||
(error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) ||
(error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) ||
(error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) ||
(error = ffOptionsParseLibraryJsonConfig(&instance.config.library, root)) ||
false
) {
fprintf(stderr, "JsonConfig Error: %s\n", error);
exit(477);
}
return false;
}
if (instance.state.configDoc)
yyjson_doc_free(instance.state.configDoc); // for `--load-config`
instance.state.configDoc = doc;
return true;
}
@@ -779,27 +800,6 @@ static void parseArguments(FFdata* data, int argc, char** argv, void (*parser)(F
static void run(FFdata* data)
{
if (instance.state.configDoc)
{
const char* error = NULL;
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
if (!yyjson_is_obj(root))
error = "Invalid JSON config format. Root value must be an object";
if (
error ||
(error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) ||
(error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) ||
(error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) ||
(error = ffOptionsParseLibraryJsonConfig(&instance.config.library, root)) ||
false
) {
fprintf(stderr, "JsonConfig Error: %s\n", error);
exit(477);
}
}
const bool useJsonConfig = data->structure.length == 0 && instance.state.configDoc;
if (useJsonConfig)
@@ -863,6 +863,7 @@ static void writeConfigFile(FFdata* data, const FFstrbuf* filename)
int main(int argc, char** argv)
{
ffInitInstance();
atexit(ffDestroyInstance);
//Data stores things only needed for the configuration of fastfetch
FFdata data = {
@@ -888,6 +889,4 @@ int main(int argc, char** argv)
ffStrbufDestroy(&customValue->value);
}
ffListDestroy(&data.customValues);
ffDestroyInstance();
}
+22
View File
@@ -0,0 +1,22 @@
..
`:]x**j-,'
.,+t***********z\<"
?******************;
'*n` .'`^,;;,^`'. ,cc.
-<. .[l
// ^^ ^^ \\
!^ $2^^$1 ":
'tt}` $2!~]rj_$1 ")t/.
Itttt?' $2~~]rr]$1 `{tttt,
\tttttt!""I$2_]r($1"""~tttttt1
'_tttttttttttt$2)f$1tttttttttttti.
\*ztttttttttttttttttttttttttf**[
l**c)tttttttttttttttttttttttt(z**,
.z*x.`tttttttttttttttttttttttt.`u*n
>` (tttttttttttttttttttttt] "I
,tttttttttttttttttttttt`
./ttttt$2f$1tttttttt$2f$1ttttt(
'I)$2))(\()($1tt$2))|\()($1{;'
$2.~~~~~~~|)~~~~~~~<$1
'$2[)))))1$1|($2)))))))$1?
$2",,," ",,,^
+14
View File
@@ -0,0 +1,14 @@
█ █ █ █ █ █ █ █ █ █ █
███████████████████████
▄▄██ ██▄▄
▄▄██ ███████████ ██▄▄
▄▄██ ██ ██ ██▄▄
▄▄██ ██ ██ ██▄▄
▄▄██ ██ ██ ██▄▄
▄▄██ █████████████ ██▄▄
▄▄██ ██ ██ ██▄▄
▄▄██ ██ ██ ██▄▄
▄▄██ ██ ██ ██▄▄
▄▄██ ██▄▄
███████████████████████
█ █ █ █ █ █ █ █ █ █ █
+19
View File
@@ -0,0 +1,19 @@
.''''....''''.
.''... ...''.
''.. ..''
'.. ..''
.'. .,,'.. .',,,' ..'.
.'. .,,,,' .,,,,,' .'.
.'. .,,,,' .,,,,,. .'.
'.. .,,,,'',,,,;. .''
.'. .,,,,,,,;;. ..'
.'. .,,,,;;;;;${c2}, ${c1}..'.
'.. .,;;;,${c2}';;;;;, ${c1}..'
.'. .;;${c2};;' .;;:::: ${c1}.,.
'.. ${c2}.;;;;' .::::::. ${c1}.,'
'.. ${c2}.;;;;' .::::::. ${c1}.,${c2}'${c1}
.'.. ${c2}.',.
${c1}',.. ${c2}.','
${c1}.,,... ${c2}..',,.
..,,''........',,,.
......
+18
View File
@@ -0,0 +1,18 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@%*+--:------=+*%@@@@@@@@@@@@
@@@@@@@@@#=. .-+#%@@@@@%#*+--=#@@@@@@@@@
@@@@@@@+. .=%@@@@@@@@@@@@@@@@*-:+@@@@@@@
@@@@@*. *@@@@@@@@@@@@@@@@@@@@@%-.*@@@@@
@@@@- -@@@@@@@@@@@@@@@@@@@@@@@#: -@@@@
@@@: -@@@@@@@=.*@@@@@@@@@@@@%- = :@@@
@@= .@@@@@@@@%- :%@@@@@@@@@+ -%@# =@@
@% +@@@@@@@@@@#. =@@@@@@*. .*@@@@. %@
@+ *@@@@@@*..*@@+ *@@%- =@@@@@@- +@
@= *@@@@%- -%@@- := -%@@@@@@@: +@
@+ :@@@= +@@= .#@@@@@@@@% *@
@% +*. .: *@@#: +@@: @@
@@+ :%@- :- :: +@@
@@@- .=@@= -@@@
@@+. . +@@
%=..:.................::...........:..-%
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-1
View File
@@ -18,4 +18,3 @@
.:ooooooolc:. .ooooooooooo'
.':loooooo; ,oooooooooc
..';::c' .;loooo:'
.
+56 -10
View File
@@ -209,6 +209,7 @@ static const FFlogo A[] = {
// AoscOsRetro_small
{
.names = {"Aosc OS/Retro_small", "aoscosretro_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_AOSCOSRETRO_SMALL,
.colors = {
FF_COLOR_FG_BLUE,
@@ -375,6 +376,24 @@ static const FFlogo A[] = {
.colorKeys = FF_COLOR_FG_CYAN,
.colorTitle = FF_COLOR_FG_CYAN,
},
// Armbian
{
.names = {"Armbian"},
.lines = FASTFETCH_DATATEXT_LOGO_ARMBIAN,
.colors = {
FF_COLOR_FG_WHITE,
FF_COLOR_FG_RED,
},
},
// Armbian2
{
.names = {"Armbian2"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_ARMBIAN2,
.colors = {
FF_COLOR_FG_RED,
},
},
// Artix
{
.names = {"artix", "artixlinux", "artix-linux"},
@@ -764,6 +783,7 @@ static const FFlogo C[] = {
// CalinixOSSmall
{
.names = {"Calinix_small", "calinixos_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_CALINIXOS_SMALL,
.colors = {
FF_COLOR_FG_MAGENTA,
@@ -875,7 +895,7 @@ static const FFlogo C[] = {
// Chimera Linux
{
.names = {"Chimera Linux"},
.lines = FASTFETCH_DATATEXT_LOGO_CHIMERALINUX,
.lines = FASTFETCH_DATATEXT_LOGO_CHIMERA_LINUX,
.colors = {
FF_COLOR_FG_RED,
FF_COLOR_FG_MAGENTA,
@@ -1241,9 +1261,9 @@ static const FFlogo D[] = {
.colorKeys = FF_COLOR_FG_RED,
.colorTitle = FF_COLOR_FG_WHITE,
},
// Drauger
// DraugerOS
{
.names = {"Drauger"},
.names = {"DraugerOS", "Drauger"},
.lines = FASTFETCH_DATATEXT_LOGO_DRAUGER,
.colors = {
FF_COLOR_FG_RED,
@@ -1336,8 +1356,8 @@ static const FFlogo E[] = {
// EndeavourSmall
{
.names = {"Endeavour_small", "endeavour-linux_small", "endeavouros_small", "endeavouros-linux_small"},
.lines = FASTFETCH_DATATEXT_LOGO_ENDEAVOUR_SMALL,
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_ENDEAVOUR_SMALL,
.colors = {
FF_COLOR_FG_RED,
FF_COLOR_FG_MAGENTA,
@@ -1823,6 +1843,7 @@ static const FFlogo G[] = {
// GuixSmall
{
.names = {"Guix_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_GUIX_SMALL,
.colors = {
FF_COLOR_FG_YELLOW,
@@ -2089,6 +2110,15 @@ static const FFlogo K[] = {
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_WHITE,
},
// KernelOS
{
.names = {"KernelOS"},
.lines = FASTFETCH_DATATEXT_LOGO_KERNELOS,
.colors = {
FF_COLOR_FG_RED,
FF_COLOR_FG_MAGENTA,
}
},
// KDENeon
{
.names = {"KDE", "kde-neon"},
@@ -2462,6 +2492,7 @@ static const FFlogo M[] = {
// MageiaSmall
{
.names = {"Mageia_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_MAGEIA_SMALL,
.colors = {
FF_COLOR_FG_CYAN,
@@ -2649,7 +2680,7 @@ static const FFlogo M[] = {
},
// MX
{
.names = {"MX"},
.names = {"MX", "MX Linux"},
.lines = FASTFETCH_DATATEXT_LOGO_MX,
.colors = {
FF_COLOR_FG_WHITE,
@@ -2659,7 +2690,8 @@ static const FFlogo M[] = {
},
// MXSmall
{
.names = {"MX_small", "mx-small"},
.names = {"MX_small", "mx linux_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_MX_SMALL,
.colors = {
FF_COLOR_FG_WHITE,
@@ -2667,6 +2699,17 @@ static const FFlogo M[] = {
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_CYAN,
},
// MX2
{
.names = {"MX2"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_MX2,
.colors = {
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_CYAN,
},
// LAST
{},
};
@@ -2730,6 +2773,7 @@ static const FFlogo N[] = {
// NixOSSmall
{
.names = {"NixOS_small", "nix_small", "nixos-linux-small", "nix-linux-small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_NIXOS_SMALL,
.colors = {
FF_COLOR_FG_BLUE,
@@ -3301,6 +3345,7 @@ static const FFlogo P[] = {
// PostMarketOSSmall
{
.names = {"PostMarketOS_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_POSTMARKETOS_SMALL,
.colors = {
FF_COLOR_FG_GREEN,
@@ -3309,7 +3354,7 @@ static const FFlogo P[] = {
},
// Proxmox
{
.names = {"proxmox"},
.names = {"Proxmox", "pve"},
.lines = FASTFETCH_DATATEXT_LOGO_PROXMOX,
.colors = {
FF_COLOR_FG_WHITE,
@@ -3560,6 +3605,7 @@ static const FFlogo R[] = {
// RockyLinuxSmall
{
.names = {"rocky_small", "rocky-linux_small", "rockylinux_small"},
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_ROCKY_SMALL,
.colors = {
FF_COLOR_FG_GREEN,
@@ -3791,14 +3837,14 @@ static const FFlogo S[] = {
FF_COLOR_FG_WHITE,
},
},
// SourceMage
// Source Mage
{
.names = {"Source Mage", "source_mage"},
.names = {"Source Mage", "Source Mage GNU/Linux", "source_mage", "sourcemage"},
.lines = FASTFETCH_DATATEXT_LOGO_SOURCE_MAGE,
.colors = {
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorKeys = FF_COLOR_FG_RED,
.colorTitle = FF_COLOR_FG_WHITE,
},
// Solaris
+32 -7
View File
@@ -1,6 +1,7 @@
#include "image.h"
#include "common/io/io.h"
#include "common/printing.h"
#include "util/stringUtils.h"
#include <limits.h>
#include <math.h>
@@ -53,13 +54,14 @@ static FFstrbuf base64Encode(const FFstrbuf* in)
return out;
}
static bool printImageIterm(void)
static bool printImageIterm(bool printError)
{
const FFOptionsLogo* options = &instance.config.logo;
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
if(!ffAppendFileBuffer(options->source.chars, &buf))
{
fputs("Logo: Failed to load image file\n", stderr);
if (printError)
fputs("Logo (iterm): Failed to load image file\n", stderr);
return false;
}
@@ -134,9 +136,17 @@ static bool printImageIterm(void)
return true;
}
static bool printImageKittyDirect(void)
static bool printImageKittyDirect(bool printError)
{
const FFOptionsLogo* options = &instance.config.logo;
if (!ffPathExists(options->source.chars, FF_PATHTYPE_FILE))
{
if (printError)
fputs("Logo (kitty-direct): Failed to load image file\n", stderr);
return false;
}
FF_STRBUF_AUTO_DESTROY base64 = base64Encode(&options->source);
if (!options->width || !options->height)
@@ -771,7 +781,7 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError)
if(!getCharacterPixelDimensions(&requestData))
{
if(printError)
fputs("Logo: getCharacterPixelDimensions() failed", stderr);
fputs("Logo: getCharacterPixelDimensions() failed\n", stderr);
return false;
}
@@ -788,7 +798,7 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError)
//We can safely return here, because if realpath failed, we surely won't be able to read the file
ffStrbufDestroy(&requestData.cacheDir);
if(printError)
fputs("Logo: Querying realpath of the image source failed", stderr);
fputs("Logo: Querying realpath of the image source failed\n", stderr);
return false;
}
ffStrbufRecalculateLength(&requestData.cacheDir);
@@ -832,6 +842,13 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError)
bool ffLogoPrintImageIfExists(FFLogoType type, bool printError)
{
if(instance.config.display.pipe)
{
if(printError)
fputs("Logo: Image logo is not supported in pipe mode\n", stderr);
return false;
}
if(!ffPathExists(instance.config.logo.source.chars, FF_PATHTYPE_FILE))
{
if(printError)
@@ -839,11 +856,19 @@ bool ffLogoPrintImageIfExists(FFLogoType type, bool printError)
return false;
}
const char* term = getenv("TERM");
if((term && ffStrEquals(term, "screen")) || getenv("ZELLIJ"))
{
if(printError)
fputs("Logo: Image logo is not supported in terminal multiplexers\n", stderr);
return false;
}
if(type == FF_LOGO_TYPE_IMAGE_ITERM)
return printImageIterm();
return printImageIterm(printError);
if(type == FF_LOGO_TYPE_IMAGE_KITTY_DIRECT)
return printImageKittyDirect();
return printImageKittyDirect(printError);
#if !defined(FF_HAVE_CHAFA)
if(type == FF_LOGO_TYPE_IMAGE_CHAFA)
+26 -16
View File
@@ -61,7 +61,7 @@ void ffLogoPrintChars(const char* data, bool doColorReplacement)
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreateA(2048);
if (instance.config.display.brightColor)
if (!instance.config.display.pipe && instance.config.display.brightColor)
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_BOLT);
ffStrbufAppendNC(&result, options->paddingTop, '\n');
@@ -70,7 +70,7 @@ void ffLogoPrintChars(const char* data, bool doColorReplacement)
instance.state.logoHeight = options->paddingTop;
//Use logoColor[0] as the default color
if(doColorReplacement)
if(doColorReplacement && !instance.config.display.pipe)
ffStrbufAppendF(&result, "\e[%sm", options->colors[0].chars);
while(*data != '\0')
@@ -143,19 +143,27 @@ void ffLogoPrintChars(const char* data, bool doColorReplacement)
continue;
}
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
int index = ((int) *data) - 49;
//If the index is valid, print the color. Otherwise continue as normal
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
if(!instance.config.display.pipe)
{
ffStrbufAppendC(&result, '$');
++currentlineLength;
//Don't continue here, we want to print the current char as unicode
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
int index = ((int) *data) - 49;
//If the index is valid, print the color. Otherwise continue as normal
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
{
ffStrbufAppendC(&result, '$');
++currentlineLength;
//Don't continue here, we want to print the current char as unicode
}
else
{
ffStrbufAppendF(&result, "\e[%sm", options->colors[index].chars);
++data;
continue;
}
}
else
{
ffStrbufAppendF(&result, "\e[%sm", options->colors[index].chars);
++data;
continue;
}
@@ -188,7 +196,8 @@ void ffLogoPrintChars(const char* data, bool doColorReplacement)
}
}
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
if(!instance.config.display.pipe)
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
if(!options->separate)
{
@@ -393,7 +402,8 @@ static bool logoPrintFileIfExists(bool doColorReplacement, bool raw)
: !ffAppendFileBuffer(options->source.chars, &content)
)
{
fprintf(stderr, "Logo: Failed to load file content from logo source: %s \n", options->source.chars);
if (instance.config.display.showErrors)
fprintf(stderr, "Logo: Failed to load file content from logo source: %s \n", options->source.chars);
return false;
}
@@ -448,7 +458,7 @@ static bool logoTryKnownType(void)
if(options->type == FF_LOGO_TYPE_IMAGE_RAW)
return logoPrintFileIfExists(false, true);
return logoPrintImageIfExists(options->type, true);
return logoPrintImageIfExists(options->type, instance.config.display.showErrors);
}
static void logoPrintKnownType(void)
@@ -459,10 +469,10 @@ static void logoPrintKnownType(void)
void ffLogoPrint(void)
{
//In pipe mode, we don't have a logo or padding.
//When generate JSON result, we don't have a logo or padding.
//We also don't need to set main color, because it won't be printed anyway.
//So we can return quickly here.
if(instance.config.display.pipe || instance.state.resultDoc)
if(instance.state.resultDoc)
{
instance.state.logoHeight = 0;
instance.state.logoWidth = 0;
+19 -14
View File
@@ -84,23 +84,28 @@ void ffPrintBattery(FFBatteryOptions* options)
if (error)
{
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return;
}
else
if(results.length == 0)
{
for(uint8_t i = 0; i < (uint8_t) results.length; i++)
{
FFBatteryResult* result = ffListGet(&results, i);
printBattery(options, result, i);
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No batteries found");
return;
}
ffStrbufDestroy(&result->manufacturer);
ffStrbufDestroy(&result->modelName);
ffStrbufDestroy(&result->technology);
ffStrbufDestroy(&result->status);
ffStrbufDestroy(&result->serial);
ffStrbufDestroy(&result->manufactureDate);
}
if(results.length == 0)
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No batteries found");
for(uint32_t i = 0; i < results.length; i++)
{
FFBatteryResult* result = ffListGet(&results, i);
printBattery(options, result, (uint8_t) i);
}
FF_LIST_FOR_EACH(FFBatteryResult, result, results)
{
ffStrbufDestroy(&result->manufacturer);
ffStrbufDestroy(&result->modelName);
ffStrbufDestroy(&result->technology);
ffStrbufDestroy(&result->status);
ffStrbufDestroy(&result->serial);
ffStrbufDestroy(&result->manufactureDate);
}
}
+10 -12
View File
@@ -150,19 +150,17 @@ void ffGenerateBluetoothJsonResult(FF_MAYBE_UNUSED FFBluetoothOptions* options,
yyjson_mut_obj_add_str(doc, module, "error", error);
return;
}
else
{
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFBluetoothResult, item, results)
{
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "address", &item->address);
yyjson_mut_obj_add_uint(doc, obj, "battery", item->battery);
yyjson_mut_obj_add_bool(doc, obj, "connected", item->connected);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
yyjson_mut_obj_add_strbuf(doc, obj, "type", &item->type);
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFBluetoothResult, item, results)
{
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "address", &item->address);
yyjson_mut_obj_add_uint(doc, obj, "battery", item->battery);
yyjson_mut_obj_add_bool(doc, obj, "connected", item->connected);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
yyjson_mut_obj_add_strbuf(doc, obj, "type", &item->type);
}
FF_LIST_FOR_EACH(FFBluetoothResult, device, results)
-6
View File
@@ -154,12 +154,6 @@ void ffGenerateBrightnessJsonResult(FF_MAYBE_UNUSED FFBrightnessOptions* options
return;
}
if(result.length == 0)
{
yyjson_mut_obj_add_str(doc, module, "error", "No result is detected.");
return;
}
yyjson_mut_val* arr = yyjson_mut_arr(doc);
yyjson_mut_obj_add_val(doc, module, "result", arr);
+8 -7
View File
@@ -16,9 +16,6 @@ static inline uint8_t max(uint8_t a, uint8_t b)
void ffPrintColors(FFColorsOptions* options)
{
if(instance.config.display.pipe)
return;
bool flag = false;
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreateA(128);
@@ -28,7 +25,8 @@ void ffPrintColors(FFColorsOptions* options)
// 3%d: Set the foreground color
for(uint8_t i = options->block.range[0]; i <= min(options->block.range[1], 7); i++)
{
ffStrbufAppendF(&result, "\e[3%dm", i);
if(!instance.config.display.pipe)
ffStrbufAppendF(&result, "\e[3%dm", i);
for (uint8_t j = 0; j < options->block.width; j++)
ffStrbufAppendS(&result, "");
}
@@ -40,7 +38,8 @@ void ffPrintColors(FFColorsOptions* options)
if(options->paddingLeft > 0)
ffPrintCharTimes(' ', options->paddingLeft);
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
if(!instance.config.display.pipe)
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
ffStrbufPutTo(&result, stdout);
ffStrbufClear(&result);
}
@@ -49,7 +48,8 @@ void ffPrintColors(FFColorsOptions* options)
// 9%d: Set the foreground to the bright color
for(uint8_t i = max(options->block.range[0], 8); i <= options->block.range[1]; i++)
{
ffStrbufAppendF(&result, "\e[1;9%dm", i - 8);
if(!instance.config.display.pipe)
ffStrbufAppendF(&result, "\e[1;9%dm", i - 8);
for (uint8_t j = 0; j < options->block.width; j++)
ffStrbufAppendS(&result, "");
}
@@ -82,7 +82,8 @@ void ffPrintColors(FFColorsOptions* options)
if(options->paddingLeft > 0)
ffPrintCharTimes(' ', options->paddingLeft);
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
if(!instance.config.display.pipe)
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
ffStrbufPutTo(&result, stdout);
}
+2 -7
View File
@@ -6,15 +6,10 @@
void ffPrintCustom(FFCustomOptions* options)
{
if (options->moduleArgs.outputFormat.length == 0)
{
ffPrintError(FF_CUSTOM_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "output format must be set for custom module");
return;
}
ffPrintLogoAndKey(FF_CUSTOM_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&options->moduleArgs.outputFormat, stdout);
puts(FASTFETCH_TEXT_MODIFIER_RESET);
if(!instance.config.display.pipe)
puts(FASTFETCH_TEXT_MODIFIER_RESET);
}
bool ffParseCustomCommandOptions(FFCustomOptions* options, const char* key, const char* value)
+1 -1
View File
@@ -152,7 +152,7 @@ void ffGenerateDateTimeJsonConfig(FFDateTimeOptions* options, yyjson_mut_doc* do
void ffGenerateDateTimeJsonResult(FF_MAYBE_UNUSED FFDateTimeOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
yyjson_mut_obj_add_uint(doc, module, "result", ffTimeGetNow());
yyjson_mut_obj_add_strcpy(doc, module, "result", ffTimeToFullStr(ffTimeGetNow()));
}
void ffPrintDateTimeHelpFormat(void)
+9 -52
View File
@@ -131,54 +131,6 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk)
}
}
static void printMountpoint(FFDiskOptions* options, const FFlist* disks, const char* mountpoint)
{
FF_LIST_FOR_EACH(FFDisk, disk, *disks)
{
if(ffStrbufEqualS(&disk->mountpoint, mountpoint))
{
printDisk(options, disk);
return;
}
}
ffPrintError(FF_DISK_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No disk found for mountpoint: %s", mountpoint);
}
static void printMountpoints(FFDiskOptions* options, const FFlist* disks)
{
#ifdef _WIN32
const char separator = ';';
#else
const char separator = ':';
#endif
FF_STRBUF_AUTO_DESTROY mountpoints = ffStrbufCreateCopy(&options->folders);
ffStrbufTrim(&mountpoints, separator);
uint32_t startIndex = 0;
while(startIndex < mountpoints.length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&mountpoints, startIndex, separator);
mountpoints.chars[colonIndex] = '\0';
printMountpoint(options, disks, mountpoints.chars + startIndex);
startIndex = colonIndex + 1;
}
}
static void printAutodetected(FFDiskOptions* options, const FFlist* disks)
{
FF_LIST_FOR_EACH(FFDisk, disk, *disks)
{
if(disk->type & ~options->showTypes)
continue;
printDisk(options, disk);
}
}
void ffPrintDisk(FFDiskOptions* options)
{
FF_LIST_AUTO_DESTROY disks = ffListCreate(sizeof (FFDisk));
@@ -190,10 +142,13 @@ void ffPrintDisk(FFDiskOptions* options)
}
else
{
if(options->folders.length == 0)
printAutodetected(options, &disks);
else
printMountpoints(options, &disks);
FF_LIST_FOR_EACH(FFDisk, disk, disks)
{
if(__builtin_expect(options->folders.length == 0, 1) && (disk->type & ~options->showTypes))
continue;
printDisk(options, disk);
}
}
FF_LIST_FOR_EACH(FFDisk, disk, disks)
@@ -451,6 +406,8 @@ void ffGenerateDiskJsonResult(FFDiskOptions* options, yyjson_mut_doc* doc, yyjso
yyjson_mut_arr_add_str(doc, typeArr, "Hidden");
if(item->type & FF_DISK_VOLUME_TYPE_READONLY_BIT)
yyjson_mut_arr_add_str(doc, typeArr, "Read-only");
if(item->type & FF_DISK_VOLUME_TYPE_UNKNOWN_BIT)
yyjson_mut_arr_add_str(doc, typeArr, "Unknown");
const char* pstr = ffTimeToFullStr(item->createTime);
if (*pstr)
+1
View File
@@ -279,6 +279,7 @@ void ffGenerateDisplayJsonResult(FF_MAYBE_UNUSED FFDisplayOptions* options, yyjs
yyjson_mut_obj_add_str(doc, module, "error", "Couldn't detect display");
return;
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFDisplayResult, item, dsResult->displays)
{
-6
View File
@@ -118,12 +118,6 @@ void ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs
return;
}
if(!result.length)
{
yyjson_mut_obj_add_str(doc, module, "error", "No devices detected");
return;
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
{
+1 -8
View File
@@ -334,13 +334,7 @@ void ffGenerateLocalIpJsonResult(FF_MAYBE_UNUSED FFLocalIpOptions* options, yyjs
if(error)
{
yyjson_mut_obj_add_str(doc, module, "error", error);
goto exit;
}
if(results.length == 0)
{
yyjson_mut_obj_add_str(doc, module, "error", "Failed to detect any IPs");
goto exit;
return;
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
@@ -354,7 +348,6 @@ void ffGenerateLocalIpJsonResult(FF_MAYBE_UNUSED FFLocalIpOptions* options, yyjs
yyjson_mut_obj_add_strbuf(doc, obj, "name", &ip->name);
}
exit:
FF_LIST_FOR_EACH(FFLocalIpResult, ip, results)
{
ffStrbufDestroy(&ip->name);
+1 -9
View File
@@ -22,7 +22,7 @@ static void buildOutputDefault(const FFOSResult* os, FFstrbuf* result)
ffStrbufAppend(result, &instance.state.platform.systemName);
//Append code name if it is missing
if(os->codename.length > 0 && !ffStrbufContain(result, &os->versionID))
if(os->codename.length > 0 && !ffStrbufContain(result, &os->codename))
{
ffStrbufAppendC(result, ' ');
ffStrbufAppend(result, &os->codename);
@@ -40,14 +40,6 @@ static void buildOutputDefault(const FFOSResult* os, FFstrbuf* result)
ffStrbufAppend(result, &os->version);
}
#ifdef __APPLE__
if(os->buildID.length > 0)
{
ffStrbufAppendC(result, ' ');
ffStrbufAppend(result, &os->buildID);
}
#endif
//Append variant if it is missing
if(os->variant.length > 0 && ffStrbufFirstIndex(result, &os->variant) == result->length)
{
+1
View File
@@ -27,6 +27,7 @@ typedef enum FFPackagesFlags
FF_PACKAGES_FLAG_WINGET_BIT = 1 << 17,
FF_PACKAGES_FLAG_XBPS_BIT = 1 << 18,
FF_PACKAGES_FLAG_AM_BIT = 1 << 19,
FF_PACKAGES_FLAG_SORCERY_BIT = 1 << 20,
} FFPackagesFlags;
typedef struct FFPackagesOptions
+18 -2
View File
@@ -4,7 +4,7 @@
#include "modules/packages/packages.h"
#include "util/stringUtils.h"
#define FF_PACKAGES_NUM_FORMAT_ARGS 26
#define FF_PACKAGES_NUM_FORMAT_ARGS 30
void ffPrintPackages(FFPackagesOptions* options)
{
@@ -65,11 +65,15 @@ void ffPrintPackages(FFPackagesOptions* options)
FF_PRINT_PACKAGE(winget)
FF_PRINT_PACKAGE(opkg)
FF_PRINT_PACKAGE(am)
FF_PRINT_PACKAGE(sorcery)
putchar('\n');
}
else
{
uint32_t nixAll = counts.nixDefault + counts.nixSystem + counts.nixUser;
uint32_t flatpakAll = counts.flatpakSystem + counts.flatpakUser;
uint32_t brewAll = counts.brew + counts.brewCask;
FF_PRINT_FORMAT_CHECKED(FF_PACKAGES_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, FF_PACKAGES_NUM_FORMAT_ARGS, ((FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT, &counts.all},
{FF_FORMAT_ARG_TYPE_UINT, &counts.pacman},
@@ -97,6 +101,10 @@ void ffPrintPackages(FFPackagesOptions* options)
{FF_FORMAT_ARG_TYPE_UINT, &counts.winget},
{FF_FORMAT_ARG_TYPE_UINT, &counts.opkg},
{FF_FORMAT_ARG_TYPE_UINT, &counts.am},
{FF_FORMAT_ARG_TYPE_UINT, &counts.sorcery},
{FF_FORMAT_ARG_TYPE_UINT, &nixAll},
{FF_FORMAT_ARG_TYPE_UINT, &flatpakAll},
{FF_FORMAT_ARG_TYPE_UINT, &brewAll},
}));
}
@@ -166,6 +174,7 @@ bool ffParsePackagesCommandOptions(FFPackagesOptions* options, const char* key,
case 'S': if (false);
FF_TEST_PACKAGE_NAME(SCOOP)
FF_TEST_PACKAGE_NAME(SNAP)
FF_TEST_PACKAGE_NAME(SORCERY)
break;
case 'W': if (false);
FF_TEST_PACKAGE_NAME(WINGET)
@@ -266,6 +275,7 @@ void ffParsePackagesJsonObject(FFPackagesOptions* options, yyjson_val* module)
case 'S': if (false);
FF_TEST_PACKAGE_NAME(SCOOP)
FF_TEST_PACKAGE_NAME(SNAP)
FF_TEST_PACKAGE_NAME(SORCERY)
break;
case 'W': if (false);
FF_TEST_PACKAGE_NAME(WINGET)
@@ -316,6 +326,7 @@ void ffGeneratePackagesJsonConfig(FFPackagesOptions* options, yyjson_mut_doc* do
FF_TEST_PACKAGE_NAME(WINGET)
FF_TEST_PACKAGE_NAME(XBPS)
FF_TEST_PACKAGE_NAME(AM)
FF_TEST_PACKAGE_NAME(SORCERY)
#undef FF_TEST_PACKAGE_NAME
}
}
@@ -362,12 +373,13 @@ void ffGeneratePackagesJsonResult(FF_MAYBE_UNUSED FFPackagesOptions* options, yy
FF_APPEND_PACKAGE_COUNT(xbps)
FF_APPEND_PACKAGE_COUNT(opkg)
FF_APPEND_PACKAGE_COUNT(am)
FF_APPEND_PACKAGE_COUNT(sorcery)
yyjson_mut_obj_add_strbuf(doc, obj, "pacmanBranch", &counts.pacmanBranch);
}
void ffPrintPackagesHelpFormat(void)
{
FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_PACKAGES_MODULE_NAME, "{2} (pacman){?3}[{3}]{?}, {4} (dpkg), {5} (rpm), {6} (emerge), {7} (eopkg), {8} (xbps), {9} (nix-system), {10} (nix-user), {11} (nix-default), {12} (apk), {13} (pkg), {14} (flatpak-system), {15} (flatpack-user), {16} (snap), {17} (brew), {18} (brew-cask), {19} (MacPorts), {20} (scoop), {21} (choco), {22} (pkgtool), {23} (paludis), {24} (winget), {25} (opkg)", FF_PACKAGES_NUM_FORMAT_ARGS, ((const char* []) {
FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_PACKAGES_MODULE_NAME, "{2} (pacman){?3}[{3}]{?}, {4} (dpkg), {5} (rpm), {6} (emerge), {7} (eopkg), {8} (xbps), {9} (nix-system), {10} (nix-user), {11} (nix-default), {12} (apk), {13} (pkg), {14} (flatpak-system), {15} (flatpack-user), {16} (snap), {17} (brew), {18} (brew-cask), {19} (MacPorts), {20} (scoop), {21} (choco), {22} (pkgtool), {23} (paludis), {24} (winget), {25} (opkg), {26} (am), {27} (sorcery)", FF_PACKAGES_NUM_FORMAT_ARGS, ((const char* []) {
"Number of all packages",
"Number of pacman packages",
"Pacman branch on manjaro",
@@ -394,6 +406,10 @@ void ffPrintPackagesHelpFormat(void)
"Number of winget packages",
"Number of opkg packages",
"Number of am packages",
"Number of sorcery packages",
"Total number of all nix packages",
"Total number of all flatpak packages",
"Total number of all brew packages",
}));
}
+2 -3
View File
@@ -107,7 +107,6 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options)
ffTempsAppendNum(dev->temperature, &tempStr, options->tempConfig);
if (dev->type & FF_PHYSICALDISK_TYPE_READWRITE)
readOnlyType = "Read-write";
ffParseSize(dev->size, &buffer);
FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_PHYSICALDISK_NUM_FORMAT_ARGS, ((FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &buffer},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->name},
@@ -118,7 +117,7 @@ void ffPrintPhysicalDisk(FFPhysicalDiskOptions* options)
{FF_FORMAT_ARG_TYPE_STRING, removableType},
{FF_FORMAT_ARG_TYPE_STRING, readOnlyType},
{FF_FORMAT_ARG_TYPE_STRBUF, &dev->revision},
{FF_FORMAT_ARG_TYPE_DOUBLE, &tempStr},
{FF_FORMAT_ARG_TYPE_STRBUF, &tempStr},
}));
}
++index;
@@ -252,7 +251,7 @@ void ffGeneratePhysicalDiskJsonResult(FFPhysicalDiskOptions* options, yyjson_mut
void ffPrintPhysicalDiskHelpFormat(void)
{
FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_PHYSICALDISK_MODULE_NAME, "{1}", FF_PHYSICALDISK_NUM_FORMAT_ARGS, ((const char* []) {
FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_PHYSICALDISK_MODULE_NAME, "{1} [{6}, {7}, {8}]", FF_PHYSICALDISK_NUM_FORMAT_ARGS, ((const char* []) {
"Device size (formatted)",
"Device name",
"Device interconnect type",
+18 -14
View File
@@ -101,24 +101,28 @@ void ffGeneratePowerAdapterJsonResult(FF_MAYBE_UNUSED FFPowerAdapterOptions* opt
if (error)
{
yyjson_mut_obj_add_str(doc, module, "error", error);
return;
}
else if(results.length == 0)
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFPowerAdapterResult, item, results)
{
yyjson_mut_obj_add_str(doc, module, "error", "No power adapters found");
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "description", &item->description);
yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &item->manufacturer);
yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &item->modelName);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &item->serial);
yyjson_mut_obj_add_int(doc, obj, "watts", item->watts);
}
else
FF_LIST_FOR_EACH(FFPowerAdapterResult, item, results)
{
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFPowerAdapterResult, item, results)
{
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "description", &item->description);
yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &item->manufacturer);
yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &item->modelName);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &item->serial);
yyjson_mut_obj_add_int(doc, obj, "watts", item->watts);
}
ffStrbufDestroy(&item->manufacturer);
ffStrbufDestroy(&item->description);
ffStrbufDestroy(&item->modelName);
ffStrbufDestroy(&item->name);
ffStrbufDestroy(&item->serial);
}
}
+15 -4
View File
@@ -12,9 +12,20 @@ static inline uint32_t max(uint32_t a, uint32_t b)
static inline uint32_t getWcsWidth(const FFstrbuf* mbstr, wchar_t* wstr, mbstate_t* state)
{
int result = 1;
for (uint32_t i = 0; i < mbstr->length; i++)
{
if (!isascii(mbstr->chars[i]))
{
result = 0;
break;
}
}
if (__builtin_expect(result, 1)) return mbstr->length;
const char* str = mbstr->chars;
uint32_t wstrLength = (uint32_t) mbsrtowcs(wstr, &str, mbstr->length, state);
int result = mk_wcswidth(wstr, wstrLength);
result = mk_wcswidth(wstr, wstrLength);
return result > 0 ? (uint32_t) result : mbstr->length;
}
@@ -32,9 +43,9 @@ void ffPrintSeparator(FFSeparatorOptions* options)
+ (fqdn ? platform->hostName.length : ffStrbufFirstIndexC(&platform->hostName, '.')); // host name
ffLogoPrintLine();
if(options->string.length == 0)
if(__builtin_expect(options->string.length == 1, 1))
{
ffPrintCharTimes('-', titleLength);
ffPrintCharTimes(options->string.chars[0], titleLength);
}
else
{
@@ -131,7 +142,7 @@ void ffInitSeparatorOptions(FFSeparatorOptions* options)
NULL,
ffGenerateSeparatorJsonConfig
);
ffStrbufInit(&options->string);
ffStrbufInitStatic(&options->string, "-");
}
void ffDestroySeparatorOptions(FFSeparatorOptions* options)
-2
View File
@@ -8,6 +8,4 @@ typedef struct FFShellOptions
{
FFModuleBaseInfo moduleInfo;
FFModuleArgs moduleArgs;
bool version;
} FFShellOptions;
-6
View File
@@ -200,12 +200,6 @@ void ffGenerateSoundJsonResult(FF_MAYBE_UNUSED FFSoundOptions* options, yyjson_m
return;
}
if(result.length == 0)
{
yyjson_mut_obj_add_str(doc, module, "error", "No active sound devices found");
return;
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFSoundDevice, item, result)
{

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