Compare commits

...

156 Commits

Author SHA1 Message Date
Carter Li 865929b173 Merge pull request #1526 from fastfetch-cli/dev
Release: v2.35.0
2025-01-26 10:14:38 +08:00
李通洲 9324136f52 Thread: optimise locking (unused though) 2025-01-26 09:49:31 +08:00
李通洲 f601d2d9f5 CPU (Linux): add comments 2025-01-26 09:47:31 +08:00
李通洲 54de7c8c96 Release: v2.35.0 2025-01-25 23:03:47 +08:00
李通洲 3bb3bd542e PhysicalDisk: change temp range to 50-70 °C
Fix #1525
2025-01-25 21:41:00 +08:00
李通洲 e6e7572bc2 Doc: update changelog again [ci skip] 2025-01-25 11:01:35 +08:00
李通洲 884d256a34 Doc: update changelog [ci skip] 2025-01-24 21:14:21 +08:00
Carter Li ed8430fb2f Doc: update json_schema [ci skip] 2025-01-24 14:17:19 +08:00
Carter Li 7fc1f0098e Doc: update changelog [ci skip] 2025-01-24 14:08:01 +08:00
Carter Li 3839ee60d6 Disk / Users: support duration printing in custom format 2025-01-24 14:05:16 +08:00
Carter Li 6f266a1609 Doc: update changelog 2025-01-24 10:13:31 +08:00
Carter Li 026489c934 CPU (Android): add QS8E for Galaxy 2025-01-24 10:05:24 +08:00
Carter Li 1d03747ec3 CMake: add option -DCUSTOM_LSB_RELEASE_PATH 2025-01-24 09:57:15 +08:00
Carter Li a2919f5b2e OS (Linux): acquire more os info from lsb-release if missing from os-release
Fix #1521
2025-01-24 09:57:15 +08:00
Carter Li 680978b0d3 Logo (Builtin): fix more escape problems
Ref: #1522
2025-01-24 09:57:15 +08:00
Carter Li af813dee00 Logo (Builtin): fix OpenBSD & OpenBSD_small
Fix #1522
2025-01-24 08:44:44 +08:00
User8395 c281c46fff Logo (Builtin): Add KDE Linux logo (#1523)
* Add KDE Linux logo

* Update coloring
2025-01-24 08:44:27 +08:00
Carter Li 1f5e56c69e CPU (Android): detect new QS8E 2025-01-23 19:33:42 +08:00
Carter Li 35d431dd3f CPU (Linux): detect SOC name on RISCV
Fix #1519
2025-01-22 22:19:23 +08:00
李通洲 6a2e8de563 Doc: update changelog [ci skip] 2025-01-22 15:48:52 +08:00
李通洲 9528cf96f0 Presets: fix percentage number printing in examples/20 [ci skip] 2025-01-22 09:01:08 +08:00
Carter Li 66deb4316b Disk (NetBSD): silence compiler warnings
Ref: https://github.com/NetBSD/pkgsrc/blob/ef998fe87c836293a337726e5f212011d4ee0327/sysutils/fastfetch/patches/patch-src_detection_disk_disk__bsd.c
2025-01-21 09:41:40 +08:00
Carter Li 61e9db97b9 Doc: update feature_request issue template 2025-01-21 08:52:07 +08:00
Carter Li 66fbda9542 Display (Linux): return reason if errored 2025-01-21 08:44:24 +08:00
李通洲 5137a9e7a4 Packages: fix file type check 2025-01-18 19:34:50 +08:00
李通洲 f76981c241 Packages (SunOS): fix building 2025-01-17 15:58:09 +08:00
李通洲 85050f7ff1 Packages: add pkgsrc; code refactor
Fix #1515
2025-01-17 11:01:47 +08:00
李通洲 0b39d6fc59 Doc: update issue templates [ci skip] 2025-01-16 15:13:41 +08:00
李通洲 b7dd7fea0a CI: add linux-armv6 2025-01-16 10:20:34 +08:00
李通洲 cc51596e5c OpenGL: suppress output of EGL again
oops...
2025-01-15 21:39:21 +08:00
李通洲 b566ffe81b Doc: update more issue templates [ci skip] 2025-01-15 14:15:03 +08:00
李通洲 60c06a888c Doc: split bug report issue template into smaller parts [ci skip] 2025-01-15 13:47:04 +08:00
Carter Li 8ceda02bbb CPU (Linux): query SOC name in cpuinfo for aarch64
Fix #1510
2025-01-14 13:54:27 +08:00
Carter Li c005bc50c2 TerminalShell (Linux): ignore proot 2025-01-14 13:46:59 +08:00
Carter Li 52411f6e37 Logo (Builtin): update netbsd small 2025-01-14 10:38:27 +08:00
Carter Li 31f620c041 Logo (Builtin): add Arch Old
Fix #1511
2025-01-14 10:38:21 +08:00
Carter Li fdbd8d9ad5 Chore: forbid using of VLAs 2025-01-14 10:28:22 +08:00
Carter Li 1cad1dfdb0 Packaging: update debian stuff [ci skip] 2025-01-13 16:16:32 +08:00
Carter Li 4a1037d2b6 Merge pull request #1509 from fastfetch-cli/dev
Release: v2.34.1
2025-01-13 15:57:52 +08:00
Carter Li dbcd5b922a Sound: fix a memleak 2025-01-13 15:39:16 +08:00
Carter Li 8982b860f9 Chore: fix spelling 2025-01-13 15:15:28 +08:00
Carter Li 373b4353bb CPU (BSD): improve base freq detection 2025-01-13 15:06:18 +08:00
Carter Li ace336dfa9 Release: v2.34.1 2025-01-13 14:55:53 +08:00
CELESTIFYX Team 4060626382 fix(logo): Rename *_LOGO_SMARTOS to *_LOGO_SNIGDHAOS (#1502) 2025-01-13 13:48:02 +08:00
李通洲 9f9e3dd931 Logo (Builtin): add Oreon 2025-01-13 13:42:20 +08:00
李通洲 3ed5a250a4 Logo (Builtin): add HeliumOS 2025-01-13 13:39:07 +08:00
carterli fc969b01c7 Memory (NetBSD): change formula to be consistant with other systems 2025-01-13 10:47:25 +08:00
carterli 41e22ea866 Memory (OpenBSD): update formula to be consistant with other systems 2025-01-13 10:47:25 +08:00
李通洲 0b4a6055c6 Logo (Builtin): add netbsd_small 2025-01-13 10:41:11 +08:00
Carter Li b340d4e149 CI: fix build 2025-01-12 12:10:10 +08:00
Carter Li 878e516880 DisplayServer (Linux): upgrade wayland protocol kde-output-device-v2
Ref: #1504
2025-01-12 11:23:42 +08:00
Carter Li 4e3673a2bb DisplayServer (Linux): check HDR support with xx_color_manager_v4_interface (WIP) 2025-01-11 13:10:07 +08:00
李通洲 10c8c1b4bf Media (Linux): use file name as media name if song title is not available 2025-01-10 22:17:36 +08:00
李通洲 17e3853f38 CPU (FreeBSD): bind process to the first 2 cores 2025-01-10 21:14:51 +08:00
李通洲 1bc41dfa54 chore: remove unnecessary NULL checks
Fix #1494
2025-01-10 14:01:48 +08:00
李通洲 8c227ae4b8 TerminalFont (macOS): fix Ghostty termfont detection
`~/Library/Application Support/com.mitchellh.ghostty/config` is generated as an empty file if the settings dialog is opened

Fix #1495
2025-01-10 09:41:19 +08:00
李通洲 c5c2589f4d GPU: set GPU vendor string when using OpenGL backend 2025-01-10 08:48:29 +08:00
Carter Li b273693842 Packaging: update debian stuff [ci skip] 2025-01-09 09:06:41 +08:00
Carter Li 52de8df1f9 Merge pull request #1492 from fastfetch-cli/dev
Release: v2.34.0
2025-01-09 09:02:12 +08:00
李通洲 be99c4ca6e Media (Linux): remove unused variables 2025-01-09 08:50:56 +08:00
李通洲 8133c3365f Doc: update JSON schema [ci skip] 2025-01-08 22:29:49 +08:00
李通洲 6226ccc70e Processing (Windows): fix get current process 2025-01-08 20:37:35 +08:00
李通洲 88917cb14f OpenGL (EGL): try GLES 2.0+; then fallback to 1.1 if failed 2025-01-08 20:13:01 +08:00
Carter Li a93e2aafdb Release: v2.34.0 2025-01-08 16:26:06 +08:00
李通洲 5848b5fc24 OpenGL (Android): enable support 2025-01-08 16:09:41 +08:00
李通洲 934b6291e3 OpenGL (Android): request GLES 2+ 2025-01-08 15:38:55 +08:00
李通洲 90068ab474 Battery (NetBSD): fix battery percentage detection 2025-01-08 13:46:08 +08:00
Carter Li 5567e6cc5e Packages (Linux): rename am-user to appman 2025-01-08 10:56:55 +08:00
Carter Li 8b3017c0d9 Packages (Linux): remove possible final newlines in am config 2025-01-08 10:28:13 +08:00
Carter Li f9f15ba844 General: don't suppress the output of preRun
Fix #1489
2025-01-08 09:46:41 +08:00
Carter Li b282ac5d47 Packages (Linux): support am-user
Fix #771
2025-01-08 09:46:12 +08:00
Carter Li 6577884417 WMDE: detect Sway by env variables 2025-01-08 08:50:53 +08:00
李通洲 c4ee606955 CPU (Android): check for MTK D9X00 SOCs 2025-01-08 08:39:09 +08:00
Bahar KURT 59c80820f2 feat: Add Rhino Linux ASCII (#1487)
Cramp all additions into one commit because I like to do it that
way. xD

Co-authored-by: Bahar KURT <kurtbahartr@users.noreply.github.com>
2025-01-07 21:30:22 +08:00
李通洲 c11e14f7e1 CMake (Android): set rpath for system Android libs
So that Vulkan & OpenCL can find them
2025-01-07 15:38:47 +08:00
Carter Li ab6a770155 Sound: detect platform API
Ref: #1454
2025-01-07 15:38:38 +08:00
李通洲 0e99486efe Processing (Windows): early return if OpenProcess failed 2025-01-07 08:35:57 +08:00
Eshan Roy f82f3002e4 Logo (Builtin): add snigdhaos ascii (#1485)
* feat: add snigdhaos ascii

* feat: insert builtin data
2025-01-06 23:49:48 +08:00
Angel Gustavo Lopez 0bed182784 fixing fastfetch wrong colors for xray_os logo (#1486) 2025-01-06 19:54:38 +08:00
Carter Li d39be955b1 Doc: update changelog [ci skip] 2025-01-06 14:39:29 +08:00
CaKrome 3b2790cccc CI (Linux): add Linux ppc64le platform (#1484) 2025-01-06 13:55:13 +08:00
Carter Li 3ea0406b69 CPU (Linux): fix var content was unexpectedly modified 2025-01-06 10:57:29 +08:00
李通洲 6429c20466 OS: prefer pretty names
Hopefully we can end the controversy.

Fix #1483 #1038
2025-01-06 08:58:14 +08:00
李通洲 88ebeb21e2 CPU: fix core count output in multi-package platforms
Fix #1413
2025-01-05 19:38:16 +08:00
Carter Li f28f5e2874 CPU (Linux): detect TZ temp if CPU temp is not available 2025-01-05 17:28:01 +08:00
Carter Li 637c37e81c Packages (macOS): remove redundant tokens 2025-01-05 17:28:01 +08:00
Simon Quigley b2c779dea9 Logo (Builtin): add the Lubuntu logo (#1481)
* Add the Lubuntu logo

* Lubuntu uses LXQt, not LXDE
2025-01-05 11:08:27 +08:00
李通洲 89d636447b Doc: update README [ci skip] 2025-01-03 13:56:48 +08:00
Carter Li 3dc51d5f88 FFstrbuf: improve performance of copying static strings 2025-01-03 10:59:01 +08:00
Carter Li 60ff89c794 Terminal (Linux): fix detection of pk-command-not-found
Fix #1467
2025-01-03 10:32:16 +08:00
Carter Li f973572c5a TerminalShell (Linux): relax detection of terminals in NixOS
Fix #1479
2025-01-03 10:18:44 +08:00
Carter Li ea78665971 Doc: update README.md 2025-01-03 10:16:38 +08:00
Carter Li 80b48dd2d1 Logo (Image): mark ghostty supports kitty image protocol 2025-01-03 09:55:38 +08:00
Carter Li df6eed7a02 TerminalSize (Linux): enable fast path when stdout is redirected. 2025-01-03 09:50:59 +08:00
李通洲 c9ac09f9eb WM (Linux): detect WM version 2025-01-02 20:19:15 +08:00
Carter Li 67597e4566 WM (Linux): add sway version detection 2025-01-02 16:36:31 +08:00
李通洲 611de77980 Terminal (macOS): improve performance of kitty version 2025-01-02 16:35:53 +08:00
李通洲 0fde835629 WM (Windows): detect version of DWM 2025-01-02 16:35:53 +08:00
李通洲 f373e07847 WM (Linux): don't crash if no wm is detected 2025-01-02 16:35:53 +08:00
李通洲 89e4403cc8 WM (macOS): add WindowServer version detection 2025-01-02 16:35:53 +08:00
李通洲 c68d21e215 WM: report version field in custom and JSON output 2025-01-02 16:35:53 +08:00
Christopher Kaster f14cd2c6e8 WM: Add support for detecting window manager versions, add support for Hyprland version (#1472) 2025-01-02 10:13:28 +08:00
Carter Li d58d786c83 Logo (Image): add --kitty-icat; honor --logo-height if set 2024-12-31 15:43:01 +08:00
Carter Li 9f37557177 Logo (Image): support generate image data via kitten icat 2024-12-31 15:30:26 +08:00
李通洲 aa63c4f5f2 Revert "GPU: support detection by EGLext"
Works only for NVIDIA GPUs

This reverts commits 9ef8580d93 and 9342d74c93.
2024-12-31 13:57:06 +08:00
李通洲 a378d2ad62 Brightness (FreeBSD): fix backlight name detection 2024-12-30 11:12:06 +08:00
Carter Li 2ab2dd4d48 TerminalFont (macOS): fix ghostty font detection; default to JetBrains Mono
Ref: https://github.com/fastfetch-cli/fastfetch/issues/1466#issuecomment-2564379883
2024-12-30 10:43:28 +08:00
Peter Zmanovsky 2a83b86ba4 Platform (Linux): fix exe path detection (#1468)
On error, -1 is returned from readlink()
2024-12-29 09:53:20 +08:00
李通洲 d967d05019 Bluetooth (DragonFly): disable module to fix build 2024-12-28 22:13:49 +08:00
李通洲 9ef8580d93 GPU (EGLext): fix build on old systems 2024-12-28 21:50:08 +08:00
Carter Li 813b80c5a8 TerminalFont: support Ghostty
Fix #1466
2024-12-28 15:34:41 +08:00
Carter Li ddce9b2357 GPU: rename ffGetGPUVendorString to ffGPUGetVendorString 2024-12-28 15:26:17 +08:00
Carter Li 9342d74c93 GPU: support detection by EGLext
Support multi-gpus
2024-12-28 15:25:22 +08:00
Carter Li d6028370e7 Bluetooth (FreeBSD): add support (not tested) 2024-12-27 14:49:15 +08:00
李通洲 e425d7df63 CI: update *BSD versions 2024-12-27 14:11:53 +08:00
李通洲 a4a2ae7d67 Host (macOS): fix thunderbolt version of new MBPs
Fix #1465
2024-12-27 14:07:17 +08:00
Carter Li 99aa0638cc Packaging: update debian stuff [ci skip] 2024-12-26 09:47:44 +08:00
Carter Li 1a9e637134 Merge pull request #1464 from fastfetch-cli/dev
Release: v2.33.0
2024-12-26 09:37:25 +08:00
李通洲 f322405c04 Release: v2.33.0 2024-12-26 09:08:33 +08:00
Carter Li e4202635af Doc: update changelog [ci skip] 2024-12-25 10:47:36 +08:00
Carter Li 2f13ee3814 Media (Linux): set player name manually for musikcube 2024-12-25 10:47:36 +08:00
Carter Li 2bfde87f84 Logo (Builtin): add GoralixOS
Fix #1462
2024-12-25 10:47:36 +08:00
Carter Li f38a51c9bc Media: make it able to print player info in custom format 2024-12-25 09:04:10 +08:00
Carter Li 28ec935c42 Media (Linux): report player name 2024-12-25 08:50:28 +08:00
李通洲 d939f95c69 Vulkan (Android): hard code path of libvulkan.so, so that users don't need to install vulkan-loader wrapper of termux 2024-12-24 21:20:03 +08:00
李通洲 e0fd5111fe Media (Linux): Fix #1461 (WIP) 2024-12-24 19:38:43 +08:00
李通洲 4736031538 Doc: update changelog [ci skip] 2024-12-22 22:19:02 +08:00
李通洲 66085c087e Logo (Builtin): add NurOS
Fix #1456
2024-12-22 21:48:18 +08:00
李通洲 e0253d71c0 Doc: add comments for running fastfetch in root 2024-12-22 20:45:51 +08:00
李通洲 dadd4bfab6 DiskIO (OpenBSD): remove debug output 2024-12-22 20:43:36 +08:00
李通洲 2f3861e732 PhysicalMemory: clean up garbage data 2024-12-22 20:27:27 +08:00
李通洲 851f271ed5 CPU (NetBSD): fix typo 2024-12-22 14:20:32 +08:00
Carter Li d3e40f625b Battery (OpenBSD): fix build 2024-12-22 09:30:42 +08:00
Carter Li 7c1991c2e3 Battery (NetBSD): add support 2024-12-21 23:54:30 +08:00
李通洲 b8048ee488 Bluetooth (BSD): disable
bluez is Linux specific
2024-12-21 23:54:30 +08:00
李通洲 b99f54b9f4 CPU (NetBSD): trim CPU vendor 2024-12-21 23:54:30 +08:00
Carter Li b38d7a4919 Brightness (NetBSD): don't error out if the screen idx isn't 0 2024-12-21 23:54:30 +08:00
李通洲 45f7e2c0b2 Version (NetBSD): report sysname 2024-12-21 23:54:30 +08:00
李通洲 5a8dda27ff CPU (NetBSD): support temp and frequency detection 2024-12-21 23:54:30 +08:00
李通洲 1ea3264b13 SMBIOS (NetBSD): add more data 2024-12-21 23:54:30 +08:00
Carter Li 852a729581 Battary (NetBSD): some basic investigation of acpi battery detection 2024-12-21 23:54:30 +08:00
Carter Li 0f454b7140 Battery (OpenBSD): add support 2024-12-21 23:54:30 +08:00
Carter Li 9c47a3a9e7 Brightness (OpenBSD): add support
Requires root permission. Not tested
2024-12-21 23:54:30 +08:00
李通洲 4adf7fda28 Brightness (NetBSD): add support for builtin display 2024-12-21 23:54:30 +08:00
李通洲 e2fc83fd48 Bluetooth (Windows): silence compiler warnings 2024-12-21 23:54:30 +08:00
Robin Candau dd41dfa000 CMake: Add a cmake option to make flashfetch target optional (#1455)
Introduces the `-DBUILD_FLASHFETCH='ON'/'OFF'` build option so one can skip the `flashfetch` target (both from executable and install targets, option at `ON` by default to preserve compatibility with the current default behavior).
This is useful when distributing pre-built downstream packages (e.g. for Linux distributions packaging `fastfetch`) as building and shipping the `flashfetch` binary in such pre-built packages serves little to no purpose.
2024-12-21 23:53:02 +08:00
Carter Li 14d6157901 PhysicalDisk (Linux): fix interconnect type detection
Regression of b5a9d64

Fix #1453
2024-12-20 16:38:30 +08:00
Carter Li 74586a9df1 Bluetooth (Linux): improve performance
1. ignore unpaired devices
2. ignore disconnected devices when `showDisconnected == false`
2024-12-20 15:57:17 +08:00
Carter Li c5d4b20729 TerminalShell (Android): ignore proot 2024-12-20 15:57:17 +08:00
李通洲 b152b383a2 Bluetooth (Windows): optimise
1. don't report disconnected devices if `showDisconnected == false`
2. don't report unknown devices
3. don't report errors when no devices found
2024-12-20 15:57:17 +08:00
李通洲 ae26692ef6 Bluetooth (macOS): don't report disconnected devices if showDisconnected == false 2024-12-20 15:57:17 +08:00
Carter Li 4f807f26a9 Bluetooth (Linux): improve performance when showDisconnected == false
If no connected devices found, no dbus calls will be emitted

Fix #1450
2024-12-20 15:57:02 +08:00
Carter Li 4bef801337 BluetoothRadio (Linux): improve performance by reducing size of dbus response 2024-12-20 15:56:48 +08:00
李通洲 41240e9460 FFlist: fix return value of ffListPop 2024-12-20 11:12:14 +08:00
JohnTheCoolingFan 3bb82423b3 OS (Linux): Refactor Armbian version detection and add support for ubuntu-based armbian detection (#1447)
* Add support for detection of Armbian as Ubuntu flavor

Ubuntu can be used to build Armbian, it is one of the official bases for
Armbian. This allows the detection of Armbian in case it is based on
Ubuntu.

* Refactor Armbian detection

* Armbian: set idLike to id before setting id to "armbian"

* Tidy up detectArmbianVersion
2024-12-19 16:18:42 +08:00
李通洲 b87df82d58 Shell (Windows): use $POWERSHELL_VERSION if available 2024-12-19 11:00:16 +08:00
157 changed files with 2872 additions and 1010 deletions
-80
View File
@@ -1,80 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: '[BUG] '
labels: bug
assignees: ''
---
Be sure to read the [FAQ](https://github.com/fastfetch-cli/fastfetch?tab=readme-ov-file#faq) before submitting a new issue.
<!-- We will try hard to solve the issue. However since platforms and hardwares vary greatly, it can be hard to find the root cause of an issue. Providing the following information may help us greatly. Thanks in advance! -->
# General description of bug:
* What happened:
* What should happen:
* Fastfetch version used: <!-- please use the latest version, if possible -->
* Did it work in an older version: <!-- if yes, which version -->
* Where did you get the binary: <!-- GitHub release / GitHub Actions / installed with a package manager (please tell us which package manager you used!) / built from source yourself -->
* Does this issue still occur in [the latest dev build](https://github.com/fastfetch-cli/fastfetch/actions/)?
# Often helpful information:
Screenshot:
<!-- Paste the screenshot here -->
The content of the configuration file you use (if any):
```
// Paste here
```
Output of `fastfetch -c ci.jsonc --format json`:
<!--
Note that this output will contain you public IP. If it is not relevant for the issue, feel free to remove it before uploading.
-->
```
// Paste here
```
Output of `fastfetch --list-features`:
```
// Paste here
```
## If fastfatch crashed or froze
Paste the stacktrace here. You may get it with:
```shell
# You may need Ctrl+C to stop the process if it freezes
gdb -q -ex 'set confirm off' -ex run -ex 'bt full' -ex quit --args /path/to/fastfetch
```
If you are able to identify which module crashed, the strace can be helpful too
```shell
strace /path/to/fastfetch --multithreading false -s {MODULE} --pipe
```
If you cannot do the instructions above, please upload the core dump file:
## If fastfetch is slow
Use `time fastfetch --stat` to show time usage for each module.
## If an image or logo didn't show
<!-- Please make sure your terminal supports the image protocol you used. Note that GNOME Terminal doesn't support any image protocols. -->
* The image protocol you used:
* The terminal you used:
* Upload the image file here, or paste the image URL:
* Does it work with `--logo-width {WIDTH} --logo-height {HEIGHT}`?
## If fastfetch behaves incorrectly on shell startup
* The bug is reproducible with a clean shell configuration (i.e. `fastfetch` is the only line in `.zshrc` or `~/.config/fish/config.fish`):
* Does `sleep 1` before running `fastfetch` work?
+113
View File
@@ -0,0 +1,113 @@
name: Crash Bug Report
description: If fastfetch crashes or freezes
title: "[BUG] "
labels: ["bug", "crash", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! We will try hard to solve the issue.
However since platforms and hardwares vary greatly, it can be hard to find the root cause of an issue.
Providing the following information may help us greatly. Thanks in advance!
- type: checkboxes
attributes:
label: Read the FAQ first
description: Please check if the issue is already covered in the FAQ.
options:
- label: I have checked the FAQ but the issue is not covered
required: true
- type: markdown
attributes:
value: "### General description of the bug"
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
placeholder: I was trying to [...] but [...]
validations:
required: true
- type: input
attributes:
label: Version used
description: Fastfetch version used. Please use the latest version (found in the [releases](https://github.com/fastfetch-cli/fastfetch/releases)) if possible.
placeholder: Result of `fastfetch --version`
validations:
required: true
- type: dropdown
attributes:
label: Bug prevalence
description: How often does the bug occur?
options:
-
- Always
- Sometimes
- Rarely
- Once
- Other
validations:
required: true
- type: dropdown
attributes:
label: Regression
description: Did it work in an older version?
options:
-
- Not sure
- 'Yes'
- 'No'
validations:
required: true
- type: dropdown
attributes:
label: Installation
description: Where did you install fastfetch from?
options:
-
- GitHub Releases
- GitHub Actions (nightly)
- Built from source
- Package manager
validations:
required: true
- type: input
attributes:
label: Package manager
description: Which package manager did you use if applicable?
placeholder: e.g. `apt`, `pacman`, `brew`, `scoop`
- type: markdown
attributes:
value: '### Often helpful information'
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
- type: textarea
attributes:
label: Configuration
description: If applicable, paste your configuration file here.
placeholder: cat ~/.config/fastfetch/config.jsonc
render: jsonc
- type: markdown
attributes:
value: |
Paste the stacktrace here. You may get it with:
```shell
# You may need Ctrl+C to stop the process if it freezes
gdb -q -ex 'set confirm off' -ex run -ex 'bt full' -ex quit --args /path/to/fastfetch
```
If you are able to identify which module crashed, the strace can be helpful too
```shell
strace /path/to/fastfetch --multithreading false -s {MODULE} --pipe
```
If you cannot do the instructions above, please upload the core dump file if available.
- type: textarea
attributes:
label: Stacktrace
description: Paste the stacktrace or core dump file here.
render: text
validations:
required: true
@@ -0,0 +1,106 @@
name: General Bug Report
description: If something is not working as expected (wrong output, missing info, etc)
title: "[BUG] "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! We will try hard to solve the issue.
However since platforms and hardwares vary greatly, it can be hard to find the root cause of an issue.
Providing the following information may help us greatly. Thanks in advance!
- type: checkboxes
attributes:
label: Read the FAQ first
description: Please check if the issue is already covered in the FAQ.
options:
- label: I have checked the FAQ but the issue is not covered
required: true
- type: markdown
attributes:
value: "### General description of the bug"
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
placeholder: I was trying to [...] but [...]
validations:
required: true
- type: input
attributes:
label: Version used
description: Fastfetch version used. Please use the latest version (found in the [releases](https://github.com/fastfetch-cli/fastfetch/releases)) if possible.
placeholder: Result of `fastfetch --version`
validations:
required: true
- type: dropdown
attributes:
label: Bug prevalence
description: How often does the bug occur?
options:
-
- Always
- Sometimes
- Rarely
- Once
- Other
validations:
required: true
- type: dropdown
attributes:
label: Regression
description: Did it work in an older version?
options:
-
- Not sure
- 'Yes'
- 'No'
validations:
required: true
- type: dropdown
attributes:
label: Installation
description: Where did you install fastfetch from?
options:
-
- GitHub Releases
- GitHub Actions (nightly)
- Built from source
- Package manager
validations:
required: true
- type: input
attributes:
label: Package manager
description: Which package manager did you use if applicable?
placeholder: e.g. `apt`, `pacman`, `brew`, `scoop`
- type: markdown
attributes:
value: '### Often helpful information'
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
- type: textarea
attributes:
label: Configuration
description: If applicable, paste your configuration file here.
placeholder: cat ~/.config/fastfetch/config.jsonc
render: jsonc
- type: textarea
attributes:
label: System information
description: Output of `fastfetch -c all.jsonc --stat --format json`
placeholder: |
Note that this output will contain you public IP.
If it is not relevant for the issue, feel free to remove it before uploading.
render: jsonc
validations:
required: true
- type: textarea
attributes:
label: Features built-in
description: Output of `fastfetch --list-features`
render: text
validations:
required: true
+129
View File
@@ -0,0 +1,129 @@
name: Logo Bug Report
description: If my image logo is not displayed correctly
title: "[BUG] "
labels: ["bug", "logo", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report! We will try hard to solve the issue.
However since platforms and hardwares vary greatly, it can be hard to find the root cause of an issue.
Providing the following information may help us greatly. Thanks in advance!
- type: checkboxes
attributes:
label: Read the FAQ first
description: Please check if the issue is already covered in the FAQ.
options:
- label: I have checked the FAQ but the issue is not covered
required: true
- type: markdown
attributes:
value: "### General description of the bug"
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the bug is.
placeholder: I was trying to [...] but [...]
validations:
required: true
- type: input
attributes:
label: Version used
description: Fastfetch version used. Please use the latest version (found in the [releases](https://github.com/fastfetch-cli/fastfetch/releases)) if possible.
placeholder: Result of `fastfetch --version`
validations:
required: true
- type: dropdown
attributes:
label: Bug prevalence
description: How often does the bug occur?
options:
-
- Always
- Sometimes
- Rarely
- Once
- Other
validations:
required: true
- type: dropdown
attributes:
label: Regression
description: Did it work in an older version?
options:
-
- Not sure
- 'Yes'
- 'No'
validations:
required: true
- type: dropdown
attributes:
label: Installation
description: Where did you install fastfetch from?
options:
-
- GitHub Releases
- GitHub Actions (nightly)
- Built from source
- Package manager
validations:
required: true
- type: input
attributes:
label: Package manager
description: Which package manager did you use if applicable?
placeholder: e.g. `apt`, `pacman`, `brew`, `scoop`
- type: markdown
attributes:
value: '### Often helpful information'
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
- type: textarea
attributes:
label: Configuration
description: If applicable, paste your configuration file here.
placeholder: cat ~/.config/fastfetch/config.jsonc
render: jsonc
- type: markdown
attributes:
value: |
#### If an image or logo didn't show
Please make sure your terminal supports the image protocol you used.
Note that GNOME Terminal doesn't support any image protocols as of now
Some tips:
1. Try `fastfetch --show-errors` to see if there are any errors.
2. Try `fastfetch --logo-width {WIDTH} --logo-height {HEIGHT}`. Some protocols may require a image size being set.
- type: input
attributes:
label: Image protocol
description: The image protocol you used
validations:
required: true
- type: input
attributes:
label: Terminal
description: The terminal you used
validations:
required: true
- type: textarea
attributes:
label: Image tried
description: Upload the image file, or paste the image URL here
validations:
required: true
- type: textarea
attributes:
label: Error message
description: Error message printed by `fastfetch -s none --show-errors`, if any
- type: textarea
attributes:
label: Features built-in
description: Output of `fastfetch --list-features`
render: text
validations:
required: true
-18
View File
@@ -1,18 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: '[FEAT] '
labels: enhancement
assignees: ''
---
Be sure to read [FAQ](https://github.com/fastfetch-cli/fastfetch?tab=readme-ov-file#faq) before submitting a new issue.
## Wanted features:
<!-- Your features here -->
## Motivation:
<!-- Your motivation here -->
@@ -0,0 +1,40 @@
name: Feature Request
description: Suggest an idea for this project
title: "[FEAT] "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Fastfetch is a system information tool. We only accept hardware or system level software feature requests.
For most personal uses, I recommend using `Command` module to detect it yourself, which can be used to grab output from a custom shell script:
```jsonc
// This module shows the git version
{
"modules": [
{
"type": "command",
"key": "Git",
"text": "git version",
"format": "{~12}" // cut the first 12 characters
}
]
}
```
- type: textarea
attributes:
label: Description
description: A clear and concise description of what the feature is.
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Why do you want this feature? Why doesn't `Command` module suffice for you?
validations:
required: true
- type: textarea
attributes:
label: Additional context
description: Add any other context or screenshots about the feature request here.
-23
View File
@@ -1,23 +0,0 @@
---
name: Logo request
about: Request a new logo
title: '[LOGO] '
labels: logo request
assignees: ''
---
Tip: A logo can be displayed by fastfetch without getting into fastfetch's official repo. For highly customized logo for personal use, it's recommended to keep it locally. Please refer to https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch
# OS
```
Paste content of /etc/os-release and /etc/lsb-release here. If none of these files exist, describe a way to identify the distro
```
# Ascii
An ASCII logo should not take up too much space (smaller than 50x20 characters). Please also include the color codes if not available in `os-release`
```
Paste ascii art here.
```
+38
View File
@@ -0,0 +1,38 @@
name: Logo Request
description: Request a new ASCII logo for your favorite distro
title: "[LOGO] "
labels: ["logo request"]
body:
- type: markdown
attributes:
value: |
Tip: A logo can be displayed by fastfetch without getting into fastfetch's official repo.
For highly customized logo for personal use, it's recommended to keep it locally.
Please refer to https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch
- type: textarea
attributes:
label: OS
description: Paste content of `/etc/os-release` and `/etc/lsb-release` here. If none of these files exist, describe a way to identify the distro
placeholder: cat /etc/os-release
validations:
required: true
- type: textarea
attributes:
label: ASCII Art
description: An ASCII logo should not take up too much space (smaller than 50x20 characters). Please also include the color codes if not available in `os-release`
placeholder: Paste ASCII art here
validations:
required: true
- type: input
attributes:
label: Original Image
description: If the ASCII art is based on an image, please provide a link to the original image
placeholder: Image URL or distro website URL
- type: checkboxes
attributes:
label: Checklist
options:
- label: The ASCII art is smaller than 50x20 characters (width x height)
required: true
- label: The ASCII art contains color codes, or the color codes are available in `os-release`
required: true
+75 -2
View File
@@ -197,6 +197,42 @@ jobs:
name: fastfetch-linux-armv7
path: ./fastfetch-*.*
linux-armv6:
name: Linux-armv6
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: uraimo/run-on-arch-action@v2
id: runcmd
with:
arch: armv6
distro: bookworm
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y wget
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-armv6
path: ./fastfetch-*.*
linux-riscv64:
name: Linux-riscv64
runs-on: ubuntu-22.04
@@ -232,6 +268,41 @@ jobs:
name: fastfetch-linux-riscv64
path: ./fastfetch-*.*
linux-ppc64le:
name: Linux-ppc64le
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: uraimo/run-on-arch-action@v2
id: runcmd
with:
arch: ppc64le
distro: ubuntu20.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-ppc64le
path: ./fastfetch-*.*
musl-amd64:
name: Musl-amd64
runs-on: ubuntu-latest
@@ -377,7 +448,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.1'
version: '14.2'
run: |
uname -a
sudo pkg update
@@ -449,7 +520,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.5'
version: '7.6'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa pulseaudio hwdata py3-requests
@@ -577,7 +648,9 @@ jobs:
- linux-amd64
- linux-aarch64
- linux-armv7
- linux-armv6
- linux-riscv64
- linux-ppc64le
- musl-amd64
- macos-universal
- freebsd-amd64
+124
View File
@@ -1,3 +1,127 @@
# 2.35.0
Bugfixes:
* Suppress output of EGL again (#1513, GPU, Linux)
* Regression of 2.34.0
Features:
* Show SOC name reported in `cpuinfo` if available (#1510, CPU, Linux)
* 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)
* 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)
* Support duration printing in custom format (Disk / Users)
* For example:
```jsonc
{
"modules": [
{
"key": "OS Installation Date", // No longer need to write bash scripts
"type": "disk",
"folders": "/", // Different OSes may need to specify different folders
"format": "{create-time:10} [{days} days]" // Reports the creation date of the root folder
}
]
}
```
Logo:
* Add Arch_old
* Update key color of NetBSD_small
* Fix OpenBSD and many other ascii logos (#1522)
# 2.34.1
An early release to fix KDE Plasma 6.3 compatibility. Hopefully it can be accepted by package managers before KDE 6.3 is officially released.
To package managers: if you find fastfetch bugs, it's highly appreciated if you can report them to the upstream, so that all users can benefit from the fix, instead of maintaining out-of-tree patches. Thanks!
Features:
* Report vendor name when detecting GPUs by OpenGL
* Note: the vendor name is actually the creator of the OpenGL driver (such as `Mesa`) and may not be the same as the GPU vendor.
Bugfixes:
* Fix Ghostty termfont detection (#1495, TerminalFont, macOS)
* Fix compatibility with KDE Plasma 6.3 (#1504, Display, Linux)
* Make memory usage detection logic consistent with other systems (Memory, OpenBSD / NetBSD)
* Report media file name if media title is not available (Media)
* Fix max frequency detection for CPUs with both performance and efficiency cores (CPU, FreeBSD)
Logo:
* Add HeliumOS
* Add Oreon
* Update SnigdhaOS
# 2.34.0
Changes:
* We now print distro pretty name if available (OS)
* This is a long requested feature. However, it may break some distros. File a bug with the content of `/etc/os-release` if it breaks your distro.
Bugfixes:
* Fix thunderbolt version of new MBPs (#1465, Host, macOS)
* Fix backlight name detection on FreeBSD (Brightness, FreeBSD)
* Fix Terminal detection when running fastfetch in `pk-command-not-found` (#1467, Terminal, Linux)
* Relax detection of terminals in NixOS (#1479, Terminal, Linux)
* Should fix konsole, ghostty and maybe others
* Fix core count output in multi-package platforms (CPU)
* Don't suppress the output of `preRun` (#1489)
* Fix battery percentage detection (Battery, NetBSD)
Features:
* Support ghostty terminal font detection (TerminalFont, Linux / macOS)
* Support `kitty-icat` image protocol, which uses `kitten icat` to generate image data
* Pros: support tmux; support gif animations; good performance
* Cons: due to the limitation of `kitten icat`, we need to clear the screen before displaying the image logo
* Support WM version detection (WM)
* In Linux, Hyprland & sway are supported currently
* Improve performance when stdout is redirected (TerminalSize)
* Report thermal zone temp if CPU temp is not available (CPU, Linux)
* Report sound server (Pipewire or PulseAudio) if available (#1454, Sound, Linux)
* Enable OpenGL & OpenCL detection on Android (OpenGL / OpenCL, Android)
* Detect & report MediaTek Dimensity 9000+ SOC name (CPU, Android)
* Support appman (am-user) package manager detection (Packages, Linux)
Logo:
* Add Lubuntu
* Update Xray_os
* Add SnigdhaOS
* Add Rhino Linux
# 2.33.0
Changes:
* Introduce a new CMake flag `-DBUILD_FLASHFETCH=OFF` to disable building flashfetch binaries
* Package managers are encouraged to enable it. See <https://github.com/fastfetch-cli/fastfetch/discussions/627> for detail
Bugfixes:
* Fix interconnect type detection (#1453, PhysicalDisk, Linux)
* Regression of v2.28
* Don't report `proot` as terminal (Terminal, Android)
* Remove a debug output (DiskIO, OpenBSD)
* Fix media detection for some players (#1461, Media, Linux)
* Regression of v2.32
Features:
* Use `$POWERSHELL_VERSION` as PowerShell version if available (Shell, Windows)
* Fetching Windows PowerShell version can be very slow. Add `$env:POWERSHELL_VERSION = $PSVersionTable.PSVersion.ToString()` in `$PROFILE` before running `fastfetch` to improve the performance of `Shell` module
* Add support for ubuntu-based armbian detection (#1447, OS, Linux)
* Improve performance of Bluetooth detection (Bluetooth)
* We no longer report disconnected bluetooth devices in `--format json` when `--bluetooth-show-disconnected` isn't specified
* Support brightness level detection for builtin displays (Brightness, OpenBSD / NetBSD)
* Requires root permission on OpenBSD
* Support battery level detection (Battery, OpenBSD / NetBSD)
* Support CPU temperature detection in NetBSD (CPU, NetBSD)
* Hard code path of `libvulkan.so` for Android
* So that users don't need to install the vulkan-loader wrapper of termux
Logo:
* Add NurOS
* Add GoralixOS
# 2.32.1
A hotfix for OpenBSD. No changes to other platforms.
+78 -36
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.32.1
VERSION 2.35.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -70,8 +70,8 @@ cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR F
cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS" OFF)
cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
cmake_dependent_option(ENABLE_ZLIB "Enable zlib" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR SunOS" OFF)
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS" OFF)
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS" OFF)
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
@@ -86,6 +86,7 @@ cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR Open
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
option(ENABLE_LTO "Enable link-time optimization in release mode if supported" ON)
option(BUILD_FLASHFETCH "Build flashfetch" ON) # Also build the flashfetch binary
option(BUILD_TESTS "Build tests" OFF) # Also create test executables
option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds
option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions
@@ -133,7 +134,7 @@ else()
message(STATUS "Threads type: disabled")
endif()
set(WARNING_FLAGS "-Wall -Wextra -Wconversion -Werror=uninitialized -Werror=return-type")
set(WARNING_FLAGS "-Wall -Wextra -Wconversion -Werror=uninitialized -Werror=return-type -Werror=vla")
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Werror=int-conversion")
@@ -533,7 +534,7 @@ if(LINUX)
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_linux.c
src/detection/wm/wm_nosupport.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -616,8 +617,7 @@ elseif(FreeBSD)
src/common/sysctl.c
src/detection/battery/battery_bsd.c
src/detection/bios/bios_bsd.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/bluetoothradio/bluetoothradio_linux.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/board/board_bsd.c
src/detection/bootmgr/bootmgr_bsd.c
src/detection/brightness/brightness_bsd.c
@@ -689,6 +689,15 @@ elseif(FreeBSD)
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
if(DragonFly)
list(APPEND LIBFASTFETCH_SRC
src/detection/bluetooth/bluetooth_nosupport.c
)
else()
list(APPEND LIBFASTFETCH_SRC
src/detection/bluetooth/bluetooth_bsd.c
)
endif()
elseif(NetBSD)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
@@ -697,13 +706,13 @@ elseif(NetBSD)
src/common/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_nosupport.c
src/detection/battery/battery_nbsd.c
src/detection/bios/bios_nbsd.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/bluetoothradio/bluetoothradio_linux.c
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/board/board_nbsd.c
src/detection/bootmgr/bootmgr_nosupport.c
src/detection/brightness/brightness_nosupport.c
src/detection/brightness/brightness_nbsd.c
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_nbsd.c
src/detection/cpu/cpu_nbsd.c
@@ -743,7 +752,7 @@ elseif(NetBSD)
src/detection/localip/localip_linux.c
src/detection/gamepad/gamepad_nosupport.c
src/detection/media/media_linux.c
src/detection/memory/memory_obsd.c
src/detection/memory/memory_nbsd.c
src/detection/mouse/mouse_nosupport.c
src/detection/netio/netio_bsd.c
src/detection/opengl/opengl_linux.c
@@ -779,13 +788,13 @@ elseif(OpenBSD)
src/common/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_nosupport.c
src/detection/battery/battery_obsd.c
src/detection/bios/bios_nosupport.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/bluetoothradio/bluetoothradio_linux.c
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/board/board_nosupport.c
src/detection/bootmgr/bootmgr_nosupport.c
src/detection/brightness/brightness_nosupport.c
src/detection/brightness/brightness_obsd.c
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_obsd.c
@@ -913,7 +922,7 @@ elseif(APPLE)
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_apple.m
src/detection/wifi/wifi_apple.m
src/detection/wm/wm_apple.c
src/detection/wm/wm_apple.m
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_apple.m
src/detection/camera/camera_apple.m
@@ -994,6 +1003,7 @@ elseif(WIN32)
src/util/windows/registry.c
src/util/windows/unicode.c
src/util/windows/wmi.cpp
src/util/windows/version.c
src/util/platform/FFPlatform_windows.c
src/util/binary_windows.c
)
@@ -1132,6 +1142,14 @@ else()
endif()
endif()
if(ANDROID)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/vendor/lib64 -Wl,-rpath,/system/lib64")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/vendor/lib -Wl,-rpath,/system/lib")
endif()
endif()
if(LINUX AND EXISTS "/lib/ld-musl-${CMAKE_HOST_SYSTEM_PROCESSOR}.so.1")
execute_process(COMMAND "/lib/ld-musl-${CMAKE_HOST_SYSTEM_PROCESSOR}.so.1"
ERROR_VARIABLE LD_MUSL_RESULT)
@@ -1220,6 +1238,10 @@ if(NOT "${CUSTOM_OS_RELEASE_PATH}" STREQUAL "")
message(STATUS "Custom file path of os_release: ${CUSTOM_OS_RELEASE_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_OS_RELEASE_PATH=${CUSTOM_OS_RELEASE_PATH})
endif()
if(NOT "${CUSTOM_LSB_RELEASE_PATH}" STREQUAL "")
message(STATUS "Custom file path of lsb_release: ${CUSTOM_LSB_RELEASE_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_LSB_RELEASE_PATH=${CUSTOM_LSB_RELEASE_PATH})
endif()
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
message(STATUS "Enabling custom link type: ${BINARY_LINK_TYPE}")
@@ -1467,6 +1489,7 @@ elseif(FreeBSD)
target_link_libraries(libfastfetch
PRIVATE "m"
PRIVATE "usbhid"
PRIVATE "bluetooth"
)
if(NOT DragonFly)
target_link_libraries(libfastfetch
@@ -1485,6 +1508,7 @@ elseif(OpenBSD)
elseif(NetBSD)
target_link_libraries(libfastfetch
PRIVATE "m"
PRIVATE "prop"
)
elseif(SunOS)
target_link_libraries(libfastfetch
@@ -1611,41 +1635,52 @@ target_link_libraries(fastfetch
PRIVATE libfastfetch
)
add_executable(flashfetch
src/flashfetch.c
)
target_compile_definitions(flashfetch
PRIVATE FASTFETCH_TARGET_BINARY_NAME=flashfetch
)
target_link_libraries(flashfetch
PRIVATE libfastfetch
)
# Prevent fastfetch from linking to libstdc++
set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "")
set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C)
set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C)
if(WIN32)
target_sources(fastfetch
PRIVATE src/util/windows/version.rc
)
target_sources(flashfetch
PRIVATE src/util/windows/version.rc
)
elseif(APPLE)
target_link_options(fastfetch
PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,Info.plist
)
target_link_options(flashfetch
PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,Info.plist
)
endif()
if(BINARY_LINK_TYPE STREQUAL "static")
target_link_options(fastfetch PRIVATE "-static")
target_link_options(flashfetch PRIVATE "-static")
endif()
# Apply all above parameters to flashfetch if it is built
if (BUILD_FLASHFETCH)
add_executable(flashfetch
src/flashfetch.c
)
target_compile_definitions(flashfetch
PRIVATE FASTFETCH_TARGET_BINARY_NAME=flashfetch
)
target_link_libraries(flashfetch
PRIVATE libfastfetch
)
set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C)
if(WIN32)
target_sources(flashfetch
PRIVATE src/util/windows/version.rc
)
elseif(APPLE)
target_link_options(flashfetch
PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,Info.plist
)
endif()
if(BINARY_LINK_TYPE STREQUAL "static")
target_link_options(flashfetch PRIVATE "-static")
endif()
endif()
###################
@@ -1687,10 +1722,17 @@ endif()
include(GNUInstallDirs)
install(
TARGETS fastfetch flashfetch
TARGETS fastfetch
DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
if (TARGET flashfetch)
install(
TARGETS flashfetch
DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
endif()
if (TARGET ffwinrt)
install(
TARGETS ffwinrt
+33
View File
@@ -199,10 +199,43 @@ Try upgrading `pci.ids`: Download <https://pci-ids.ucw.cz/v2.2/pci.ids> and over
Alternatively, you may try to use `fastfetch --gpu-driver-specific`, so that `fastfetch` will try to ask the driver for GPU name if supported.
### Q: I get error `Authorization required, but no authorization protocol specified` when running fastfetch in root
Try `export XAUTHORITY=$HOME/.Xauthority`
### Q: Fastfetch cannot detect my awesome 3rd-party macOS window manager!
Try `fastfetch --wm-detect-plugin`. See also [#984](https://github.com/fastfetch-cli/fastfetch/issues/984)
### Q: How can I change the colors of my ASCII logo?
Try `fastfetch --logo-color-[1-9] <color>`. `[1-9]` is the index of color placeholders.
For example: `fastfetch --logo-color-1 red --logo-color-2 green`.
In JSONC, you can use:
```jsonc
{
"logo": {
"color": {
"1": "red",
"2": "green"
}
}
}
```
### Q: How to hide a key?
Set the key to a white space.
```jsonc
{
"key": " "
}
```
### Q: I want feature A / B / C. Will fastfetch support it?
Fastfetch is a system information tool. We only accept hardware or system level software feature requests. For most personal uses, I recommend using `Command` module to detect it yourself, which can be used to grab output from a custom shell script:
+18
View File
@@ -1,3 +1,21 @@
fastfetch (2.34.1) jammy; urgency=medium
* Update to 2.34.1
-- Carter Li <zhangsongcui@live.cn> Mon, 13 Jan 2025 16:06:22 +0800
fastfetch (2.34.0) jammy; urgency=medium
* Update to 2.34.0
-- Carter Li <zhangsongcui@live.cn> Thu, 09 Jan 2025 09:03:17 +0800
fastfetch (2.33.0) jammy; urgency=medium
* Update to 2.33.0
-- Carter Li <zhangsongcui@live.cn> Thu, 26 Dec 2024 09:42:27 +0800
fastfetch (2.32.0) jammy; urgency=medium
* Update to 2.32.0
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.32.0_source.buildinfo universe/utils optional
fastfetch_2.34.1_source.buildinfo universe/utils optional
+7 -6
View File
@@ -183,7 +183,7 @@
"type": "string"
},
"diskFormat": {
"description": "Output format of the module `Disk`. See `-h format` for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {(null)}: (null)",
"description": "Output format of the module `Disk`. See `-h format` for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation",
"type": "string"
},
"diskioFormat": {
@@ -275,11 +275,11 @@
"type": "string"
},
"osFormat": {
"description": "Output format of the module `OS`. See `-h format` for formatting syntax\n 1. {sysname}: Name of the kernel\n 2. {name}: Name of the OS\n 3. {pretty-name}: Pretty name of the OS\n 4. {id}: ID of the OS\n 5. {id-like}: ID like of the OS\n 6. {variant}: Variant of the OS\n 7. {variant-id}: Variant ID of the OS\n 8. {version}: Version of the OS\n 9. {version-id}: Version ID of the OS\n 10. {codename}: Version codename of the OS\n 11. {build-id}: Build ID of the OS\n 12. {arch}: Architecture of the OS",
"description": "Output format of the module `OS`. See `-h format` for formatting syntax\n 1. {sysname}: Name of the kernel\n 2. {name}: Name of the OS\n 3. {pretty-name}: Pretty name of the OS, if available\n 4. {id}: ID of the OS\n 5. {id-like}: ID like of the OS\n 6. {variant}: Variant of the OS\n 7. {variant-id}: Variant ID of the OS\n 8. {version}: Version of the OS\n 9. {version-id}: Version ID of the OS\n 10. {codename}: Version codename of the OS\n 11. {build-id}: Build ID of the OS\n 12. {arch}: Architecture of the OS",
"type": "string"
},
"packagesFormat": {
"description": "Output format of the module `Packages`. See `-h format` for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am}: Number of am packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi packages\n 37. {nix-all}: Total number of all nix packages\n 38. {flatpak-all}: Total number of all flatpak app packages\n 39. {brew-all}: Total number of all brew packages\n 40. {guix-all}: Total number of all guix packages",
"description": "Output format of the module `Packages`. See `-h format` for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop}: Number of scoop packages\n 21. {choco}: Number of choco packages\n 22. {pkgtool}: Number of pkgtool packages\n 23. {paludis}: Number of paludis packages\n 24. {winget}: Number of winget packages\n 25. {opkg}: Number of opkg packages\n 26. {am-system}: Number of am-system packages\n 27. {sorcery}: Number of sorcery packages\n 28. {lpkg}: Number of lpkg packages\n 29. {lpkgbuild}: Number of lpkgbuild packages\n 30. {guix-system}: Number of guix-system packages\n 31. {guix-user}: Number of guix-user packages\n 32. {guix-home}: Number of guix-home packages\n 33. {linglong}: Number of linglong packages\n 34. {pacstall}: Number of pacstall packages\n 35. {mport}: Number of mport packages\n 36. {qi}: Number of qi packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {nix-all}: Total number of all nix packages\n 40. {flatpak-all}: Total number of all flatpak app packages\n 41. {brew-all}: Total number of all brew packages\n 42. {guix-all}: Total number of all guix packages",
"type": "string"
},
"physicaldiskFormat": {
@@ -315,7 +315,7 @@
"type": "string"
},
"soundFormat": {
"description": "Output format of the module `Sound`. See `-h format` for formatting syntax\n 1. {is-main}: Is main sound device\n 2. {name}: Device name\n 3. {volume-percentage}: Volume (in percentage num)\n 4. {identifier}: Identifier\n 5. {volume-percentage-bar}: Volume (in percentage bar)",
"description": "Output format of the module `Sound`. See `-h format` for formatting syntax\n 1. {is-main}: Is main sound device\n 2. {name}: Device name\n 3. {volume-percentage}: Volume (in percentage num)\n 4. {identifier}: Identifier\n 5. {volume-percentage-bar}: Volume (in percentage bar)\n 6. {platform-api}: Platform API used",
"type": "string"
},
"swapFormat": {
@@ -355,7 +355,7 @@
"type": "string"
},
"usersFormat": {
"description": "Output format of the module `Users`. See `-h format` for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone",
"description": "Output format of the module `Users`. See `-h format` for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login",
"type": "string"
},
"versionFormat": {
@@ -375,7 +375,7 @@
"type": "string"
},
"wmFormat": {
"description": "Output format of the module `WM`. See `-h format` for formatting syntax\n 1. {process-name}: WM process name\n 2. {pretty-name}: WM pretty name\n 3. {protocol-name}: WM protocol name\n 4. {plugin-name}: WM plugin name",
"description": "Output format of the module `WM`. See `-h format` for formatting syntax\n 1. {process-name}: WM process name\n 2. {pretty-name}: WM pretty name\n 3. {protocol-name}: WM protocol name\n 4. {plugin-name}: WM plugin name\n 5. {version}: WM version",
"type": "string"
},
"wifiFormat": {
@@ -432,6 +432,7 @@
"sixel",
"kitty",
"kitty-direct",
"kitty-icat",
"iterm",
"chafa",
"raw",
+18 -6
View File
@@ -9,7 +9,7 @@
},
"separator": "│ ",
"percent": {
"type": 6
"type": ["bar", "hide-others"]
},
"bar": {
"borderLeft": "",
@@ -70,7 +70,7 @@
"type": "localip",
"key": "│ MAC ADDR │{$1}",
"format": "{mac} ({ifname})",
"showIPv4": false,
"showIpv4": false,
"showMac": true
},
{
@@ -120,12 +120,18 @@
{
"type": "memory",
"key": "│ MEMORY │{$1}",
"format": "{used} / {total} [{percentage}]"
"format": "{used} / {total} [{percentage}]",
"percent": {
"type": ["num"]
}
},
{
"type": "memory",
"key": "│ USAGE │{$1}",
"format": ""
"format": "",
"percent": {
"type": ["bar", "hide-others"]
}
},
{
"type": "custom",
@@ -135,12 +141,18 @@
"type": "disk",
"key": "│ VOLUME │{$1}",
"format": "{size-used} / {size-total} [{size-percentage}]",
"folders": "/"
"folders": "/",
"percent": {
"type": ["num"]
}
},
{
"type": "disk",
"key": "│ DISK USAGE │{$1}",
"format": ""
"format": "",
"percent": {
"type": ["bar", "hide-others"]
}
},
{
"type": "custom",
+3
View File
@@ -169,6 +169,9 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst
? GetCurrentProcess()
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess == NULL)
return false;
if (gui)
*gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0;
+12 -4
View File
@@ -36,11 +36,19 @@
#if FF_HAVE_PTHREAD_NP
#include <pthread_np.h>
#endif
#define FF_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t FFThreadMutex;
typedef pthread_t FFThreadType;
static inline void ffThreadMutexLock(FFThreadMutex* mutex) { pthread_mutex_lock(mutex); }
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { pthread_mutex_unlock(mutex); }
#if __APPLE__
#include <os/lock.h>
#define FF_THREAD_MUTEX_INITIALIZER OS_UNFAIR_LOCK_INIT
typedef os_unfair_lock FFThreadMutex;
static inline void ffThreadMutexLock(os_unfair_lock* mutex) { os_unfair_lock_lock(mutex); }
static inline void ffThreadMutexUnlock(os_unfair_lock* mutex) { os_unfair_lock_unlock(mutex); }
#else
#define FF_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
typedef pthread_mutex_t FFThreadMutex;
static inline void ffThreadMutexLock(FFThreadMutex* mutex) { pthread_mutex_lock(mutex); }
static inline void ffThreadMutexUnlock(FFThreadMutex* mutex) { pthread_mutex_unlock(mutex); }
#endif
static inline FFThreadType ffThreadCreate(void* (* func)(void*), void* data) {
FFThreadType newThread = 0;
pthread_create(&newThread, NULL, func, data);
+10 -1
View File
@@ -186,7 +186,8 @@
"data-raw": "Text data, printed as is",
"sixel": "Image file, printed as sixel codes",
"kitty": "Image file, printed as kitty graphics protocol",
"kitty_direct": "Image file, tell the terminal emulator to read image data from the specified file (Supported by kitty and wezterm)",
"kitty-direct": "Image file, tell the terminal emulator to read image data from the specified file (Supported by kitty and wezterm)",
"kitty-icat": "Image file, use `kitten icat` to display the image. Requires binary `kitten` to be installed",
"iterm": "Image file, printed as iterm graphics protocol",
"chafa": "Image file, printed as ascii art using libchafa",
"raw": "Image file, printed as raw binary string",
@@ -351,6 +352,14 @@
"type": "path"
}
},
{
"long": "kitty-icat",
"desc": "Short for --logo-type kitty-icat --logo <path>",
"remark": "See \"--help logo-type\" for more info",
"arg": {
"type": "path"
}
},
{
"long": "iterm",
"desc": "Short for --logo-type iterm --logo <path>",
+107
View File
@@ -0,0 +1,107 @@
#include "battery.h"
#include "common/io/io.h"
#include "util/FFstrbuf.h"
#include "util/stringUtils.h"
#include <prop/prop_array.h>
#include <prop/prop_bool.h>
#include <prop/prop_dictionary.h>
#include <prop/prop_object.h>
#include <sys/envsys.h>
#include <prop/proplib.h>
#include <paths.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
{
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
prop_dictionary_t root = NULL;
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed";
bool acConnected = false;
{
prop_array_t acad = prop_dictionary_get(root, "acpiacad0");
if (acad)
{
prop_dictionary_t dict = prop_array_get(acad, 0);
prop_dictionary_get_uint8(dict, "cur-value", (uint8_t*) &acConnected);
}
}
prop_object_iterator_t itKey = prop_dictionary_iterator(root);
for (prop_dictionary_keysym_t key; (key = prop_object_iterator_next(itKey)) != NULL; )
{
if (!ffStrStartsWith(prop_dictionary_keysym_value(key), "acpibat")) continue;
prop_array_t bat = prop_dictionary_get_keysym(root, key);
uint32_t max = 0, curr = 0, dischargeRate = 0;
bool charging = false, critical = false;
prop_object_iterator_t iter = prop_array_iterator(bat);
for (prop_dictionary_t dict; (dict = prop_object_iterator_next(iter)) != NULL;)
{
if (prop_object_type(dict) != PROP_TYPE_DICTIONARY)
continue;
const char* desc = NULL;
if (!prop_dictionary_get_string(dict, "description", &desc))
continue;
if (ffStrEquals(desc, "present"))
{
int value = 0;
if (prop_dictionary_get_int(dict, "cur-value", &value) && value == 0)
continue;
}
else if (ffStrEquals(desc, "charging"))
{
prop_dictionary_get_uint8(dict, "cur-value", (uint8_t*) &charging);
}
else if (ffStrEquals(desc, "charge"))
{
prop_dictionary_get_uint32(dict, "max-value", &max);
prop_dictionary_get_uint32(dict, "cur-value", &curr);
const char* state = NULL;
if (prop_dictionary_get_string(dict, "state", &state) && ffStrEquals(state, "critical"))
critical = true;
}
else if (ffStrEquals(desc, "discharge rate"))
{
prop_dictionary_get_uint(dict, "cur-value", &dischargeRate);
}
}
if (max > 0)
{
FFBatteryResult* battery = ffListAdd(results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
battery->cycleCount = 0;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->serial);
ffStrbufInit(&battery->manufactureDate);
battery->timeRemaining = -1;
battery->capacity = (double) curr / (double) max * 100.;
if (charging)
ffStrbufAppendS(&battery->status, "Charging, ");
else if (dischargeRate)
ffStrbufAppendS(&battery->status, "Discharging, ");
if (critical)
ffStrbufAppendS(&battery->status, "Critical, ");
if (acConnected)
ffStrbufAppendS(&battery->status, "AC Connected");
ffStrbufTrimRight(&battery->status, ' ');
ffStrbufTrimRight(&battery->status, ',');
}
}
prop_object_iterator_release(itKey);
return NULL;
}
+52
View File
@@ -0,0 +1,52 @@
#include "battery.h"
#include "common/io/io.h"
#include <machine/apmvar.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* result)
{
FF_AUTO_CLOSE_FD int devfd = open("/dev/apm", O_RDONLY);
if (devfd < 0) return "open(dev/apm, O_RDONLY) failed";
struct apm_power_info info = {};
if (ioctl(devfd, APM_IOC_GETPOWER, &info) < 0)
return "ioctl(APM_IOC_GETPOWER) failed";
if (info.battery_state == APM_BATTERY_ABSENT)
return NULL;
FFBatteryResult* battery = (FFBatteryResult*) ffListAdd(result);
battery->temperature = FF_BATTERY_TEMP_UNSET;
battery->cycleCount = 0;
battery->timeRemaining = -1;
battery->capacity = info.battery_life;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->serial);
ffStrbufInit(&battery->manufactureDate);
if (info.ac_state == APM_AC_ON)
ffStrbufAppendS(&battery->status, "AC Connected");
else if (info.ac_state == APM_AC_BACKUP)
ffStrbufAppendS(&battery->status, "Backup In Use");
else if (info.ac_state == APM_AC_OFF)
{
battery->timeRemaining = (int) info.minutes_left * 60;
ffStrbufAppendS(&battery->status, "Discharging");
}
if (info.battery_state == APM_BATT_CRITICAL || info.battery_state == APM_BATT_CHARGING)
{
if (battery->status.length) ffStrbufAppendS(&battery->status, ", ");
ffStrbufAppendS(&battery->status, info.battery_state == APM_BATT_CRITICAL ? "Critical" : "Charging");
}
return NULL;
}
+1 -1
View File
@@ -11,4 +11,4 @@ typedef struct FFBluetoothResult
bool connected;
} FFBluetoothResult;
const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */);
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */);
+4 -1
View File
@@ -10,7 +10,7 @@
@property (nonatomic) uint8_t batteryPercentSingle;
@end
const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */)
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
{
NSArray<IOBluetoothDevice*>* ioDevices = IOBluetoothDevice.pairedDevices;
if(!ioDevices)
@@ -18,6 +18,9 @@ const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */)
for(IOBluetoothDevice* ioDevice in ioDevices)
{
if (!options->showDisconnected && !ioDevice.isConnected)
continue;
FFBluetoothResult* device = ffListAdd(devices);
ffStrbufInitS(&device->name, ioDevice.name.UTF8String);
ffStrbufInitS(&device->address, ioDevice.addressString.UTF8String);
+25
View File
@@ -0,0 +1,25 @@
#include "bluetooth.h"
#define L2CAP_SOCKET_CHECKED
#include <bluetooth.h>
static int enumDev(FF_MAYBE_UNUSED int sockfd, struct bt_devinfo const* dev, FFlist* devices)
{
FFBluetoothResult* device = ffListAdd(devices);
ffStrbufInitS(&device->name, bt_devremote_name_gen(dev->devname, &dev->bdaddr));
ffStrbufInitS(&device->address, bt_ntoa(&dev->bdaddr, NULL));
ffStrbufUpperCase(&device->address);
ffStrbufInit(&device->type);
device->battery = 0;
device->connected = true;
return 0;
}
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
{
// struct hostent* ent = bt_gethostent();
if (bt_devenum((void*) enumDev, devices) < 0)
return "bt_devenum() failed";
return 0;
}
+68 -22
View File
@@ -3,6 +3,7 @@
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
#include "common/io/io.h"
/* Example dbus reply, striped to only the relevant parts:
array [ //root
@@ -44,16 +45,16 @@ array [ //root
]
*/
static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device)
static bool detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
return true;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
return;
return true;
const char* deviceProperty;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty);
@@ -74,6 +75,13 @@ static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBlue
}
else if(ffStrEquals(deviceProperty, "Connected"))
ffDBusGetBool(dbus, &dictIter, &device->connected);
else if(ffStrEquals(deviceProperty, "Paired"))
{
bool paired = true;
ffDBusGetBool(dbus, &dictIter, &paired);
if (!paired) return false;
}
return true;
}
static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothResult* device)
@@ -103,32 +111,37 @@ static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFB
do
{
detectBluetoothValue(dbus, &arrayIter, device);
bool shouldContinue = detectBluetoothValue(dbus, &arrayIter, device);
if (!shouldContinue)
{
ffStrbufClear(&device->name);
break;
}
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
}
static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
static FFBluetoothResult* detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
return NULL;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH)
return;
return NULL;
const char* objectPath;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath);
// We don't want adapter objects
if(!ffStrContains(objectPath, "/dev_"))
return;
return NULL;
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
return;
return NULL;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
@@ -145,16 +158,10 @@ static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessage
detectBluetoothProperty(dbus, &arrayIter, device);
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
if(device->name.length == 0)
{
ffStrbufDestroy(&device->name);
ffStrbufDestroy(&device->address);
ffStrbufDestroy(&device->type);
--devices->length;
}
return device;
}
static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter, int32_t connectedCount)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
return;
@@ -164,11 +171,25 @@ static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIt
do
{
detectBluetoothObject(devices, dbus, &arrayIter);
FFBluetoothResult* device = detectBluetoothObject(devices, dbus, &arrayIter);
if (device)
{
if(device->name.length == 0 || (connectedCount > 0 && !device->connected))
{
ffStrbufDestroy(&device->name);
ffStrbufDestroy(&device->address);
ffStrbufDestroy(&device->type);
--devices->length;
}
if (device->connected && --connectedCount == 0)
break;
}
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
}
static const char* detectBluetooth(FFlist* devices)
static const char* detectBluetooth(FFlist* devices, int32_t connectedCount)
{
FFDBusData dbus;
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
@@ -186,18 +207,43 @@ static const char* detectBluetooth(FFlist* devices)
return "Failed to get root iterator of GetManagedObjects";
}
detectBluetoothRoot(devices, &dbus, &rootIter);
detectBluetoothRoot(devices, &dbus, &rootIter, connectedCount);
dbus.lib->ffdbus_message_unref(managedObjects);
return NULL;
}
static uint32_t connectedDevices(void)
{
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth");
if(dirp == NULL)
return 0;
uint32_t result = 0;
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL)
{
if (strchr(entry->d_name, ':') != NULL)
++result;
}
return result;
}
#endif
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
{
#ifdef FF_HAVE_DBUS
return detectBluetooth(devices);
int32_t connectedCount = -1;
if (!options->showDisconnected)
{
connectedCount = (int32_t) connectedDevices();
if (connectedCount == 0)
return NULL;
}
return detectBluetooth(devices, connectedCount);
#else
return "Fastfetch was compiled without DBus support";
#endif
@@ -1,6 +1,6 @@
#include "bluetooth.h"
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
{
return "Not supported on this platform";
}
+5 -4
View File
@@ -7,7 +7,7 @@
#pragma GCC diagnostic ignored "-Wpointer-sign"
const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */)
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */)
{
// Actually bluetoothapis.dll, but it's missing on Windows 7
FF_LIBRARY_LOAD(bluetoothapis, "dlopen bthprops.cpl failed", "bthprops.cpl", 1)
@@ -20,13 +20,14 @@ const char* ffDetectBluetooth(FFlist* devices /* FFBluetoothResult */)
};
HBLUETOOTH_DEVICE_FIND hFind = ffBluetoothFindFirstDevice(&(BLUETOOTH_DEVICE_SEARCH_PARAMS) {
.fReturnConnected = TRUE,
.fReturnRemembered = TRUE,
.fReturnAuthenticated = TRUE,
.fReturnUnknown = TRUE,
.fReturnRemembered = options->showDisconnected,
.fReturnAuthenticated = options->showDisconnected,
.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS)
}, &btdi);
if(!hFind)
{
if (GetLastError() == ERROR_NO_MORE_ITEMS)
return NULL;
return "BluetoothFindFirstDevice() failed";
}
@@ -55,7 +55,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices)
on_scope_exit releaseCallResult([&] { pCallResult && pCallResult->Release(); });
IWbemClassObject* pResultObject = nullptr;
if (FAILED(pCallResult->GetResultObject(WBEM_INFINITE, &pResultObject)))
if (FAILED(pCallResult->GetResultObject((LONG) WBEM_INFINITE, &pResultObject)))
continue;
on_scope_exit releaseResultObject([&] { pResultObject && pResultObject->Release(); });
@@ -3,56 +3,47 @@
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
#include "common/io/io.h"
/* Example dbus reply, striped to only the relevant parts:
array [ //root
/* Example dbus reply:
array [
dict entry(
object path "/org/bluez/hci0"
array [
dict entry(
string "org.bluez.Adapter1"
array [
dict entry(
string "Address"
variant string "XX:XX:XX:XX:XX:XX"
)
dict entry(
string "Name"
variant string "xxxxxxxx"
)
dict entry(
string "Powered"
variant boolean true
)
dict entry(
string "PowerState"
variant string "on"
)
dict entry(
string "Manufacturer"
variant uint16 2
)
dict entry(
string "Version"
variant byte 12
)
]
)
]
string "Address"
variant string "XX:XX:XX:XX:XX:XX"
)
dict entry(
string "Name"
variant string "xxxxxxxx"
)
dict entry(
string "Powered"
variant boolean true
)
dict entry(
string "PowerState"
variant string "on"
)
dict entry(
string "Manufacturer"
variant uint16 2
)
dict entry(
string "Version"
variant byte 12
)
]
*/
static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothRadioResult* device)
static const char* detectBluetoothProperty(FFBluetoothRadioResult* device, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
return "Expected dict entry";
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
return;
return "Expected dict entry key to be a string";
const char* deviceProperty;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty);
@@ -77,121 +68,73 @@ static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBlue
ffDBusGetBool(dbus, &dictIter, &device->discoverable);
else if(ffStrEquals(deviceProperty, "Pairable"))
ffDBusGetBool(dbus, &dictIter, &device->connectable);
return NULL;
}
static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothRadioResult* device)
static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const char* hciName, FFDBusData* dbus)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
char objPath[300];
snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName);
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1");
if(!properties)
return "Failed to call org.freedesktop.DBus.Properties.GetAll";
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
return;
const char* propertyType;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &propertyType);
if(!ffStrContains(propertyType, ".Adapter"))
return; //We don't care about other properties
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
return;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
do
DBusMessageIter rootIter;
if(!dbus->lib->ffdbus_message_iter_init(properties, &rootIter))
{
detectBluetoothValue(dbus, &arrayIter, device);
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
}
static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH)
return;
const char* objectPath;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath);
//We want adapter objects
if(!ffStrStartsWith(objectPath, "/org/bluez/hci") || ffStrContains(objectPath, "/dev_"))
return;
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
return;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
FFBluetoothRadioResult* device = ffListAdd(devices);
ffStrbufInit(&device->name);
ffStrbufInit(&device->address);
ffStrbufInitStatic(&device->vendor, "Unknown");
device->lmpVersion = INT_MIN;
device->lmpSubversion = INT_MIN;
device->enabled = false;
do
{
detectBluetoothProperty(dbus, &arrayIter, device);
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
if(device->name.length == 0)
{
ffStrbufDestroy(&device->name);
ffStrbufDestroy(&device->address);
--devices->length;
dbus->lib->ffdbus_message_unref(properties);
return "Failed to get root iterator of org.freedesktop.DBus.Properties.GetAll";
}
}
static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
return;
if(dbus->lib->ffdbus_message_iter_get_arg_type(&rootIter) != DBUS_TYPE_ARRAY)
{
dbus->lib->ffdbus_message_unref(properties);
return "Expected array";
}
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &arrayIter);
dbus->lib->ffdbus_message_iter_recurse(&rootIter, &arrayIter);
do
{
detectBluetoothObject(devices, dbus, &arrayIter);
detectBluetoothProperty(device, dbus, &arrayIter);
} while (dbus->lib->ffdbus_message_iter_next(&arrayIter));
dbus->lib->ffdbus_message_unref(properties);
return NULL;
}
static const char* detectBluetooth(FFlist* devices)
{
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/bluetooth");
if(dirp == NULL)
return "Failed to open /sys/class/bluetooth";
FFDBusData dbus;
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
if(error)
return error;
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL);
if(!managedObjects)
return "Failed to call GetManagedObjects";
DBusMessageIter rootIter;
if(!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter))
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL)
{
dbus.lib->ffdbus_message_unref(managedObjects);
return "Failed to get root iterator of GetManagedObjects";
if (entry->d_name[0] == '.')
continue;
if (strchr(entry->d_name, ':') != NULL) // ignore connected devices
continue;
FFBluetoothRadioResult* device = ffListAdd(devices);
ffStrbufInit(&device->name);
ffStrbufInit(&device->address);
ffStrbufInitStatic(&device->vendor, "Unknown");
device->lmpVersion = INT_MIN;
device->lmpSubversion = INT_MIN;
device->enabled = false;
detectBluetoothRoot(device, entry->d_name, &dbus);
}
detectBluetoothRoot(devices, &dbus, &rootIter);
dbus.lib->ffdbus_message_unref(managedObjects);
return NULL;
}
@@ -202,7 +145,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
#ifdef FF_HAVE_DBUS
return detectBluetooth(devices);
#else
FF_UNUSED(devices)
FF_UNUSED(devices)
return "Fastfetch was compiled without DBus support";
#endif
}
+2
View File
@@ -10,6 +10,8 @@ const char* ffDetectBoard(FFBoardResult* board)
ffCleanUpSmbiosValue(&board->version);
if (ffSysctlGetString("machdep.dmi.board-vendor", &board->vendor) == NULL)
ffCleanUpSmbiosValue(&board->vendor);
if (ffSysctlGetString("machdep.dmi.board-serial", &board->serial) == NULL)
ffCleanUpSmbiosValue(&board->serial);
return NULL;
}
+1 -1
View File
@@ -34,7 +34,7 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
brightness->current = status.brightness;
struct backlight_info info;
if(ioctl(blfd, BACKLIGHTGETINFO, &info) < 0)
if(ioctl(blfd, BACKLIGHTGETINFO, &info) == 0)
ffStrbufAppendS(&brightness->name, info.name);
else
ffStrbufAppendS(&brightness->name, path + strlen("/dev/backlight/"));
@@ -0,0 +1,25 @@
#include "brightness.h"
#include "common/sysctl.h"
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
{
// https://man.netbsd.org/NetBSD-10.1/acpiout.4#DESCRIPTION
char key[] = "hw.acpi.acpiout0.brightness";
char* pn = key + strlen("hw.acpi.acpiout");
for (uint32_t i = 0; i <= 9; ++i)
{
*pn = (char) ('0' + i);
int value = ffSysctlGetInt(key, -1);
if (value == -1) continue;
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
ffStrbufInitF(&brightness->name, "acpiout%d", i);
brightness->max = 100;
brightness->min = 0;
brightness->current = value;
}
return NULL;
}
@@ -0,0 +1,30 @@
#include "brightness.h"
#include "common/io/io.h"
#include <dev/wscons/wsconsio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result)
{
FF_AUTO_CLOSE_FD int devfd = open("/dev/ttyC0", O_RDONLY);
if (devfd < 0) return "open(dev/ttyC0, O_RDONLY) failed";
struct wsdisplay_param param = {
.param = WSDISPLAYIO_PARAM_BRIGHTNESS,
};
if (ioctl(devfd, WSDISPLAYIO_GETPARAM, &param) < 0)
return "ioctl(WSDISPLAYIO_GETPARAM) failed";
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
ffStrbufInitStatic(&brightness->name, "wsdisplay");
brightness->max = param.max;
brightness->min = param.min;
brightness->current = param.curval;
return NULL;
}
+1 -1
View File
@@ -24,7 +24,7 @@ static const char* enumerateDevices(FFBtrfsResult* item, int dfd, FFstrbuf* buff
ffStrbufAppendC(&item->devices, ',');
ffStrbufAppendS(&item->devices, entry->d_name);
char path[ARRAY_SIZE(entry->d_name) + ARRAY_SIZE("/size") + 1];
char path[sizeof(entry->d_name) + sizeof("/size") + 1];
snprintf(path, ARRAY_SIZE(path), "%s/size", entry->d_name);
if (ffReadFileBufferRelative(subfd, path, buffer))
+2
View File
@@ -10,6 +10,8 @@ const char* ffDetectChassis(FFChassisResult* chassis)
ffCleanUpSmbiosValue(&chassis->version);
if (ffSysctlGetString("machdep.dmi.chassis-vendor", &chassis->vendor) == NULL)
ffCleanUpSmbiosValue(&chassis->vendor);
if (ffSysctlGetString("machdep.dmi.chassis-serial", &chassis->serial) == NULL)
ffCleanUpSmbiosValue(&chassis->serial);
return NULL;
}
+17 -1
View File
@@ -1,6 +1,12 @@
#include "cpu.h"
#include "common/sysctl.h"
#include <sys/param.h>
#if __has_include(<sys/cpuset.h>)
#include <sys/cpuset.h>
#define FF_HAVE_CPUSET 1
#endif
static const char* detectCpuTemp(double* current)
{
int temp = ffSysctlGetInt("dev.cpu.0.temperature", -999999);
@@ -60,9 +66,19 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
}
}
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
// Bind current process to the first two cores, which is *usually* a performance core
cpuset_t currentCPU;
CPU_ZERO(&currentCPU);
CPU_SET(1, &currentCPU);
CPU_SET(2, &currentCPU);
cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &currentCPU);
#endif
ffCPUDetectSpeedByCpuid(cpu);
cpu->frequencyBase = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
if (clockrate > cpu->frequencyBase) cpu->frequencyBase = clockrate;
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)
+76 -25
View File
@@ -44,12 +44,20 @@ static double parseHwmonDir(FFstrbuf* dir, FFstrbuf* buffer)
if(
ffStrbufContainS(buffer, "cpu") ||
ffStrbufEqualS(buffer, "k10temp") || // AMD
ffStrbufEqualS(buffer, "fam15h_power") || // AMD
ffStrbufEqualS(buffer, "coretemp") // Intel
) return value / 1000.;
return 0.0/0.0;
}
static double detectTZTemp(FFstrbuf* buffer)
{
if (ffReadFileBuffer("/sys/class/thermal/thermal_zone0/temp", buffer))
return ffStrbufToDouble(buffer) / 1000.;
return 0.0/0.0;
}
static double detectCPUTemp(void)
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
@@ -79,7 +87,7 @@ static double detectCPUTemp(void)
ffStrbufSubstrBefore(&baseDir, baseDirLength);
}
return 0.0/0.0;
return detectTZTemp(&buffer);
}
#ifdef __ANDROID__
@@ -89,7 +97,11 @@ static void detectQualcomm(FFCPUResult* cpu)
{
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips
if (ffStrbufEqualS(&cpu->name, "SM8750"))
if (ffStrbufEqualS(&cpu->name, "SM8750-AC"))
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite for Galaxy [SM8750-AC]");
else if (ffStrbufEqualS(&cpu->name, "SM8750-3"))
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750-3]");
else if (ffStrbufEqualS(&cpu->name, "SM8750"))
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750]");
else if (ffStrbufEqualS(&cpu->name, "SM8635"))
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8s Gen 3 [SM8635]");
@@ -136,6 +148,36 @@ static void detectQualcomm(FFCPUResult* cpu)
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 1 [SM4375]");
}
static void detectMediaTek(FFCPUResult* cpu)
{
// https://en.wikipedia.org/wiki/List_of_MediaTek_systems_on_chips
if (ffStrbufEqualS(&cpu->name, "MT6991"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991]");
else if (ffStrbufEqualS(&cpu->name, "MT6991Z"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991Z]");
else if (ffStrbufEqualS(&cpu->name, "MT6989Z"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT6989Z]");
else if (ffStrbufEqualS(&cpu->name, "MT8796Z"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT8796Z]");
else if (ffStrbufEqualS(&cpu->name, "MT6989"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT6989]");
else if (ffStrbufEqualS(&cpu->name, "MT8796"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT8796]");
else if (ffStrbufEqualS(&cpu->name, "MT6985W"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200+ [MT6985W]");
else if (ffStrbufEqualS(&cpu->name, "MT6985"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200 [MT6985]");
else if (ffStrbufEqualS(&cpu->name, "MT6983W"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT6983W]");
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/T"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT8798Z/T]");
else if (ffStrbufEqualS(&cpu->name, "MT6983Z"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT6983Z]");
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/C"))
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT8798Z/C]");
}
static void detectAndroid(FFCPUResult* cpu)
{
if (cpu->name.length == 0)
@@ -153,6 +195,8 @@ static void detectAndroid(FFCPUResult* cpu)
if (ffStrbufEqualS(&cpu->vendor, "QTI") && ffStrbufStartsWithS(&cpu->name, "SM"))
detectQualcomm(cpu);
else if (ffStrbufEqualS(&cpu->vendor, "MTK") && ffStrbufStartsWithS(&cpu->name, "MT"))
detectMediaTek(cpu);
}
#endif
@@ -188,6 +232,7 @@ static void detectArmName(FFstrbuf* cpuinfo, FFCPUResult* cpu, uint32_t implId)
{
// https://github.com/Dr-Noob/cpufetch/issues/213#issuecomment-1927782105
ffStrbufSetStatic(&cpu->name, "Virtualized Apple Silicon");
ffStrbufGetlineRestore(&line, &len, cpuinfo);
return;
}
name = applePartId2name(partId);
@@ -239,11 +284,14 @@ static const char* parseCpuInfo(
{
//Stop after reasonable information is acquired
if((*line == '\0' || *line == '\n')
#if __arm__ || __loongarch__
#if __arm__ || __aarch64__ || __loongarch__
&& cpu->name.length > 0 // #1202 #1204
#endif
)
{
ffStrbufGetlineRestore(&line, &len, cpuinfo);
break;
}
(void)(
// arm64 doesn't have "model name"; arm32 does have "model name" but its value is not useful.
@@ -388,7 +436,7 @@ FF_MAYBE_UNUSED static void parseIsa(FFstrbuf* cpuIsa)
}
}
FF_MAYBE_UNUSED static void detectArmSoc(FFCPUResult* cpu)
FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu)
{
if (cpu->name.length > 0)
return;
@@ -512,6 +560,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical);
#if __x86_64__ || __i386__
cpu->packages = getPackageCount(&cpuinfo);
if (cpu->packages > 1)
cpu->coresPhysical *= cpu->packages; // https://github.com/hykilpikonna/hyfetch/issues/374#issuecomment-2571578914
#endif
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
@@ -519,35 +569,36 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
if (!detectFrequency(cpu, options) || cpu->frequencyBase == 0)
cpu->frequencyBase = (uint32_t) ffStrbufToUInt(&cpuMHz, 0);
#if !(__x86_64__ || __i386__ || __arm__ || __aarch64__)
if(cpuUarch.length > 0)
{
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuUarch);
}
if(cpuIsa.length > 0)
{
parseIsa(&cpuIsa);
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuIsa);
}
#if __ANDROID__
detectAndroid(cpu);
#elif !(__x86_64__ || __i386__)
detectSocName(cpu);
#endif
#if __arm__ || __aarch64__
uint32_t cpuImplementer = (uint32_t) strtoul(cpuImplementerStr.chars, NULL, 16);
ffStrbufSetStatic(&cpu->vendor, hwImplId2Vendor(cpuImplementer));
#if __ANDROID__
detectAndroid(cpu);
#else
detectArmSoc(cpu);
#endif
if (cpu->name.length == 0)
detectArmName(&cpuinfo, cpu, cpuImplementer);
#elif !(__x86_64__ || __i386__)
if (cpu->name.length == 0)
{
if(cpuUarch.length > 0)
{
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuUarch);
}
if(cpuIsa.length > 0)
{
parseIsa(&cpuIsa);
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuIsa);
}
}
#endif
return NULL;
+37 -26
View File
@@ -1,26 +1,42 @@
#include "cpu.h"
#include "common/sysctl.h"
#include <sys/sysctl.h>
#include "common/io/io.h"
#include <sys/envsys.h>
#include <prop/proplib.h>
#include <paths.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
static const char* detectCpuTemp(double* current)
{
int temp = ffSysctlGetInt("dev.cpu.0.temperature", -999999);
if (temp == -999999)
return "ffSysctlGetInt(\"dev.cpu.0.temperature\") failed";
FF_AUTO_CLOSE_FD int fd = open(_PATH_SYSMON, O_RDONLY);
if (fd < 0) return "open(_PATH_SYSMON, O_RDONLY) failed";
// In tenth of degrees Kelvin
*current = (double) temp / 10 - 273.15;
return NULL;
}
prop_dictionary_t root = NULL;
if (prop_dictionary_recv_ioctl(fd, ENVSYS_GETDICTIONARY, &root) < 0)
return "prop_dictionary_recv_ioctl(ENVSYS_GETDICTIONARY) failed";
static const char* detectThermalTemp(double* current)
{
int temp = ffSysctlGetInt("hw.acpi.thermal.tz0.temperature", -999999);
if (temp == -999999)
return "ffSysctlGetInt(\"hw.acpi.thermal.tz0.temperature\") failed";
prop_array_t array = prop_dictionary_get(root, "coretemp0");
if (!array) array = prop_dictionary_get(root, "amdzentemp0");
if (!array) array = prop_dictionary_get(root, "viac7temp0");
if (!array) array = prop_dictionary_get(root, "acpitz0"); // Thermal Zones
if (!array) return "No temp data found in root dictionary";
if (prop_array_count(array) != 2)
return "Unexpected `xtemp0` data";
prop_dictionary_t dict = prop_array_get(array, 0);
if (prop_object_type(dict) != PROP_TYPE_DICTIONARY)
return "Unexpected `xtemp0[0]`";
int temp = 0; // in µK
if (!prop_dictionary_get_int(dict, "cur-value", &temp))
return "Failed to get temperature";
*current = temp / 1e6 - 273.15;
// In tenth of degrees Kelvin
*current = (double) temp / 10 - 273.15;
return NULL;
}
@@ -32,26 +48,21 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
return "sysctlbyname(machdep.cpu_brand) failed";
}
if (ffSysctlGetString("machdep.dmi.processor-vendor", &cpu->vendor) == NULL)
ffStrbufTrimRightSpace(&cpu->vendor);
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
cpu->coresLogical = cpu->coresPhysical;
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.ncpuonline", cpu->coresLogical);
ffCPUDetectSpeedByCpuid(cpu);
{
struct clockinfo info;
size_t length = sizeof(info);
if (sysctl((int[]) {CTL_KERN, KERN_CLOCKRATE}, 2, &info, &length, NULL, 0) == 0)
cpu->frequencyBase = (uint32_t) info.hz / 1000;
}
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)
{
if (detectCpuTemp(&cpu->temperature) != NULL)
detectThermalTemp(&cpu->temperature);
}
if (options->temp) detectCpuTemp(&cpu->temperature);
return NULL;
}
+3 -1
View File
@@ -15,7 +15,9 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
ffCPUDetectSpeedByCpuid(cpu);
cpu->frequencyBase = (uint32_t) ffSysctlGetInt(CTL_HW, HW_CPUSPEED, 0);
uint32_t cpuspeed = (uint32_t) ffSysctlGetInt(CTL_HW, HW_CPUSPEED, 0);
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)
{
+11 -4
View File
@@ -8,7 +8,6 @@
#ifdef __NetBSD__
#include <sys/types.h>
#include <sys/statvfs.h>
#define getfsstat(...) getvfsstat(__VA_ARGS__)
#define statfs statvfs
#define f_flags f_flag
#define f_bsize f_frsize
@@ -125,14 +124,22 @@ static void detectFsInfo(struct statfs* fs, FFDisk* disk)
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
#ifndef __NetBSD__
int size = getfsstat(NULL, 0, MNT_WAIT);
if(size <= 0)
return "getfsstat(NULL, 0, MNT_WAIT) failed";
if(size <= 0) return "getfsstat(NULL, 0, MNT_WAIT) failed";
#else
int size = getvfsstat(NULL, 0, ST_WAIT);
if(size <= 0) return "getvfsstat(NULL, 0, ST_WAIT) failed";
#endif
FF_AUTO_FREE struct statfs* buf = malloc(sizeof(*buf) * (unsigned) size);
#ifndef __NetBSD__
if(getfsstat(buf, (int) (sizeof(*buf) * (unsigned) size), MNT_NOWAIT) <= 0)
return "getfsstat(buf, size, MNT_NOWAIT) failed";
#else
if(getvfsstat(buf, sizeof(*buf) * (unsigned) size, ST_NOWAIT) <= 0)
return "getvfsstat(buf, size, ST_NOWAIT) failed";
#endif
for(struct statfs* fs = buf; fs < buf + size; ++fs)
{
+1 -2
View File
@@ -99,8 +99,7 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
device->writeCount = current->num_writes;
}
if (stats.dinfo->mem_ptr)
free(stats.dinfo->mem_ptr);
free(stats.dinfo->mem_ptr);
free(stats.dinfo);
return NULL;
-2
View File
@@ -13,8 +13,6 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
return "sysctl({HW_DISKSTATS}, NULL) failed";
uint32_t nDrive = (uint32_t) (len / sizeof(struct diskstats));
printf("C: %d\n", nDrive);
struct diskstats* stats = malloc(len);
if (sysctl(mib, ARRAY_SIZE(mib), stats, &len, NULL, 0) < 0)
@@ -78,11 +78,11 @@ static struct zxdg_output_v1_listener zxdgOutputListener = {
.description = (void*) ffWaylandOutputDescriptionListener,
};
void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
if(output == NULL)
return;
return "Failed to create wl_output";
WaylandDisplay display = {
.parent = wldata,
@@ -94,8 +94,16 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist
.edidName = ffStrbufCreate(),
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
if (wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to wl_output";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip wl_output";
}
if (wldata->zxdgOutputManager)
{
@@ -112,7 +120,7 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist
wldata->ffwl_proxy_destroy(output);
if(display.width <= 0 || display.height <= 0)
return;
return "Failed to get display information from wl_output";
uint32_t rotation = ffWaylandHandleRotation(&display);
@@ -156,15 +164,19 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
return NULL;
}
void ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* manager = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zxdg_output_manager_v1_interface, version, name, zxdg_output_manager_v1_interface.name, version, NULL);
if(manager == NULL)
return;
return "Failed to create zxdg_output_manager_v1";
wldata->zxdgOutputManager = manager;
return NULL;
}
#endif
@@ -1,4 +1,4 @@
/* Generated by wayland-scanner 1.22.0 */
/* Generated by wayland-scanner 1.23.1 */
#ifndef KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H
#define KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H
@@ -53,6 +53,11 @@ struct kde_output_device_v2;
* This object is published as global during start up for every available
* display devices, or when one later becomes available, for example by
* being hotplugged via a physical connector.
*
* Warning! The protocol described in this file is a desktop environment
* implementation detail. Regular clients must not use this protocol.
* Backward incompatible changes may be added without bumping the major
* version of the extension.
* @section page_iface_kde_output_device_v2_api API
* See @ref iface_kde_output_device_v2.
*/
@@ -75,6 +80,11 @@ struct kde_output_device_v2;
* This object is published as global during start up for every available
* display devices, or when one later becomes available, for example by
* being hotplugged via a physical connector.
*
* Warning! The protocol described in this file is a desktop environment
* implementation detail. Regular clients must not use this protocol.
* Backward incompatible changes may be added without bumping the major
* version of the extension.
*/
extern const struct wl_interface kde_output_device_v2_interface;
#endif
@@ -199,6 +209,11 @@ enum kde_output_device_v2_capability {
* @since 5
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_ICC_PROFILE = 0x40,
/**
* if this outputdevice supports the brightness setting
* @since 9
*/
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80,
};
/**
* @ingroup iface_kde_output_device_v2
@@ -216,6 +231,10 @@ enum kde_output_device_v2_capability {
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_ICC_PROFILE_SINCE_VERSION 5
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
@@ -274,6 +293,29 @@ enum kde_output_device_v2_color_profile_source {
};
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_ENUM */
#ifndef KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM
#define KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM
/**
* @ingroup iface_kde_output_device_v2
* tradeoff between power and accuracy
*
* The compositor can do a lot of things that trade between
* performance, power and color accuracy. This setting describes
* a high level preference from the user about in which direction
* that tradeoff should be made.
*/
enum kde_output_device_v2_color_power_tradeoff {
/**
* prefer efficiency and performance
*/
KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_EFFICIENCY = 0,
/**
* prefer accuracy
*/
KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ACCURACY = 1,
};
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */
/**
* @ingroup iface_kde_output_device_v2
* @struct kde_output_device_v2_listener
@@ -593,6 +635,29 @@ struct kde_output_device_v2_listener {
void (*brightness)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t brightness);
/**
* the preferred color/power tradeoff
*
*
* @since 10
*/
void (*color_power_tradeoff)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t preference);
/**
* dimming multiplier
*
* This is the dimming multiplier of the output. This is similar
* to the brightness setting, except it's meant to be a temporary
* setting only, not persistent and may be implemented differently
* depending on the display. 0 is the minimum dimming factor (not
* completely dark) and 10000 means the output is not dimmed.
* @param multiplier multiplier in 0-10000
* @since 11
*/
void (*dimming)(void *data,
struct kde_output_device_v2 *kde_output_device_v2,
uint32_t multiplier);
};
/**
@@ -706,34 +771,42 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_SINCE_VERSION 8
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_SINCE_VERSION 10
/**
* @ingroup iface_kde_output_device_v2
*/
#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11
// /** @ingroup iface_kde_output_device_v2 */
// static inline void
// kde_output_device_v2_set_user_data(struct kde_output_device_v2 *kde_output_device_v2, void *user_data)
// {
// wl_proxy_set_user_data((struct wl_proxy *) kde_output_device_v2, user_data);
// }
/** @ingroup iface_kde_output_device_v2 */
static inline void
kde_output_device_v2_set_user_data(struct kde_output_device_v2 *kde_output_device_v2, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) kde_output_device_v2, user_data);
}
// /** @ingroup iface_kde_output_device_v2 */
// static inline void *
// kde_output_device_v2_get_user_data(struct kde_output_device_v2 *kde_output_device_v2)
// {
// return wl_proxy_get_user_data((struct wl_proxy *) kde_output_device_v2);
// }
/** @ingroup iface_kde_output_device_v2 */
static inline void *
kde_output_device_v2_get_user_data(struct kde_output_device_v2 *kde_output_device_v2)
{
return wl_proxy_get_user_data((struct wl_proxy *) kde_output_device_v2);
}
// static inline uint32_t
// kde_output_device_v2_get_version(struct kde_output_device_v2 *kde_output_device_v2)
// {
// return wl_proxy_get_version((struct wl_proxy *) kde_output_device_v2);
// }
static inline uint32_t
kde_output_device_v2_get_version(struct kde_output_device_v2 *kde_output_device_v2)
{
return wl_proxy_get_version((struct wl_proxy *) kde_output_device_v2);
}
// /** @ingroup iface_kde_output_device_v2 */
// static inline void
// kde_output_device_v2_destroy(struct kde_output_device_v2 *kde_output_device_v2)
// {
// wl_proxy_destroy((struct wl_proxy *) kde_output_device_v2);
// }
/** @ingroup iface_kde_output_device_v2 */
static inline void
kde_output_device_v2_destroy(struct kde_output_device_v2 *kde_output_device_v2)
{
wl_proxy_destroy((struct wl_proxy *) kde_output_device_v2);
}
/**
* @ingroup iface_kde_output_device_mode_v2
@@ -811,32 +884,32 @@ kde_output_device_mode_v2_add_listener(struct kde_output_device_mode_v2 *kde_out
#define KDE_OUTPUT_DEVICE_MODE_V2_REMOVED_SINCE_VERSION 1
// /** @ingroup iface_kde_output_device_mode_v2 */
// static inline void
// kde_output_device_mode_v2_set_user_data(struct kde_output_device_mode_v2 *kde_output_device_mode_v2, void *user_data)
// {
// wl_proxy_set_user_data((struct wl_proxy *) kde_output_device_mode_v2, user_data);
// }
/** @ingroup iface_kde_output_device_mode_v2 */
static inline void
kde_output_device_mode_v2_set_user_data(struct kde_output_device_mode_v2 *kde_output_device_mode_v2, void *user_data)
{
wl_proxy_set_user_data((struct wl_proxy *) kde_output_device_mode_v2, user_data);
}
// /** @ingroup iface_kde_output_device_mode_v2 */
// static inline void *
// kde_output_device_mode_v2_get_user_data(struct kde_output_device_mode_v2 *kde_output_device_mode_v2)
// {
// return wl_proxy_get_user_data((struct wl_proxy *) kde_output_device_mode_v2);
// }
/** @ingroup iface_kde_output_device_mode_v2 */
static inline void *
kde_output_device_mode_v2_get_user_data(struct kde_output_device_mode_v2 *kde_output_device_mode_v2)
{
return wl_proxy_get_user_data((struct wl_proxy *) kde_output_device_mode_v2);
}
// static inline uint32_t
// kde_output_device_mode_v2_get_version(struct kde_output_device_mode_v2 *kde_output_device_mode_v2)
// {
// return wl_proxy_get_version((struct wl_proxy *) kde_output_device_mode_v2);
// }
static inline uint32_t
kde_output_device_mode_v2_get_version(struct kde_output_device_mode_v2 *kde_output_device_mode_v2)
{
return wl_proxy_get_version((struct wl_proxy *) kde_output_device_mode_v2);
}
// /** @ingroup iface_kde_output_device_mode_v2 */
// static inline void
// kde_output_device_mode_v2_destroy(struct kde_output_device_mode_v2 *kde_output_device_mode_v2)
// {
// wl_proxy_destroy((struct wl_proxy *) kde_output_device_mode_v2);
// }
/** @ingroup iface_kde_output_device_mode_v2 */
static inline void
kde_output_device_mode_v2_destroy(struct kde_output_device_mode_v2 *kde_output_device_mode_v2)
{
wl_proxy_destroy((struct wl_proxy *) kde_output_device_mode_v2);
}
#ifdef __cplusplus
}
@@ -1,6 +1,6 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.22.0 */
/* Generated by wayland-scanner 1.23.1 */
/*
* SPDX-FileCopyrightText: 2008-2011 Kristian Høgsberg
@@ -12,6 +12,7 @@
* SPDX-License-Identifier: MIT-CMU
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <wayland-util.h>
@@ -57,12 +58,14 @@ static const struct wl_message kde_output_device_v2_events[] = {
{ "sdr_gamut_wideness", "6u", kde_output_device_v2_types + 0 },
{ "color_profile_source", "7u", kde_output_device_v2_types + 0 },
{ "brightness", "8u", kde_output_device_v2_types + 0 },
{ "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 },
{ "dimming", "11u", kde_output_device_v2_types + 0 },
};
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
"kde_output_device_v2", 8,
"kde_output_device_v2", 11,
0, NULL,
25, kde_output_device_v2_events,
27, kde_output_device_v2_events,
};
static const struct wl_message kde_output_device_mode_v2_events[] = {
@@ -163,13 +163,15 @@ static struct kde_output_device_v2_listener outputListener = {
.sdr_gamut_wideness = (void*) stubListener,
.color_profile_source = (void*) stubListener,
.brightness = (void*) stubListener,
.color_power_tradeoff = (void*) stubListener,
.dimming = (void*) stubListener,
};
void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, version, name, kde_output_device_v2_interface.name, version, NULL);
if(output == NULL)
return;
return "Failed to create kde_output_device_v2";
FF_LIST_AUTO_DESTROY modes = ffListCreate(sizeof(WaylandKdeMode));
WaylandDisplay display = {
@@ -183,12 +185,21 @@ void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry,
.internal = &modes,
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
if (wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to kde_output_device_v2";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip kde_output_device_v2";
}
wldata->ffwl_proxy_destroy(output);
if(display.width <= 0 || display.height <= 0 || !display.internal)
return;
return "Failed to get display information from kde_output_device_v2";
uint32_t rotation = ffWaylandHandleRotation(&display);
@@ -231,6 +242,8 @@ void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry,
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
return NULL;
}
@@ -241,20 +254,30 @@ static void waylandKdeOutputOrderListener(void *data, FF_MAYBE_UNUSED struct kde
*id = ffWaylandGenerateIdFromName(output_name);
}
void ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_order_v1_interface, version, name, kde_output_order_v1_interface.name, version, NULL);
if(output == NULL)
return;
return "Failed to create kde_output_order_v1";
struct kde_output_order_v1_listener orderListener = {
.output = waylandKdeOutputOrderListener,
.done = (void*) stubListener,
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &orderListener, &wldata->primaryDisplayId);
wldata->ffwl_display_roundtrip(wldata->display);
if (wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &orderListener, &wldata->primaryDisplayId) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to kde_output_order_v1";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip kde_output_order_v1";
}
wldata->ffwl_proxy_destroy(output);
return NULL;
}
#endif
@@ -80,17 +80,20 @@ static void waylandGlobalAddListener(void* data, struct wl_registry* registry, u
if((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wldata->ffwl_output_interface->name))
{
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_GLOBAL;
ffWaylandHandleGlobalOutput(wldata, registry, name, version);
if (ffWaylandHandleGlobalOutput(wldata, registry, name, version) != NULL)
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
else if((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_ZWLR) && ffStrEquals(interface, zwlr_output_manager_v1_interface.name))
{
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_ZWLR;
ffWaylandHandleZwlrOutput(wldata, registry, name, version);
if (ffWaylandHandleZwlrOutput(wldata, registry, name, version) != NULL)
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
else if((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE) && ffStrEquals(interface, kde_output_device_v2_interface.name))
{
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE;
ffWaylandHandleKdeOutput(wldata, registry, name, version);
if (ffWaylandHandleKdeOutput(wldata, registry, name, version) != NULL)
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
else if(ffStrEquals(interface, kde_output_order_v1_interface.name))
{
@@ -79,10 +79,10 @@ void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output
// Modifies content of display. Don't call this function when calling ffdsAppendDisplay
uint32_t ffWaylandHandleRotation(WaylandDisplay* display);
void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
#endif
@@ -188,11 +188,11 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output
wldata->ffwl_proxy_destroy((void*) head);
}
void ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, version, name, zwlr_output_manager_v1_interface.name, version, NULL);
if(output == NULL)
return;
return "Failed to bind zwlr_output_manager_v1";
const struct zwlr_output_manager_v1_listener outputListener = {
.head = waylandHandleZwlrHead,
@@ -200,9 +200,19 @@ void ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry
.finished = (void*) stubListener,
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, wldata);
wldata->ffwl_display_roundtrip(wldata->display);
if (wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, wldata) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to zwlr_output_manager_v1";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0)
{
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip display";
}
wldata->ffwl_proxy_destroy(output);
return NULL;
}
#endif
+3
View File
@@ -62,6 +62,9 @@ static const char* parseEnv(void)
if(getenv("HYPRLAND_CMD") != NULL)
return "Hyprland";
if(getenv("SWAYSOCK") != NULL)
return "Sway";
#ifdef __linux__
if(
getenv("WAYLAND_DISPLAY") != NULL &&
+3 -3
View File
@@ -16,7 +16,7 @@ const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat";
const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle";
const char* ffGetGPUVendorString(unsigned vendorId)
const char* ffGPUGetVendorString(unsigned vendorId)
{
// https://devicehunt.com/all-pci-vendors
switch (vendorId)
@@ -51,9 +51,9 @@ const char* detectByOpenGL(FFlist* gpus)
{
FFGPUResult* gpu = (FFGPUResult*) ffListAdd(gpus);
gpu->type = FF_GPU_TYPE_UNKNOWN;
ffStrbufInit(&gpu->vendor);
ffStrbufInitMove(&gpu->vendor, &result.vendor);
ffStrbufInitMove(&gpu->name, &result.renderer);
ffStrbufInitMove(&gpu->driver, &result.vendor);
ffStrbufInit(&gpu->driver);
ffStrbufInitF(&gpu->platformApi, "OpenGL %s", result.version.chars);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
+1 -1
View File
@@ -46,7 +46,7 @@ typedef struct FFGPUResult
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result);
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus);
const char* ffGetGPUVendorString(unsigned vendorId);
const char* ffGPUGetVendorString(unsigned vendorId);
#if defined(__linux__) || defined(__FreeBSD__) || defined(__sun) || defined(__NetBSD__) || defined(__OpenBSD__)
void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu);
+1 -1
View File
@@ -161,7 +161,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
int vendorId;
if(ffCfDictGetInt(properties, CFSTR("vendor-id"), &vendorId) == NULL)
{
const char* vendorStr = ffGetGPUVendorString((unsigned) vendorId);
const char* vendorStr = ffGPUGetVendorString((unsigned) vendorId);
ffStrbufAppendS(&gpu->vendor, vendorStr);
if (vendorStr == FF_GPU_VENDOR_NAME_APPLE || vendorStr == FF_GPU_VENDOR_NAME_INTEL)
gpu->type = FF_GPU_TYPE_INTEGRATED;
+1 -1
View File
@@ -38,7 +38,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
struct pci_conf* pc = &confs[i];
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString(pc->pc_vendor));
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pc->pc_vendor));
ffStrbufInit(&gpu->name);
ffStrbufInitS(&gpu->driver, pc->pd_name);
ffStrbufInit(&gpu->platformApi);
+2 -2
View File
@@ -15,7 +15,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_slot_match_iterator_create)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_device_next)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pciaccess, pci_system_cleanup)
{
// Requires root access
// Same behavior can be observed with `cp $(which scanpci) /tmp/ && /tmp/scanpci`
@@ -31,7 +31,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
continue;
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString(dev->vendor_id));
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->vendor_id));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
+1 -1
View File
@@ -435,7 +435,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
return "Invalid PCI device path";
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString((uint16_t) vendorId));
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString((uint16_t) vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
+1 -1
View File
@@ -51,7 +51,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
uint32_t revision = (uint32_t) strtoul(pclass, NULL, 16);
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
+2 -2
View File
@@ -72,7 +72,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
{
uint32_t vendorId = 0;
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
ffStrbufSetStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
@@ -147,7 +147,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_HARDWAREID, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
{
swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
ffStrbufSetStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
}
detectFn(
+1 -1
View File
@@ -104,7 +104,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
DXCoreHardwareID hardwareId;
if (SUCCEEDED(adapter->GetProperty(DXCoreAdapterProperty::HardwareID, sizeof(hardwareId), &hardwareId)))
{
const char* vendorStr = ffGetGPUVendorString((unsigned) hardwareId.vendorID);
const char* vendorStr = ffGPUGetVendorString((unsigned) hardwareId.vendorID);
ffStrbufSetStatic(&gpu->vendor, vendorStr);
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && (options->driverSpecific || options->temp))
+1 -2
View File
@@ -74,8 +74,7 @@ static bool detectPlasmaFromFile(const char* filename, FFQtResult* result)
}
}
if(line != NULL)
free(line);
free(line);
fclose(kdeglobals);
+4 -4
View File
@@ -109,11 +109,11 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
const char* version = hwModel->chars + strlen("Mac");
if(ffStrEquals(version, "16,3")) return "iMac (24-inch, 2024, Four Thunderbolt / USB 4 ports)";
if(ffStrEquals(version, "16,2")) return "iMac (24-inch, 2024, Two Thunderbolt / USB 4 ports)";
if(ffStrEquals(version, "16,1") ||
ffStrEquals(version, "16,6") ||
ffStrEquals(version, "16,8")) return "MacBook Pro (14-inch, 2024, Three Thunderbolt 4 ports)";
if(ffStrEquals(version, "16,1")) return "MacBook Pro (14-inch, 2024, Three Thunderbolt 4 ports)";
if(ffStrEquals(version, "16,6") ||
ffStrEquals(version, "16,8")) return "MacBook Pro (14-inch, 2024, Three Thunderbolt 5 ports)";
if(ffStrEquals(version, "16,7") ||
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 4 ports)";
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 5 ports)";
if(ffStrEquals(version, "16,15") ||
ffStrEquals(version, "16,10")) return "Mac mini (2024)";
if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)";
+4
View File
@@ -12,6 +12,10 @@ const char* ffDetectHost(FFHostResult* host)
ffCleanUpSmbiosValue(&host->vendor);
if (ffSysctlGetString("machdep.dmi.system-version", &host->version) == NULL)
ffCleanUpSmbiosValue(&host->version);
if (ffSysctlGetString("machdep.dmi.system-serial", &host->serial) == NULL)
ffCleanUpSmbiosValue(&host->serial);
if (ffSysctlGetString("machdep.dmi.system-uuid", &host->uuid) == NULL)
ffCleanUpSmbiosValue(&host->uuid);
return NULL;
}
+43 -20
View File
@@ -8,7 +8,6 @@
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
#include "common/library.h"
#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
{ \
@@ -78,7 +77,7 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator,
static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result)
{
// Get all properties at once to reduce the number of IPCs
DBusMessage* reply = ffDBusGetAllProperties(data, busName, "/org/mpris/MediaPlayer2", "");
DBusMessage* reply = ffDBusGetAllProperties(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player");
if(reply == NULL)
return false;
@@ -93,8 +92,6 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
DBusMessageIter arrayIterator;
data->lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
FF_STRBUF_AUTO_DESTROY desktopIdentity = ffStrbufCreate();
while(true)
{
if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
@@ -112,35 +109,61 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
parseMprisMetadata(data, &dictIterator, result);
else if(ffStrEquals(key, "PlaybackStatus"))
ffDBusGetString(data, &dictIterator, &result->status);
else if(ffStrEquals(key, "Identity"))
ffDBusGetString(data, &dictIterator, &result->player);
else if(ffStrEquals(key, "DesktopEntry"))
ffDBusGetString(data, &dictIterator, &desktopIdentity);
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
}
if(result->song.length == 0)
{
ffStrbufClear(&result->artist);
ffStrbufClear(&result->album);
ffStrbufClear(&result->url);
return false;
}
if (result->player.length == 0)
{
if (desktopIdentity.length > 0)
if(result->url.length)
{
ffStrbufDestroy(&result->player);
ffStrbufInitMove(&result->player, &desktopIdentity);
const char* fileName = memrchr(result->url.chars, '/', result->url.length);
assert(fileName);
++fileName;
ffStrbufEnsureFixedLengthFree(&result->song, result->url.length - (uint32_t) (fileName - result->url.chars));
for(; *fileName && *fileName != '?'; ++fileName)
{
if (*fileName != '%')
{
ffStrbufAppendC(&result->song, *fileName);
}
else
{
char str[] = { fileName[1], fileName[2], 0 };
if (str[0] == 0 || str[1] == 0)
break;
ffStrbufAppendC(&result->song, (char) strtoul(str, NULL, 16));
fileName += 2;
}
}
}
else
{
ffStrbufAppend(&result->player, &result->playerId);
ffStrbufClear(&result->artist);
ffStrbufClear(&result->album);
ffStrbufClear(&result->url);
return false;
}
}
//Set short bus name
ffStrbufAppendS(&result->playerId, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
//We found a song, get the player name
if (ffStrbufStartsWithS(&result->playerId, "musikcube.instance"))
{
// dbus calls are EXTREMELY slow on musikcube, so we set the player name manually
ffStrbufSetStatic(&result->player, "musikcube");
}
else
{
ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player);
if(result->player.length == 0)
ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player);
if(result->player.length == 0)
ffStrbufAppend(&result->player, &result->playerId);
}
data->lib->ffdbus_message_unref(reply);
return true;
+1 -7
View File
@@ -4,13 +4,7 @@
const char* ffDetectMemory(FFMemoryResult* ram)
{
size_t length = sizeof(ram->bytesTotal);
if (sysctl((int[]){ CTL_HW,
#if __NetBSD__
HW_PHYSMEM64
#else
HW_PHYSMEM
#endif
}, 2, &ram->bytesTotal, &length, NULL, 0))
if (sysctl((int[]){ CTL_HW, HW_PHYSMEM }, 2, &ram->bytesTotal, &length, NULL, 0))
return "Failed to read hw.physmem";
// vm.stats.vm.* are int values
+18
View File
@@ -0,0 +1,18 @@
#include "memory.h"
#include "common/sysctl.h"
#include <sys/param.h>
#include <uvm/uvm_extern.h>
const char* ffDetectMemory(FFMemoryResult* ram)
{
struct uvmexp_sysctl buf;
size_t length = sizeof(buf);
if (sysctl((int[]){ CTL_VM, VM_UVMEXP2 }, 2, &buf, &length, NULL, 0) < 0)
return "sysctl(CTL_VM, VM_UVMEXP2) failed";
ram->bytesTotal = (uint64_t) buf.npages * instance.state.platform.sysinfo.pageSize;
ram->bytesUsed = ((uint64_t) buf.active + (uint64_t) buf.inactive + (uint64_t) buf.wired) * instance.state.platform.sysinfo.pageSize;
return NULL;
}
+2 -5
View File
@@ -2,10 +2,7 @@
#include "common/sysctl.h"
#include <sys/param.h>
#if __NetBSD__
#include <uvm/uvm_extern.h>
#endif
#include <uvm/uvm_extern.h>
const char* ffDetectMemory(FFMemoryResult* ram)
{
@@ -15,7 +12,7 @@ const char* ffDetectMemory(FFMemoryResult* ram)
return "sysctl(CTL_VM, VM_UVMEXP) failed";
ram->bytesTotal = (uint64_t) buf.npages * instance.state.platform.sysinfo.pageSize;
ram->bytesUsed = ram->bytesTotal - (uint64_t) buf.free * instance.state.platform.sysinfo.pageSize;
ram->bytesUsed = ((uint64_t) buf.active + (uint64_t) buf.inactive + (uint64_t) buf.wired) * instance.state.platform.sysinfo.pageSize;
return NULL;
}
+1 -1
View File
@@ -112,7 +112,7 @@ static const char* openCLHandleData(OpenCLData* data, FFOpenCLResult* result)
{
cl_uint vendorId;
if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VENDOR_ID, sizeof(vendorId), &vendorId, NULL) == CL_SUCCESS)
ffStrbufSetStatic(&gpu->vendor, ffGetGPUVendorString(vendorId));
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
if (gpu->vendor.length == 0 && data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VENDOR, sizeof(buffer), buffer, NULL) == CL_SUCCESS)
ffStrbufSetS(&gpu->vendor, buffer);
}
+7
View File
@@ -4,6 +4,13 @@
#include <string.h>
#if __ANDROID__ && !defined(FF_HAVE_EGL)
// On Android, installing OpenGL headers is enough (mesa-dev)
#if __has_include(<EGL/egl.h>)
#define FF_HAVE_EGL 1
#endif
#endif
#if defined(FF_HAVE_EGL) || defined(FF_HAVE_GLX) || defined(FF_HAVE_OSMESA)
#define FF_HAVE_GL 1
+11 -5
View File
@@ -3,7 +3,7 @@
#if __has_include(<GL/gl.h>)
#include <GL/gl.h>
#elif __has_include(<OpenGL/gl.h>)
#elif __APPLE__
#define GL_SILENCE_DEPRECATION 1
#include <OpenGL/gl.h>
#else
@@ -64,9 +64,14 @@ static const char* eglHandleContext(FFOpenGLResult* result, EGLData* data)
return NULL;
}
static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data)
static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data, bool gles)
{
data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE});
data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){
EGL_CONTEXT_CLIENT_VERSION, gles ? 2 : 1, // Try GLES 2.0+ first
EGL_NONE
});
if(data->context == EGL_NO_CONTEXT && gles) // Some ANGLE builds support GLES 1.1 only
data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE});
if(data->context == EGL_NO_CONTEXT)
return "eglCreateContext returned EGL_NO_CONTEXT";
@@ -78,10 +83,11 @@ static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data)
static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data)
{
// try use OpenGL API. If failed, use the default API (usually OpenGL ES)
data->ffeglBindAPI(EGL_OPENGL_API);
bool gles = !data->ffeglBindAPI(EGL_OPENGL_API);
EGLint eglConfigCount;
data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount);
if(eglConfigCount == 0)
return "eglGetConfigs returned 0 configs";
@@ -94,7 +100,7 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data)
if(data->surface == EGL_NO_SURFACE)
return "eglCreatePbufferSurface returned EGL_NO_SURFACE";
const char* error = eglHandleSurface(result, data);
const char* error = eglHandleSurface(result, data, gles);
data->ffeglDestroySurface(data->display, data->surface);
return error;
}
-2
View File
@@ -5,8 +5,6 @@ void ffDetectOSImpl(FFOSResult* os)
{
ffStrbufSetStatic(&os->name, "Android");
ffStrbufSetStatic(&os->prettyName, "Android");
ffStrbufSetStatic(&os->id, "android");
ffSettingsGetAndroidProperty("ro.build.version.release", &os->version);
+11 -13
View File
@@ -54,18 +54,18 @@ static bool detectOSCodeName(FFOSResult* os)
case 14: ffStrbufSetStatic(&os->codename, "Mojave"); return true;
case 13: ffStrbufSetStatic(&os->codename, "High Sierra"); return true;
case 12: ffStrbufSetStatic(&os->codename, "Sierra"); return true;
case 11: ffStrbufSetStatic(&os->codename, "El Capitan"); ffStrbufSetStatic(&os->prettyName, "OS X"); return true;
case 10: ffStrbufSetStatic(&os->codename, "Yosemite"); ffStrbufSetStatic(&os->prettyName, "OS X"); return true;
case 9: ffStrbufSetStatic(&os->codename, "Mavericks"); ffStrbufSetStatic(&os->prettyName, "OS X"); return true;
case 8: ffStrbufSetStatic(&os->codename, "Mountain Lion"); ffStrbufSetStatic(&os->prettyName, "OS X"); return true;
case 7: ffStrbufSetStatic(&os->codename, "Lion"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 6: ffStrbufSetStatic(&os->codename, "Snow Leopard"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 5: ffStrbufSetStatic(&os->codename, "Leopard"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 4: ffStrbufSetStatic(&os->codename, "Tiger"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 11: ffStrbufSetStatic(&os->codename, "El Capitan"); return true;
case 10: ffStrbufSetStatic(&os->codename, "Yosemite"); return true;
case 9: ffStrbufSetStatic(&os->codename, "Mavericks"); return true;
case 8: ffStrbufSetStatic(&os->codename, "Mountain Lion"); return true;
case 7: ffStrbufSetStatic(&os->codename, "Lion"); return true;
case 6: ffStrbufSetStatic(&os->codename, "Snow Leopard"); return true;
case 5: ffStrbufSetStatic(&os->codename, "Leopard"); return true;
case 4: ffStrbufSetStatic(&os->codename, "Tiger"); return true;
case 3: ffStrbufSetStatic(&os->codename, "Panther"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 2: ffStrbufSetStatic(&os->codename, "Jaguar"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 1: ffStrbufSetStatic(&os->codename, "Puma"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 0: ffStrbufSetStatic(&os->codename, "Cheetah"); ffStrbufSetStatic(&os->prettyName, "Mac OS X"); return true;
case 2: ffStrbufSetStatic(&os->codename, "Jaguar"); return true;
case 1: ffStrbufSetStatic(&os->codename, "Puma"); return true;
case 0: ffStrbufSetStatic(&os->codename, "Cheetah"); return true;
}
}
}
@@ -106,8 +106,6 @@ void ffDetectOSImpl(FFOSResult* os)
if(os->buildID.length == 0)
ffSysctlGetString("kern.osversion", &os->buildID);
if(os->prettyName.length == 0)
ffStrbufSetStatic(&os->prettyName, "macOS");
ffStrbufAppend(&os->versionID, &os->version);
if(!detectOSCodeName(os))
+41 -40
View File
@@ -11,14 +11,6 @@
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
static inline bool allRelevantValuesSet(const FFOSResult* result)
{
return result->id.length > 0
&& result->name.length > 0
&& result->prettyName.length > 0
;
}
static bool parseLsbRelease(const char* fileName, FFOSResult* result)
{
return ffParsePropFileValues(fileName, 4, (FFpropquery[]) {
@@ -46,13 +38,33 @@ static bool parseOsRelease(const char* fileName, FFOSResult* result)
});
}
// Common logic for detecting Armbian image version
FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
{
if (ffStrbufStartsWithS(&result->prettyName, "Armbian ")) // Official Armbian release images
ffStrbufSetS(&result->name, "Armbian");
else if (ffStrbufStartsWithS(&result->prettyName, "Armbian-unofficial ")) // Unofficial Armbian image built from source
ffStrbufSetS(&result->name, "Armbian (custom build)");
else
return false;
ffStrbufSet(&result->idLike, &result->id);
ffStrbufSetS(&result->id, "armbian");
ffStrbufClear(&result->versionID);
uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1;
uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' ');
ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart);
return true;
}
FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
{
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
if (detectArmbianVersion(result))
return;
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
{
ffStrbufSetS(&result->name, "Linux Lite");
ffStrbufSetS(&result->id, "linuxlite");
@@ -60,6 +72,14 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Linux Lite "));
return;
}
else if(ffStrbufStartsWithS(&result->prettyName, "Rhino Linux "))
{
ffStrbufSetS(&result->name, "Rhino Linux");
ffStrbufSetS(&result->id, "rhinolinux");
ffStrbufSetS(&result->idLike, "ubuntu");
ffStrbufSetS(&result->versionID, result->prettyName.chars + strlen("Rhino Linux "));
return;
}
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
{
@@ -79,7 +99,7 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
return;
}
if(ffStrContains(xdgConfigDirs, "lxde") || ffStrContains(xdgConfigDirs, "lubuntu"))
if(ffStrContains(xdgConfigDirs, "lxqt") || ffStrContains(xdgConfigDirs, "lubuntu"))
{
ffStrbufSetS(&result->name, "Lubuntu");
ffStrbufSetS(&result->prettyName, "Lubuntu");
@@ -164,28 +184,8 @@ FF_MAYBE_UNUSED static void getDebianVersion(FFOSResult* result)
FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
{
if (ffStrbufStartsWithS(&result->prettyName, "Armbian ")) // Armbian 24.2.1 bookworm
{
ffStrbufSetS(&result->name, "Armbian");
ffStrbufSetS(&result->id, "armbian");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufClear(&result->versionID);
uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1;
uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' ');
ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart);
if (detectArmbianVersion(result))
return true;
}
else if (ffStrbufStartsWithS(&result->prettyName, "Armbian-unofficial ")) // Unofficial Armbian image built from source
{
ffStrbufSetS(&result->name, "Armbian (custom build)");
ffStrbufSetS(&result->id, "armbian");
ffStrbufSetS(&result->idLike, "debian");
ffStrbufClear(&result->versionID);
uint32_t versionStart = ffStrbufFirstIndexC(&result->prettyName, ' ') + 1;
uint32_t versionEnd = ffStrbufNextIndexC(&result->prettyName, versionStart, ' ');
ffStrbufSetNS(&result->versionID, versionEnd - versionStart, result->prettyName.chars + versionStart);
return true;
}
else if (ffStrbufStartsWithS(&result->name, "Loc-OS"))
{
ffStrbufSetS(&result->id, "locos");
@@ -252,7 +252,9 @@ static void detectOS(FFOSResult* os)
{
#ifdef FF_CUSTOM_OS_RELEASE_PATH
parseOsRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
parseLsbRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
#ifdef FF_CUSTOM_LSB_RELEASE_PATH
parseLsbRelease(FF_STR(FF_CUSTOM_LSB_RELEASE_PATH), os);
#endif
return;
#endif
@@ -267,18 +269,17 @@ static void detectOS(FFOSResult* os)
if(os->prettyName.length == 0)
ffStrbufAppendS(&os->prettyName, "Bedrock Linux");
if(parseOsRelease("/bedrock" FASTFETCH_TARGET_DIR_ETC "/os-release", os) && allRelevantValuesSet(os))
return;
parseOsRelease("/bedrock" FASTFETCH_TARGET_DIR_ETC "/os-release", os);
return;
}
// Refer: https://gist.github.com/natefoo/814c5bf936922dad97ff
if((parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os) ||
parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os)) &&
allRelevantValuesSet(os))
return;
parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os);
parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os);
if (os->id.length == 0 || os->version.length == 0 || os->prettyName.length == 0 || os->codename.length == 0)
parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os);
if (os->id.length == 0 || os->name.length > 0 || os->prettyName.length > 0)
parseOsRelease(FASTFETCH_TARGET_DIR_USR "/lib/os-release", os);
}
void ffDetectOSImpl(FFOSResult* os)
+3 -4
View File
@@ -13,6 +13,7 @@ void ffDetectOSImpl(FFOSResult* os)
const wchar_t* rawName = BrandingFormatString(L"%WINDOWS_LONG%");
ffStrbufSetWS(&os->variant, rawName);
GlobalFree((HGLOBAL)rawName);
ffStrbufSet(&os->prettyName, &os->variant);
ffStrbufTrimRight(&os->variant, ' ');
//WMI returns the "Microsoft" prefix while BrandingFormatString doesn't. Make them consistent.
@@ -22,14 +23,12 @@ void ffDetectOSImpl(FFOSResult* os)
if(ffStrbufStartsWithS(&os->variant, "Windows "))
{
ffStrbufAppendS(&os->name, "Windows");
ffStrbufAppendS(&os->prettyName, "Windows");
ffStrbufSubstrAfter(&os->variant, strlen("Windows ") - 1);
if(ffStrbufStartsWithS(&os->variant, "Server "))
{
ffStrbufAppendS(&os->name, " Server");
ffStrbufAppendS(&os->prettyName, " Server");
ffStrbufSubstrAfter(&os->variant, strlen(" Server") - 1);
}
@@ -38,7 +37,7 @@ void ffDetectOSImpl(FFOSResult* os)
ffStrbufSubstrAfter(&os->variant, index);
// Windows Server 20xx Rx
if(ffStrbufEndsWithC(&os->prettyName, 'r'))
if(ffStrbufEndsWithC(&os->name, 'r'))
{
if(os->variant.chars[0] == 'R' &&
ffCharIsDigit(os->variant.chars[1]) &&
@@ -56,6 +55,6 @@ void ffDetectOSImpl(FFOSResult* os)
ffStrbufClear(&os->variant);
}
ffStrbufAppendF(&os->id, "%*s %*s", os->prettyName.length, os->prettyName.chars, os->version.length, os->version.chars);
ffStrbufAppendF(&os->id, "%s %s", os->name.chars, os->version.chars);
ffStrbufSetStatic(&os->idLike, "Windows");
}
+35
View File
@@ -85,3 +85,38 @@ bool ffPackagesWriteCache(FFstrbuf* cacheDir, FFstrbuf* cacheContent, uint32_t n
ffStrbufAppendF(cacheContent, "%" PRIu32, num_elements);
return ffWriteFileBuffer(cacheDir->chars, cacheContent);
}
#ifndef _WIN32
uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir)
{
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(dirname);
if(dirp == NULL)
return 0;
uint32_t num_elements = 0;
struct dirent *entry;
while((entry = readdir(dirp)) != NULL)
{
bool ok = false;
#ifndef __sun
if(entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK)
ok = entry->d_type == (isdir ? DT_DIR : DT_REG);
else
#endif
{
struct stat stbuf;
if (fstatat(dirfd(dirp), entry->d_name, &stbuf, 0) == 0)
ok = isdir ? S_ISDIR(stbuf.st_mode) : S_ISREG(stbuf.st_mode);
}
if(ok) ++num_elements;
}
if(isdir && num_elements >= 2)
num_elements -= 2; // accounting for . and ..
return num_elements;
}
#endif
+7 -1
View File
@@ -4,7 +4,8 @@
typedef struct FFPackagesResult
{
uint32_t am;
uint32_t amSystem;
uint32_t amUser;
uint32_t apk;
uint32_t brew;
uint32_t brewCask;
@@ -30,6 +31,7 @@ typedef struct FFPackagesResult
uint32_t pacstall;
uint32_t paludis;
uint32_t pkg;
uint32_t pkgsrc;
uint32_t pkgtool;
uint32_t qi;
uint32_t rpm;
@@ -47,3 +49,7 @@ typedef struct FFPackagesResult
const char* ffDetectPackages(FFPackagesResult* result, FFPackagesOptions* options);
bool ffPackagesReadCache(FFstrbuf* cacheDir, FFstrbuf* cacheContent, const char* filePath, const char* packageId, uint32_t* result);
bool ffPackagesWriteCache(FFstrbuf* cacheDir, FFstrbuf* cacheContent, uint32_t num_elements);
#ifndef _WIN32
uint32_t ffPackagesGetNumElements(const char* dirname, bool isdir);
#endif
+4 -24
View File
@@ -4,26 +4,6 @@
#include "common/processing.h"
#include "util/stringUtils.h"
static uint32_t getNumElements(const char* dirname, unsigned char type)
{
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(dirname);
if(dirp == NULL)
return 0;
uint32_t num_elements = 0;
struct dirent *entry;
while((entry = readdir(dirp)) != NULL) {
if(entry->d_type == type)
++num_elements;
}
if(type == DT_DIR)
num_elements -= 2; // accounting for . and ..
return num_elements;
}
static void countBrewPackages(const char* dirname, FFPackagesResult* result)
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(dirname);
@@ -31,11 +11,11 @@ static void countBrewPackages(const char* dirname, FFPackagesResult* result)
uint32_t baseDirLength = baseDir.length;
ffStrbufAppendS(&baseDir, "/Caskroom");
result->brewCask += getNumElements(baseDir.chars, DT_DIR);
result->brewCask += ffPackagesGetNumElements(baseDir.chars, true);
ffStrbufSubstrBefore(&baseDir, baseDirLength);
ffStrbufAppendS(&baseDir, "/Cellar");
result->brew += getNumElements(baseDir.chars, DT_DIR);
result->brew += ffPackagesGetNumElements(baseDir.chars, true);
ffStrbufSubstrBefore(&baseDir, baseDirLength);
}
@@ -52,9 +32,9 @@ static void getBrewPackages(FFPackagesResult* result)
static uint32_t countMacPortsPackages(const char* dirname)
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(dirname);
ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT "/var/macports/software");
ffStrbufAppendS(&baseDir, "/var/macports/software");
return getNumElements(baseDir.chars, DT_DIR);
return ffPackagesGetNumElements(baseDir.chars, true);
}
static uint32_t getMacPortsPackages()
+56 -54
View File
@@ -7,33 +7,11 @@
#include "detection/os/os.h"
#include "util/stringUtils.h"
#include <dirent.h>
static uint32_t getNumElementsImpl(const char* dirname, unsigned char type)
{
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(dirname);
if(dirp == NULL)
return 0;
uint32_t num_elements = 0;
struct dirent *entry;
while((entry = readdir(dirp)) != NULL) {
if(entry->d_type == type)
++num_elements;
}
if(type == DT_DIR && num_elements >= 2)
num_elements -= 2; // accounting for . and ..
return num_elements;
}
static uint32_t getNumElements(FFstrbuf* baseDir, const char* dirname, unsigned char type)
static uint32_t getNumElements(FFstrbuf* baseDir, const char* dirname, bool isdir)
{
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, dirname);
uint32_t num_elements = getNumElementsImpl(baseDir->chars, type);
uint32_t num_elements = ffPackagesGetNumElements(baseDir->chars, isdir);
ffStrbufSubstrBefore(baseDir, baseDirLength);
return num_elements;
}
@@ -332,10 +310,10 @@ static uint32_t getXBPS(FFstrbuf* baseDir, const char* dirname)
static uint32_t getSnap(FFstrbuf* baseDir)
{
uint32_t result = getNumElements(baseDir, "/snap", DT_DIR);
uint32_t result = getNumElements(baseDir, "/snap", true);
if (result == 0)
result = getNumElements(baseDir, "/var/lib/snapd/snap", DT_DIR);
result = getNumElements(baseDir, "/var/lib/snapd/snap", true);
//Accounting for the /snap/bin folder
return result > 0 ? result - 1 : 0;
@@ -386,7 +364,29 @@ static uint32_t getRpmFromLibrpm(void)
#endif //FF_HAVE_RPM
static uint32_t getAM(FFstrbuf* baseDir)
static uint32_t getAMPackages(FFstrbuf* baseDir)
{
uint32_t baseLength = baseDir->length;
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
if (!dirp) return 0;
uint32_t result = 0;
struct dirent *entry;
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_name[0] == '.') continue;
if (entry->d_type == DT_DIR)
{
ffStrbufAppendF(baseDir, "/%s/remove", entry->d_name);
if (ffPathExists(baseDir->chars, FF_PATHTYPE_FILE))
++result;
ffStrbufSubstrBefore(baseDir, baseLength);
}
}
return result;
}
static uint32_t getAMSystem(FFstrbuf* baseDir)
{
// #771
uint32_t baseDirLength = baseDir->length;
@@ -401,28 +401,27 @@ static uint32_t getAM(FFstrbuf* baseDir)
{
++result; // `am` itself is counted as a package too
ffStrbufSubstrBefore(baseDir, optDirLength);
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
if(dirp)
{
struct dirent *entry;
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_name[0] == '.') continue;
if (entry->d_type == DT_DIR)
{
ffStrbufAppendF(baseDir, "/%s/AM-updater", entry->d_name);
if (ffPathExists(baseDir->chars, FF_PATHTYPE_FILE))
++result;
ffStrbufSubstrBefore(baseDir, optDirLength);
}
}
}
result = getAMPackages(baseDir);
}
ffStrbufSubstrBefore(baseDir, baseDirLength);
return result;
}
static uint32_t getAMUser(void)
{
// check if $XDG_CONFIG_HOME/appman/appman-config exists
FFstrbuf* baseDir = FF_LIST_GET(FFstrbuf, instance.state.platform.configDirs, 0);
uint32_t baseLen = baseDir->length;
ffStrbufAppendS(baseDir, "appman/appman-config");
FF_STRBUF_AUTO_DESTROY packagesPath = ffStrbufCreate();
if (ffReadFileBuffer(baseDir->chars, &packagesPath))
ffStrbufTrimRightSpace(&packagesPath);
ffStrbufSubstrBefore(baseDir, baseLen);
return packagesPath.length > 0 ? getAMPackages(&packagesPath) : 0;
}
static int compareHash(const void* a, const void* b)
{
return memcmp(a, b, 32);
@@ -480,7 +479,7 @@ static inline uint32_t getFlatpakRuntimePackagesArch(FFstrbuf* baseDir)
{
if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
{
num_elements += getNumElements(baseDir, entry->d_name, DT_DIR);
num_elements += getNumElements(baseDir, entry->d_name, true);
}
}
@@ -529,7 +528,7 @@ static uint32_t getFlatpakPackages(FFstrbuf* baseDir, const char* dirname)
uint32_t flatpakDirLength = baseDir->length;
ffStrbufAppendS(baseDir, "app");
num_elements += getNumElementsImpl(baseDir->chars, DT_DIR);
num_elements += ffPackagesGetNumElements(baseDir->chars, true);
ffStrbufSubstrBefore(baseDir, flatpakDirLength);
num_elements += getFlatpakRuntimePackages(baseDir);
@@ -545,34 +544,34 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
if (!(options->disabled & FF_PACKAGES_FLAG_DPKG_BIT)) packageCounts->dpkg += getNumStrings(baseDir, "/var/lib/dpkg/status", "Status: install ok installed", "dpkg");
if (!(options->disabled & FF_PACKAGES_FLAG_LPKG_BIT)) packageCounts->lpkg += getNumStrings(baseDir, "/opt/Loc-OS-LPKG/installed-lpkg/Listinstalled-lpkg.list", "\n", "lpkg");
if (!(options->disabled & FF_PACKAGES_FLAG_EMERGE_BIT)) packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE");
if (!(options->disabled & FF_PACKAGES_FLAG_EOPKG_BIT)) packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", DT_DIR);
if (!(options->disabled & FF_PACKAGES_FLAG_EOPKG_BIT)) packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", true);
if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT)) packageCounts->flatpakSystem += getFlatpakPackages(baseDir, "/var/lib");
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
{
packageCounts->nixDefault += getNixPackages(baseDir, "/nix/var/nix/profiles/default");
packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system");
}
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", DT_DIR);
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", DT_REG);
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", DT_REG);
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages", "rpm");
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
{
packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", DT_DIR);
packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", DT_DIR);
packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", true);
packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", true);
}
if (!(options->disabled & FF_PACKAGES_FLAG_PALUDIS_BIT)) packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2");
if (!(options->disabled & FF_PACKAGES_FLAG_OPKG_BIT)) packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:", "opkg"); // openwrt
if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT)) packageCounts->am = getAM(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT)) packageCounts->amSystem = getAMSystem(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_SORCERY_BIT)) packageCounts->sorcery += getNumStrings(baseDir, "/var/state/sorcery/packages", ":installed:", "sorcery");
if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
{
packageCounts->guixSystem += getGuixPackages(baseDir, "/run/current-system/profile");
}
if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT)) packageCounts->linglong += getNumElements(baseDir, "/var/lib/linglong/repo/refs/heads/main", DT_DIR);
if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT)) packageCounts->pacstall += getNumElements(baseDir, "/var/lib/pacstall/metadata", DT_REG);
if (!(options->disabled & FF_PACKAGES_FLAG_LINGLONG_BIT)) packageCounts->linglong += getNumElements(baseDir, "/var/lib/linglong/repo/refs/heads/main", true);
if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT)) packageCounts->pacstall += getNumElements(baseDir, "/var/lib/pacstall/metadata", false);
if (!(options->disabled & FF_PACKAGES_FLAG_QI_BIT)) packageCounts->qi += getNumStrings(baseDir, "/var/qi/installed_packages.list", "\n", "qi");
}
@@ -678,4 +677,7 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT))
result->flatpakUser = getFlatpakPackages(&baseDir, "/.local/share");
if (!(options->disabled & FF_PACKAGES_FLAG_AM_BIT))
result->amUser = getAMUser();
}
+6 -29
View File
@@ -2,36 +2,13 @@
#include "common/io/io.h"
static uint32_t getNumElementsImpl(const char* dirname, unsigned char type)
{
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(dirname);
if(dirp == NULL)
return 0;
uint32_t num_elements = 0;
struct dirent *entry;
while((entry = readdir(dirp)) != NULL) {
if(entry->d_type == type)
++num_elements;
}
if(type == DT_DIR && num_elements >= 2)
num_elements -= 2; // accounting for . and ..
return num_elements;
}
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
#if __OpenBSD__
if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT))
{
result->pkg = getNumElementsImpl(FASTFETCH_TARGET_DIR_ROOT
#if __OpenBSD__
"/var/db/pkg"
#else
"/usr/pkg/pkgdb"
#endif
, DT_DIR);
}
result->pkg = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg", true);
#elif __NetBSD__
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
#endif
}
+3
View File
@@ -1,4 +1,5 @@
#include "packages.h"
#include <dirent.h>
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
@@ -12,4 +13,6 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
result->pkg = (uint32_t) yyjson_get_uint(packageCount);
}
}
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
}
+21 -17
View File
@@ -80,24 +80,28 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
{
ffStrbufInit(&device->interconnect);
char pathSysDeviceReal[PATH_MAX];
ssize_t pathLength = readlinkat(dfd, "device", pathSysDeviceReal, ARRAY_SIZE(pathSysDeviceReal) - 1);
if (pathLength > 0)
if (ffStrStartsWith(devName, "nvme"))
ffStrbufSetStatic(&device->interconnect, "NVMe");
else
{
pathSysDeviceReal[pathLength] = '\0';
if (strstr(pathSysDeviceReal, "/usb") != NULL)
ffStrbufSetS(&device->interconnect, "USB");
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
ffStrbufSetS(&device->interconnect, "NVMe");
else if (strstr(pathSysDeviceReal, "/ata") != NULL)
ffStrbufSetS(&device->interconnect, "ATA");
else if (strstr(pathSysDeviceReal, "/scsi") != NULL)
ffStrbufSetS(&device->interconnect, "SCSI");
else
char pathSysDeviceLink[64];
snprintf(pathSysDeviceLink, ARRAY_SIZE(pathSysDeviceLink), "/sys/block/%s/device", devName);
char pathSysDeviceReal[PATH_MAX];
if (realpath(pathSysDeviceLink, pathSysDeviceReal))
{
if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect))
ffStrbufTrimRightSpace(&device->interconnect);
if (strstr(pathSysDeviceReal, "/usb") != NULL)
ffStrbufSetStatic(&device->interconnect, "USB");
else if (strstr(pathSysDeviceReal, "/ata") != NULL)
ffStrbufSetStatic(&device->interconnect, "ATA");
else if (strstr(pathSysDeviceReal, "/scsi") != NULL)
ffStrbufSetStatic(&device->interconnect, "SCSI");
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
ffStrbufSetStatic(&device->interconnect, "NVMe");
else
{
if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect))
ffStrbufTrimRightSpace(&device->interconnect);
}
}
}
}
@@ -169,7 +173,7 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
if (devName[0] == '.')
continue;
char pathSysBlock[ARRAY_SIZE("/sys/block/") + ARRAY_SIZE(sysBlockEntry->d_name)];
char pathSysBlock[sizeof("/sys/block/") + sizeof(sysBlockEntry->d_name)];
snprintf(pathSysBlock, ARRAY_SIZE(pathSysBlock), "/sys/block/%s", devName);
int dfd = openat(dirfd(sysBlockDirp), devName, O_RDONLY | O_CLOEXEC | O_PATH | O_DIRECTORY);
@@ -23,6 +23,7 @@ static inline const char* getVendorString(unsigned vendorId)
void FFPhysicalMemoryUpdateVendorString(FFPhysicalMemoryResult* device)
{
if (device->vendor.length == 0) return;
if (ffStrbufEqualS(&device->vendor, "Unknown"))
{
ffStrbufClear(&device->vendor);
@@ -191,6 +191,7 @@ const char* ffDetectPhysicalMemory(FFlist* result)
device->maxSpeed = data->Speed == 0xFFFF ? data->ExtendedSpeed : data->Speed;
ffStrbufSetStatic(&device->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
ffCleanUpSmbiosValue(&device->vendor);
FFPhysicalMemoryUpdateVendorString(device);
ffStrbufSetStatic(&device->serial, ffSmbiosLocateString(strings, data->SerialNumber));
+1
View File
@@ -8,6 +8,7 @@ typedef struct FFSoundDevice
{
FFstrbuf identifier;
FFstrbuf name;
FFstrbuf platformApi;
uint8_t volume; // 0-100%
bool main;
bool active;
+1
View File
@@ -73,6 +73,7 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
device->volume = FF_SOUND_VOLUME_UNKNOWN;
ffStrbufInitF(&device->identifier, "%u", (unsigned) deviceId);
ffStrbufInit(&device->name);
ffStrbufInitStatic(&device->platformApi, "Core Audio");
ffCfStrGetString(name, &device->name);
uint32_t muted;
+2 -1
View File
@@ -39,7 +39,8 @@ const char* ffDetectSound(FFlist* devices)
FFSoundDevice* device = ffListAdd(devices);
ffStrbufInitS(&device->identifier, path);
ffStrbufInitF(&device->name, "%s %s", ci.longname, ci.hw_info);
ffStrbufTrimRightSpace(&device->name);
ffStrbufTrimRightSpace(&device->name);
ffStrbufInitStatic(&device->platformApi, "OSS");
device->volume = mutemask & SOUND_MASK_VOLUME
? 0
: ((uint8_t) volume /*left*/ + (uint8_t) (volume >> 8) /*right*/) / 2;
+14 -9
View File
@@ -13,6 +13,7 @@ static void paSinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, vo
FFSoundDevice* device = ffListAdd(userdata);
ffStrbufInitS(&device->identifier, i->name);
ffStrbufInitStatic(&device->platformApi, "PulseAudio");
ffStrbufTrimRightSpace(&device->identifier);
ffStrbufInitS(&device->name, i->description);
ffStrbufTrimRightSpace(&device->name);
@@ -22,20 +23,24 @@ static void paSinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, vo
device->main = false;
}
static void paServerInfoCallback(pa_context *c, const pa_server_info *i, void *userdata)
static void paServerInfoCallback(FF_MAYBE_UNUSED pa_context *c, const pa_server_info *i, void *userdata)
{
FF_UNUSED(c);
if(!i) return;
if(!i)
return;
FF_STRBUF_AUTO_DESTROY api = ffStrbufCreate();
const char* realServer = strstr(i->server_name, "(on ");
if (realServer)
{
ffStrbufSetS(&api, realServer + strlen("(on "));
ffStrbufTrimRight(&api, ')');
}
else
ffStrbufSetF(&api, "%s %s", i->server_name, i->server_version);
FF_LIST_FOR_EACH(FFSoundDevice, device, *(FFlist*)userdata)
{
if(ffStrbufEqualS(&device->identifier, i->default_sink_name))
{
device->main = true;
break;
}
device->main = ffStrbufEqualS(&device->identifier, i->default_sink_name);
ffStrbufSet(&device->platformApi, &api);
}
}
+1
View File
@@ -65,6 +65,7 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
device->volume = FF_SOUND_VOLUME_UNKNOWN;
ffStrbufInitWS(&device->identifier, immDeviceId);
ffStrbufInit(&device->name);
ffStrbufInitStatic(&device->platformApi, "Core Audio APIs");
{
PROPVARIANT __attribute__((__cleanup__(PropVariantClear))) friendlyName;
+27
View File
@@ -48,6 +48,31 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont)
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}
static void detectGhostty(FFTerminalFontResult* terminalFont)
{
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
FFpropquery fontQueryToml[] = {
{"font-family =", &fontName},
{"font-size =", &fontSize},
};
#if __APPLE__
ffParsePropFileConfigValues("com.mitchellh.ghostty/config", 2, fontQueryToml);
#endif
ffParsePropFileConfigValues("ghostty/config", 2, fontQueryToml);
if(fontName.length == 0)
ffStrbufAppendS(&fontName, "JetBrainsMono Nerd Font");
if(fontSize.length == 0)
ffStrbufAppendS(&fontSize, "13");
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}
FF_MAYBE_UNUSED static void detectTTY(FFTerminalFontResult* terminalFont)
{
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
@@ -230,6 +255,8 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina
detectTabby(terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour"))
detectContour(&terminal->exe, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty"))
detectGhostty(terminalFont);
#ifndef _WIN32
else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/pts/"))
+61 -36
View File
@@ -15,41 +15,18 @@
#define _PATH_LOCALBASE "/usr/local"
#elif __NetBSD__
#define _PATH_LOCALBASE "/usr/pkg"
#endif
#elif _WIN32
#ifdef _WIN32
#include "util/windows/version.h"
#include <windows.h>
#include "util/mallocHelper.h"
#include <winver.h>
static bool getFileVersion(const char* exePath, FFstrbuf* version)
static bool getFileVersion(const FFstrbuf* exePath, FFstrbuf* version)
{
DWORD handle;
DWORD size = GetFileVersionInfoSizeA(exePath, &handle);
if(size > 0)
{
FF_AUTO_FREE void* versionData = malloc(size);
if(GetFileVersionInfoA(exePath, handle, size, versionData))
{
VS_FIXEDFILEINFO* verInfo;
UINT len;
if(VerQueryValueW(versionData, L"\\", (void**)&verInfo, &len) && len && verInfo->dwSignature == 0xFEEF04BD)
{
ffStrbufAppendF(version, "%u.%u.%u.%u",
(unsigned)(( verInfo->dwFileVersionMS >> 16 ) & 0xffff),
(unsigned)(( verInfo->dwFileVersionMS >> 0 ) & 0xffff),
(unsigned)(( verInfo->dwFileVersionLS >> 16 ) & 0xffff),
(unsigned)(( verInfo->dwFileVersionLS >> 0 ) & 0xffff)
);
return true;
}
}
}
return false;
wchar_t exePathW[PATH_MAX];
int len = MultiByteToWideChar(CP_UTF8, 0, exePath->chars, (int)exePath->length, exePathW, ARRAY_SIZE(exePathW));
if (len <= 0) return false;
return ffGetFileVersion(exePathW, version);
}
#endif
static bool getExeVersionRaw(FFstrbuf* exe, FFstrbuf* version)
@@ -109,8 +86,17 @@ static bool getShellVersionFish(FFstrbuf* exe, FFstrbuf* version)
static bool getShellVersionPwsh(FFstrbuf* exe, FFstrbuf* version)
{
// Requires manually setting $POWERSHELL_VERSION
// $env:POWERSHELL_VERSION = $PSVersionTable.PSVersion.ToString(); fastfetch.exe
const char* env = getenv("POWERSHELL_VERSION");
if (env)
{
ffStrbufSetS(version, env);
return true;
}
#ifdef _WIN32
if(getFileVersion(exe->chars, version))
if(getFileVersion(exe, version))
{
ffStrbufSubstrBeforeLastC(version, '.');
return true;
@@ -249,6 +235,13 @@ static bool getShellVersionZsh(FFstrbuf* exe, FFstrbuf* exePath, FFstrbuf* versi
#ifdef _WIN32
static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version)
{
const char* env = getenv("POWERSHELL_VERSION");
if (env)
{
ffStrbufSetS(version, env);
return true;
}
return ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"-NoLogo",
@@ -296,7 +289,7 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* exePath,
if(ffStrEqualsIgnCase(exeName, "powershell") || ffStrEqualsIgnCase(exeName, "powershell_ise"))
return getShellVersionWinPowerShell(exe, version);
return getFileVersion(exe->chars, version);
return getFileVersion(exe, version);
#endif
return false;
@@ -605,6 +598,38 @@ static bool getTerminalVersionKitty(FFstrbuf* exe, FFstrbuf* version)
}
}
}
#elif __APPLE__
if (ffStrbufEndsWithS(exe, "/kitty.app/Contents/MacOS/kitty"))
{
ffStrbufSet(version, exe);
ffStrbufSubstrBeforeLastC(version, '/');
ffStrbufSubstrBeforeLastC(version, '/');
ffStrbufAppendS(version, "/Info.plist");
char buf[4096];
ssize_t size = ffReadFileData(version->chars, ARRAY_SIZE(buf) - 1, buf);
if (size > 0)
{
buf[size] = '\0';
const char* p = strstr(buf, "<key>CFBundleShortVersionString</key>");
if (p)
{
p += strlen("<key>CFBundleShortVersionString</key>");
p = strchr(p, '>');
if (p)
{
p++;
const char* end = strchr(p, '<');
if (end)
{
ffStrbufSetNS(version, (uint32_t) (end - p), p);
return true;
}
}
}
}
ffStrbufClear(version);
}
#endif
char versionHex[64];
@@ -690,7 +715,7 @@ static bool getTerminalVersionWindowsTerminal(FFstrbuf* exe, FFstrbuf* version)
return true;
}
return getFileVersion(exe->chars, version);
return getFileVersion(exe, version);
}
static bool getTerminalVersionConEmu(FFstrbuf* exe, FFstrbuf* version)
@@ -700,7 +725,7 @@ static bool getTerminalVersionConEmu(FFstrbuf* exe, FFstrbuf* version)
if(version->length)
return true;
return getFileVersion(exe->chars, version);
return getFileVersion(exe, version);
}
#endif
@@ -859,7 +884,7 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe
#ifdef _WIN32
return getFileVersion(exe->chars, version);
return getFileVersion(exe, version);
#else
@@ -56,7 +56,8 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
ffStrbufEqualS(&result->processName, "fastfetch") || //994
ffStrbufEqualS(&result->processName, "flashfetch") ||
ffStrbufContainS(&result->processName, "debug") ||
ffStrbufContainS(&result->processName, "not-found") ||
ffStrbufContainS(&result->processName, "command-not-") ||
ffStrbufEqualS(&result->processName, "proot") ||
ffStrbufEndsWithS(&result->processName, ".sh")
)
{
@@ -105,6 +106,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
ffStrbufEqualS(&result->processName, "login") ||
ffStrbufEqualS(&result->processName, "clifm") || // https://github.com/leo-arch/clifm/issues/289
ffStrbufEqualS(&result->processName, "chezmoi") || // #762
ffStrbufEqualS(&result->processName, "proot") ||
#ifdef __linux__
ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707
#endif
@@ -307,11 +309,11 @@ static void setShellInfoDetails(FFShellResult* result)
static void setTerminalInfoDetails(FFTerminalResult* result)
{
if(ffStrbufStartsWithC(&result->processName, '.') && ffStrbufEndsWithS(&result->processName, "-wrapped"))
if(ffStrbufStartsWithC(&result->processName, '.') && ffStrbufContainS(&result->processName, "-wrap"))
{
// For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428
// We use processName when detecting version and font, overriding it for simplification
ffStrbufSubstrBefore(&result->processName, result->processName.length - (uint32_t) strlen("-wrapped"));
ffStrbufSubstrBeforeLastC(&result->processName, '-');
ffStrbufSubstrAfter(&result->processName, 0);
}
@@ -5,39 +5,13 @@
#include "util/mallocHelper.h"
#include "util/windows/registry.h"
#include "util/windows/unicode.h"
#include "util/windows/version.h"
#include "util/stringUtils.h"
#include <windows.h>
#include <wchar.h>
#include <tlhelp32.h>
static bool getProductVersion(const wchar_t* filePath, FFstrbuf* version)
{
DWORD handle;
DWORD size = GetFileVersionInfoSizeW(filePath, &handle);
if(size > 0)
{
FF_AUTO_FREE void* versionData = malloc(size);
if(GetFileVersionInfoW(filePath, handle, size, versionData))
{
VS_FIXEDFILEINFO* verInfo;
UINT len;
if(VerQueryValueW(versionData, L"\\", (void**)&verInfo, &len) && len && verInfo->dwSignature == 0xFEEF04BD)
{
ffStrbufAppendF(version, "%u.%u.%u.%u",
(unsigned)(( verInfo->dwProductVersionMS >> 16 ) & 0xffff),
(unsigned)(( verInfo->dwProductVersionMS >> 0 ) & 0xffff),
(unsigned)(( verInfo->dwProductVersionLS >> 16 ) & 0xffff),
(unsigned)(( verInfo->dwProductVersionLS >> 0 ) & 0xffff)
);
return true;
}
}
}
return false;
}
bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, const FFstrbuf* exePath, FFstrbuf* version);
static uint32_t getShellInfo(FFShellResult* result, uint32_t pid)
@@ -113,7 +87,7 @@ static void setShellInfoDetails(FFShellResult* result)
if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0)
{
ffStrbufAppendS(&result->prettyName, " (with Clink ");
getProductVersion(module.szExePath, &result->prettyName);
ffGetFileVersion(module.szExePath, &result->prettyName);
ffStrbufAppendC(&result->prettyName, ')');
break;
}
@@ -2,6 +2,7 @@
#include "common/io/io.h"
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef __sun
@@ -11,7 +12,11 @@
bool ffDetectTerminalSize(FFTerminalSizeResult* result)
{
struct winsize winsize = {};
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
static int ttyfd = STDOUT_FILENO;
if (!isatty(ttyfd))
ttyfd = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC);
ioctl(ttyfd, TIOCGWINSZ, &winsize);
if (winsize.ws_row == 0 || winsize.ws_col == 0)
ffGetTerminalResponse("\e[18t", 2, "\e[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
+2
View File
@@ -40,6 +40,8 @@
#define FF_SYSNAME "SunOS"
#elif defined(__OpenBSD__)
#define FF_SYSNAME "OpenBSD"
#elif defined(__NetBSD__)
#define FF_SYSNAME "NetBSD"
#else
#define FF_SYSNAME "unknown"
#endif
+7 -7
View File
@@ -39,13 +39,13 @@ static void applyDriverName(VkPhysicalDeviceDriverPropertiesKHR* properties, FFs
static const char* detectVulkan(FFVulkanResult* result)
{
FF_LIBRARY_LOAD(vulkan, "dlopen libvulkan"FF_LIBRARY_EXTENSION " failed",
#ifdef __APPLE__
"libMoltenVK"FF_LIBRARY_EXTENSION, -1
#elif defined(_WIN32)
"vulkan-1"FF_LIBRARY_EXTENSION, -1
FF_LIBRARY_LOAD(vulkan, "dlopen libvulkan" FF_LIBRARY_EXTENSION " failed",
#if __APPLE__
"libMoltenVK" FF_LIBRARY_EXTENSION, -1
#elif _WIN32
"vulkan-1" FF_LIBRARY_EXTENSION, -1
#else
"libvulkan"FF_LIBRARY_EXTENSION, 2
"libvulkan" FF_LIBRARY_EXTENSION, 2
#endif
)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkGetInstanceProcAddr)
@@ -218,7 +218,7 @@ static const char* detectVulkan(FFVulkanResult* result)
ffStrbufInitS(&gpu->name, physicalDeviceProperties.properties.deviceName);
gpu->type = physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
ffStrbufInitS(&gpu->vendor, ffGetGPUVendorString(physicalDeviceProperties.properties.vendorID));
ffStrbufInitS(&gpu->vendor, ffGPUGetVendorString(physicalDeviceProperties.properties.vendorID));
ffStrbufInitS(&gpu->driver, driverProperties.driverInfo);
VkPhysicalDeviceMemoryProperties memoryProperties = {};
+1
View File
@@ -3,3 +3,4 @@
#include "fastfetch.h"
const char* ffDetectWMPlugin(FFstrbuf* pluginName);
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FFWMOptions* options);
@@ -5,6 +5,7 @@
#include "util/stringUtils.h"
#include <ctype.h>
#import <Foundation/Foundation.h>
const char* ffDetectWMPlugin(FFstrbuf* pluginName)
{
@@ -38,3 +39,19 @@ const char* ffDetectWMPlugin(FFstrbuf* pluginName)
return NULL;
}
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
{
if (!wmName)
return "No WM detected";
if (ffStrbufEqualS(wmName, "WindowServer"))
{
NSError* error;
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:@"file:///System/Library/CoreServices/WindowManager.app/Contents/version.plist"]
error:&error];
ffStrbufInitS(result, ((NSString*) dict[@"CFBundleVersion"]).UTF8String);
}
return NULL;
}
+113
View File
@@ -0,0 +1,113 @@
#include "wm.h"
#include "common/processing.h"
#include "common/io/io.h"
#include "detection/displayserver/displayserver.h"
#include "util/binary.h"
#include "util/path.h"
#include "util/stringUtils.h"
const char* ffDetectWMPlugin(FF_MAYBE_UNUSED FFstrbuf* pluginName)
{
return "Not supported on this platform";
}
static bool extractHyprlandVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
if (line[0] != 'v') return true;
int count = 0;
sscanf(line + 1, "%*d.%*d.%*d%n", &count);
if (count == 0) return true;
ffStrbufSetNS((FFstrbuf*) userdata, len - 1, line + 1);
return false;
}
static const char* getHyprland(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("Hyprland", &path);
if (error) return "Failed to find Hyprland executable path";
if (ffBinaryExtractStrings(path.chars, extractHyprlandVersion, result, (uint32_t) strlen("v0.0.0")) == NULL)
return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // Hyprland 0.46.2 built from branch v0.46.2-b at... long and multi line
ffStrbufSubstrAfterFirstC(result, ' ');
ffStrbufSubstrBeforeFirstC(result, ' ');
return NULL;
}
return "Failed to run command `Hyprland --version`";
}
static bool extractSwayVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
if (!ffStrStartsWith(line, "sway version ")) return true;
ffStrbufSetNS((FFstrbuf*) userdata, len - (uint32_t) strlen("sway version "), line + strlen("sway version "));
return false;
}
static const char* getSway(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("sway", &path);
if (error) return "Failed to find sway executable path";
if (ffBinaryExtractStrings(path.chars, extractSwayVersion, result, (uint32_t) strlen("v0.0.0")) == NULL)
{
ffStrbufTrimRightSpace(result);
return NULL;
}
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // sway version 1.10
ffStrbufSubstrAfterLastC(result, ' ');
ffStrbufTrimRightSpace(result);
return NULL;
}
return "Failed to run command `sway --version`";
}
static const char* getWslg(FFstrbuf* result)
{
if (!ffAppendFileBuffer("/mnt/wslg/versions.txt", result))
return "Failed to read /mnt/wslg/versions.txt";
if (!ffStrbufStartsWithS(result, "WSLg "))
return "Failed to find WSLg version";
ffStrbufSubstrBeforeFirstC(result, '\n');
ffStrbufSubstrBeforeFirstC(result, '+');
ffStrbufSubstrAfterFirstC(result, ':');
ffStrbufTrimLeft(result, ' ');
return NULL;
}
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
{
if (!wmName)
return "No WM detected";
if (ffStrbufEqualS(wmName, "Hyprland"))
return getHyprland(result);
if (ffStrbufEqualS(wmName, "sway"))
return getSway(result);
if (ffStrbufEqualS(wmName, "WSLg"))
return getWslg(result);
return "Unsupported WM";
}
+5
View File
@@ -4,3 +4,8 @@ const char* ffDetectWMPlugin(FF_MAYBE_UNUSED FFstrbuf* pluginName)
{
return "Not supported on this platform";
}
const char* ffDetectWMVersion(FF_MAYBE_UNUSED const FFstrbuf* wmName, FF_MAYBE_UNUSED FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
{
return "Not supported on this platform";
}
+22
View File
@@ -3,6 +3,7 @@ extern "C"
#include "wm.h"
#include "common/io/io.h"
#include "detection/terminalshell/terminalshell.h"
#include "util/windows/version.h"
}
#include "util/windows/com.hpp"
@@ -64,3 +65,24 @@ const char* ffDetectWMPlugin(FFstrbuf* pluginName)
}
return NULL;
}
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
{
if (!wmName)
return "No WM detected";
if (ffStrbufEqualS(wmName, "dwm.exe"))
{
PWSTR pPath = NULL;
if(SUCCEEDED(SHGetKnownFolderPath(FOLDERID_System, KF_FLAG_DEFAULT, NULL, &pPath)))
{
wchar_t fullPath[MAX_PATH];
wcscpy(fullPath, pPath);
wcscat(fullPath, L"\\dwm.exe");
ffGetFileVersion(fullPath, result);
}
CoTaskMemFree(pPath);
return NULL;
}
return "Not supported on this platform";
}
+6 -6
View File
@@ -1,6 +1,6 @@
${c1} /\\ /\\
/${c2}/ ${c1}\\ \\
/${c2}// ${c1}\\ \\
/${c2}// ${c1}\\ \\
${c2}// ${c1}\\ \\
\\
${c1} /\ /\
/${c2}/ ${c1}\ \
/${c2}// ${c1}\ \
/${c2}// ${c1}\ \
${c2}// ${c1}\ \
\

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