Compare commits

...

78 Commits

Author SHA1 Message Date
dependabot[bot] 37ec63d1bd CI: Bump the github-actions group with 4 updates
Bumps the github-actions group with 4 updates: [cross-platform-actions/action](https://github.com/cross-platform-actions/action), [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [signpath/github-action-submit-signing-request](https://github.com/signpath/github-action-submit-signing-request).


Updates `cross-platform-actions/action` from 1.3.0 to 1.4.0
- [Release notes](https://github.com/cross-platform-actions/action/releases)
- [Changelog](https://github.com/cross-platform-actions/action/blob/master/changelog.md)
- [Commits](https://github.com/cross-platform-actions/action/compare/5ea7e8e4677bd726033a10b094ba1c5762b15dee...24ef01df165c76df1ed2b9f9e9212e78dc2fc963)

Updates `github/codeql-action/init` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `github/codeql-action/analyze` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `signpath/github-action-submit-signing-request` from 2.2 to 2.3
- [Release notes](https://github.com/signpath/github-action-submit-signing-request/releases)
- [Commits](https://github.com/signpath/github-action-submit-signing-request/compare/b9d91eadd323de506c0c81cf0c7fe7438f3360fd...c92b958760219087e01f8d67a1669ed57afe2627)

---
updated-dependencies:
- dependency-name: cross-platform-actions/action
  dependency-version: 1.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: signpath/github-action-submit-signing-request
  dependency-version: '2.3'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-23 18:07:14 +00:00
Carter Li e7ecba4460 Doc: updates README [ci skip] 2026-08-21 10:40:50 +08:00
Carter Li e0c239729b L10n: adds cs id tr uk vi
Assisted-By: LLM
2026-08-21 10:19:06 +08:00
Samuel Torres 6570a7accc L10n (ES): fixes Spanish translations (#2537) 2026-08-21 08:31:42 +08:00
Samuel Torres 0c4ec62cac L10n: (gl) Added Galician Support 2026-08-21 00:25:32 +08:00
Carter Li 5d11b65d53 TerminalFont (Android): adds font size detection 2026-08-20 16:18:07 +08:00
Carter Li 8b40117c08 Wifi (OpenBSD): fortifies detection and adds channel to frequency helper 2026-08-20 16:04:00 +08:00
Carter Li b1f2bf3526 WM: uses full name in EN, as DE and LM modules do 2026-08-20 15:23:21 +08:00
Carter Li d8452f71ed Wifi (SunOS): fortifies code 2026-08-20 15:05:18 +08:00
Carter Li 2a269bfd4c Wifi: removes driver detection support 2026-08-19 23:28:23 +08:00
Carter Li cafe82b462 Battery (SunOS): adds basic detection impl 2026-08-19 13:24:05 +08:00
Carter Li db8ee8159d Wifi (Haiku): adds basic Wifi detection impl 2026-08-19 11:05:35 +08:00
Carter Li f0765b1a13 Wifi (SunOS): adds basic Wifi detection impl 2026-08-19 10:43:34 +08:00
Carter Li 93566cb73c Wifi (Android / OpenBSD): inits unsupported properties 2026-08-19 10:16:30 +08:00
Carter Li 6d0d093d62 Wifi (NetBSD): adds channel width detection 2026-08-19 10:15:30 +08:00
Carter Li 54fe4ffece Wifi (FreeBSD): adds channel width detection 2026-08-19 09:40:23 +08:00
Carter Li 124bbb06f9 Wifi (macOS): fixes compatibility for old Intel MBP 2026-08-19 09:17:12 +08:00
Carter Li f04a53337d Wifi (macOS): adds channel width, accurate channel frequency and device driver detection 2026-08-18 19:32:01 +08:00
李通洲 514efab8eb Wifi (Windows): adds channel width and device driver detection 2026-08-18 19:32:01 +08:00
Carter Li 232cd6659b Wifi (Linux): adds channel width and device driver detection 2026-08-18 19:32:01 +08:00
Carter Li 7c93f9c82a GPU (macOS): removes useless @available tests 2026-08-18 19:32:01 +08:00
Wehrwolfmann e5b6e3612a L10n: falls back to English when the auto-detected locale is unsupported
--key-language with an empty value (and "language": null in the config)
asks for the system locale, not for a specific language. When that locale
has no translation, fastfetch aborted with exit 477 instead of printing
anything, so the same config broke on every locale outside the twelve
supported ones, and under LC_ALL=C variants such as POSIX.

Auto-detected locales now fall back to English. An explicitly requested
language still errors out, so typos and zh are still reported.
2026-08-17 20:14:39 -05:00
Carter Li 6cb15885c7 L10n: don't use ffStrbufCreateStatic for buffers that will be modified later 2026-08-18 09:11:50 +08:00
Carter Li e6d90c2081 L10n (Zh): uses a different name for Monitor 2026-08-17 14:20:46 +08:00
Carter Li 679d868b4a L10n (Zh): clarifies Disk actually detects Disk partitions 2026-08-17 13:57:23 +08:00
Carter Li 72d240f325 L10n (Zh): clarifies Bluetooth actually detects Bluetooth devices 2026-08-17 13:42:30 +08:00
Carter Li 2ca7e037ef L10n (Zh): translates shell 2026-08-17 13:36:09 +08:00
Carter Li 5e9c31ac31 Completion (Fish): prints enum description [ci skip] 2026-08-17 10:42:24 +08:00
Wehrwolfmann bcb48774a0 Modules: proofreads Russian l10n strings 2026-08-16 12:01:42 -05:00
Wehrwolfmann 9ff7969acf Bluetooth / BluetoothRadio: keeps the brand name in Latin script in Russian keys 2026-08-16 12:01:42 -05:00
李通洲 7fbd06a135 Doc: updates README.md [ci skip] 2026-08-16 22:16:56 +08:00
Hashing bbb906ba10 L10n (Pt): matches all Portuguese locales, not only bare pt (#2521)
359cb0a79a renamed the key from `pt_BR` to
`pt` but kept the exact-match guard, so only the literal string `pt`
matched. Every real Portuguese locale (`pt_BR`, `pt_PT` and their charset
and modifier variants) fell through to `goto error` and aborted.

Return the offset unconditionally, matching every other two-letter case.
2026-08-16 02:15:39 -05:00
李通洲 2de674ec9a L10n (Ar / He): adds support
Fixes #2520
2026-08-16 10:52:23 +08:00
李通洲 b700d9ded5 L10n (Ru): changes Блютус to Блютуз
Ref: https://github.com/fastfetch-cli/fastfetch/issues/2503#issuecomment-5304614812
2026-08-16 10:52:23 +08:00
李通洲 359cb0a79a L10n (Pt): renames pt_BR to pt 2026-08-16 10:52:14 +08:00
李通洲 45f9de6cd2 L10n: improves performance 2026-08-16 10:36:33 +08:00
Guiorgy 233c481f7a CMAKE: bumps minimum CMake version to 3.21.0 (#2517)
C_STANDARD 23 was added in 3.21
2026-08-15 09:15:03 +08:00
Carter Li b677f1e902 Theme: improves GTK theme/icons/font detection on standalone WMs (Hyprland, sway, niri, i3)
Fixes #2504
2026-08-15 09:08:29 +08:00
Carter Li 8d82eedaef DiskIO / NetIO: updates default value of waitTime to reduce latency
Also corrects docs.
2026-08-15 08:53:00 +08:00
Carter Li 4dc27b365f DiskIO / NetIO: fixes I/O rate calculation precision, prevent div-by-zero 2026-08-15 08:51:45 +08:00
李通洲 e5c3fa4023 CI: fixes compiling errors 2026-08-15 00:00:27 +08:00
李通洲 bdba78c45c CI: silences codespell errors 2026-08-14 23:56:29 +08:00
Carter Li f95167e907 Global: adds option key-language
Fixes #2503
2026-08-14 23:33:54 +08:00
Carter Li 3908c39ce2 Modules: adds l10n strings 2026-08-14 22:47:24 +08:00
李通洲 858d3749f4 FFstrbuf: adds FF_STRBUF_STATIC 2026-08-14 18:27:53 +08:00
李通洲 51f36fa4b4 FFstrbuf: adds comments [ci skip] 2026-08-14 17:54:36 +08:00
李通洲 bfe30eec79 Doc: updates changelog [ci skip] 2026-08-14 17:05:06 +08:00
Carter Li 4dd2f2d34b Merge pull request #2516 from fastfetch-cli/dev 2026-08-14 01:20:28 -05:00
Carter Li 60431c0321 Doc: update changelog [ci skip] 2026-08-14 13:50:22 +08:00
李通洲 7b2b3405ae Locale (Windows): reports the code page used by the console 2026-08-14 13:38:14 +08:00
Carter Li 965ed4ba79 Library (Windows): don't assume DataTableEntry->FullDllName is null-terminated 2026-08-14 09:41:30 +08:00
李通洲 00603357ea Processing (Windows): improves performance of environement string creation 2026-08-14 09:41:30 +08:00
OctoBored 5ea299a8d2 Doc: restores Star History in README.md
The Star History chart was removed in 8df0a1c9 (Fixes #2508) because the previous chart was broken due to GitHub stargazer API restrictions. This restores it at the same location using a working data source that requires no API token, so the chart renders correctly again.
2026-08-13 05:43:43 -05:00
Carter Li 368a4c5a73 Release v2.67.1 2026-08-13 11:02:18 +08:00
Carter Li 8df0a1c97e Doc: removes Star History in README.md
Fixes #2508
2026-08-13 10:44:35 +08:00
Carter Li 7098cd86cb Display: fixes bright colours incorrectly active in light theme
Fixes #2509
2026-08-13 10:44:35 +08:00
njk 681749ed54 TerminalFont (Ghostty): fixes font-family fallback order (#2510) 2026-08-12 20:04:19 -05:00
李通洲 c4695b8cf1 Processing (Windows): sets LANG=C when spawning child processes 2026-08-12 13:54:32 +08:00
李通洲 1d12003555 Locale (Windows): uses $LANG if available e.g. MSYS2 2026-08-12 10:19:22 +08:00
Carter Li 16b10c162b Revert "Locale (macOS): queries system-wide locale preference"
This reverts commit 8b8efcdcce.
2026-08-12 10:07:34 +08:00
Carter Li 51cfd4b5ed OS (Android): optimises code 2026-08-12 09:52:31 +08:00
JunaidQrysh a0452b8323 Logo (Image): don't block images support in zellij 2026-08-11 17:41:45 +08:00
Carter Li ebf38e829d OS (Android): reports real code names 2026-08-11 11:02:20 +08:00
HashimAbdulaziz 4c2af4071c TerminalFont (Alacritty): fix font size never being parsed from config
The query array gained a third entry in
dd30c82b83 but numQueries stayed at 2, so
`size =` was never queried and every Alacritty user silently got the
hardcoded 11.25 fallback.
2026-08-09 02:23:17 -05:00
李通洲 e3b8e94055 Wallpaper (macOS): uses the official API if possible 2026-08-09 11:33:58 +08:00
李通洲 1d4b0236ac WMTheme (macOS): migrates impl to pure C using CoreFoundation 2026-08-09 10:25:13 +08:00
李通洲 da42108732 Cursor (macOS): migrates impl to pure C using CoreFoundation 2026-08-09 10:22:21 +08:00
李通洲 8b8efcdcce Locale (macOS): queries system-wide locale preference 2026-08-09 10:12:37 +08:00
李通洲 8bc4464b64 Library: makes ffLibraryIterateDynamicLibs return false on failure 2026-08-09 10:11:25 +08:00
Carter Li 4361c5e787 Library: adds function ffLibraryIterateDynamicLibs 2026-08-09 01:07:19 +08:00
李通洲 558a90d4e0 Loadavg (Haiku): adds support on R1B6 2026-08-09 01:07:19 +08:00
Carter Li 881730d0bd TerminalFont: improves Ghostty config loading with fallback support
Fixes: #2500
2026-08-08 22:40:34 +08:00
Carter Li ac8fc63c28 Doc: updates changelog [ci skip] 2026-08-07 16:39:23 +08:00
Yelninei 8686820c1a CMake (Hurd): Define O_PATH to O_NORW.
This is a noop because O_RW is 0 but O_NORW is the correct constant to
open a file without read/write permissions.
2026-08-07 02:23:29 -05:00
Carter Li 39b3dc001a CMake: adds C23 feature detection and compatibility workarounds for Apple clang 17 2026-08-07 11:00:12 +08:00
Carter Li ba60d7975c Camera (macOS): simplifies code 2026-08-07 09:37:39 +08:00
Carter Li 51a4f34bb5 Codec (macOS): fixes a symbol not found error when running on 10.15 2026-08-07 09:37:39 +08:00
Carter Li 01bb73b9e8 Packaging: updates debian stuff [ci skip] 2026-08-06 16:40:38 +08:00
211 changed files with 3952 additions and 1033 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h,./src/detection/cpu/cpu_x86.c,./src/detection/gpu/gpu_bsddrm.c,./src/detection/displayserver/linux/wayland/*-protocol.*,./build,./build-*,./build_*,./src/common/impl/genconfig.c
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu,renderD,SME,Carmel,kinda
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu,renderD,SME,Carmel,kinda,symbole,connexion,comando,processus,lokale,adres,titel,som,environnement,Sistem,Lokal,Lokal,Sistem,Paket,Hava
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: dragonflybsd
version: '6.4.2'
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: freebsd
version: '15.1'
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: haiku
version: 'r1beta5'
+2 -2
View File
@@ -52,7 +52,7 @@ jobs:
- name: Initialize CodeQL
if: inputs.arch == 'amd64'
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
languages: c
@@ -64,7 +64,7 @@ jobs:
- name: perform CodeQL analysis
if: inputs.arch == 'amd64'
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
- name: list features
run: ./fastfetch --list-features
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: netbsd
version: '10.1'
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: omnios
version: 'r151058'
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@5ea7e8e4677bd726033a10b094ba1c5762b15dee # v1.3.0
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: openbsd
version: '7.9'
+1 -1
View File
@@ -94,7 +94,7 @@ jobs:
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
name: submit signing request
uses: signpath/github-action-submit-signing-request@b9d91eadd323de506c0c81cf0c7fe7438f3360fd # v2.2
uses: signpath/github-action-submit-signing-request@c92b958760219087e01f8d67a1669ed57afe2627 # v2.3
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
+1
View File
@@ -12,3 +12,4 @@ fastfetch.kdev4
*.user
*.user.*
*.swp
*.log
+52 -9
View File
@@ -1,3 +1,46 @@
# Unreleased
Changes:
* The DE / WM / LM modules now reports the full name "Desktop Environment" / "Window Manager" / "Login Manager" instead of the abbreviations.
Features:
* Added module key localization support. (General)
* Added a new option `--key-language <?lang>` (`display.key.language: "<?lang>"` in JSON config). When left empty, it defaults to the system locale.
* See `fastfetch -h key-language` for all supported languages.
* Improved Wi-Fi module
* Added Wifi channel width detection, exposed via `{channel-width}` in custom format (reports 0 when not supported).
* Improved Wifi channel frequency accuracy and fortified detection on Windows, macOS.
* Added Wifi detection support on SunOS, Haiku.
* Added Battery detection support on SunOS. (Battery, SunOS)
* Added terminal font size detection support on Termux. (TerminalFont, Android)
* Improved GTK theme/icons/font detection on standalone WMs such as Hyprland, sway, niri and i3. (Theme, Linux)
* Improved fish completion scripts to print enum descriptions. (Completion)
Bugfixes:
* Fixed I/O rate calculation precision in DiskIO and NetIO, and prevented division by zero. (DiskIO / NetIO)
* Some internal cleanups and optimizations.
# 2.67.1
Bugfixes:
* Fixed a `Symbol not found` error when running on macOS 10.15. (#2499, Codec, macOS)
* Fixed Alacritty font size never being parsed from the TOML config. (#2501, TerminalFont)
* Fixed bright colors incorrectly being active when the terminal uses a light theme. (#2509, Display)
* Fixed Ghostty terminal font detection (TerminalFont)
* Now tries to load the config with the `.ghostty` extension. (#2500)
* Fixed `font-family` fallback order. (#2510)
* Some internal cleanups and optimizations.
Features:
* Added a C23 compiler check so the build process gracefully exits during CMake configuration if the compiler is unsupported. (CMake)
* Added compatibility workarounds for Apple Clang 16 to fix building on macOS 14. (CMake, macOS)
* Reported real Android version codenames (e.g., "Baklava", "Vanilla Ice Cream") instead of "REL". (OS, Android)
* Added Loadavg detection support on Haiku R1B6. (Loadavg, Haiku)
* Enabled image logo support in the Zellij terminal multiplexer. (#2507, Logo)
* Improved Locale detection on Windows (Locale, Windows)
* Now respects `LC_ALL` and `LANG` environment variables if set for better compatibility with MSYS2/cygwin.
* Appends the active system Code Page (e.g., `.UTF-8` or `.Windows-1252`) to the default system locale fallback.
# 2.67.0
Changes:
@@ -31,12 +74,12 @@ Bugfixes:
* Fixed invalid URL parsing in the PublicIP module. (PublicIP)
* Correctly reported virtual GPUs on Windows. (#2461, GPU, Windows)
* Added a size limit for network responses to prevent excessive memory usage and mitigate potential attacks. (PublicIP / Weather)
* Fixed Ubuntu Studio Core detection (OS, Linux)
* Fixed Ubuntu Studio Core detection. (OS, Linux)
* Relaxed the HTTP response check so that both `HTTP/1.0` and `HTTP/1.1` responses are accepted when fetching data over the network. (PublicIP / Weather)
* Various internal cleanups and optimizations:
* Fixed multiple memory leaks (Separator, Camera, Codec, Display)
* Added integer overflow checks to the string buffer implementation
* Various code cleanups and compiler warning fixes
* Fixed multiple memory leaks (Separator, Camera, Codec, Display).
* Added integer overflow checks to the string buffer implementation.
* Various code cleanups and compiler warning fixes.
Logos:
* Removed Hypros, MagpieOS, Furreto, EmperorOS and Magix
@@ -49,9 +92,9 @@ Changes:
Bugfixes:
* Fixed compatibility with WSL 2.9.3 (#2433, WM, Linux)
* Fixed accurate AMD GPU names are not queried in `driverSpecific` mode (GPU, Linux)
* Fixed AMD GPU names not being queried accurately in `driverSpecific` mode (GPU, Linux)
* Fixed GPU core counting for Apple Silicon GPU on Asahi Linux (GPU, Linux)
* Some internal cleanups and optimizations
* Some internal cleanups and optimizations.
Features:
* Added Astra Linux version detection (OS, Linux)
@@ -784,7 +827,7 @@ Features:
* Added support for interface speed detection on SunOS (LocalIP, SunOS)
* Added detection support for Xlibre (#1888, WM, Linux)
* Improved the accuracy of color detection (Cursor, macOS)
* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS)
* Improved the performance of `Nix` package manager detection on macOS by porting optimizations from the Linux port (#1893, Packages, macOS)
Bugfixes:
* Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477)
@@ -1295,7 +1338,7 @@ Features:
* Change package manager name of NetBSD from `pkg` to `pkgsrc` (#1515, Packages, NetBSD)
* Detect SOC name on RISCV (#1519, CPU, Linux)
* Report marketing name of new QS8Es (CPU, Android)
* Acquire acquire more os info from lsb-release if missing from os-release (#1521)
* Acquire more OS info from lsb-release if missing from os-release (#1521)
* CMake: add option `-DCUSTOM_LSB_RELEASE_PATH` to specify the path of `lsb-release` file
* `-DCUSTOM_OS_RELEASE_PATH` has been supported since `v2.11.4`
* Report more SOC names on Android (CPU, Android)
@@ -1763,7 +1806,7 @@ Logos:
Bugfixes:
* Fix bad Intel Arc GPU name detection, which was supposed to be fixed in the last version but the change was reverted accidentally (#1177, GPU, Linux)
* Fix arm32 CPU name detection no longer work. Regression of 2.21.2 (CPU, Linux)
* Fix arm32 CPU name detection no longer working. Regression of 2.21.2 (CPU, Linux)
# 2.21.2
+33 -12
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
cmake_minimum_required(VERSION 3.21.0) # C_STANDARD
project(fastfetch
VERSION 2.67.0
VERSION 2.67.1
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -62,6 +62,7 @@ if(NOT PKG_CONFIG_FOUND)
endif()
include(CheckIncludeFile)
include(CheckFunctionExists)
if(LINUX)
CHECK_INCLUDE_FILE("linux/version.h" HAVE_LINUX_VERSION_H)
@@ -1022,7 +1023,7 @@ elseif(APPLE)
src/detection/cpu/cpu_apple.c
src/detection/cpucache/cpucache_apple.c
src/detection/cpuusage/cpuusage_apple.c
src/detection/cursor/cursor_apple.m
src/detection/cursor/cursor_apple.c
src/detection/disk/disk_bsd.c
src/detection/dns/dns_apple.c
src/detection/physicaldisk/physicaldisk_apple.c
@@ -1063,7 +1064,7 @@ elseif(APPLE)
src/detection/wifi/wifi_apple.m
src/detection/wm/wm_apple.m
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_apple.m
src/detection/wmtheme/wmtheme_apple.c
src/detection/camera/camera_apple.m
)
# CMAKE_SYSTEM_PROCESSOR has been normalized before
@@ -1168,7 +1169,7 @@ elseif(SunOS)
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/common/impl/kmod_sunos.c
src/detection/battery/battery_nosupport.c
src/detection/battery/battery_sunos.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
src/detection/bootmgr/bootmgr_nosupport.c
@@ -1234,7 +1235,7 @@ elseif(SunOS)
src/detection/uptime/uptime_sunos.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wifi/wifi_sunos.c
src/detection/wm/wm_nosupport.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
@@ -1281,7 +1282,6 @@ elseif(Haiku)
src/detection/keyboard/keyboard_haiku.cpp
src/detection/libc/libc_nosupport.c
src/detection/lm/lm_nosupport.c
src/detection/loadavg/loadavg_nosupport.c
src/detection/locale/locale_linux.c
src/detection/localip/localip_linux.c
src/detection/gamepad/gamepad_haiku.cpp
@@ -1305,12 +1305,19 @@ elseif(Haiku)
src/detection/uptime/uptime_haiku.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_haiku.cpp
src/detection/wifi/wifi_nosupport.c
src/detection/wifi/wifi_haiku.cpp
src/detection/wm/wm_nosupport.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_haiku.cpp
src/detection/camera/camera_nosupport.c
)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} bsd)
check_function_exists(getloadavg HAVE_GETLOADAVG)
if(HAVE_GETLOADAVG)
list(APPEND LIBFASTFETCH_SRC src/detection/loadavg/loadavg_sunos.c)
else()
list(APPEND LIBFASTFETCH_SRC src/detection/loadavg/loadavg_nosupport.c)
endif()
elseif(GNU)
list(APPEND LIBFASTFETCH_SRC
src/common/impl/dbus.c
@@ -1428,7 +1435,6 @@ if(WIN32)
endif()
endif()
endif()
include(CheckFunctionExists)
if(NOT WIN32)
check_function_exists(pipe2 HAVE_PIPE2)
endif()
@@ -1469,10 +1475,24 @@ endforeach()
include(CheckCSourceCompiles)
check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF)
if(COMPILER_SUPPORTS_COUNT_OF)
message(STATUS "_Countof is supported by the compiler")
message(STATUS "C2Y _Countof is supported by the compiler")
target_compile_definitions(libfastfetch PUBLIC FF_SUPPORTS_COUNT_OF=1)
else()
message(STATUS "_Countof is NOT supported by the compiler")
message(STATUS "C2Y _Countof is NOT supported by the compiler")
endif()
# Test C23 compiler support
check_c_source_compiles("enum my_enum: long{MY_ENUM_ZERO}; void test(void*p){} int main(int,const char**){[[gnu::cleanup(test)]] void* x=nullptr; return (int)MY_ENUM_ZERO;}" COMPILER_SUPPORTS_C23)
if(NOT COMPILER_SUPPORTS_C23)
message(FATAL_ERROR "Compiler does not support C23. Please use a newer compiler.")
endif()
# A hack for AppleClang 17, which supports most C23 features we use except for the `auto` keyword.
# See https://github.com/Homebrew/homebrew-core/pull/297403
check_c_source_compiles("int main(void){auto v = 12.34; return (int)v;}" COMPILER_SUPPORTS_AUTO)
if(NOT COMPILER_SUPPORTS_AUTO)
message(WARNING "Compiler does not support C23 'auto' keyword. A workaround will be applied.")
target_compile_definitions(libfastfetch PUBLIC $<$<COMPILE_LANGUAGE:C>:auto=__auto_type>)
endif()
if(yyjson_FOUND)
@@ -1555,7 +1575,7 @@ elseif(Haiku)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
elseif(GNU)
# On Hurd PATH_MAX is not defined. Set an arbitrary limit as workaround.
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=0)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=O_NORW)
endif()
if(APPLE)
@@ -2006,6 +2026,7 @@ elseif(Haiku)
PRIVATE "GL"
PRIVATE "be"
PRIVATE "gnu"
PRIVATE "bsd"
)
endif()
+5 -5
View File
@@ -99,7 +99,7 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
* Display help messages: `fastfetch --help`
* Generate a minimal config file: `fastfetch [-s <module1>[:<module2>]] --gen-config [</path/to/config.jsonc>]`
* Use: `--gen-config-full` to generate a full config file with all optional options
* Use [The online configuration generator](https://fastfetch-cli.github.io/fastfetch-config/) to generate a full config file with all optional options
## Customization
@@ -335,10 +335,10 @@ If you find Fastfetch useful, please consider donating.
Give us a star to show your support!
<a href="https://star-history.com/#fastfetch-cli/fastfetch&Date">
<a href="https://star-history.dera.page/#fastfetch-cli/fastfetch&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=fastfetch-cli/fastfetch&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=fastfetch-cli/fastfetch&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=fastfetch-cli/fastfetch&type=Date" />
<source media="(prefers-color-scheme: dark)" srcset="https://star-history.dera.page/svg?repos=fastfetch-cli/fastfetch&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://star-history.dera.page/svg?repos=fastfetch-cli/fastfetch&type=Date" />
<img alt="Star History Chart" src="https://star-history.dera.page/svg?repos=fastfetch-cli/fastfetch&type=Date" />
</picture>
</a>
+56 -24
View File
@@ -63,46 +63,78 @@ echo '
import json, subprocess, sys
def escape_fish_dq(s: str) -> str:
"""Escape special characters for Fish double quotes to prevent unexpected expansions. One slash in output needs four slashes in script"""
return str(s).replace("\\\\", "\\\\\\\\").replace("\\"", "\\\\\\"").replace("$", "\\\\$")
def main():
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
enum_functions = []
complete_commands = []
for key in data:
for flag in data[key]:
if flag["long"] == "logo-color-[1-9]":
long_name = flag.get("long", "")
# Handle pseudo flag logo-color-[1-9]
if long_name == "logo-color-[1-9]":
safe_desc_global = escape_fish_dq(flag.get("desc", ""))
for i in range(1, 10):
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
complete_commands.append(f"complete -c fastfetch -d \"{safe_desc_global}\" -l \"logo-color-{i}\" -x -a \"(__fastfetch_complete_color)\"")
continue
if flag.get("pseudo", False):
continue
command_prefix = f"""complete -c fastfetch -d "{flag["desc"]}" -l "{flag["long"]}\""""
safe_desc_global = escape_fish_dq(flag.get("desc", ""))
command_prefix = f"complete -c fastfetch -d \"{safe_desc_global}\" -l \"{long_name}\""
if "short" in flag:
command_prefix += f""" -o {flag["short"]}"""
short_name = flag["short"]
command_prefix += f" -o {short_name}"
if "arg" in flag:
type: str = flag["arg"]["type"]
if type == "bool":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif type == "color":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_color)\"")
elif type == "command":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_command)\"")
elif type == "config":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_config)\"")
elif type == "enum":
temp: str = " ".join(flag["arg"]["enum"])
print(f"{command_prefix} -x -a \"{temp}\"")
elif type == "logo":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_logo)\"")
elif type == "structure":
print(f"{command_prefix} -x -a \"(__fish_complete_list : __fastfetch_complete_structure)\"")
elif type == "path":
print(f"{command_prefix} -r -F")
arg_type: str = flag["arg"]["type"]
if arg_type == "bool":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif arg_type == "color":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_color)\"")
elif arg_type == "command":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_command)\"")
elif arg_type == "config":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_config)\"")
elif arg_type == "enum":
# Sanitize flag name to create a valid Fish function name
func_name = long_name.replace("-", "_").replace("[", "_").replace("]", "_")
func_name = f"__fastfetch_complete_enum_{func_name}"
# Generate the enum function
func_lines = [f"function {func_name}"]
for enum_val, enum_desc in flag["arg"]["enum"].items():
safe_val = escape_fish_dq(enum_val)
safe_desc = escape_fish_dq(enum_desc)
func_lines.append(f" echo -e \"{safe_val}\\t{safe_desc}\"")
func_lines.append("end\n")
enum_functions.append("\n".join(func_lines))
# Append complete command pointing to the new function
complete_commands.append(f"{command_prefix} -x -a \"({func_name})\"")
elif arg_type == "logo":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_logo)\"")
elif arg_type == "structure":
complete_commands.append(f"{command_prefix} -x -a \"(__fish_complete_list : __fastfetch_complete_structure)\"")
elif arg_type == "path":
complete_commands.append(f"{command_prefix} -r -F")
else:
print(f"{command_prefix} -x")
complete_commands.append(f"{command_prefix} -x")
else:
print(f"{command_prefix} -f")
complete_commands.append(f"{command_prefix} -f")
# Print generated enum functions first, then complete rules
print("\n".join(enum_functions))
print("\n".join(complete_commands))
if __name__ == "__main__":
+6
View File
@@ -1,3 +1,9 @@
fastfetch (2.67.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.67.0
-- Carter Li <zhangsongcui@live.cn> Thu, 06 Aug 2026 16:22:22 +0800
fastfetch (2.66.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.66.0
+32
View File
@@ -585,6 +585,38 @@
"default": "string"
}
},
{
"long": "key-language",
"desc": "Specify the language used for module keys",
"remark": "Leave empty for auto-detection based on the system locale. Unsupported locales fall back to English",
"arg": {
"type": "enum",
"default": "en",
"optional": true,
"enum": {
"en": "English",
"ar": "Arabic",
"cs": "Czech",
"de": "German",
"es": "Spanish",
"fr": "French",
"gl": "Galician",
"he": "Hebrew",
"id": "Indonesian",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"pl": "Polish",
"pt": "Portuguese",
"ru": "Russian",
"tr": "Turkish",
"uk": "Ukrainian",
"vi": "Vietnamese",
"zh_CN": "Simplified Chinese",
"zh_TW": "Traditional Chinese"
}
}
},
{
"long": "bright-color",
"desc": "Specify whether keys, title, and ASCII logo should be printed in bright color",
+114 -4
View File
@@ -1057,6 +1057,116 @@
"description": "Left padding for keys",
"minimum": 0,
"default": 0
},
"language": {
"description": "Language used for module keys. `null` for auto detection based on system locale",
"oneOf": [
{
"type": "null",
"description": "Auto detection based on system locale"
},
{
"type": "string",
"const": "en",
"description": "English"
},
{
"type": "string",
"const": "ar",
"description": "Arabic"
},
{
"type": "string",
"const": "cs",
"description": "Czech"
},
{
"type": "string",
"const": "de",
"description": "German"
},
{
"type": "string",
"const": "es",
"description": "Spanish"
},
{
"type": "string",
"const": "fr",
"description": "French"
},
{
"type": "string",
"const": "gl",
"description": "Galician"
},
{
"type": "string",
"const": "he",
"description": "Hebrew"
},
{
"type": "string",
"const": "id",
"description": "Indonesian"
},
{
"type": "string",
"const": "it",
"description": "Italian"
},
{
"type": "string",
"const": "ja",
"description": "Japanese"
},
{
"type": "string",
"const": "ko",
"description": "Korean"
},
{
"type": "string",
"const": "pl",
"description": "Polish"
},
{
"type": "string",
"const": "pt",
"description": "Portuguese"
},
{
"type": "string",
"const": "ru",
"description": "Russian"
},
{
"type": "string",
"const": "tr",
"description": "Turkish"
},
{
"type": "string",
"const": "uk",
"description": "Ukrainian"
},
{
"type": "string",
"const": "vi",
"description": "Vietnamese"
},
{
"type": "string",
"const": "zh_CN",
"description": "Simplified Chinese"
},
{
"type": "string",
"const": "zh_TW",
"description": "Traditional Chinese"
}
],
"default": "en"
}
}
},
@@ -2585,8 +2695,8 @@
},
"waitTime": {
"type": "integer",
"description": "Wait time (in ms). Disk I/O = (totalBytesEnd - totalBytesStart) / waitTime",
"default": 200,
"description": "Wait time (in ms) used to measure the I/O rate (calculated in bytes/sec).\nAvoid setting this too low, as the kernel requires time to accurately update counters.\nIgnored if 'detectTotal' is true.",
"default": 500,
"minimum": 1
},
"key": {
@@ -3486,8 +3596,8 @@
},
"waitTime": {
"type": "integer",
"description": "Wait time (in ms). Net I/O = (totalBytesEnd - totalBytesStart) / waitTime",
"default": 200,
"description": "Wait time (in ms) used to measure the I/O rate (calculated in bytes/sec).\nAvoid setting this too low, as the kernel requires time to accurately update counters.\nIgnored if 'detectTotal' is true.",
"default": 500,
"minimum": 1
},
"key": {
+4
View File
@@ -31,6 +31,10 @@ typedef struct FFPlatform {
FFstrbuf userShell;
FFPlatformSysinfo sysinfo;
#if _WIN32
uint32_t initCP; // The code page used by the console when the program started
#endif
} FFPlatform;
void ffPlatformInit(FFPlatform* platform);
+2
View File
@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <assert.h>
#include "common/memrchr.h"
#include "common/arrutil.h"
#ifdef FF_USE_SYSTEM_YYJSON
#include <yyjson.h>
@@ -628,3 +629,4 @@ static inline void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) {
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
#define FF_STRBUF_AUTO_DESTROY [[gnu::cleanup(ffStrbufDestroy)]] FFstrbuf
#define FF_STRBUF_STATIC(str) { .allocated = 0, .length = (uint32_t) sizeof(str) - 1, .chars = str }
+1
View File
@@ -18,6 +18,7 @@ void ffPlatformInit(FFPlatform* platform) {
#ifdef _WIN32
ffStrbufInit(&platform->sid);
platform->initCP = 0;
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
+1
View File
@@ -83,6 +83,7 @@ void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free) {
// Round up to the next power of 2.
// If the value is already a power of 2, it will be rounded up to the next power of 2.
// allocate = __builtin_stdc_bit_ceil(allocate + 1); // Currently generates worse asm code
allocate = 1U << (32 - __builtin_clz(allocate));
}
+6 -6
View File
@@ -67,13 +67,13 @@ void ffPrepareCommandOption(FFdata* data) {
char* moduleType = nullptr;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) && ffStrEqualsIgnCase(moduleType, moduleNameConstant) && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (ffStrEqualsIgnCase(moduleType, moduleNameConstant) && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
switch (moduleType[0]) {
#if !FF_MODULE_DISABLE_CPUUSAGE
case 'C':
case 'c':
FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME)
FF_IF_MODULE_MATCH(ffCPUUsageModuleInfo.name)
ffPrepareCPUUsage();
break;
#endif
@@ -81,7 +81,7 @@ void ffPrepareCommandOption(FFdata* data) {
#if !FF_MODULE_DISABLE_DISKIO
case 'D':
case 'd':
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME) {
FF_IF_MODULE_MATCH(ffDiskIOModuleInfo.name) {
[[gnu::cleanup(ffDestroyDiskIOOptions)]] FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
@@ -92,7 +92,7 @@ void ffPrepareCommandOption(FFdata* data) {
#if !FF_MODULE_DISABLE_NETIO
case 'N':
case 'n':
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME) {
FF_IF_MODULE_MATCH(ffNetIOModuleInfo.name) {
[[gnu::cleanup(ffDestroyNetIOOptions)]] FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
@@ -103,7 +103,7 @@ void ffPrepareCommandOption(FFdata* data) {
#if !FF_MODULE_DISABLE_PUBLICIP
case 'P':
case 'p':
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME) {
FF_IF_MODULE_MATCH(ffPublicIPModuleInfo.name) {
[[gnu::cleanup(ffDestroyPublicIpOptions)]] FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
@@ -114,7 +114,7 @@ void ffPrepareCommandOption(FFdata* data) {
#if !FF_MODULE_DISABLE_WEATHER
case 'W':
case 'w':
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME) {
FF_IF_MODULE_MATCH(ffWeatherModuleInfo.name) {
[[gnu::cleanup(ffDestroyWeatherOptions)]] FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
+5 -13
View File
@@ -5,7 +5,6 @@
#include "common/textModifier.h"
#include "common/strutil.h"
#include "detection/displayserver/displayserver.h"
#include "detection/terminaltheme/terminaltheme.h"
#include "logo/logo.h"
#include <stdlib.h>
@@ -27,21 +26,10 @@ static void initState(FFstate* state) {
state->logoWidth = 0;
state->logoHeight = 0;
state->keysHeight = 0;
state->terminalLightTheme = false;
state->titleFqdn = false;
ffPlatformInit(&state->platform);
state->dynamicInterval = 0;
#if !FF_MODULE_DISABLE_TERMINALTHEME
{
// don't enable bright color if the terminal is in light mode
FFTerminalThemeResult result;
if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark) {
state->terminalLightTheme = true;
}
}
#endif
}
static void defaultConfig(void) {
@@ -51,7 +39,7 @@ static void defaultConfig(void) {
}
#ifdef _WIN32
static volatile UINT oldCp = CP_UTF8;
static UINT oldCp = CP_UTF8;
void resetConsoleCP(void) {
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(oldCp);
@@ -81,6 +69,10 @@ void ffInitInstance(void) {
defaultConfig();
initState(&instance.state);
#ifdef _WIN32
instance.state.platform.initCP = oldCp;
#endif
}
static volatile bool ffDisableLinewrap = false;
+6 -6
View File
@@ -136,9 +136,9 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#if !FF_MODULE_DISABLE_CPUUSAGE
case 'c':
case 'C': {
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
if (ffStrEqualsIgnCase(type, ffCPUUsageModuleInfo.name)) {
ffPrepareCPUUsage();
} else if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME)) {
} else if (ffStrEqualsIgnCase(type, ffCommandModuleInfo.name)) {
[[gnu::cleanup(ffDestroyCommandOptions)]] FFCommandOptions options;
ffInitCommandOptions(&options);
if (module) {
@@ -153,7 +153,7 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#if !FF_MODULE_DISABLE_DISKIO
case 'd':
case 'D': {
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME)) {
if (ffStrEqualsIgnCase(type, ffDiskIOModuleInfo.name)) {
[[gnu::cleanup(ffDestroyDiskIOOptions)]] FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
if (module) {
@@ -168,7 +168,7 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#if !FF_MODULE_DISABLE_NETIO
case 'n':
case 'N': {
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME)) {
if (ffStrEqualsIgnCase(type, ffNetIOModuleInfo.name)) {
[[gnu::cleanup(ffDestroyNetIOOptions)]] FFNetIOOptions options;
ffInitNetIOOptions(&options);
if (module) {
@@ -183,7 +183,7 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#if !FF_MODULE_DISABLE_PUBLICIP
case 'p':
case 'P': {
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME)) {
if (ffStrEqualsIgnCase(type, ffPublicIPModuleInfo.name)) {
[[gnu::cleanup(ffDestroyPublicIpOptions)]] FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
if (module) {
@@ -198,7 +198,7 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#if !FF_MODULE_DISABLE_WEATHER
case 'w':
case 'W': {
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME)) {
if (ffStrEqualsIgnCase(type, ffWeatherModuleInfo.name)) {
[[gnu::cleanup(ffDestroyWeatherOptions)]] FFWeatherOptions options;
ffInitWeatherOptions(&options);
if (module) {
+80
View File
@@ -178,3 +178,83 @@ void* ffLibraryGetModule(const wchar_t* libraryFileName) {
return module;
}
#endif
struct LibraryIterateDynamicLibsBundle {
FFLibraryIterateCallback callback;
void* userData;
};
#if _WIN32
static void ffLibraryIterateDynamicLibsCallback(PLDR_DATA_TABLE_ENTRY DataTableEntry, PVOID Context, BOOLEAN* StopEnumeration) {
if (DataTableEntry->FullDllName.Buffer == nullptr || DataTableEntry->FullDllName.Buffer[0] == L'\0') {
return;
}
char path[PATH_MAX * 3];
ULONG outBytes;
if (NT_SUCCESS(RtlUnicodeToUTF8N(path, sizeof(path), &outBytes, DataTableEntry->FullDllName.Buffer, DataTableEntry->FullDllName.Length))) {
path[outBytes] = '\0';
struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) Context;
*StopEnumeration = !bundle->callback(path, bundle->userData);
}
}
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) {
struct LibraryIterateDynamicLibsBundle bundle = {
.callback = callback,
.userData = userData,
};
return NT_SUCCESS(LdrEnumerateLoadedModules(FALSE, ffLibraryIterateDynamicLibsCallback, &bundle));
}
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) {
uint32_t imageCount = _dyld_image_count();
for (uint32_t i = 0; i < imageCount; ++i) {
const char* name = _dyld_get_image_name(i);
if (name == nullptr || name[0] == '\0') {
continue;
}
if (!callback(name, userData)) {
break;
}
}
return true;
}
#elif __has_include(<link.h>)
#include <link.h>
static int ffLibraryIterateDynamicLibsCallback(struct dl_phdr_info* info, size_t, void* data) {
if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') {
return 0;
}
struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) data;
return !bundle->callback(info->dlpi_name, bundle->userData);
}
bool ffLibraryIterateDynamicLibs(bool (*callback)(const char* name, void* userData), void* userData) {
dl_iterate_phdr(
ffLibraryIterateDynamicLibsCallback,
&(struct LibraryIterateDynamicLibsBundle) {
.callback = callback,
.userData = userData,
});
return true;
}
#else
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback, void*) {
// Not implemented for this platform
return false;
}
#endif
+46 -10
View File
@@ -48,6 +48,41 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result) {
}
}
static wchar_t* createChildEnvironment(void) {
auto pparams = ffGetPeb()->ProcessParameters;
const wchar_t* readStart = pparams->Environment;
if (!readStart) {
return nullptr;
}
RtlAcquirePebLock();
wchar_t* result = malloc(pparams->EnvironmentSize + sizeof(L"LANG=C.UTF-8"));
const wchar_t* entry = readStart;
wchar_t* writeStart = result;
// Copy all environment variables except LANG
while (*entry) {
assert((const uint8_t*) entry <= (const uint8_t*) pparams->Environment + pparams->EnvironmentSize);
size_t entryLength = wcslen(entry);
if (entryLength >= strlen("LANG=") && memcmp(entry, L"LANG=", strlen("LANG=") * sizeof(wchar_t)) == 0) {
memcpy(writeStart, readStart, (size_t) (entry - readStart) * sizeof(wchar_t));
writeStart += (size_t) (entry - readStart);
readStart = entry + entryLength + 1;
}
entry += entryLength + 1;
}
// Copy the remaining environment variables
memcpy(writeStart, readStart, (size_t) (entry - readStart) * sizeof(wchar_t));
writeStart += (size_t) (entry - readStart);
// Add LANG=C.UTF-8 and double null terminator
memcpy(writeStart, L"LANG=C.UTF-8\0", sizeof(L"LANG=C.UTF-8\0"));
RtlReleasePebLock();
return result;
}
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle) {
const int32_t timeout = instance.config.general.processingTimeout;
@@ -108,17 +143,18 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
}
}
FF_AUTO_FREE wchar_t* environment = createChildEnvironment();
BOOL success = CreateProcessW(
nullptr, // application name
cmdline, // command line
nullptr, // process security attributes
nullptr, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
nullptr, // use parent's environment
nullptr, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
nullptr, // application name
cmdline, // command line
nullptr, // process security attributes
nullptr, // primary thread security attributes
TRUE, // handles are inherited
CREATE_UNICODE_ENVIRONMENT, // creation flags
environment, // child environment
nullptr, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
NtClose(hChildPipeWrite);
+6 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "fastfetch.h"
#include "fastfetch.h" // IWYU pragma: keep
#ifndef FF_DISABLE_DLOPEN
@@ -111,3 +111,8 @@ void* ffLibraryLoadMulti(const char* path, int maxVersion, ...);
#if _WIN32
void* ffLibraryGetModule(const wchar_t* libraryFileName);
#endif
// Return false to stop iterating, true to continue
typedef bool (*FFLibraryIterateCallback)(const char* name, void* userData);
// Iterate over all loaded dynamic libraries. Returns true on success, false on failure.
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData);
+27
View File
@@ -18,10 +18,35 @@ typedef struct FFModuleFormatArgList {
#define FF_FORMAT_ARG_LIST(list) { .args = list, .count = sizeof(list) / sizeof(FFModuleFormatArg) }
typedef struct FFModuleDisplayName {
const char* en; // English
const char* ar; // Arabic
const char* cs; // Czech
const char* de; // German
const char* es; // Spanish
const char* fr; // French
const char* gl; // Galician
const char* he; // Hebrew
const char* id; // Indonesian
const char* it; // Italian
const char* ja; // Japanese
const char* ko; // Korean
const char* pl; // Polish
const char* pt; // (Brazilian) Portuguese
const char* ru; // Russian
const char* tr; // Turkish
const char* uk; // Ukrainian
const char* vi; // Vietnamese
const char* zh_CN; // Simplified Chinese
const char* zh_TW; // Traditional Chinese
} FFModuleDisplayName;
// Must be the first field of FFModuleOptions
typedef struct FFModuleBaseInfo {
const char* name;
const char* description;
FFModuleDisplayName displayName;
// A dirty polymorphic implementation in C.
// This is UB, because `void*` is not compatible with `FF*Options*`.
// However we can't do it better unless we move to C++, so that `option` becomes a `this` pointer
@@ -94,3 +119,5 @@ static inline void ffOptionDestroyModuleArg(FFModuleArgs* args) {
}
enum { FF_OPTION_MAX_SIZE = 1 << 8 }; // Maximum size of a single option value, used for static allocation
#define FF_MODULE_GET_DISPLAY_NAME(moduleName) (*(const char**) ((uint8_t*) &ff ## moduleName ## ModuleInfo.displayName + instance.config.display.keyLanguage))
+20 -1
View File
@@ -169,7 +169,7 @@ NTSTATUS NTAPI NtQuerySystemEnvironmentValueEx(
);
NTSTATUS NTAPI RtlGUIDFromString(IN PCUNICODE_STRING GuidString, OUT GUID* Guid);
NTSTATUS NTAPI RtlStringFromGUIDEx(IN GUID* Guid, OUT PCUNICODE_STRING GuidString, _In_ BOOLEAN AllocateGuidString);
NTSTATUS NTAPI RtlStringFromGUIDEx(IN const GUID* Guid, OUT PUNICODE_STRING GuidString, IN BOOLEAN AllocateGuidString);
typedef struct _SYSTEM_SECUREBOOT_INFORMATION {
BOOLEAN SecureBootEnabled;
@@ -1279,6 +1279,22 @@ NTSYSAPI NTSTATUS NTAPI LdrGetProcedureAddress(
_In_opt_ ULONG ProcedureNumber,
_Out_ PVOID* ProcedureAddress);
typedef _Function_class_(LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION)
VOID NTAPI LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION(
_In_ PLDR_DATA_TABLE_ENTRY DataTableEntry,
_In_opt_ PVOID Context,
_Inout_ BOOLEAN* StopEnumeration
);
NTSYSAPI
NTSTATUS
NTAPI
LdrEnumerateLoadedModules(
_In_ BOOLEAN ReservedFlag,
_In_ LDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION* EnumProc,
_In_opt_ PVOID Context
);
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
@@ -1323,3 +1339,6 @@ NTSYSAPI NTSTATUS NTAPI NtCancelIoFileEx(
NTSYSAPI NTSTATUS NTAPI NtTerminateProcess(
_In_opt_ HANDLE ProcessHandle,
_In_ NTSTATUS ExitStatus);
NTSYSAPI NTSTATUS NTAPI RtlAcquirePebLock(VOID);
NTSYSAPI NTSTATUS NTAPI RtlReleasePebLock(VOID);
+113
View File
@@ -0,0 +1,113 @@
#include "battery.h"
#include <kstat.h>
static inline void kstatFreeWrap(kstat_ctl_t** pkc) {
assert(pkc);
if (*pkc) {
kstat_close(*pkc);
}
}
static bool getUint32(kstat_t* ksp, const char* name, uint32_t* value) {
kstat_named_t* stat = kstat_data_lookup(ksp, name);
if (!stat) {
return false;
}
switch (stat->data_type) {
case KSTAT_DATA_UINT32:
*value = stat->value.ui32;
return true;
case KSTAT_DATA_INT32:
if (stat->value.i32 >= 0) {
*value = (uint32_t) stat->value.i32;
return true;
}
break;
#ifdef _INT64_TYPE
case KSTAT_DATA_UINT64:
if (stat->value.ui64 <= UINT32_MAX) {
*value = (uint32_t) stat->value.ui64;
return true;
}
break;
case KSTAT_DATA_INT64:
if (stat->value.i64 >= 0 && (uint64_t) stat->value.i64 <= UINT32_MAX) {
*value = (uint32_t) stat->value.i64;
return true;
}
break;
#endif
default:
break;
}
return false;
}
const char* ffDetectBattery([[maybe_unused]] FFBatteryOptions* options, FFlist* results) {
// https://github.com/illumos/illumos-gate/blob/master/usr/src/cmd/powertop/common/battery.c
[[gnu::cleanup(kstatFreeWrap)]] kstat_ctl_t* kc = kstat_open();
if (!kc) {
return "kstat_open() failed";
}
// illumos exposes battery information through either of these modules.
const char* modules[] = { "battery", "acpi_drv" };
kstat_t* bif = nullptr;
kstat_t* bst = nullptr;
for (size_t i = 0; i < ARRAY_SIZE(modules); ++i) {
bif = kstat_lookup(kc, modules[i], 0, "battery BIF0");
bst = kstat_lookup(kc, modules[i], 0, "battery BST0");
if (bif && bst) {
break;
}
bif = nullptr;
bst = nullptr;
}
if (!bif || !bst || kstat_read(kc, bif, nullptr) < 0 || kstat_read(kc, bst, nullptr) < 0) {
return nullptr;
}
uint32_t lastCapacity, remainingCapacity, rate, state;
if (!getUint32(bif, "bif_last_cap", &lastCapacity) ||
!getUint32(bst, "bst_rem_cap", &remainingCapacity) ||
!getUint32(bst, "bst_state", &state)) {
return "kstat_data_lookup() failed";
}
if (lastCapacity == 0 || remainingCapacity == UINT32_MAX) {
return nullptr;
}
FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *results);
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->manufactureDate);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->serial);
battery->status = FF_BATTERY_STATUS_NONE;
battery->capacity = (double) remainingCapacity * 100.0 / (double) lastCapacity;
battery->temperature = FF_BATTERY_TEMP_UNSET;
battery->cycleCount = 0;
battery->timeRemaining = -1;
// illumos BST state: bit 0 discharging, bit 1 charging, bit 2 critical.
if (state & (1u << 0)) {
battery->status |= FF_BATTERY_STATUS_DISCHARGING;
}
if (state & (1u << 1)) {
battery->status |= FF_BATTERY_STATUS_CHARGING;
}
if (state & (1u << 2)) {
battery->status |= FF_BATTERY_STATUS_CRITICAL;
}
if ((state & (1u << 0)) && getUint32(bst, "bst_rate", &rate) && rate > 0 && rate != UINT32_MAX) {
battery->timeRemaining = (int32_t) (((uint64_t) remainingCapacity * 3600) / rate);
}
return nullptr;
}
+2 -6
View File
@@ -19,12 +19,8 @@ const char* ffDetectCamera(FFlist* result)
AVCaptureDeviceType deviceType = nullptr;
#ifdef MAC_OS_VERSION_14_0
// Strangely `@available(macOS 14.0, *)` doesn't work here (#1594)
if (@available(macOS 14.0, *))
{
if (&AVCaptureDeviceTypeExternal)
deviceType = AVCaptureDeviceTypeExternal;
}
if (&AVCaptureDeviceTypeExternal)
deviceType = AVCaptureDeviceTypeExternal;
#endif
if (deviceType == nullptr)
deviceType = AVCaptureDeviceTypeExternalUnknown;
+7 -1
View File
@@ -3,6 +3,10 @@
#include <VideoToolbox/VideoToolbox.h>
#include "common/apple/cf_helpers.h"
#ifdef MAC_OS_VERSION_11_0
[[clang::weak_import]] VT_EXPORT void VTRegisterSupplementalVideoDecoderIfAvailable(CMVideoCodecType codecType);
#endif
static const struct {
CMVideoCodecType codec;
FFCodecType type;
@@ -70,9 +74,11 @@ static FFCodecType ffCodecDetectDecoders() {
continue;
}
if (__builtin_available(macOS 11.0, *)) {
#ifdef MAC_OS_VERSION_11_0
if (VTRegisterSupplementalVideoDecoderIfAvailable) {
VTRegisterSupplementalVideoDecoderIfAvailable(codec.codec);
}
#endif
bool supported = VTIsHardwareDecodeSupported(codec.codec);
if (!supported) {
continue;
+70
View File
@@ -0,0 +1,70 @@
#include "cursor.h"
#include "common/apple/cf_helpers.h"
static bool appendColor(FFstrbuf* str, CFDictionaryRef dict) {
double r, g, b, a;
if (
ffCfDictGetDouble(dict, CFSTR("red"), &r) ||
ffCfDictGetDouble(dict, CFSTR("green"), &g) ||
ffCfDictGetDouble(dict, CFSTR("blue"), &b) ||
ffCfDictGetDouble(dict, CFSTR("alpha"), &a)) {
return false;
}
r = r * 255 + .5;
g = g * 255 + .5;
b = b * 255 + .5;
a = a * 255 + .5;
uint32_t color = ((uint32_t) r << 24) | ((uint32_t) g << 16) | ((uint32_t) b << 8) | ((uint32_t) a);
// clang-format off
switch (color)
{
case 0x000000FF: ffStrbufAppendS(str, "Black"); break;
case 0x0433FFFF: ffStrbufAppendS(str, "Blue"); break;
case 0xAA7942FF: ffStrbufAppendS(str, "Brown"); break;
case 0x00FDFFFF: ffStrbufAppendS(str, "Cyan"); break;
case 0x00F900FF: ffStrbufAppendS(str, "Green"); break;
case 0xFF40FFFF: ffStrbufAppendS(str, "Magenta"); break;
case 0xFF9300FF: ffStrbufAppendS(str, "Orange"); break;
case 0x942192FF: ffStrbufAppendS(str, "Purple"); break;
case 0xFF2600FF: ffStrbufAppendS(str, "Red"); break;
case 0xFFFB00FF: ffStrbufAppendS(str, "Yellow"); break;
case 0xFFFFFFFF: ffStrbufAppendS(str, "White"); break;
case 0x00000000: ffStrbufAppendS(str, "Transparent"); break;
default: ffStrbufAppendF(str, "#%08X", color); break;
}
// clang-format on
return true;
}
void ffDetectCursor(FFCursorResult* result) {
// Read via cfprefsd (equivalent to `defaults read com.apple.universalaccess <key>`)
ffStrbufAppendS(&result->theme, "Fill - ");
{
FF_CFTYPE_AUTO_RELEASE CFTypeRef color = CFPreferencesCopyAppValue(CFSTR("cursorFill"), CFSTR("com.apple.universalaccess"));
if (!color || CFGetTypeID(color) != CFDictionaryGetTypeID() || !appendColor(&result->theme, (CFDictionaryRef) color)) {
ffStrbufAppendS(&result->theme, "Black");
}
}
ffStrbufAppendS(&result->theme, ", Outline - ");
{
FF_CFTYPE_AUTO_RELEASE CFTypeRef color = CFPreferencesCopyAppValue(CFSTR("cursorOutline"), CFSTR("com.apple.universalaccess"));
if (!color || CFGetTypeID(color) != CFDictionaryGetTypeID() || !appendColor(&result->theme, (CFDictionaryRef) color)) {
ffStrbufAppendS(&result->theme, "White");
}
}
{
FF_CFTYPE_AUTO_RELEASE CFTypeRef mouseDriverCursorSize = CFPreferencesCopyAppValue(CFSTR("mouseDriverCursorSize"), CFSTR("com.apple.universalaccess"));
double size = 32;
if (mouseDriverCursorSize && ffCfNumGetDouble(mouseDriverCursorSize, &size) == nullptr) {
ffStrbufAppendUInt(&result->size, (uint32_t) (size * 32 + 0.5));
} else {
ffStrbufAppendS(&result->size, "32");
}
}
}
-63
View File
@@ -1,63 +0,0 @@
#include "cursor.h"
#import <Foundation/Foundation.h>
static void appendColor(FFstrbuf* str, NSDictionary* dict)
{
uint32_t r = (uint32_t) (((NSNumber*) dict[@"red"]).doubleValue * 255 + .5);
uint32_t g = (uint32_t) (((NSNumber*) dict[@"green"]).doubleValue * 255 + .5);
uint32_t b = (uint32_t) (((NSNumber*) dict[@"blue"]).doubleValue * 255 + .5);
uint32_t a = (uint32_t) (((NSNumber*) dict[@"alpha"]).doubleValue * 255 + .5);
uint32_t color = (r << 24) | (g << 16) | (b << 8) | a;
switch (color)
{
case 0x000000FF: ffStrbufAppendS(str, "Black"); return;
case 0x0433FFFF: ffStrbufAppendS(str, "Blue"); return;
case 0xAA7942FF: ffStrbufAppendS(str, "Brown"); return;
case 0x00FDFFFF: ffStrbufAppendS(str, "Cyan"); return;
case 0x00F900FF: ffStrbufAppendS(str, "Green"); return;
case 0xFF40FFFF: ffStrbufAppendS(str, "Magenta"); return;
case 0xFF9300FF: ffStrbufAppendS(str, "Orange"); return;
case 0x942192FF: ffStrbufAppendS(str, "Purple"); return;
case 0xFF2600FF: ffStrbufAppendS(str, "Red"); return;
case 0xFFFB00FF: ffStrbufAppendS(str, "Yellow"); return;
case 0xFFFFFFFF: ffStrbufAppendS(str, "White"); return;
case 0x00000000: ffStrbufAppendS(str, "Transparent"); return;
default: ffStrbufAppendF(str, "#%08X", color); return;
}
}
void ffDetectCursor(FFCursorResult* result)
{
NSError* error;
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/com.apple.universalaccess.plist", instance.state.platform.homeDir.chars];
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
error:&error];
if(error)
{
ffStrbufAppendS(&result->error, error.localizedDescription.UTF8String);
return;
}
NSDictionary* color;
ffStrbufAppendS(&result->theme, "Fill - ");
if ((color = dict[@"cursorFill"]))
appendColor(&result->theme, color);
else
ffStrbufAppendS(&result->theme, "Black");
ffStrbufAppendS(&result->theme, ", Outline - ");
if ((color = dict[@"cursorOutline"]))
appendColor(&result->theme, color);
else
ffStrbufAppendS(&result->theme, "White");
NSNumber* mouseDriverCursorSize = dict[@"mouseDriverCursorSize"];
if (mouseDriverCursorSize)
ffStrbufAppendF(&result->size, "%d", (int) (mouseDriverCursorSize.doubleValue * 32 + 0.5));
else
ffStrbufAppendS(&result->size, "32");
}
+1 -2
View File
@@ -72,8 +72,7 @@ const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options) {
uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
uint64_t temp = *currValue;
*currValue -= *prevValue;
*currValue /= (time2 - time1) / 1000 /* seconds */;
*currValue = (*currValue - *prevValue) * 1000 / (time2 - time1); // Calculate per second
// For next function call
*prevValue = temp;
+58 -64
View File
@@ -14,74 +14,68 @@
#define MTLFeatureSet_macOS_GPUFamily2_v1 ((MTLFeatureSet) 10005)
#endif
const char* ffGpuDetectDriverVersion(FFlist* gpus)
{
if (@available(macOS 10.7, *))
{
NSMutableArray* arr = NSMutableArray.new;
FF_LIST_FOR_EACH(FFGPUResult, x, *gpus)
[arr addObject:@(x->driver.chars)];
NSDictionary* dict = CFBridgingRelease(KextManagerCopyLoadedKextInfo((__bridge CFArrayRef)arr, (__bridge CFArrayRef)@[@"CFBundleVersion"]));
FF_LIST_FOR_EACH(FFGPUResult, x, *gpus)
{
NSString* version = dict[@(x->driver.chars)][@"CFBundleVersion"];
if (version)
{
ffStrbufAppendC(&x->driver, ' ');
ffStrbufAppendS(&x->driver, version.UTF8String);
}
}
return nullptr;
const char* ffGpuDetectDriverVersion(FFlist* gpus) {
NSMutableArray* arr = NSMutableArray.new;
FF_LIST_FOR_EACH (FFGPUResult, x, *gpus) {
[arr addObject:@(x->driver.chars)];
}
return "Unsupported macOS version";
NSDictionary* dict = CFBridgingRelease(KextManagerCopyLoadedKextInfo((__bridge CFArrayRef) arr, (__bridge CFArrayRef) @[ @"CFBundleVersion" ]));
FF_LIST_FOR_EACH (FFGPUResult, x, *gpus) {
NSString* version = dict[@(x->driver.chars)][@"CFBundleVersion"];
if (version) {
ffStrbufAppendC(&x->driver, ' ');
ffStrbufAppendS(&x->driver, version.UTF8String);
}
}
return nullptr;
}
const char* ffGpuDetectMetal(FFlist* gpus)
{
if (@available(macOS 10.13, *))
{
for (id<MTLDevice> device in MTLCopyAllDevices())
{
FFGPUResult* gpu = nullptr;
FF_LIST_FOR_EACH(FFGPUResult, x, *gpus)
{
if (x->deviceId == device.registryID)
{
gpu = x;
break;
}
const char* ffGpuDetectMetal(FFlist* gpus) {
// Metal.framework is statically linked into the application,
// so `MTLCopyAllDevices` is always available, or the application will not start.
for (id<MTLDevice> device in MTLCopyAllDevices()) {
FFGPUResult* gpu = nullptr;
FF_LIST_FOR_EACH (FFGPUResult, x, *gpus) {
if (x->deviceId == device.registryID) {
gpu = x;
break;
}
if (!gpu) continue;
#ifndef MAC_OS_X_VERSION_10_15
if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily2_v1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 2");
else if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1");
#else // MAC_OS_X_VERSION_10_15
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
if ([device supportsFamily:MTLGPUFamilyMetal4])
ffStrbufSetStatic(&gpu->platformApi, "Metal 4");
else if ([device supportsFamily:MTLGPUFamilyMetal3])
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
#pragma clang diagnostic pop
else if ([device supportsFamily:MTLGPUFamilyCommon3])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
else if ([device supportsFamily:MTLGPUFamilyCommon2])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 2");
else if ([device supportsFamily:MTLGPUFamilyCommon1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->index = (uint32_t) device.locationNumber;
if (device.hasUnifiedMemory && device.recommendedMaxWorkingSetSize > 0)
gpu->shared.total = device.recommendedMaxWorkingSetSize;
#endif
}
return nullptr;
if (!gpu) {
continue;
}
#ifndef MAC_OS_X_VERSION_10_15
if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily2_v1]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 2");
} else if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal Feature Set 1");
}
#else // MAC_OS_X_VERSION_10_15
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
if ([device supportsFamily:MTLGPUFamilyMetal4]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal 4");
} else if ([device supportsFamily:MTLGPUFamilyMetal3]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal 3");
}
#pragma clang diagnostic pop
else if ([device supportsFamily:MTLGPUFamilyCommon3]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 3");
} else if ([device supportsFamily:MTLGPUFamilyCommon2]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 2");
} else if ([device supportsFamily:MTLGPUFamilyCommon1]) {
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
}
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->index = (uint32_t) device.locationNumber;
if (device.hasUnifiedMemory && device.recommendedMaxWorkingSetSize > 0) {
gpu->shared.total = device.recommendedMaxWorkingSetSize;
}
#endif
}
return "Metal API is not supported by this macOS version";
return nullptr;
}
+56 -43
View File
@@ -62,50 +62,63 @@ static void detectGTKFromSettings(FFGTKResult* result) {
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4)) {
themeName = ffSettingsGetXFConf("xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetXFConf("xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetXFConf("xsettings", "/Gtk/FontName", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetXFConfFirstMatch("xfce4-desktop", "/backdrop/screen0", FF_VARIANT_TYPE_STRING, nullptr, testXfconfWallpaperPropKey).strValue;
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON)) {
themeName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", nullptr, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", nullptr, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", nullptr, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", nullptr, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", nullptr, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_MATE)) {
themeName = ffSettingsGetGnome("/org/mate/interface/gtk-theme", "org.mate.interface", nullptr, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/mate/interface/icon-theme", "org.mate.interface", nullptr, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/mate/interface/font-name", "org.mate.interface", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", nullptr, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", nullptr, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/mate/desktop/background", "org.mate.background", nullptr, "picture-filename", FF_VARIANT_TYPE_STRING).strValue;
} else if (
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_NEBIDE)) {
themeName = ffSettingsGetGnome("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", nullptr, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", nullptr, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", nullptr, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", nullptr, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", nullptr, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
} else if (
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_ENLIGHTENMENT)) {
ffEnlightenmentSettings settings = {};
if (ffSettingsGetEnlightenmentProperty(&settings)) {
themeName = settings.theme;
iconsName = settings.icon_theme;
fontName = settings.font;
cursorTheme = settings.use_e_cursor ? "Enlightenment" : "Application";
cursorSize = settings.cursor_size;
wallpaper = settings.desktop_default_background;
if (wmde->dePrettyName.length > 0) {
if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4)) {
themeName = ffSettingsGetXFConf("xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetXFConf("xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetXFConf("xsettings", "/Gtk/FontName", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetXFConfFirstMatch("xfce4-desktop", "/backdrop/screen0", FF_VARIANT_TYPE_STRING, nullptr, testXfconfWallpaperPropKey).strValue;
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON)) {
themeName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", nullptr, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", nullptr, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", nullptr, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", nullptr, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", nullptr, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_MATE)) {
themeName = ffSettingsGetGnome("/org/mate/interface/gtk-theme", "org.mate.interface", nullptr, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/mate/interface/icon-theme", "org.mate.interface", nullptr, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/mate/interface/font-name", "org.mate.interface", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", nullptr, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", nullptr, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/mate/desktop/background", "org.mate.background", nullptr, "picture-filename", FF_VARIANT_TYPE_STRING).strValue;
} else if (
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_NEBIDE)) {
themeName = ffSettingsGetGnome("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", nullptr, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", nullptr, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", nullptr, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", nullptr, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", nullptr, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
} else if (
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_ENLIGHTENMENT)) {
ffEnlightenmentSettings settings = {};
if (ffSettingsGetEnlightenmentProperty(&settings)) {
themeName = settings.theme;
iconsName = settings.icon_theme;
fontName = settings.font;
cursorTheme = settings.use_e_cursor ? "Enlightenment" : "Application";
cursorSize = settings.cursor_size;
wallpaper = settings.desktop_default_background;
}
}
} else {
// Standalone WMs (Hyprland, sway, niri, i3, ...) report no DE and have no settings
// daemon, but GTK apps on them still read org.gnome.desktop.interface.
// Read via DConf, not GSettings: GSettings synthesises the schema default for keys
// the user never set, DConf returns nothing. Runs last; applyGTKSettings() only
// fills still-empty fields, so config files always win.
themeName = ffSettingsGetDConf("/org/gnome/desktop/interface/gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetDConf("/org/gnome/desktop/interface/icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetDConf("/org/gnome/desktop/interface/font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetDConf("/org/gnome/desktop/interface/cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetDConf("/org/gnome/desktop/interface/cursor-size", FF_VARIANT_TYPE_INT).intValue;
}
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper);
+5 -1
View File
@@ -1,6 +1,10 @@
#include "detection/loadavg/loadavg.h"
#include <sys/loadavg.h>
#if __has_include(<sys/loadavg.h>)
#include <sys/loadavg.h>
#else
#include <stdlib.h>
#endif
const char* ffDetectLoadavg(double result[3]) {
return getloadavg(result, 3) == 3 ? nullptr : "getloadavg() failed";
+73 -2
View File
@@ -1,16 +1,87 @@
#include "detection/locale/locale.h"
#include "common/windows/unicode.h"
#include <windows.h>
#include <winnls.h>
const char* ffDetectLocale(FFstrbuf* result) {
ffStrbufAppendS(result, getenv("LC_ALL"));
if (result->length > 0) {
return nullptr;
}
ffStrbufAppendS(result, getenv("LANG")); // Available in MSYS2 and Cygwin
if (result->length > 0) {
return nullptr;
}
wchar_t name[LOCALE_NAME_MAX_LENGTH];
int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH);
if (size <= 1) { // including '\0'
return "GetUserDefaultLocaleName() failed";
}
ffStrbufAppendNWS(result, (uint32_t) size - 1, name);
if (result->length > 2 && result->chars[2] == '-') { // Windows uses '-' instead of '_'
result->chars[2] = '_';
}
ffStrbufSetNWS(result, (uint32_t) size - 1, name);
uint32_t codePage = instance.state.platform.initCP;
if (__builtin_expect(codePage != 0, true)) {
ffStrbufAppendC(result, '.');
switch (codePage) {
case CP_UTF8:
ffStrbufAppendS(result, "UTF-8");
break;
case CP_UTF7:
ffStrbufAppendS(result, "UTF-7");
break;
case 1200:
ffStrbufAppendS(result, "UTF-16LE");
break;
case 1201:
ffStrbufAppendS(result, "UTF-16BE");
break;
case 936:
ffStrbufAppendS(result, "GBK");
break;
case 54936:
ffStrbufAppendS(result, "GB18030");
break;
case 950:
ffStrbufAppendS(result, "BIG5");
break;
case 932:
ffStrbufAppendS(result, "Shift_JIS");
break;
case 949:
ffStrbufAppendS(result, "EUC-KR");
break;
case 20932:
ffStrbufAppendS(result, "EUC-JP");
break;
case 20866:
ffStrbufAppendS(result, "KOI8-R");
break;
case 21866:
ffStrbufAppendS(result, "KOI8-U");
break;
case 20127:
ffStrbufAppendS(result, "US-ASCII");
break;
case 874:
case 1250 ... 1258:
ffStrbufAppendS(result, "Windows-");
ffStrbufAppendUInt(result, codePage);
break;
default:
ffStrbufAppendS(result, "CP");
ffStrbufAppendUInt(result, codePage);
break;
}
}
return nullptr;
}
+1 -2
View File
@@ -70,8 +70,7 @@ const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options) {
uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
uint64_t temp = *currValue;
*currValue -= *prevValue;
*currValue /= (time2 - time1) / 1000 /* seconds */;
*currValue = (*currValue - *prevValue) * 1000 / (time2 - time1); // Calculate per second
*prevValue = temp;
}
}
+32 -2
View File
@@ -8,9 +8,39 @@ void ffDetectOSImpl(FFOSResult* os) {
ffSettingsGetAndroidProperty("ro.build.version.release", &os->version);
ffSettingsGetAndroidProperty("ro.build.version.release", &os->versionID);
ffStrbufSet(&os->versionID, &os->version);
ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename);
unsigned major = 0;
for (const char* p = os->version.chars; *p >= '0' && *p <= '9'; ++p) {
major = major * 10 + (unsigned) (*p - '0');
}
const char* codename = NULL;
// https://en.wikipedia.org/wiki/Android_version_history
// Android 5 is the oldest version supported by Termux
// clang-format off
switch (major) {
case 17: codename = "Cinnamon Bun"; break;
case 16: codename = "Baklava"; break;
case 15: codename = "Vanilla Ice Cream"; break;
case 14: codename = "Upside Down Cake"; break;
case 13: codename = "Tiramisu"; break;
case 12: codename = "Snow Cone"; break;
case 11: codename = "Red Velvet Cake"; break;
case 10: codename = "Quince Tart"; break;
case 9: codename = "Pie"; break;
case 8: codename = "Oreo"; break;
case 7: codename = "Nougat"; break;
case 6: codename = "Marshmallow"; break;
case 5: codename = "Lollipop"; break;
}
// clang-format on
if (codename) {
ffStrbufSetStatic(&os->codename, codename);
} else {
ffSettingsGetAndroidProperty("ro.build.version.codename", &os->codename);
}
ffSettingsGetAndroidProperty("ro.build.id", &os->buildID);
}
+27 -12
View File
@@ -23,13 +23,13 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont) {
};
// alacritty parses config files in this order
if (ffParsePropFileConfigValues("alacritty/alacritty.toml", 2, fontQueryToml)) {
if (ffParsePropFileConfigValues("alacritty/alacritty.toml", 3, fontQueryToml)) {
break;
}
if (ffParsePropFileConfigValues("alacritty.toml", 2, fontQueryToml)) {
if (ffParsePropFileConfigValues("alacritty.toml", 3, fontQueryToml)) {
break;
}
if (ffParsePropFileConfigValues(".alacritty.toml", 2, fontQueryToml)) {
if (ffParsePropFileConfigValues(".alacritty.toml", 3, fontQueryToml)) {
break;
}
} while (false);
@@ -69,7 +69,7 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont) {
ffFontInitMoveValues(&terminalFont->font, &fontFamily, &fontSize, &fontStyle);
}
static void parseGhosttyConfig(const FFstrbuf* path, FFstrbuf* fontName, FFstrbuf* fontNameFallback, FFstrbuf* fontSize, FFlist* configFiles /* list of FFstrbuf */) {
static void parseGhosttyConfig(FFstrbuf* path, FFstrbuf* fontName, FFstrbuf* fontNameFallback, FFstrbuf* fontSize, FFlist* configFiles /* list of FFstrbuf */) {
// Maximum number of `config-file` directives to follow, guarding against runaway includes
enum { FF_GHOSTTY_MAX_CONFIG_FILES = 16 };
@@ -79,7 +79,18 @@ static void parseGhosttyConfig(const FFstrbuf* path, FFstrbuf* fontName, FFstrbu
FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate();
if (!ffAppendFileBuffer(path->chars, &buffer)) {
FF_DEBUG("cannot read config: %s", path->chars);
return;
if (ffStrbufEndsWithS(path, ".ghostty")) {
FF_DEBUG("Trying to load config without .ghostty extension");
path->chars[path->length - strlen(".ghostty")] = '\0';
bool ok = ffAppendFileBuffer(path->chars, &buffer);
path->chars[path->length - strlen(".ghostty")] = '.';
if (!ok) {
FF_DEBUG("cannot read config: %s", path->chars);
return;
}
} else {
return;
}
}
char* line = nullptr;
@@ -87,13 +98,17 @@ static void parseGhosttyConfig(const FFstrbuf* path, FFstrbuf* fontName, FFstrbu
while (ffStrbufGetline(&line, &len, &buffer)) {
if (ffParsePropLine(line, "font-family =", &temp)) {
FF_DEBUG("found font-family='%s' in %s", temp.chars, path->chars);
// Latter overrides former; former becomes the fallback font
if (fontName->length > 0) {
ffStrbufDestroy(fontNameFallback);
ffStrbufInitMove(fontNameFallback, fontName);
// Ghostty appends to a fallback list; the first entry is the primary font.
// An empty value resets the list.
if (temp.length == 0) {
ffStrbufClear(fontName);
ffStrbufClear(fontNameFallback);
} else if (fontName->length == 0) {
ffStrbufSet(fontName, &temp);
} else if (fontNameFallback->length == 0) {
ffStrbufSet(fontNameFallback, &temp);
}
ffStrbufDestroy(fontName);
ffStrbufInitMove(fontName, &temp);
ffStrbufClear(&temp);
} else if (ffParsePropLine(line, "font-size =", &temp)) {
FF_DEBUG("found font-size='%s' in %s", temp.chars, path->chars);
// Latter overrides former
@@ -394,7 +409,7 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina
} else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour")) {
detectContour(&terminal->exe, terminalFont);
} else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty")) {
detectGhostty(terminalFont, "com.mitchellh.ghostty/config", "ghostty/config");
detectGhostty(terminalFont, "com.mitchellh.ghostty/config.ghostty", "ghostty/config.ghostty");
} else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "Muxy")) {
detectGhostty(terminalFont, "Muxy/ghostty.conf", "muxy/ghostty.conf");
} else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "rio")) {
@@ -2,6 +2,7 @@
#include "terminalfont.h"
#include "detection/terminalshell/terminalshell.h"
#include "common/io.h"
#include "common/properties.h"
#ifdef FF_HAVE_FREETYPE
#include "common/library.h"
@@ -10,10 +11,17 @@
#endif
#define FF_TERMUX_FONT_PATH FASTFETCH_TARGET_DIR_HOME "/.termux/font.ttf"
#define FF_TERMUX_PREF_PATH "/data/data/com.termux/shared_prefs/com.termux_preferences.xml"
const char* detectTermux(FFTerminalFontResult* terminalFont) {
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
// SharedPreferences XML: <string name="fontsize">14</string>, in px
if (ffParsePropFile(FF_TERMUX_PREF_PATH, "<string name=\"fontsize\">", &fontSize)) {
ffStrbufAppendS(&fontSize, "px");
}
if (!ffPathExists(FF_TERMUX_FONT_PATH, FF_PATHTYPE_FILE)) {
ffFontInitCopy(&terminalFont->font, "monospace");
ffFontInitValues(&terminalFont->font, "monospace", fontSize.length ? fontSize.chars : nullptr);
return nullptr;
}
@@ -39,7 +47,7 @@ const char* detectTermux(FFTerminalFontResult* terminalFont) {
goto exit;
}
ffFontInitCopy(&terminalFont->font, face->family_name);
ffFontInitValues(&terminalFont->font, face->family_name, fontSize.length ? fontSize.chars : nullptr);
exit:
if (face) {
@@ -53,7 +61,7 @@ exit:
#else
FF_UNUSED(terminalFont);
ffFontInitValues(&terminalFont->font, "monospace", fontSize.length ? fontSize.chars : nullptr);
return "Fastfetch was built without freetype2 support";
#endif
+11
View File
@@ -3,9 +3,20 @@
#include "common/apple/osascript.h"
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
const char* ffDetectWallpaper(FFstrbuf* result)
{
{
// Reliable for user-picked static images.
NSURL* url = [NSWorkspace.sharedWorkspace desktopImageURLForScreen:NSScreen.mainScreen];
if (url.fileURL && ![url.path isEqualToString:@"/System/Library/CoreServices/DefaultDesktop.heic"] /* dynamic wallpapers */)
{
ffStrbufSetS(result, url.path.UTF8String);
return nullptr;
}
}
{
// For Sonoma
// https://github.com/JohnCoates/Aerial/issues/1332
+17 -1
View File
@@ -18,7 +18,8 @@ struct FFWifiConnection {
double rxRate;
double txRate;
uint16_t channel;
uint16_t frequency; // MHz
uint16_t channelWidth; // MHz
uint16_t frequency; // MHz
};
typedef struct FFWifiResult {
@@ -60,3 +61,18 @@ static inline uint16_t ffWifiFreqToChannel(uint16_t frequency) {
return 0;
}
static inline uint16_t ffWifiChannelToFreq(uint16_t channel) {
// Inverse of ffWifiFreqToChannel for the common 2.4 GHz and 5 GHz bands.
// 4.9 GHz and 6 GHz channels overlap numerically, so they are not handled here.
if (channel == 14) {
return 2484;
}
if (channel >= 1 && channel <= 13) {
return (uint16_t) (2407 + 5 * channel);
}
if (channel >= 36 && channel <= 177) { // 5 GHz: 5000 + 5*channel covers 36..177
return (uint16_t) (5000 + 5 * channel);
}
return 0;
}
+1
View File
@@ -42,6 +42,7 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
ffStrbufAppendJsonVal(&item->inf.status, yyjson_obj_get(root, "supplicant_state"));
+58 -30
View File
@@ -1,26 +1,28 @@
#include "wifi.h"
#include "common/processing.h"
#include "common/strutil.h"
#include "common/apple/cf_helpers.h"
#import <CoreWLAN/CoreWLAN.h>
#import <IOKit/IOKitLib.h>
#import <IOKit/kext/KextManager.h>
static inline double rssiToSignalQuality(int rssi)
{
return (double) (rssi >= -50 ? 100 : rssi <= -100 ? 0 : (rssi + 100) * 2);
static inline double rssiToSignalQuality(int rssi) {
return (double) (rssi >= -50 ? 100 : rssi <= -100 ? 0
: (rssi + 100) * 2);
}
@interface CWNetworkProfile()
@property(readonly, retain, nullable) NSArray<NSDictionary *> *bssidList;
@interface CWNetworkProfile ()
@property (readonly, retain, nullable) NSArray<NSDictionary*>* bssidList;
@end
const char* ffDetectWifi(FFlist* result)
{
const char* ffDetectWifi(FFlist* result) {
NSArray<CWInterface*>* interfaces = CWWiFiClient.sharedWiFiClient.interfaces;
if (!interfaces)
if (!interfaces) {
return "CWWiFiClient.sharedWiFiClient.interfaces is nil";
}
for (CWInterface* inf in interfaces)
{
for (CWInterface* inf in interfaces) {
FFWifiResult* item = FF_LIST_ADD(FFWifiResult, *result);
ffStrbufInit(&item->inf.description);
ffStrbufInit(&item->inf.status);
@@ -33,37 +35,42 @@ const char* ffDetectWifi(FFlist* result)
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
ffStrbufAppendS(&item->inf.description, inf.interfaceName.UTF8String);
ffStrbufSetS(&item->inf.description, inf.interfaceName.UTF8String);
ffStrbufSetStatic(&item->inf.status, inf.powerOn ? "Power On" : "Power Off");
if(!inf.powerOn)
if (!inf.powerOn) {
continue;
}
ffStrbufSetStatic(&item->conn.status, inf.interfaceMode != kCWInterfaceModeNone ? "Active" : "Inactive");
if(inf.interfaceMode == kCWInterfaceModeNone)
if (inf.interfaceMode == kCWInterfaceModeNone) {
continue;
}
FF_STRBUF_AUTO_DESTROY ipconfig = ffStrbufCreate();
CWNetworkProfile* networkProfile = inf.configuration.networkProfiles.firstObject;
if (inf.ssid) // https://developer.apple.com/forums/thread/732431
if (inf.ssid) { // https://developer.apple.com/forums/thread/732431
ffStrbufAppendS(&item->conn.ssid, inf.ssid.UTF8String);
else if (networkProfile.ssid)
} else if (networkProfile.ssid) {
ffStrbufSetStatic(&item->conn.ssid, inf.configuration.networkProfiles.firstObject.ssid.UTF8String);
else
} else {
ffStrbufSetStatic(&item->conn.ssid, "<redacted>"); // https://developer.apple.com/forums/thread/732431
}
if (inf.bssid)
if (inf.bssid) {
ffStrbufAppendS(&item->conn.bssid, inf.bssid.UTF8String);
else if (networkProfile.bssidList)
} else if (networkProfile.bssidList) {
ffStrbufSetStatic(&item->conn.bssid, [networkProfile.bssidList.firstObject[@"BSSID"] UTF8String]);
else
} else {
ffStrbufSetStatic(&item->conn.bssid, "<redacted>");
}
switch(inf.activePHYMode)
{
switch (inf.activePHYMode) {
case kCWPHYModeNone:
ffStrbufSetStatic(&item->conn.protocol, "none");
break;
@@ -89,15 +96,15 @@ const char* ffDetectWifi(FFlist* result)
ffStrbufSetStatic(&item->conn.protocol, "802.11be (Wi-Fi 7)");
break;
default:
if (inf.activePHYMode < 8)
if (inf.activePHYMode < 8) {
ffStrbufAppendF(&item->conn.protocol, "Unknown (%ld)", inf.activePHYMode);
}
break;
}
item->conn.signalQuality = rssiToSignalQuality((int) inf.rssiValue);
item->conn.txRate = inf.transmitRate;
switch(inf.security)
{
switch (inf.security) {
case kCWSecurityNone:
ffStrbufSetStatic(&item->conn.security, "Insecure");
break;
@@ -152,12 +159,33 @@ const char* ffDetectWifi(FFlist* result)
}
item->conn.channel = (uint16_t) inf.wlanChannel.channelNumber;
switch (inf.wlanChannel.channelBand)
{
case kCWChannelBand2GHz: item->conn.frequency = 2400; break;
case kCWChannelBand5GHz: item->conn.frequency = 5400; break;
case 3 /*kCWChannelBand6GHz*/: item->conn.frequency = 6400; break;
default: item->conn.frequency = 0; break;
switch (inf.wlanChannel.channelWidth) {
case kCWChannelWidth20MHz: item->conn.channelWidth = 20; break;
case kCWChannelWidth40MHz: item->conn.channelWidth = 40; break;
case kCWChannelWidth80MHz: item->conn.channelWidth = 80; break;
case kCWChannelWidth160MHz: item->conn.channelWidth = 160; break;
default: item->conn.channelWidth = 0; break;
}
FF_IOOBJECT_AUTO_RELEASE io_object_t service = IOServiceGetMatchingService(MACH_PORT_NULL, IOBSDNameMatching(MACH_PORT_NULL, 0, item->inf.description.chars));
FF_CFTYPE_AUTO_RELEASE CFNumberRef frequency;
// Note: IO80211ChannelFrequency is only available when the interface is connected
while (!(frequency = IORegistryEntryCreateCFProperty(service, CFSTR("IO80211ChannelFrequency"), nullptr, kNilOptions))) {
io_object_t parentService = IO_OBJECT_NULL;
if (IORegistryEntryGetParentEntry(service, kIOServicePlane, &parentService) == KERN_SUCCESS) {
IOObjectRelease(service);
service = parentService;
} else {
IOObjectRelease(service);
service = IO_OBJECT_NULL;
break;
}
}
if (frequency) {
int64_t value;
if (ffCfNumGetInt64(frequency, &value) == nil) {
item->conn.frequency = (uint16_t) value;
}
}
}
+11
View File
@@ -37,6 +37,7 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
char ssid[IEEE80211_NWID_LEN + 1] = {};
@@ -80,6 +81,16 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.channel = curchan.ic_ieee;
item->conn.frequency = curchan.ic_freq;
// Determine channel width from channel flags
if (curchan.ic_flags & IEEE80211_CHAN_VHT160)
item->conn.channelWidth = 160;
else if (curchan.ic_flags & IEEE80211_CHAN_VHT80)
item->conn.channelWidth = 80;
else if (curchan.ic_flags & IEEE80211_CHAN_HT40)
item->conn.channelWidth = 40;
else
item->conn.channelWidth = 20;
#ifdef IEEE80211_IS_CHAN_HE // for future use
if (IEEE80211_IS_CHAN_HE(&curchan)) {
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
+101
View File
@@ -0,0 +1,101 @@
extern "C" {
#include "wifi.h"
}
#include <NetworkDevice.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
static void initWifiResult(FFWifiResult* item, const char* name) {
ffStrbufInitS(&item->inf.description, name);
ffStrbufInit(&item->inf.status);
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.bssid);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = -DBL_MAX;
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
}
static void setWifiSecurity(FFstrbuf* security, const wireless_network& network) {
switch (network.authentication_mode) {
case B_NETWORK_AUTHENTICATION_NONE:
if (network.flags & B_NETWORK_IS_ENCRYPTED) {
ffStrbufSetStatic(security, "Encrypted");
} else {
ffStrbufSetStatic(security, "Insecure");
}
break;
case B_NETWORK_AUTHENTICATION_WEP:
ffStrbufSetStatic(security, "WEP");
break;
case B_NETWORK_AUTHENTICATION_WPA:
ffStrbufSetStatic(security, "WPA");
break;
case B_NETWORK_AUTHENTICATION_WPA2:
ffStrbufSetStatic(security, "WPA2");
break;
case B_NETWORK_AUTHENTICATION_EAP:
ffStrbufSetStatic(security, "WPA Enterprise");
break;
default:
ffStrbufSetF(security, "Unknown (%lu)", (unsigned long) network.authentication_mode);
break;
}
}
static void setWifiBssid(FFstrbuf* bssid, const wireless_network& network) {
const uint8* address = network.address.LinkLevelAddress();
if (address == nullptr || network.address.LinkLevelAddressLength() < 6) {
return;
}
ffStrbufSetF(bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
address[0], address[1], address[2], address[3], address[4], address[5]);
}
const char* ffDetectWifi(FFlist* result) {
BNetworkRoster& roster = BNetworkRoster::Default();
BNetworkInterface interface;
uint32 cookie = 0;
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
if (!interface.Exists()) {
continue;
}
BNetworkDevice device(interface.Name());
if (!device.Exists() || !device.IsWireless()) {
continue;
}
FFWifiResult* item = FF_LIST_ADD(FFWifiResult, *result);
initWifiResult(item, interface.Name());
ffStrbufSetStatic(&item->inf.status, interface.HasLink() ? "Up" : "Down");
if (!interface.HasLink() || !device.HasLink()) {
ffStrbufSetStatic(&item->conn.status, "Not connected");
continue;
}
ffStrbufSetStatic(&item->conn.status, "Connected");
uint32 networkCookie = 0;
wireless_network network = {};
if (device.GetNextAssociatedNetwork(networkCookie, network) != B_OK) {
continue;
}
ffStrbufSetNS(&item->conn.ssid, (uint32_t) strnlen(network.name, sizeof(network.name)), network.name);
setWifiBssid(&item->conn.bssid, network);
item->conn.signalQuality = network.signal_strength > 100 ? 100 : network.signal_strength;
setWifiSecurity(&item->conn.security, network);
}
return nullptr;
}
+159 -5
View File
@@ -212,8 +212,9 @@ static bool ffWifiNlInit(FFWifiNlContext* ctx) {
return true;
}
static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFstrbuf* protocol) {
static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFstrbuf* protocol, uint16_t* channelWidth) {
double rate = -DBL_MAX;
uint16_t width = 0;
size_t remaining = ffWifiNlAttrPayload(rateAttr);
for (const struct nlattr* info = (const struct nlattr*) ffWifiNlAttrData(rateAttr);
@@ -223,6 +224,40 @@ static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFst
size_t payload = ffWifiNlAttrPayload(info);
switch (type) {
case NL80211_RATE_INFO_40_MHZ_WIDTH:
width = 40;
break;
case NL80211_RATE_INFO_80_MHZ_WIDTH:
case NL80211_RATE_INFO_80P80_MHZ_WIDTH:
width = 80;
break;
case NL80211_RATE_INFO_160_MHZ_WIDTH:
width = 160;
break;
case 18 /* NL80211_RATE_INFO_320_MHZ_WIDTH */:
width = 320;
break;
case NL80211_RATE_INFO_10_MHZ_WIDTH:
width = 10;
break;
case NL80211_RATE_INFO_5_MHZ_WIDTH:
width = 5;
break;
case 25 /* NL80211_RATE_INFO_1_MHZ_WIDTH */:
width = 1;
break;
case 26 /* NL80211_RATE_INFO_2_MHZ_WIDTH */:
width = 2;
break;
case 27 /* NL80211_RATE_INFO_4_MHZ_WIDTH */:
width = 4;
break;
case 28 /* NL80211_RATE_INFO_8_MHZ_WIDTH */:
width = 8;
break;
case 29 /* NL80211_RATE_INFO_16_MHZ_WIDTH */:
width = 16;
break;
case 30 /* NL80211_RATE_INFO_UHR_MCS */:
ffStrbufSetStatic(protocol, "802.11bn (Wi-Fi 8)");
break;
@@ -254,9 +289,126 @@ static double ffWifiParseBitrateFromRateInfo(const struct nlattr* rateAttr, FFst
}
}
if (rate != -DBL_MAX && *channelWidth == 0) {
*channelWidth = width;
}
return rate;
}
static uint16_t ffWifiChannelWidthToMhz(uint32_t width) {
switch (width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
return 20;
case NL80211_CHAN_WIDTH_40:
return 40;
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80:
return 80;
case NL80211_CHAN_WIDTH_160:
return 160;
case NL80211_CHAN_WIDTH_5:
return 5;
case NL80211_CHAN_WIDTH_10:
return 10;
case NL80211_CHAN_WIDTH_1:
return 1;
case NL80211_CHAN_WIDTH_2:
return 2;
case NL80211_CHAN_WIDTH_4:
return 4;
case NL80211_CHAN_WIDTH_8:
return 8;
case NL80211_CHAN_WIDTH_16:
return 16;
case 13 /* NL80211_CHAN_WIDTH_320 */:
return 320;
default:
return 0;
}
}
static bool ffWifiFetchInterfaceInfo(FFWifiNlContext* ctx, FFWifiResult* item, uint32_t ifIndex) {
struct {
struct nlmsghdr nlh;
struct genlmsghdr genl;
char attrs[32];
} req = {
.nlh = {
.nlmsg_len = NLMSG_LENGTH(sizeof(struct genlmsghdr)),
.nlmsg_type = ctx->nl80211FamilyId,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
.nlmsg_seq = ++ctx->seq,
.nlmsg_pid = ctx->portId,
},
.genl = {
.cmd = NL80211_CMD_GET_INTERFACE,
.version = 0,
},
};
if (!ffWifiNlAppendAttr(&req.nlh, sizeof(req), NL80211_ATTR_IFINDEX, &ifIndex, sizeof(ifIndex))) {
FF_DEBUG("Failed to build nl80211 interface request");
return false;
}
struct sockaddr_nl addr = {
.nl_family = AF_NETLINK,
};
ssize_t sent = sendto(ctx->sockFd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*) &addr, sizeof(addr));
if (sent != (ssize_t) req.nlh.nlmsg_len) {
FF_DEBUG("Failed to send nl80211 interface request");
return false;
}
uint8_t buffer[8192];
while (true) {
ssize_t received = recvfrom(ctx->sockFd, buffer, sizeof(buffer), 0, nullptr, nullptr);
if (received < 0) {
FF_DEBUG("Failed to receive nl80211 interface reply: %s", strerror(errno));
return false;
}
for (const struct nlmsghdr* nlh = (const struct nlmsghdr*) buffer;
NLMSG_OK(nlh, received);
nlh = NLMSG_NEXT(nlh, received)) {
if (nlh->nlmsg_seq != req.nlh.nlmsg_seq) {
continue;
}
if (nlh->nlmsg_type == NLMSG_ERROR) {
const struct nlmsgerr* err = (const struct nlmsgerr*) NLMSG_DATA(nlh);
if (err->error != 0) {
FF_DEBUG("nl80211 interface request failed: %s", strerror(-err->error));
}
return false;
}
if (nlh->nlmsg_type != ctx->nl80211FamilyId) {
continue;
}
const struct genlmsghdr* genl = (const struct genlmsghdr*) NLMSG_DATA(nlh);
size_t attrRemaining = nlh->nlmsg_len - NLMSG_HDRLEN - GENL_HDRLEN;
for (const struct nlattr* attr = (const struct nlattr*) ((const char*) genl + GENL_HDRLEN);
ffWifiNlAttrOk(attr, attrRemaining);
attr = ffWifiNlAttrNext(attr, &attrRemaining)) {
if ((attr->nla_type & NLA_TYPE_MASK) != NL80211_ATTR_CHANNEL_WIDTH ||
ffWifiNlAttrPayload(attr) < sizeof(uint32_t)) {
continue;
}
item->conn.channelWidth = ffWifiChannelWidthToMhz(*(const uint32_t*) ffWifiNlAttrData(attr));
return item->conn.channelWidth != 0;
}
return false;
}
}
}
static void ffWifiApplySecurityFlags(FFWifiResult* item, const FFWifiSecurityFlags* sec) {
ffStrbufClear(&item->conn.security);
@@ -566,13 +718,13 @@ static void ffWifiParseStationInfo(const struct nlattr* staInfoAttr, FFWifiResul
if (type == NL80211_STA_INFO_SIGNAL && payload >= sizeof(uint8_t) && item->conn.signalQuality == -DBL_MAX) {
int rssi = (int8_t) *(const uint8_t*) ffWifiNlAttrData(attr);
item->conn.signalQuality = rssiToSignalQuality(rssi);
} else if (type == NL80211_STA_INFO_TX_BITRATE && item->conn.txRate == -DBL_MAX) {
double tx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol);
} else if (type == NL80211_STA_INFO_TX_BITRATE && (item->conn.txRate == -DBL_MAX || item->conn.channelWidth == 0)) {
double tx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol, &item->conn.channelWidth);
if (tx != -DBL_MAX) {
item->conn.txRate = tx;
}
} else if (type == NL80211_STA_INFO_RX_BITRATE && item->conn.rxRate == -DBL_MAX) {
double rx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol);
} else if (type == NL80211_STA_INFO_RX_BITRATE && (item->conn.rxRate == -DBL_MAX || item->conn.channelWidth == 0)) {
double rx = ffWifiParseBitrateFromRateInfo(attr, &item->conn.protocol, &item->conn.channelWidth);
if (rx != -DBL_MAX) {
item->conn.rxRate = rx;
}
@@ -680,6 +832,7 @@ static const char* detectWithNetlink(FFWifiNlContext* ctx, FFWifiResult* item, u
if (ffWifiFetchScanInfo(ctx, item, ifIndex)) {
FF_DEBUG("found associated BSS: %s", item->conn.ssid.chars);
ffStrbufSetStatic(&item->conn.status, "connected");
ffWifiFetchInterfaceInfo(ctx, item, ifIndex);
ffWifiFetchStationInfo(ctx, item, ifIndex);
if (!item->conn.protocol.length && item->conn.txRate != -DBL_MAX) {
FF_DEBUG("nl80211 station info did not include MCS family fields");
@@ -923,6 +1076,7 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
char operstate;
+11
View File
@@ -47,6 +47,7 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
char ssid[IEEE80211_NWID_LEN + 1] = {};
@@ -91,6 +92,16 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.channel = ffWifiFreqToChannel(curchan.ic_freq);
item->conn.frequency = curchan.ic_freq;
// Determine channel width from channel flags
if (curchan.ic_flags & IEEE80211_CHAN_VHT160)
item->conn.channelWidth = 160;
else if (curchan.ic_flags & IEEE80211_CHAN_VHT80)
item->conn.channelWidth = 80;
else if (curchan.ic_flags & IEEE80211_CHAN_HT40)
item->conn.channelWidth = 40;
else
item->conn.channelWidth = 20;
#ifdef IEEE80211_IS_CHAN_HE // for future use
if (IEEE80211_IS_CHAN_HE(&curchan)) {
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
+36 -21
View File
@@ -1,6 +1,5 @@
#include "wifi.h"
#include "common/io.h"
#include "common/strutil.h"
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -17,12 +16,20 @@ const char* ffDetectWifi(FFlist* result) {
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
if_freenameindex(infs);
return "socket() failed";
}
for (struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == nullptr); ++i) {
if (!ffStrStartsWith(i->if_name, "iwm")) {
continue;
struct ieee80211_nodereq nr = {};
strlcpy(nr.nr_ifname, i->if_name, sizeof(nr.nr_ifname));
int err = 0;
if (ioctl(sock, SIOCG80211NODE, &nr) < 0) {
err = errno;
if (err == ENXIO || err == ENODEV || err == EINVAL || err == ENOTTY) {
continue; // Not a Wi-Fi interface
}
}
FFWifiResult* item = FF_LIST_ADD(FFWifiResult, *result);
@@ -37,11 +44,9 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0; // not exposed by ieee80211_nodereq
item->conn.frequency = 0;
struct ieee80211_nodereq nr = {};
strlcpy(nr.nr_ifname, i->if_name, sizeof(nr.nr_ifname));
struct ifreq ifr = {};
strlcpy(ifr.ifr_name, i->if_name, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
@@ -50,31 +55,34 @@ const char* ffDetectWifi(FFlist* result) {
ffStrbufSetStatic(&item->inf.status, ifr.ifr_flags & IFF_UP ? "Up" : "Down");
}
if (ioctl(sock, SIOCG80211NODE, &nr) < 0) {
ffStrbufSetStatic(&item->conn.status, "Not associated");
continue;
}
if (nr.nr_nwid_len > 0) {
ffStrbufSetStatic(&item->conn.status, "Associated");
ffStrbufAppendNS(&item->conn.ssid, nr.nr_nwid_len, (char*) nr.nr_nwid);
} else {
if (err != 0 || nr.nr_nwid_len == 0) {
ffStrbufSetStatic(&item->conn.status, "Not associated");
continue;
}
ffStrbufSetStatic(&item->conn.status, "Associated");
ffStrbufAppendNS(&item->conn.ssid, nr.nr_nwid_len, (char*) nr.nr_nwid);
ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X", nr.nr_bssid[0], nr.nr_bssid[1], nr.nr_bssid[2], nr.nr_bssid[3], nr.nr_bssid[4], nr.nr_bssid[5]);
item->conn.channel = nr.nr_channel;
if (item->conn.channel == 0) {
struct ieee80211chanreq chreq = {};
strlcpy(chreq.i_name, i->if_name, sizeof(chreq.i_name));
if (ioctl(sock, SIOCG80211CHANNEL, &chreq) >= 0) {
item->conn.channel = chreq.i_channel;
}
}
item->conn.frequency = ffWifiChannelToFreq(item->conn.channel);
if (nr.nr_max_rssi) {
item->conn.signalQuality = ((float) nr.nr_rssi / nr.nr_max_rssi) * 100.0;
item->conn.signalQuality = ((double) nr.nr_rssi / (double) nr.nr_max_rssi) * 100.0;
}
if (nr.nr_flags & IEEE80211_NODEREQ_HT) {
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
} else if (nr.nr_flags & IEEE80211_NODEREQ_VHT) {
// VHT implies HT, so test VHT first
if (nr.nr_flags & IEEE80211_NODEREQ_VHT) {
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
} else if (nr.nr_flags & IEEE80211_NODEREQ_HT) {
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
} else if (nr.nr_chan_flags & IEEE80211_CHANINFO_5GHZ) {
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
} else if (nr.nr_chan_flags & IEEE80211_CHANINFO_2GHZ) {
@@ -85,15 +93,22 @@ const char* ffDetectWifi(FFlist* result) {
strlcpy(wpa.i_name, i->if_name, sizeof(wpa.i_name));
if (ioctl(sock, SIOCG80211WPAPARMS, &wpa) >= 0 && wpa.i_enabled) {
if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2) {
if (wpa.i_akms & IEEE80211_WPA_AKM_SAE) {
if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2) {
ffStrbufSetStatic(&item->conn.security, "WPA2/WPA3");
} else {
ffStrbufSetStatic(&item->conn.security, "WPA3");
}
} else if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2) {
ffStrbufSetStatic(&item->conn.security, "WPA2");
} else if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1) {
ffStrbufSetStatic(&item->conn.security, "WPA");
} else {
ffStrbufSetStatic(&item->conn.security, "Unknown");
}
} else {
struct ieee80211_nwkey nwkey = {};
strlcpy(nwkey.i_name, i->if_name, sizeof(nwkey.i_name));
if (ioctl(sock, SIOCG80211NWKEY, &nwkey) >= 0) {
if (nwkey.i_wepon) {
ffStrbufSetStatic(&item->conn.security, "WEP");
+195
View File
@@ -0,0 +1,195 @@
#include "wifi.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include <dirent.h>
#include <fcntl.h>
#include <stropts.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <inet/wifi_ioctl.h>
static bool getWifiValue(int fd, uint32_t id, void* value, size_t valueSize, wldp_t* buffer) {
memset(buffer, 0, MAX_BUF_LEN);
buffer->wldp_type = NET_802_11;
buffer->wldp_id = id;
struct strioctl request = {
.ic_cmd = WLAN_GET_PARAM,
.ic_timout = 0,
.ic_len = MAX_BUF_LEN,
.ic_dp = (char*) buffer,
};
if (ioctl(fd, I_STR, &request) != 0 || buffer->wldp_result != WL_SUCCESS || buffer->wldp_length < WIFI_BUF_OFFSET + valueSize || buffer->wldp_length > MAX_BUF_LEN) {
return false;
}
memcpy(value, buffer->wldp_buf, valueSize);
return true;
}
static void setWifiProtocol(FFstrbuf* protocol, uint32_t subtype, bool htEnabled) {
switch (subtype) {
case WL_FHSS:
ffStrbufSetStatic(protocol, "802.11 (FHSS)");
break;
case WL_DSSS:
ffStrbufSetStatic(protocol, "802.11 (DSSS)");
break;
case WL_IRBASE:
ffStrbufSetStatic(protocol, "802.11 (IR)");
break;
case WL_OFDM:
ffStrbufSetStatic(protocol, htEnabled ? "802.11n (Wi-Fi 4)" : "802.11a");
break;
case WL_HRDS:
ffStrbufSetStatic(protocol, "802.11b");
break;
case WL_ERP:
ffStrbufSetStatic(protocol, htEnabled ? "802.11n (Wi-Fi 4)" : "802.11g");
break;
default:
break;
}
}
static void setWifiSecurity(FFstrbuf* security, uint32_t encryption, bool haveAuthMode, uint32_t authMode) {
switch (encryption) {
case WL_NOENCRYPTION:
ffStrbufSetStatic(security, "Insecure");
break;
case WL_ENC_WEP:
ffStrbufSetStatic(security, "WEP");
break;
case WL_ENC_WPA:
ffStrbufSetStatic(security, haveAuthMode && authMode == WL_SHAREDKEY ? "WPA Shared Key" : "WPA");
break;
default:
ffStrbufSetStatic(security, "Unknown");
break;
}
}
const char* ffDetectWifi(FFlist* result) {
// https://github.com/illumos/illumos-gate/blob/master/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c
FF_AUTO_CLOSE_DIR DIR* directory = opendir("/dev/wifi");
if (!directory) {
return nullptr;
}
FF_AUTO_FREE void* bufferMemory = malloc(MAX_BUF_LEN);
if (!bufferMemory) {
return "malloc() failed";
}
wldp_t* buffer = (wldp_t*) bufferMemory;
struct dirent* entry;
while ((entry = readdir(directory)) != nullptr) {
size_t nameLength = strlen(entry->d_name);
if (nameLength == 0 || entry->d_name[nameLength - 1] < '0' || entry->d_name[nameLength - 1] > '9') {
continue;
}
char devicePath[PATH_MAX];
int pathLength = snprintf(devicePath, sizeof(devicePath), "/dev/wifi/%s", entry->d_name);
if (pathLength < 0 || (size_t) pathLength >= sizeof(devicePath)) {
continue;
}
FF_AUTO_CLOSE_FD int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if (fd < 0) {
continue;
}
if (!isastream(fd)) {
continue;
}
FFWifiResult* item = FF_LIST_ADD(FFWifiResult, *result);
ffStrbufInitS(&item->inf.description, entry->d_name);
ffStrbufInit(&item->inf.status);
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.bssid);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = -DBL_MAX;
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
wl_radio_t radio;
if (getWifiValue(fd, WL_RADIO, &radio, sizeof(radio), buffer)) {
ffStrbufSetStatic(&item->inf.status, radio ? "Up" : "Down");
} else {
ffStrbufSetStatic(&item->inf.status, "Unknown");
}
wl_linkstatus_t linkStatus;
if (!getWifiValue(fd, WL_LINKSTATUS, &linkStatus, sizeof(linkStatus), buffer)) {
ffStrbufSetStatic(&item->conn.status, "Unknown");
continue;
}
if (linkStatus != WL_CONNECTED) {
ffStrbufSetStatic(&item->conn.status, "Not connected");
continue;
}
ffStrbufSetStatic(&item->conn.status, "Connected");
wl_essid_t essid;
if (getWifiValue(fd, WL_ESSID, &essid, sizeof(essid), buffer) && essid.wl_essid_length > 0 && essid.wl_essid_length < sizeof(essid.wl_essid_essid) && essid.wl_essid_length <= MAX_ESSID_LENGTH - 1) {
ffStrbufSetNS(&item->conn.ssid, essid.wl_essid_length, essid.wl_essid_essid);
}
wl_bssid_t bssid;
if (getWifiValue(fd, WL_BSSID, bssid, sizeof(bssid), buffer)) {
ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X", (uint8_t) bssid[0], (uint8_t) bssid[1], (uint8_t) bssid[2], (uint8_t) bssid[3], (uint8_t) bssid[4], (uint8_t) bssid[5]);
}
wl_rssi_t rssi;
if (getWifiValue(fd, WL_RSSI, &rssi, sizeof(rssi), buffer)) {
item->conn.signalQuality = rssi >= MAX_RSSI ? 100.0 : ((double) rssi / MAX_RSSI) * 100.0;
}
wl_phy_conf_t phy;
if (getWifiValue(fd, WL_PHY_CONFIG, &phy, sizeof(phy), buffer)) {
uint32_t subtype = phy.wl_phy_dsss_conf.wl_dsss_subtype;
switch (subtype) {
case WL_FHSS:
item->conn.channel = (uint16_t) phy.wl_phy_fhss_conf.wl_fhss_channel;
setWifiProtocol(&item->conn.protocol, subtype, false);
break;
case WL_DSSS:
item->conn.channel = (uint16_t) phy.wl_phy_dsss_conf.wl_dsss_channel;
setWifiProtocol(&item->conn.protocol, subtype, false);
break;
case WL_OFDM:
item->conn.frequency = (uint16_t) phy.wl_phy_ofdm_conf.wl_ofdm_frequency;
item->conn.channel = ffWifiFreqToChannel(item->conn.frequency);
setWifiProtocol(&item->conn.protocol, subtype, phy.wl_phy_ofdm_conf.wl_ofdm_ht_enabled);
break;
case WL_ERP:
item->conn.channel = (uint16_t) phy.wl_phy_erp_conf.wl_erp_channel;
setWifiProtocol(&item->conn.protocol, subtype, phy.wl_phy_erp_conf.wl_erp_ht_enabled);
break;
default:
setWifiProtocol(&item->conn.protocol, subtype, false);
break;
}
}
wl_encryption_t encryption;
wl_authmode_t authMode;
bool haveEncryption = getWifiValue(fd, WL_ENCRYPTION, &encryption, sizeof(encryption), buffer);
bool haveAuthMode = getWifiValue(fd, WL_AUTH_MODE, &authMode, sizeof(authMode), buffer);
if (haveEncryption) {
setWifiSecurity(&item->conn.security, encryption, haveAuthMode, authMode);
}
}
return nullptr;
}
+68 -24
View File
@@ -5,41 +5,59 @@
#include <windows.h>
#include <wlanapi.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
static void convertIfStateToString(WLAN_INTERFACE_STATE state, FFstrbuf* result) {
switch (state) {
case wlan_interface_state_not_ready:
ffStrbufAppendS(result, "Not ready");
ffStrbufSetStatic(result, "Not ready");
break;
case wlan_interface_state_connected:
ffStrbufAppendS(result, "Connected");
ffStrbufSetStatic(result, "Connected");
break;
case wlan_interface_state_ad_hoc_network_formed:
ffStrbufAppendS(result, "Ad hoc network formed");
ffStrbufSetStatic(result, "Ad hoc network formed");
break;
case wlan_interface_state_disconnecting:
ffStrbufAppendS(result, "Disconnecting");
ffStrbufSetStatic(result, "Disconnecting");
break;
case wlan_interface_state_disconnected:
ffStrbufAppendS(result, "Disconnected");
ffStrbufSetStatic(result, "Disconnected");
break;
case wlan_interface_state_associating:
ffStrbufAppendS(result, "Associating");
ffStrbufSetStatic(result, "Associating");
break;
case wlan_interface_state_discovering:
ffStrbufAppendS(result, "Discovering");
ffStrbufSetStatic(result, "Discovering");
break;
case wlan_interface_state_authenticating:
ffStrbufAppendS(result, "Authenticating");
ffStrbufSetStatic(result, "Authenticating");
break;
default:
ffStrbufAppendS(result, "Unknown");
ffStrbufSetStatic(result, "Unknown");
break;
}
}
typedef struct _WLAN_REALTIME_CONNECTION_QUALITY_LINK_INFO {
UCHAR ucLinkID;
ULONG ulChannelCenterFrequencyMhz;
ULONG ulBandwidth;
LONG lRssi;
WLAN_RATE_SET wlanRateSet;
} WLAN_REALTIME_CONNECTION_QUALITY_LINK_INFO, *PWLAN_REALTIME_CONNECTION_QUALITY_LINK_INFO;
typedef struct _WLAN_REALTIME_CONNECTION_QUALITY {
DOT11_PHY_TYPE dot11PhyType;
ULONG ulLinkQuality;
ULONG ulRxRate;
ULONG ulTxRate;
BOOL bIsMLOConnection;
ULONG ulNumLinks;
// Array of size ulNumLinks
WLAN_REALTIME_CONNECTION_QUALITY_LINK_INFO linksInfo[];
} WLAN_REALTIME_CONNECTION_QUALITY, *PWLAN_REALTIME_CONNECTION_QUALITY;
enum { wlan_intf_opcode_realtime_connection_quality = 19 };
const char* ffDetectWifi(FFlist* result) {
FF_LIBRARY_LOAD_MESSAGE(wlanapi, "wlanapi" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wlanapi, WlanOpenHandle)
@@ -54,7 +72,7 @@ const char* ffDetectWifi(FFlist* result) {
WLAN_INTERFACE_INFO_LIST* ifList = nullptr;
const char* error = nullptr;
if (ffWlanOpenHandle(2, nullptr, &curVersion, &hClient) != ERROR_SUCCESS) {
if (ffWlanOpenHandle(2 /*maxClientVersion*/, nullptr, &curVersion, &hClient) != ERROR_SUCCESS) {
error = "WlanOpenHandle() failed";
goto exit;
}
@@ -79,6 +97,7 @@ const char* ffDetectWifi(FFlist* result) {
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.channelWidth = 0;
item->conn.frequency = 0;
convertIfStateToString(ifInfo->isState, &item->inf.status);
@@ -200,17 +219,44 @@ const char* ffDetectWifi(FFlist* result) {
ffStrbufAppendS(&item->conn.security, "Insecure");
}
WLAN_BSS_LIST* bssList = nullptr;
if (ffWlanGetNetworkBssList(hClient,
WLAN_REALTIME_CONNECTION_QUALITY* connectionQuality = nullptr;
bufSize = 0;
if (ffWlanQueryInterface(hClient,
&ifInfo->InterfaceGuid,
&connInfo->wlanAssociationAttributes.dot11Ssid,
connInfo->wlanAssociationAttributes.dot11BssType,
connInfo->wlanSecurityAttributes.bSecurityEnabled,
wlan_intf_opcode_realtime_connection_quality,
nullptr,
&bssList) == ERROR_SUCCESS &&
bssList->dwNumberOfItems > 0) {
item->conn.frequency = (uint16_t) (bssList->wlanBssEntries[0].ulChCenterFrequency / 1000);
ffWlanFreeMemory(bssList);
&bufSize,
(PVOID*) &connectionQuality,
&opCode) == ERROR_SUCCESS) {
const WLAN_REALTIME_CONNECTION_QUALITY_LINK_INFO* bestLink = nullptr;
for (ULONG linkIndex = 0; linkIndex < connectionQuality->ulNumLinks; ++linkIndex) {
const WLAN_REALTIME_CONNECTION_QUALITY_LINK_INFO* link = &connectionQuality->linksInfo[linkIndex];
if (!bestLink || link->lRssi > bestLink->lRssi) {
bestLink = link;
}
}
if (bestLink) {
item->conn.channelWidth = (uint16_t) bestLink->ulBandwidth;
item->conn.frequency = (uint16_t) bestLink->ulChannelCenterFrequencyMhz;
}
}
if (connectionQuality) {
ffWlanFreeMemory(connectionQuality);
}
if (item->conn.frequency == 0) {
WLAN_BSS_LIST* bssList = nullptr;
if (ffWlanGetNetworkBssList(hClient,
&ifInfo->InterfaceGuid,
&connInfo->wlanAssociationAttributes.dot11Ssid,
connInfo->wlanAssociationAttributes.dot11BssType,
connInfo->wlanSecurityAttributes.bSecurityEnabled,
nullptr,
&bssList) == ERROR_SUCCESS &&
bssList->dwNumberOfItems > 0) {
item->conn.frequency = (uint16_t) (bssList->wlanBssEntries[0].ulChCenterFrequency / 1000);
ffWlanFreeMemory(bssList);
}
}
ffWlanFreeMemory(connInfo);
@@ -238,5 +284,3 @@ exit:
}
return error;
}
#pragma GCC diagnostic pop
+52
View File
@@ -0,0 +1,52 @@
#include "fastfetch.h"
#include "wmtheme.h"
#include "common/apple/cf_helpers.h"
bool ffDetectWmTheme(FFstrbuf* themeOrError) {
// Read via cfprefsd instead of the raw plist file to keep cache consistency with the system
FF_CFTYPE_AUTO_RELEASE CFTypeRef wmThemeColor = CFPreferencesCopyAppValue(CFSTR("AppleAccentColor"), kCFPreferencesAnyApplication);
int32_t accentColor = -2; // -2: not set; -1 is Graphite
if (wmThemeColor && ffCfNumGetInt(wmThemeColor, &accentColor) == nullptr) {
switch (accentColor) {
case -1:
ffStrbufAppendS(themeOrError, "Graphite");
break;
case 0:
ffStrbufAppendS(themeOrError, "Red");
break;
case 1:
ffStrbufAppendS(themeOrError, "Orange");
break;
case 2:
ffStrbufAppendS(themeOrError, "Yellow");
break;
case 3:
ffStrbufAppendS(themeOrError, "Green");
break;
case 4:
ffStrbufAppendS(themeOrError, "Blue");
break;
case 5:
ffStrbufAppendS(themeOrError, "Purple");
break;
case 6:
ffStrbufAppendS(themeOrError, "Pink");
break;
default:
ffStrbufAppendS(themeOrError, "Unknown");
break;
}
} else {
ffStrbufAppendS(themeOrError, "Multicolor");
}
FF_STRBUF_AUTO_DESTROY style = ffStrbufCreate();
FF_CFTYPE_AUTO_RELEASE CFTypeRef wmTheme = CFPreferencesCopyAppValue(CFSTR("AppleInterfaceStyle"), kCFPreferencesAnyApplication);
if (wmTheme && ffCfStrGetString(wmTheme, &style) == nullptr) {
ffStrbufAppendF(themeOrError, " (%s)", style.chars);
} else {
ffStrbufAppendS(themeOrError, " (Light)");
}
return true;
}
-40
View File
@@ -1,40 +0,0 @@
#include "fastfetch.h"
#include "wmtheme.h"
#import <Foundation/Foundation.h>
bool ffDetectWmTheme(FFstrbuf* themeOrError)
{
NSError* error;
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/.GlobalPreferences.plist", instance.state.platform.homeDir.chars];
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
error:&error];
if(error)
{
ffStrbufAppendS(themeOrError, error.localizedDescription.UTF8String);
return false;
}
NSNumber* wmThemeColor = dict[@"AppleAccentColor"];
if(!wmThemeColor)
ffStrbufAppendS(themeOrError, "Multicolor");
else
{
switch(wmThemeColor.intValue)
{
case -1: ffStrbufAppendS(themeOrError, "Graphite"); break;
case 0: ffStrbufAppendS(themeOrError, "Red"); break;
case 1: ffStrbufAppendS(themeOrError, "Orange"); break;
case 2: ffStrbufAppendS(themeOrError, "Yellow"); break;
case 3: ffStrbufAppendS(themeOrError, "Green"); break;
case 4: ffStrbufAppendS(themeOrError, "Blue"); break;
case 5: ffStrbufAppendS(themeOrError, "Purple"); break;
case 6: ffStrbufAppendS(themeOrError, "Pink"); break;
default: ffStrbufAppendS(themeOrError, "Unknown"); break;
}
}
NSString* wmTheme = dict[@"AppleInterfaceStyle"];
ffStrbufAppendF(themeOrError, " (%s)", wmTheme ? wmTheme.UTF8String : "Light");
return true;
}
-1
View File
@@ -31,7 +31,6 @@ typedef struct FFstate {
uint32_t logoWidth;
uint32_t logoHeight;
uint32_t keysHeight;
bool terminalLightTheme;
bool titleFqdn;
uint32_t dynamicInterval;
FFPlatform platform;
+1 -1
View File
@@ -996,7 +996,7 @@ bool ffLogoPrintImageIfExists(FFLogoType type, bool printError) {
}
const char* term = getenv("TERM");
if ((term && ffStrEquals(term, "screen")) || getenv("ZELLIJ")) {
if (term && ffStrEquals(term, "screen")) {
if (printError) {
fputs("Logo: Image logo is not supported in terminal multiplexers\n", stderr);
}
+28 -6
View File
@@ -11,9 +11,9 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
if (options->moduleArgs.key.length == 0) {
if (result->modelName.length > 0) {
ffStrbufSetF(&key, "%s (%s)", FF_BATTERY_MODULE_NAME, result->modelName.chars);
ffStrbufSetF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Battery), result->modelName.chars);
} else {
ffStrbufSetS(&key, FF_BATTERY_MODULE_NAME);
ffStrbufSetS(&key, FF_MODULE_GET_DISPLAY_NAME(Battery));
}
} else {
ffStrbufClear(&key);
@@ -170,11 +170,11 @@ bool ffPrintBattery(FFBatteryOptions* options) {
const char* error = ffDetectBattery(options, &results);
if (error) {
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Battery), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (results.length == 0) {
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No batteries found");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Battery), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No batteries found");
return false;
}
@@ -209,7 +209,7 @@ void ffParseBatteryJsonObject(FFBatteryOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Battery), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -297,8 +297,30 @@ void ffDestroyBatteryOptions(FFBatteryOptions* options) {
}
FFModuleBaseInfo ffBatteryModuleInfo = {
.name = FF_BATTERY_MODULE_NAME,
.name = "Battery",
.description = "Print battery information",
.displayName = {
.en = "Battery",
.ar = "البطارية",
.cs = "Baterie",
.de = "Akku",
.es = "Batería",
.fr = "Batterie",
.gl = "Batería",
.he = "סוללה",
.id = "Baterai",
.it = "Batteria",
.ja = "バッテリー",
.ko = "배터리",
.pl = "Bateria",
.pt = "Bateria",
.ru = "Батарея",
.tr = "Pil",
.uk = "Батарея",
.vi = "Pin",
.zh_CN = "电池",
.zh_TW = "電池",
},
.initOptions = (void*) ffInitBatteryOptions,
.destroyOptions = (void*) ffDestroyBatteryOptions,
.parseJsonObject = (void*) ffParseBatteryJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BATTERY_MODULE_NAME "Battery"
bool ffPrintBattery(FFBatteryOptions* options);
void ffInitBatteryOptions(FFBatteryOptions* options);
void ffDestroyBatteryOptions(FFBatteryOptions* options);
+27 -5
View File
@@ -18,12 +18,12 @@ bool ffPrintBios(FFBiosOptions* options) {
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
if (error) {
ffPrintError(FF_BIOS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bios), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
goto exit;
}
if (bios.version.length == 0) {
ffPrintError(FF_BIOS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "bios_version is not set.");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bios), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "bios_version is not set.");
goto exit;
}
@@ -34,7 +34,7 @@ bool ffPrintBios(FFBiosOptions* options) {
ffStrbufSetStatic(&bios.type, "Legacy");
}
ffStrbufSetF(&key, FF_BIOS_MODULE_NAME " (%s)", bios.type.chars);
ffStrbufSetF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Bios), bios.type.chars);
} else {
ffStrbufClear(&key);
FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
@@ -80,7 +80,7 @@ void ffParseBiosJsonObject(FFBiosOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_BIOS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bios), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -130,8 +130,30 @@ void ffDestroyBiosOptions(FFBiosOptions* options) {
}
FFModuleBaseInfo ffBiosModuleInfo = {
.name = FF_BIOS_MODULE_NAME,
.name = "BIOS",
.description = "Print first-stage bootloader information (name, version, release date, etc.)",
.displayName = {
.en = "BIOS",
.ar = "BIOS",
.cs = "BIOS",
.de = "BIOS",
.es = "BIOS",
.fr = "BIOS",
.gl = "BIOS",
.he = "BIOS",
.id = "BIOS",
.it = "BIOS",
.ja = "BIOS",
.ko = "BIOS",
.pl = "BIOS",
.pt = "BIOS",
.ru = "BIOS",
.tr = "BIOS",
.uk = "BIOS",
.vi = "BIOS",
.zh_CN = "BIOS",
.zh_TW = "BIOS",
},
.initOptions = (void*) ffInitBiosOptions,
.destroyOptions = (void*) ffDestroyBiosOptions,
.parseJsonObject = (void*) ffParseBiosJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BIOS_MODULE_NAME "BIOS"
bool ffPrintBios(FFBiosOptions* options);
void ffInitBiosOptions(FFBiosOptions* options);
void ffDestroyBiosOptions(FFBiosOptions* options);
+28 -6
View File
@@ -8,7 +8,7 @@
static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* device, uint8_t index) {
FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Bluetooth), index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
bool showBatteryLevel = device->battery > 0 && device->battery <= 100;
@@ -44,7 +44,7 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de
ffPercentAppendBar(&percentageBar, device->battery, options->percent, &options->moduleArgs);
}
FF_PRINT_FORMAT_CHECKED(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Bluetooth), index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(device->name, "name"),
FF_ARG(device->address, "address"),
FF_ARG(device->type, "type"),
@@ -60,12 +60,12 @@ bool ffPrintBluetooth(FFBluetoothOptions* options) {
const char* error = ffDetectBluetooth(options, &devices);
if (error) {
ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bluetooth), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (devices.length == 0) {
ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No bluetooth devices found");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bluetooth), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No bluetooth devices found");
return false;
}
@@ -100,7 +100,7 @@ void ffParseBluetoothJsonObject(FFBluetoothOptions* options, yyjson_val* module)
continue;
}
ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bluetooth), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -151,8 +151,30 @@ void ffDestroyBluetoothOptions(FFBluetoothOptions* options) {
}
FFModuleBaseInfo ffBluetoothModuleInfo = {
.name = FF_BLUETOOTH_MODULE_NAME,
.name = "Bluetooth",
.description = "List connected Bluetooth devices",
.displayName = {
.en = "Bluetooth",
.ar = "بلوتوث",
.cs = "Bluetooth",
.de = "Bluetooth",
.es = "Bluetooth",
.fr = "Bluetooth",
.gl = "Bluetooth",
.he = "בלוטות'",
.id = "Bluetooth",
.it = "Bluetooth",
.ja = "ブルートゥース",
.ko = "블루투스",
.pl = "Bluetooth",
.pt = "Bluetooth",
.ru = "Bluetooth",
.tr = "Bluetooth",
.uk = "Bluetooth",
.vi = "Bluetooth",
.zh_CN = "蓝牙设备",
.zh_TW = "藍牙裝置",
},
.initOptions = (void*) ffInitBluetoothOptions,
.destroyOptions = (void*) ffDestroyBluetoothOptions,
.parseJsonObject = (void*) ffParseBluetoothJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BLUETOOTH_MODULE_NAME "Bluetooth"
bool ffPrintBluetooth(FFBluetoothOptions* options);
void ffInitBluetoothOptions(FFBluetoothOptions* options);
void ffDestroyBluetoothOptions(FFBluetoothOptions* options);
+28 -8
View File
@@ -5,8 +5,6 @@
#include "detection/bluetoothradio/bluetoothradio.h"
#include "modules/bluetoothradio/bluetoothradio.h"
#define FF_BLUETOOTHRADIO_DISPLAY_NAME "Bluetooth Radio"
static void destroyBluetoothRadios(FFlist* radios) {
FF_LIST_FOR_EACH (FFBluetoothRadioResult, radio, *radios) {
ffStrbufDestroy(&radio->name);
@@ -18,7 +16,7 @@ static void destroyBluetoothRadios(FFlist* radios) {
static void printDevice(FFBluetoothRadioOptions* options, const FFBluetoothRadioResult* radio, uint8_t index) {
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
if (options->moduleArgs.key.length == 0) {
ffStrbufAppendF(&key, "%s (%s)", FF_BLUETOOTHRADIO_DISPLAY_NAME, radio->name.chars);
ffStrbufAppendF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(BluetoothRadio), radio->name.chars);
} else {
FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
FF_ARG(index, "index"),
@@ -101,7 +99,7 @@ bool ffPrintBluetoothRadio(FFBluetoothRadioOptions* options) {
const char* error = ffDetectBluetoothRadio(&radios);
if (error) {
ffPrintError(FF_BLUETOOTHRADIO_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(BluetoothRadio), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
@@ -117,9 +115,9 @@ bool ffPrintBluetoothRadio(FFBluetoothRadioOptions* options) {
if (index == 0) {
if (radios.length > 0) {
ffPrintError(FF_BLUETOOTHRADIO_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Bluetooth radios found but none enabled");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(BluetoothRadio), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Bluetooth radios found but none enabled");
} else {
ffPrintError(FF_BLUETOOTHRADIO_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No devices detected");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(BluetoothRadio), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No devices detected");
}
destroyBluetoothRadios(&radios);
return false;
@@ -137,7 +135,7 @@ void ffParseBluetoothRadioJsonObject(FFBluetoothRadioOptions* options, yyjson_va
continue;
}
ffPrintError(FF_BLUETOOTHRADIO_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(BluetoothRadio), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -190,8 +188,30 @@ void ffDestroyBluetoothRadioOptions(FFBluetoothRadioOptions* options) {
}
FFModuleBaseInfo ffBluetoothRadioModuleInfo = {
.name = FF_BLUETOOTHRADIO_MODULE_NAME,
.name = "BluetoothRadio",
.description = "List Bluetooth radios (supported versions, vendors, etc.)",
.displayName = {
.en = "Bluetooth Radio",
.ar = "راديو بلوتوث",
.cs = "Bluetooth rádio",
.de = "Bluetooth-Adapter",
.es = "Adaptador Bluetooth",
.fr = "Adaptateur Bluetooth",
.gl = "Adaptador Bluetooth",
.he = "רדיו בלוטות'",
.id = "Radio Bluetooth",
.it = "Adattatore Bluetooth",
.ja = "ブルートゥースアダプター",
.ko = "블루투스 어댑터",
.pl = "Adapter Bluetooth",
.pt = "Adaptador Bluetooth",
.ru = "Bluetooth-адаптер",
.tr = "Bluetooth Radyosu",
.uk = "Радіомодуль Bluetooth",
.vi = "Radio Bluetooth",
.zh_CN = "蓝牙适配器",
.zh_TW = "藍牙配接器",
},
.initOptions = (void*) ffInitBluetoothRadioOptions,
.destroyOptions = (void*) ffDestroyBluetoothRadioOptions,
.parseJsonObject = (void*) ffParseBluetoothRadioJsonObject,
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BLUETOOTHRADIO_MODULE_NAME "BluetoothRadio"
bool ffPrintBluetoothRadio(FFBluetoothRadioOptions* options);
void ffInitBluetoothRadioOptions(FFBluetoothRadioOptions* options);
void ffDestroyBluetoothRadioOptions(FFBluetoothRadioOptions* options);
+28 -6
View File
@@ -14,24 +14,24 @@ bool ffPrintBoard(FFBoardOptions* options) {
const char* error = ffDetectBoard(&result);
if (error) {
ffPrintError(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Board), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
goto exit;
}
if (result.name.length == 0) {
ffPrintError(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "board_name is not set.");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Board), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "board_name is not set.");
goto exit;
}
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Board), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&result.name, stdout);
if (result.version.length) {
printf(" (%s)", result.version.chars);
}
putchar('\n');
} else {
FF_PRINT_FORMAT_CHECKED(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Board), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(result.name, "name"),
FF_ARG(result.vendor, "vendor"),
FF_ARG(result.version, "version"),
@@ -56,7 +56,7 @@ void ffParseBoardJsonObject(FFBoardOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Board), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -108,8 +108,30 @@ void ffDestroyBoardOptions(FFBoardOptions* options) {
}
FFModuleBaseInfo ffBoardModuleInfo = {
.name = FF_BOARD_MODULE_NAME,
.name = "Board",
.description = "Print motherboard name and other information",
.displayName = {
.en = "Board",
.ar = "اللوحة الأم",
.cs = "Základní deska",
.de = "Mainboard",
.es = "Placa base",
.fr = "Carte mère",
.gl = "Placa base",
.he = "לוח אם",
.id = "Papan Induk",
.it = "Scheda madre",
.ja = "マザーボード",
.ko = "메인보드",
.pl = "Płyta główna",
.pt = "Placa-mãe",
.ru = "Материнская плата",
.tr = "Anakart",
.uk = "Материнська плата",
.vi = "Bo mạch chủ",
.zh_CN = "主板",
.zh_TW = "主機板",
},
.initOptions = (void*) ffInitBoardOptions,
.destroyOptions = (void*) ffDestroyBoardOptions,
.parseJsonObject = (void*) ffParseBoardJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BOARD_MODULE_NAME "Board"
bool ffPrintBoard(FFBoardOptions* options);
void ffInitBoardOptions(FFBoardOptions* options);
void ffDestroyBoardOptions(FFBoardOptions* options);
+27 -5
View File
@@ -14,7 +14,7 @@ bool ffPrintBootmgr(FFBootmgrOptions* options) {
const char* error = ffDetectBootmgr(&bootmgr);
if (error) {
ffPrintError(FF_BOOTMGR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bootmgr), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
goto exit;
} else {
FF_STRBUF_AUTO_DESTROY firmwareName = ffStrbufCreateCopy(&bootmgr.firmware);
@@ -25,7 +25,7 @@ bool ffPrintBootmgr(FFBootmgrOptions* options) {
#endif
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_BOOTMGR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Bootmgr), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&bootmgr.name, stdout);
if (firmwareName.length > 0) {
printf(" - %s\n", firmwareName.chars);
@@ -33,7 +33,7 @@ bool ffPrintBootmgr(FFBootmgrOptions* options) {
putchar('\n');
}
} else {
FF_PRINT_FORMAT_CHECKED(FF_BOOTMGR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Bootmgr), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(bootmgr.name, "name"),
FF_ARG(bootmgr.firmware, "firmware-path"),
FF_ARG(firmwareName, "firmware-name"),
@@ -59,7 +59,7 @@ void ffParseBootmgrJsonObject(FFBootmgrOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_BOOTMGR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Bootmgr), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -103,8 +103,30 @@ void ffDestroyBootmgrOptions(FFBootmgrOptions* options) {
}
FFModuleBaseInfo ffBootmgrModuleInfo = {
.name = FF_BOOTMGR_MODULE_NAME,
.name = "Bootmgr",
.description = "Print second-stage bootloader information (name, firmware, etc.)",
.displayName = {
.en = "Boot Manager",
.ar = "مدير الإقلاع",
.cs = "Správce spouštění",
.de = "Boot-Manager",
.es = "Gestor de arranque",
.fr = "Gestionnaire de démarrage",
.gl = "Xestor de arranque",
.he = "מנהל אתחול",
.id = "Manajer Boot",
.it = "Gestore di avvio",
.ja = "ブートマネージャー",
.ko = "부트 매니저",
.pl = "Menedżer rozruchu",
.pt = "Gerenciador de inicialização",
.ru = "Менеджер загрузки",
.tr = "Önyükleme Yöneticisi",
.uk = "Менеджер завантаження",
.vi = "Trình quản lý khởi động",
.zh_CN = "启动管理器",
.zh_TW = "啟動管理器",
},
.initOptions = (void*) ffInitBootmgrOptions,
.destroyOptions = (void*) ffDestroyBootmgrOptions,
.parseJsonObject = (void*) ffParseBootmgrJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BOOTMGR_MODULE_NAME "Bootmgr"
bool ffPrintBootmgr(FFBootmgrOptions* options);
void ffInitBootmgrOptions(FFBootmgrOptions* options);
void ffDestroyBootmgrOptions(FFBootmgrOptions* options);
+24 -2
View File
@@ -16,7 +16,7 @@ void ffParseBreakJsonObject([[maybe_unused]] FFBreakOptions* options, [[maybe_un
continue;
}
ffPrintError(FF_BREAK_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Break), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -27,8 +27,30 @@ void ffDestroyBreakOptions([[maybe_unused]] FFBreakOptions* options) {
}
FFModuleBaseInfo ffBreakModuleInfo = {
.name = FF_BREAK_MODULE_NAME,
.name = "Break",
.description = "Print an empty line",
.displayName = {
.en = "Break",
.ar = "فاصل",
.cs = "Konec řádku",
.de = "Umbruch",
.es = "Salto de línea",
.fr = "Saut de ligne",
.gl = "Salto de liña",
.he = "מעבר שורה",
.id = "Baris Baru",
.it = "Interruzione",
.ja = "改行",
.ko = "줄 바꿈",
.pl = "Przerwa",
.pt = "Quebra",
.ru = "Разрыв",
.tr = "Satır Sonu",
.uk = "Розрив рядка",
.vi = "Xuống dòng",
.zh_CN = "换行",
.zh_TW = "換行",
},
.initOptions = (void*) ffInitBreakOptions,
.destroyOptions = (void*) ffDestroyBreakOptions,
.parseJsonObject = (void*) ffParseBreakJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BREAK_MODULE_NAME "Break"
bool ffPrintBreak(FFBreakOptions* options);
void ffInitBreakOptions(FFBreakOptions* options);
void ffDestroyBreakOptions(FFBreakOptions* options);
+28 -6
View File
@@ -11,12 +11,12 @@ bool ffPrintBrightness(FFBrightnessOptions* options) {
const char* error = ffDetectBrightness(options, &result);
if (error) {
ffPrintError(FF_BRIGHTNESS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (result.length == 0) {
ffPrintError(FF_BRIGHTNESS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No result is detected.");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No result is detected.");
return false;
}
@@ -34,7 +34,7 @@ bool ffPrintBrightness(FFBrightnessOptions* options) {
ffPercentAppendNum(&str, percent, options->percent, false, &options->moduleArgs);
}
ffPrintLogoAndKey(FF_BRIGHTNESS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufPutTo(&str, stdout);
return true;
}
@@ -44,7 +44,7 @@ bool ffPrintBrightness(FFBrightnessOptions* options) {
uint32_t index = 0;
FF_LIST_FOR_EACH (FFBrightnessResult, item, result) {
if (options->moduleArgs.key.length == 0) {
ffStrbufAppendF(&key, "%s (%s)", FF_BRIGHTNESS_MODULE_NAME, item->name.chars);
ffStrbufAppendF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Brightness), item->name.chars);
} else {
uint32_t moduleIndex = result.length == 1 ? 0 : index + 1;
FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
@@ -130,7 +130,7 @@ void ffParseBrightnessJsonObject(FFBrightnessOptions* options, yyjson_val* modul
continue;
}
ffPrintError(FF_BRIGHTNESS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Brightness), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -190,8 +190,30 @@ void ffDestroyBrightnessOptions(FFBrightnessOptions* options) {
}
FFModuleBaseInfo ffBrightnessModuleInfo = {
.name = FF_BRIGHTNESS_MODULE_NAME,
.name = "Brightness",
.description = "Print the current brightness level of your monitors",
.displayName = {
.en = "Brightness",
.ar = "السطوع",
.cs = "Jas",
.de = "Helligkeit",
.es = "Brillo",
.fr = "Luminosité",
.gl = "Brillo",
.he = "בהירות",
.id = "Kecerahan",
.it = "Luminosità",
.ja = "明るさ",
.ko = "밝기",
.pl = "Jasność",
.pt = "Brilho",
.ru = "Яркость",
.tr = "Parlaklık",
.uk = "Яскравість",
.vi = "Độ sáng",
.zh_CN = "亮度",
.zh_TW = "亮度",
},
.initOptions = (void*) ffInitBrightnessOptions,
.destroyOptions = (void*) ffDestroyBrightnessOptions,
.parseJsonObject = (void*) ffParseBrightnessJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BRIGHTNESS_MODULE_NAME "Brightness"
bool ffPrintBrightness(FFBrightnessOptions* options);
void ffInitBrightnessOptions(FFBrightnessOptions* options);
void ffDestroyBrightnessOptions(FFBrightnessOptions* options);
+28 -6
View File
@@ -10,9 +10,9 @@ static void printBtrfs(FFBtrfsOptions* options, FFBtrfsResult* result, uint8_t i
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if (options->moduleArgs.key.length == 0) {
if (result->name.length > 0) {
ffStrbufSetF(&buffer, "%s (%s)", FF_BTRFS_MODULE_NAME, result->name.chars);
ffStrbufSetF(&buffer, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Btrfs), result->name.chars);
} else {
ffStrbufSetS(&buffer, FF_BTRFS_MODULE_NAME);
ffStrbufSetS(&buffer, FF_MODULE_GET_DISPLAY_NAME(Btrfs));
}
} else {
ffStrbufClear(&buffer);
@@ -100,11 +100,11 @@ bool ffPrintBtrfs(FFBtrfsOptions* options) {
const char* error = ffDetectBtrfs(&results);
if (error) {
ffPrintError(FF_BTRFS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Btrfs), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (results.length == 0) {
ffPrintError(FF_BTRFS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No btrfs drive found");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Btrfs), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "No btrfs drive found");
return false;
}
@@ -136,7 +136,7 @@ void ffParseBtrfsJsonObject(FFBtrfsOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_BTRFS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Btrfs), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -198,8 +198,30 @@ void ffDestroyBtrfsOptions(FFBtrfsOptions* options) {
}
FFModuleBaseInfo ffBtrfsModuleInfo = {
.name = FF_BTRFS_MODULE_NAME,
.name = "Btrfs",
.description = "Print Linux BTRFS volumes",
.displayName = {
.en = "BTRFS",
.ar = "BTRFS",
.cs = "BTRFS",
.de = "BTRFS",
.es = "BTRFS",
.fr = "BTRFS",
.gl = "BTRFS",
.he = "BTRFS",
.id = "BTRFS",
.it = "BTRFS",
.ja = "BTRFS",
.ko = "BTRFS",
.pl = "BTRFS",
.pt = "BTRFS",
.ru = "BTRFS",
.tr = "BTRFS",
.uk = "BTRFS",
.vi = "BTRFS",
.zh_CN = "BTRFS",
.zh_TW = "BTRFS",
},
.initOptions = (void*) ffInitBtrfsOptions,
.destroyOptions = (void*) ffDestroyBtrfsOptions,
.parseJsonObject = (void*) ffParseBtrfsJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_BTRFS_MODULE_NAME "Btrfs"
bool ffPrintBtrfs(FFBtrfsOptions* options);
void ffInitBtrfsOptions(FFBtrfsOptions* options);
void ffDestroyBtrfsOptions(FFBtrfsOptions* options);
+28 -6
View File
@@ -5,7 +5,7 @@
static void printDevice(FFCameraOptions* options, const FFCameraResult* device, uint8_t index) {
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_CAMERA_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Camera), index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&device->name, stdout);
if (device->colorspace.length > 0) {
@@ -19,7 +19,7 @@ static void printDevice(FFCameraOptions* options, const FFCameraResult* device,
putchar('\n');
}
} else {
FF_PRINT_FORMAT_CHECKED(FF_CAMERA_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, (((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Camera), index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, (((FFformatarg[]) {
FF_ARG(device->name, "name"),
FF_ARG(device->vendor, "vendor"),
FF_ARG(device->colorspace, "colorspace"),
@@ -35,12 +35,12 @@ bool ffPrintCamera(FFCameraOptions* options) {
const char* error = ffDetectCamera(&result);
if (error) {
ffPrintError(FF_CAMERA_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Camera), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (result.length == 0) {
ffPrintError(FF_CAMERA_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No camera found");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Camera), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No camera found");
return false;
}
@@ -67,7 +67,7 @@ void ffParseCameraJsonObject(FFCameraOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CAMERA_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Camera), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -115,8 +115,30 @@ void ffDestroyCameraOptions(FFCameraOptions* options) {
}
FFModuleBaseInfo ffCameraModuleInfo = {
.name = FF_CAMERA_MODULE_NAME,
.name = "Camera",
.description = "Print available cameras",
.displayName = {
.en = "Camera",
.ar = "الكاميرا",
.cs = "Kamera",
.de = "Kamera",
.es = "Cámara",
.fr = "Caméra",
.gl = "Cámara",
.he = "מצלמה",
.id = "Kamera",
.it = "Fotocamera",
.ja = "カメラ",
.ko = "카메라",
.pl = "Kamera",
.pt = "Câmera",
.ru = "Камера",
.tr = "Kamera",
.uk = "Камера",
.vi = "Máy ảnh",
.zh_CN = "摄像头",
.zh_TW = "攝像頭",
},
.initOptions = (void*) ffInitCameraOptions,
.destroyOptions = (void*) ffDestroyCameraOptions,
.parseJsonObject = (void*) ffParseCameraJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CAMERA_MODULE_NAME "Camera"
bool ffPrintCamera(FFCameraOptions* options);
void ffInitCameraOptions(FFCameraOptions* options);
void ffDestroyCameraOptions(FFCameraOptions* options);
+28 -6
View File
@@ -16,24 +16,24 @@ bool ffPrintChassis(FFChassisOptions* options) {
const char* error = ffDetectChassis(&result);
if (error) {
ffPrintError(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Chassis), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
goto exit;
}
if (result.type.length == 0) {
ffPrintError(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "chassis_type is not set by O.E.M.");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Chassis), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "chassis_type is not set by O.E.M.");
goto exit;
}
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Chassis), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&result.type, stdout);
if (result.version.length) {
printf(" (%s)", result.version.chars);
}
putchar('\n');
} else {
FF_PRINT_FORMAT_CHECKED(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Chassis), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(result.type, "type"),
FF_ARG(result.vendor, "vendor"),
FF_ARG(result.version, "version"),
@@ -58,7 +58,7 @@ void ffParseChassisJsonObject(FFChassisOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Chassis), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -110,8 +110,30 @@ void ffDestroyChassisOptions(FFChassisOptions* options) {
}
FFModuleBaseInfo ffChassisModuleInfo = {
.name = FF_CHASSIS_MODULE_NAME,
.name = "Chassis",
.description = "Print chassis type information (desktop, laptop, etc.)",
.displayName = {
.en = "Chassis",
.ar = "الهيكل",
.cs = "Skříň",
.de = "Gehäuse",
.es = "Chasis",
.fr = "Châssis",
.gl = "Chasis",
.he = "מארז",
.id = "Casing",
.it = "Telaio",
.ja = "シャーシ",
.ko = "섀시",
.pl = "Obudowa",
.pt = "Chassi",
.ru = "Корпус",
.tr = "Kasa",
.uk = "Корпус",
.vi = "Vỏ máy",
.zh_CN = "机箱",
.zh_TW = "機箱",
},
.initOptions = (void*) ffInitChassisOptions,
.destroyOptions = (void*) ffDestroyChassisOptions,
.parseJsonObject = (void*) ffParseChassisJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CHASSIS_MODULE_NAME "Chassis"
bool ffPrintChassis(FFChassisOptions* options);
void ffInitChassisOptions(FFChassisOptions* options);
void ffDestroyChassisOptions(FFChassisOptions* options);
+29 -7
View File
@@ -51,9 +51,9 @@ static void printCodecLine(const FFCodecOptions* options, uint8_t index, FFstrbu
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
if (options->moduleArgs.key.length == 0) {
if (gpu->length > 0) {
ffStrbufSetF(&key, "%s (%s - %s)", FF_CODEC_MODULE_NAME, direction, gpu->chars);
ffStrbufSetF(&key, "%s (%s - %s)", FF_MODULE_GET_DISPLAY_NAME(Codec), direction, gpu->chars);
} else {
ffStrbufSetF(&key, "%s (%s)", FF_CODEC_MODULE_NAME, direction);
ffStrbufSetF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Codec), direction);
}
} else {
FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]){
@@ -100,12 +100,12 @@ bool ffPrintCodec(FFCodecOptions* options) {
const char* error = ffDetectCodec(options, &result);
if (error) {
ffPrintError(FF_CODEC_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Codec), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (result.length == 0) {
ffPrintError(FF_CODEC_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No hardware video acceleration found");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Codec), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No hardware video acceleration found");
return false;
}
@@ -174,14 +174,14 @@ void ffParseCodecJsonObject(FFCodecOptions* options, yyjson_val* module) {
{},
});
if (error) {
ffPrintError(FF_CODEC_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Codec), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
} else {
options->showType = (FFCodecShowType) value;
}
continue;
}
ffPrintError(FF_CODEC_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Codec), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -251,8 +251,30 @@ void ffDestroyCodecOptions(FFCodecOptions* options) {
}
FFModuleBaseInfo ffCodecModuleInfo = {
.name = FF_CODEC_MODULE_NAME,
.name = "Codec",
.description = "Print hardware video acceleration codec types (decode / encode)",
.displayName = {
.en = "Codec",
.ar = "الترميز",
.cs = "Kodek",
.de = "Codec",
.es = "Códec",
.fr = "Codec",
.gl = "Códec",
.he = "קודק",
.id = "Kodek",
.it = "Codec",
.ja = "コーデック",
.ko = "코덱",
.pl = "Kodek",
.pt = "Codec",
.ru = "Кодек",
.tr = "Kodek",
.uk = "Кодек",
.vi = "Codec",
.zh_CN = "编解码器",
.zh_TW = "編解碼器",
},
.initOptions = (void*) ffInitCodecOptions,
.destroyOptions = (void*) ffDestroyCodecOptions,
.parseJsonObject = (void*) ffParseCodecJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CODEC_MODULE_NAME "Codec"
bool ffPrintCodec(FFCodecOptions* options);
void ffInitCodecOptions(FFCodecOptions* options);
void ffDestroyCodecOptions(FFCodecOptions* options);
+33 -11
View File
@@ -37,7 +37,7 @@ bool ffPrintColors(FFColorsOptions* options) {
}
}
if (result.length > 0) {
ffPrintLogoAndKey(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
flag = true;
if (options->paddingLeft > 0) {
@@ -122,7 +122,7 @@ bool ffPrintColors(FFColorsOptions* options) {
if (flag) {
ffLogoPrintLine();
} else {
ffPrintLogoAndKey(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
flag = true;
}
@@ -136,7 +136,7 @@ bool ffPrintColors(FFColorsOptions* options) {
}
if (!flag) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "Nothing to print");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", "Nothing to print");
return false;
}
@@ -164,7 +164,7 @@ void ffParseColorsJsonObject(FFColorsOptions* options, yyjson_val* module) {
{},
});
if (error) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
} else {
options->symbol = (FFColorsSymbol) value;
}
@@ -178,7 +178,7 @@ void ffParseColorsJsonObject(FFColorsOptions* options, yyjson_val* module) {
if (unsafe_yyjson_equals_str(key, "block")) {
if (!yyjson_is_obj(val)) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: must be an object", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: must be an object", unsafe_yyjson_get_str(key));
} else {
yyjson_val* width = yyjson_obj_get(val, "width");
if (width) {
@@ -188,14 +188,14 @@ void ffParseColorsJsonObject(FFColorsOptions* options, yyjson_val* module) {
yyjson_val* range = yyjson_obj_get(val, "range");
if (range) {
if (!yyjson_is_arr(range) || yyjson_arr_size(range) != 2) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: must be an array of 2 elements", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: must be an array of 2 elements", unsafe_yyjson_get_str(key));
} else {
uint8_t start = (uint8_t) yyjson_get_uint(yyjson_arr_get(range, 0));
uint8_t end = (uint8_t) yyjson_get_uint(yyjson_arr_get(range, 1));
if (start > end) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: range[0] > range[1]", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: range[0] > range[1]", unsafe_yyjson_get_str(key));
} else if (end > 15) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: range[1] > 15", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: range[1] > 15", unsafe_yyjson_get_str(key));
} else {
options->block.range[0] = start;
options->block.range[1] = end;
@@ -215,14 +215,14 @@ void ffParseColorsJsonObject(FFColorsOptions* options, yyjson_val* module) {
{},
});
if (error) {
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
} else {
options->brightness = (FFColorsBrightness) value;
}
continue;
}
ffPrintError(FF_COLORS_MODULE_NAME, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Colors), 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -295,8 +295,30 @@ void ffDestroyColorsOptions(FFColorsOptions* options) {
}
FFModuleBaseInfo ffColorsModuleInfo = {
.name = FF_COLORS_MODULE_NAME,
.name = "Colors",
.description = "Display the terminal's 16-color palette",
.displayName = {
.en = "Colors",
.ar = "الألوان",
.cs = "Barvy",
.de = "Farben",
.es = "Colores",
.fr = "Couleurs",
.gl = "Cores",
.he = "צבעים",
.id = "Warna",
.it = "Colori",
.ja = "",
.ko = "색상",
.pl = "Kolory",
.pt = "Cores",
.ru = "Цвета",
.tr = "Renkler",
.uk = "Кольори",
.vi = "Màu sắc",
.zh_CN = "颜色",
.zh_TW = "顏色",
},
.initOptions = (void*) ffInitColorsOptions,
.destroyOptions = (void*) ffDestroyColorsOptions,
.parseJsonObject = (void*) ffParseColorsJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_COLORS_MODULE_NAME "Colors"
bool ffPrintColors(FFColorsOptions* options);
void ffInitColorsOptions(FFColorsOptions* options);
void ffDestroyColorsOptions(FFColorsOptions* options);
+30 -8
View File
@@ -8,12 +8,12 @@ bool ffPrintCommand(FFCommandOptions* options) {
const char* error = ffDetectCommand(options, &result);
if (error) {
ffPrintError(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Command), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
if (!result.length) {
ffPrintError(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No result generated");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Command), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No result generated");
return false;
}
@@ -23,18 +23,18 @@ bool ffPrintCommand(FFCommandOptions* options) {
size_t len = 0;
while (ffStrbufGetline(&line, &len, &result)) {
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_COMMAND_MODULE_NAME, ++index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Command), ++index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
puts(line);
} else {
FF_PRINT_FORMAT_CHECKED(FF_COMMAND_MODULE_NAME, ++index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(line, "result") }));
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Command), ++index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(line, "result") }));
}
}
} else {
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Command), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufPutTo(&result, stdout);
} else {
FF_PRINT_FORMAT_CHECKED(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(result, "result") }));
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Command), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(result, "result") }));
}
}
@@ -79,7 +79,7 @@ void ffParseCommandJsonObject(FFCommandOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_COMMAND_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Command), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -153,8 +153,30 @@ void ffDestroyCommandOptions(FFCommandOptions* options) {
}
FFModuleBaseInfo ffCommandModuleInfo = {
.name = FF_COMMAND_MODULE_NAME,
.name = "Command",
.description = "Run custom shell scripts",
.displayName = {
.en = "Command",
.ar = "الأمر",
.cs = "Příkaz",
.de = "Befehl",
.es = "Comando",
.fr = "Commande",
.gl = "Comando",
.he = "פקודה",
.id = "Perintah",
.it = "Comando",
.ja = "コマンド",
.ko = "명령어",
.pl = "Polecenie",
.pt = "Comando",
.ru = "Команда",
.tr = "Komut",
.uk = "Команда",
.vi = "Lệnh",
.zh_CN = "命令",
.zh_TW = "命令",
},
.initOptions = (void*) ffInitCommandOptions,
.destroyOptions = (void*) ffDestroyCommandOptions,
.parseJsonObject = (void*) ffParseCommandJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_COMMAND_MODULE_NAME "Command"
bool ffPrepareCommand(FFCommandOptions* options);
bool ffPrintCommand(FFCommandOptions* options);
+29 -7
View File
@@ -23,9 +23,9 @@ bool ffPrintCPU(FFCPUOptions* options) {
const char* error = ffDetectCPU(options, &cpu);
if (error) {
ffPrintError(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPU), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
} else if (cpu.vendor.length == 0 && cpu.name.length == 0 && cpu.coresOnline <= 1) {
ffPrintError(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No CPU detected");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPU), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No CPU detected");
} else {
FF_STRBUF_AUTO_DESTROY coreTypes = ffStrbufCreate();
if (options->showPeCoreCount) {
@@ -43,7 +43,7 @@ bool ffPrintCPU(FFCPUOptions* options) {
}
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(CPU), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate();
@@ -85,7 +85,7 @@ bool ffPrintCPU(FFCPUOptions* options) {
FF_STRBUF_AUTO_DESTROY tempStr = ffStrbufCreate();
ffTempsAppendNum(cpu.temperature, &tempStr, options->tempConfig, &options->moduleArgs);
FF_PRINT_FORMAT_CHECKED(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(CPU), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(cpu.name, "name"),
FF_ARG(cpu.vendor, "vendor"),
FF_ARG(cpu.coresPhysical, "cores-physical"),
@@ -131,7 +131,7 @@ void ffParseCPUJsonObject(FFCPUOptions* options, yyjson_val* module) {
}
if (unsafe_yyjson_equals_str(key, "freqNdigits")) {
ffPrintError(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "modules.CPU.freqNdigits has been moved to display.freq.ndigits");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPU), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "modules.CPU.freqNdigits has been moved to display.freq.ndigits");
continue;
}
@@ -140,7 +140,7 @@ void ffParseCPUJsonObject(FFCPUOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPU), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -251,8 +251,30 @@ void ffDestroyCPUOptions(FFCPUOptions* options) {
}
FFModuleBaseInfo ffCPUModuleInfo = {
.name = FF_CPU_MODULE_NAME,
.name = "CPU",
.description = "Print CPU name, frequency, etc.",
.displayName = {
.en = "CPU",
.ar = "المعالج",
.cs = "CPU",
.de = "CPU",
.es = "CPU",
.fr = "CPU",
.gl = "CPU",
.he = "מעבד",
.id = "CPU",
.it = "CPU",
.ja = "CPU",
.ko = "CPU",
.pl = "CPU",
.pt = "CPU",
.ru = "Процессор",
.tr = "CPU",
.uk = "CPU",
.vi = "CPU",
.zh_CN = "CPU",
.zh_TW = "CPU",
},
.initOptions = (void*) ffInitCPUOptions,
.destroyOptions = (void*) ffDestroyCPUOptions,
.parseJsonObject = (void*) ffParseCPUJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CPU_MODULE_NAME "CPU"
bool ffPrintCPU(FFCPUOptions* options);
void ffInitCPUOptions(FFCPUOptions* options);
void ffDestroyCPUOptions(FFCPUOptions* options);
+28 -8
View File
@@ -5,8 +5,6 @@
#include "detection/cpucache/cpucache.h"
#include "modules/cpucache/cpucache.h"
#define FF_CPUCACHE_DISPLAY_NAME "CPU Cache"
static void printCPUCacheNormal(const FFCPUCacheResult* result, FFCPUCacheOptions* options) {
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
@@ -16,7 +14,7 @@ static void printCPUCacheNormal(const FFCPUCacheResult* result, FFCPUCacheOption
ffStrbufClear(&key);
levelStr[1] = (char) ('1' + i);
if (options->moduleArgs.key.length == 0) {
ffStrbufAppendF(&key, "%s (%s)", FF_CPUCACHE_DISPLAY_NAME, levelStr);
ffStrbufAppendF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(CPUCache), levelStr);
} else {
uint32_t index = i + 1;
FF_PARSE_FORMAT_STRING_CHECKED(&key, &options->moduleArgs.key, ((FFformatarg[]) {
@@ -88,12 +86,12 @@ static void printCPUCacheCompact(const FFCPUCacheResult* result, FFCPUCacheOptio
}
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_CPUCACHE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufPutTo(&buffer, stdout);
} else {
FF_STRBUF_AUTO_DESTROY buffer2 = ffStrbufCreate();
ffSizeAppendNum(sum, &buffer2);
FF_PRINT_FORMAT_CHECKED(FF_CPUCACHE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(buffer, "result"),
FF_ARG(buffer2, "sum"),
}));
@@ -114,7 +112,7 @@ bool ffPrintCPUCache(FFCPUCacheOptions* options) {
const char* error = ffDetectCPUCache(&result);
if (error) {
ffPrintError(FF_CPUCACHE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
goto exit;
}
@@ -147,7 +145,7 @@ void ffParseCPUCacheJsonObject(FFCPUCacheOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CPUCACHE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPUCache), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -223,8 +221,30 @@ void ffDestroyCPUCacheOptions(FFCPUCacheOptions* options) {
}
FFModuleBaseInfo ffCPUCacheModuleInfo = {
.name = FF_CPUCACHE_MODULE_NAME,
.name = "CPUCache",
.description = "Print CPU cache sizes",
.displayName = {
.en = "CPU Cache",
.ar = "ذاكرة المعالج المؤقتة",
.cs = "Mezipaměť CPU",
.de = "CPU-Cache",
.es = "Caché de la CPU",
.fr = "Cache CPU",
.gl = "Caché da CPU",
.he = "מטמון מעבד",
.id = "Cache CPU",
.it = "Cache CPU",
.ja = "CPUキャッシュ",
.ko = "CPU 캐시",
.pl = "Pamięć podręczna CPU",
.pt = "Cache da CPU",
.ru = "Кэш процессора",
.tr = "CPU Önbelleği",
.uk = "Кеш ЦП",
.vi = "Bộ nhớ đệm CPU",
.zh_CN = "CPU缓存",
.zh_TW = "CPU快取記憶體",
},
.initOptions = (void*) ffInitCPUCacheOptions,
.destroyOptions = (void*) ffDestroyCPUCacheOptions,
.parseJsonObject = (void*) ffParseCPUCacheJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CPUCACHE_MODULE_NAME "CPUCache"
bool ffPrintCPUCache(FFCPUCacheOptions* options);
void ffInitCPUCacheOptions(FFCPUCacheOptions* options);
void ffDestroyCPUCacheOptions(FFCPUCacheOptions* options);
+27 -7
View File
@@ -5,14 +5,12 @@
#include "detection/cpuusage/cpuusage.h"
#include "modules/cpuusage/cpuusage.h"
#define FF_CPUUSAGE_DISPLAY_NAME "CPU Usage"
bool ffPrintCPUUsage(FFCPUUsageOptions* options) {
FF_LIST_AUTO_DESTROY percentages = ffListCreate();
const char* error = ffGetCpuUsageResult(options, &percentages);
if (error) {
ffPrintError(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPUUsage), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
return false;
}
@@ -54,7 +52,7 @@ bool ffPrintCPUUsage(FFCPUUsageOptions* options) {
FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(CPUUsage), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate();
if (!options->separate) {
@@ -102,7 +100,7 @@ bool ffPrintCPUUsage(FFCPUUsageOptions* options) {
ffPercentAppendBar(&maxBar, maxValue, options->percent, &options->moduleArgs);
}
FF_PRINT_FORMAT_CHECKED(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(CPUUsage), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(avgNum, "avg"),
FF_ARG(maxNum, "max"),
FF_ARG(maxIndex, "max-index"),
@@ -139,7 +137,7 @@ void ffParseCPUUsageJsonObject(FFCPUUsageOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CPUUSAGE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(CPUUsage), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -181,8 +179,30 @@ void ffDestroyCPUUsageOptions(FFCPUUsageOptions* options) {
}
FFModuleBaseInfo ffCPUUsageModuleInfo = {
.name = FF_CPUUSAGE_MODULE_NAME,
.name = "CPUUsage",
.description = "Print CPU usage. Collecting data takes some time",
.displayName = {
.en = "CPU Usage",
.ar = "استخدام المعالج",
.cs = "Využití CPU",
.de = "CPU-Auslastung",
.es = "Uso de la CPU",
.fr = "Utilisation du CPU",
.gl = "Uso da CPU",
.he = "שימוש במעבד",
.id = "Penggunaan CPU",
.it = "Utilizzo della CPU",
.ja = "CPU使用率",
.ko = "CPU 사용량",
.pl = "Użycie CPU",
.pt = "Uso da CPU",
.ru = "Использование процессора",
.tr = "CPU Kullanımı",
.uk = "Використання ЦП",
.vi = "Mức sử dụng CPU",
.zh_CN = "CPU使用率",
.zh_TW = "CPU使用率",
},
.initOptions = (void*) ffInitCPUUsageOptions,
.destroyOptions = (void*) ffDestroyCPUUsageOptions,
.parseJsonObject = (void*) ffParseCPUUsageJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CPUUSAGE_MODULE_NAME "CPUUsage"
void ffPrepareCPUUsage();
bool ffPrintCPUUsage(FFCPUUsageOptions* options);
+27 -5
View File
@@ -14,7 +14,7 @@ bool ffPrintCursor(FFCursorOptions* options) {
ffDetectCursor(&result);
if (result.error.length) {
ffPrintError(FF_CURSOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", result.error.chars);
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Cursor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", result.error.chars);
} else {
ffStrbufRemoveIgnCaseEndS(&result.theme, "cursors");
ffStrbufRemoveIgnCaseEndS(&result.theme, "cursor");
@@ -25,7 +25,7 @@ bool ffPrintCursor(FFCursorOptions* options) {
}
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_CURSOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Cursor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&result.theme, stdout);
if (result.size.length > 0 && !ffStrbufEqualS(&result.size, "0")) {
@@ -34,7 +34,7 @@ bool ffPrintCursor(FFCursorOptions* options) {
putchar('\n');
} else {
FF_PRINT_FORMAT_CHECKED(FF_CURSOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Cursor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
FF_ARG(result.theme, "theme"),
FF_ARG(result.size, "size"),
}));
@@ -58,7 +58,7 @@ void ffParseCursorJsonObject(FFCursorOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CURSOR_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Cursor), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -100,8 +100,30 @@ void ffDestroyCursorOptions(FFCursorOptions* options) {
}
FFModuleBaseInfo ffCursorModuleInfo = {
.name = FF_CURSOR_MODULE_NAME,
.name = "Cursor",
.description = "Print cursor style name",
.displayName = {
.en = "Cursor",
.ar = "المؤشر",
.cs = "Kurzor",
.de = "Mauszeiger",
.es = "Cursor",
.fr = "Curseur",
.gl = "Cursor",
.he = "סמן",
.id = "Kursor",
.it = "Cursore",
.ja = "カーソル",
.ko = "커서",
.pl = "Kursor",
.pt = "Cursor",
.ru = "Курсор",
.tr = "İmleç",
.uk = "Курсор",
.vi = "Con trỏ",
.zh_CN = "光标",
.zh_TW = "游標",
},
.initOptions = (void*) ffInitCursorOptions,
.destroyOptions = (void*) ffDestroyCursorOptions,
.parseJsonObject = (void*) ffParseCursorJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CURSOR_MODULE_NAME "Cursor"
bool ffPrintCursor(FFCursorOptions* options);
void ffInitCursorOptions(FFCursorOptions* options);
void ffDestroyCursorOptions(FFCursorOptions* options);
+24 -3
View File
@@ -5,7 +5,7 @@
#include "modules/custom/custom.h"
bool ffPrintCustom(FFCustomOptions* options) {
ffPrintFormat(FF_CUSTOM_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, 0, ((FFformatarg[]) {}));
ffPrintFormat(FF_MODULE_GET_DISPLAY_NAME(Custom), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, 0, ((FFformatarg[]) {}));
return true;
}
@@ -21,7 +21,7 @@ void ffParseCustomJsonObject(FFCustomOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_CUSTOM_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Custom), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -35,8 +35,29 @@ void ffDestroyCustomOptions(FFCustomOptions* options) {
}
FFModuleBaseInfo ffCustomModuleInfo = {
.name = FF_CUSTOM_MODULE_NAME,
.name = "Custom",
.description = "Print a custom string, with or without key",
.displayName = {
.en = "Custom",
.ar = "مخصص",
.cs = "Vlastní",
.de = "Benutzerdefiniert",
.es = "Personalizado",
.fr = "Personnalisé",
.he = "מותאם אישית",
.id = "Kustom",
.it = "Personalizzato",
.ja = "カスタム",
.ko = "사용자 정의",
.pl = "Niestandardowy",
.pt = "Personalizado",
.ru = "Пользовательский",
.tr = "Özel",
.uk = "Власний",
.vi = "Tùy chỉnh",
.zh_CN = "自定义",
.zh_TW = "自訂",
},
.initOptions = (void*) ffInitCustomOptions,
.destroyOptions = (void*) ffDestroyCustomOptions,
.parseJsonObject = (void*) ffParseCustomJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_CUSTOM_MODULE_NAME "Custom"
bool ffPrintCustom(FFCustomOptions* options);
void ffInitCustomOptions(FFCustomOptions* options);
void ffDestroyCustomOptions(FFCustomOptions* options);
+27 -7
View File
@@ -8,8 +8,6 @@
#pragma GCC diagnostic ignored "-Wformat" // warning: unknown conversion type character 'F' in format
#define FF_DATETIME_DISPLAY_NAME "Date & Time"
typedef struct FFDateTimeResult {
// Examples for 21.02.2022 - 15:18:37
uint16_t year; // 2022
@@ -67,7 +65,7 @@ static void printDateTimeFormat(struct tm* tm, const FFModuleArgs* moduleArgs) {
strftime(result.amPm, sizeof(result.amPm), "%p", tm);
FF_PRINT_FORMAT_CHECKED(
FF_DATETIME_DISPLAY_NAME,
FF_MODULE_GET_DISPLAY_NAME(DateTime),
0,
moduleArgs,
FF_PRINT_TYPE_DEFAULT,
@@ -112,11 +110,11 @@ bool ffPrintDateTime(FFDateTimeOptions* options) {
char buffer[32];
if (strftime(buffer, ARRAY_SIZE(buffer), "%F %T", tm) == 0) // yyyy-MM-dd HH:mm:ss
{
ffPrintError(FF_DATETIME_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "strftime() failed");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(DateTime), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "strftime() failed");
return false;
}
ffPrintLogoAndKey(FF_DATETIME_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(DateTime), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
puts(buffer);
return true;
@@ -130,7 +128,7 @@ void ffParseDateTimeJsonObject(FFDateTimeOptions* options, yyjson_val* module) {
continue;
}
ffPrintError(FF_DATETIME_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(DateTime), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -152,8 +150,30 @@ void ffDestroyDateTimeOptions(FFDateTimeOptions* options) {
}
FFModuleBaseInfo ffDateTimeModuleInfo = {
.name = FF_DATETIME_MODULE_NAME,
.name = "DateTime",
.description = "Print the current date and time",
.displayName = {
.en = "Date & Time",
.ar = "التاريخ والوقت",
.cs = "Datum a čas",
.de = "Datum & Uhrzeit",
.es = "Fecha y hora",
.fr = "Date et heure",
.gl = "Data e hora",
.he = "תאריך ושעה",
.id = "Tanggal & Waktu",
.it = "Data e ora",
.ja = "日付と時刻",
.ko = "날짜/시간",
.pl = "Data i godzina",
.pt = "Data e hora",
.ru = "Дата и время",
.tr = "Tarih ve Saat",
.uk = "Дата й час",
.vi = "Ngày giờ",
.zh_CN = "日期时间",
.zh_TW = "日期時間",
},
.initOptions = (void*) ffInitDateTimeOptions,
.destroyOptions = (void*) ffDestroyDateTimeOptions,
.parseJsonObject = (void*) ffParseDateTimeJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_DATETIME_MODULE_NAME "DateTime"
bool ffPrintDateTime(FFDateTimeOptions* options);
void ffInitDateTimeOptions(FFDateTimeOptions* options);
void ffDestroyDateTimeOptions(FFDateTimeOptions* options);
+28 -6
View File
@@ -9,7 +9,7 @@ bool ffPrintDE(FFDEOptions* options) {
const FFDisplayServerResult* result = ffConnectDisplayServer();
if (result->dePrettyName.length == 0) {
ffPrintError(FF_DE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No DE found");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(DE), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No DE found");
return false;
}
@@ -17,7 +17,7 @@ bool ffPrintDE(FFDEOptions* options) {
ffDetectDEVersion(&result->dePrettyName, &version, options);
if (options->moduleArgs.outputFormat.length == 0) {
ffPrintLogoAndKey(FF_DE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(DE), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&result->dePrettyName, stdout);
@@ -28,7 +28,7 @@ bool ffPrintDE(FFDEOptions* options) {
putchar('\n');
} else {
FF_PRINT_FORMAT_CHECKED(FF_DE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(result->deProcessName, "process-name"), FF_ARG(result->dePrettyName, "pretty-name"), FF_ARG(version, "version") }));
FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(DE), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(result->deProcessName, "process-name"), FF_ARG(result->dePrettyName, "pretty-name"), FF_ARG(version, "version") }));
}
return true;
@@ -43,11 +43,11 @@ void ffParseDEJsonObject(FFDEOptions* options, yyjson_val* module) {
}
if (unsafe_yyjson_equals_str(key, "slowVersionDetection")) {
ffPrintError(FF_DE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Key `slowVersionDetection` is deprecated, it's always true");
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(DE), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Key `slowVersionDetection` is deprecated, it's always true");
continue;
}
ffPrintError(FF_DE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(DE), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -82,8 +82,30 @@ void ffDestroyDEOptions(FFDEOptions* options) {
}
FFModuleBaseInfo ffDEModuleInfo = {
.name = FF_DE_MODULE_NAME,
.name = "DE",
.description = "Print desktop environment name",
.displayName = {
.en = "Desktop Environment",
.ar = "بيئة سطح المكتب",
.cs = "Pracovní prostředí",
.de = "Desktop-Umgebung",
.es = "Entorno de escritorio",
.fr = "Environnement de Bureau",
.gl = "Contorno do Escritorio",
.he = "סביבת שולחן עבודה",
.id = "Lingkungan Desktop",
.it = "Ambiente Desktop",
.ja = "デスクトップ環境",
.ko = "데스크탑 환경",
.pl = "Środowisko graficzne",
.pt = "Ambiente de desktop",
.ru = "Рабочее окружение",
.tr = "Masaüstü Ortamı",
.uk = "Стільниче середовище",
.vi = "Môi trường desktop",
.zh_CN = "桌面环境",
.zh_TW = "桌面環境",
},
.initOptions = (void*) ffInitDEOptions,
.destroyOptions = (void*) ffDestroyDEOptions,
.parseJsonObject = (void*) ffParseDEJsonObject,
-2
View File
@@ -2,8 +2,6 @@
#include "option.h"
#define FF_DE_MODULE_NAME "DE"
bool ffPrintDE(FFDEOptions* options);
void ffInitDEOptions(FFDEOptions* options);
void ffDestroyDEOptions(FFDEOptions* options);

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