Compare commits

..

81 Commits

Author SHA1 Message Date
李通洲 9ab5c33008 CI: fix release action 2025-09-23 10:19:55 +08:00
Carter Li 613b1d63f1 Packaging: updates debian stuff [ci skip] 2025-09-23 10:03:30 +08:00
Carter Li 8c86cafec7 Merge pull request #1976 from fastfetch-cli/dev
Release: v2.53.0
2025-09-23 09:55:28 +08:00
李通洲 4098cf51b3 Release: v2.53.0 2025-09-23 09:27:52 +08:00
李通洲 bfc23232f8 CPU (Android): adds support for new Qualcomm and MediaTek SoC codes 2025-09-23 09:13:10 +08:00
李通洲 483fba44dc Doc: update changelog [ci skip] 2025-09-22 16:40:10 +08:00
李通洲 851751f99d CPU (Linux): adds support for new ARM C1 series CPU part IDs
Follows changes of util-linux
2025-09-22 16:24:36 +08:00
李通洲 3e86130ddd Zpool: increase libzfs so version to 6
Fixes #1973
2025-09-22 14:32:19 +08:00
李通洲 350ffced13 CI: upgrades runner of intel macOS 2025-09-22 14:13:41 +08:00
李通洲 cdcdb78b97 CPU (Windows): refines ARMv8.4-A detection to require LSE2 2025-09-22 14:08:29 +08:00
Osama Albahrani 2ae9d01200 OS (Linux): Better Ubuntu flavor detection
- Fixes https://github.com/fastfetch-cli/fastfetch/issues/1974
2025-09-22 10:04:45 +08:00
李通洲 e95393750b Wifi (macOS): add (B)SSID detection back for Tohoe 26.0
Fixes #1874
2025-09-22 09:37:07 +08:00
李通洲 de9229697a TerminalFont: improve ghostty with command ghostty +show-config
Ref: #1972
2025-09-20 23:34:07 +08:00
NEOAPPS 9d23d28594 Logo (Builtin): update ObsidianOS logo (#1970)
* feat(logos): add new ObsidianOS logo

* feat(logos): update colors

* chore: remove internal paddings since they're not allowed
2025-09-20 23:02:25 +08:00
李通洲 57a4b9b6ed Disk: refactors mountpoint matching to use shared string utilities 2025-09-19 14:54:13 +08:00
李通洲 ef3989d18d CommandOption: refactors code with ffStrbufSeparatedContainIgnCaseS 2025-09-19 14:51:31 +08:00
李通洲 3079b44f63 FFstrbuf: adds more functions to match separated strings
1. ffStrbufMatchSeparatedIgnCaseNS
2. ffStrbufSeparatedContainNS
3. ffStrbufSeparatedContainNS
2025-09-19 14:34:27 +08:00
李通洲 403900639c Gamepad / Keyboard / Mouse: improves device error handling and memory cleanup 2025-09-19 13:36:02 +08:00
李通洲 0bb5b4cc9c Gamepad / Keyboard / Mouse: adds support to ignore input devices by name prefix
Fixes #1950
2025-09-19 11:00:18 +08:00
李通洲 1180eb55a4 Logo (Builtin): adds TempleOS
Fixes #1969
2025-09-19 09:46:23 +08:00
李通洲 f0e9caaf04 Disk: allows array input for disk folder and filesystem options 2025-09-18 14:51:00 +08:00
李通洲 2c22c3b0c0 CI (Windows): add chafa dependency 2025-09-18 13:44:51 +08:00
李通洲 e9065e15e8 TerminalFont: Improves Ghostty font config parsing with fallback font detection
Fixes #1967
2025-09-18 10:30:28 +08:00
李通洲 9e7816069b Revert "Logo (Builtin): add Starry Linux"
Ref: #1963

This reverts commit 4df4a1de78.
2025-09-17 16:09:05 +08:00
李通洲 82cdc4cd91 Disk (Linux): avoids invalid disk creation times before Linux epoch
Prevent fastfetch from printing invalid create date on Android
2025-09-17 15:37:51 +08:00
Carter Li 822ddc6dc6 Disk (Linux): replace statx(2) call to syscall(2) 2025-09-17 15:09:39 +08:00
李通洲 8bd171a9ff CI: adds glibc polyfill step for compatibility 2025-09-17 14:28:40 +08:00
李通洲 509d6bf30c CI: merge more jobs 2025-09-17 14:00:23 +08:00
李通洲 ab8a13b2d3 CI: update cmake version 2025-09-17 10:39:59 +08:00
Carter Li 3bcdcc5dbf CI: merge amd64 and aarch64 code with matrix 2025-09-16 16:28:45 +08:00
李通洲 38f4215a94 CPU (Windows): trims vendor string read from registry 2025-09-16 10:55:17 +08:00
李通洲 e3eec3f62a CPU (Windows): handles zero temperature data and refactors value use
Fixes #1960
2025-09-14 19:39:17 +08:00
李通洲 e025f28cdc Wifi (macOS): removes wdutil-based Wi-Fi detection code
Let's stop this hide and seek game.
2025-09-12 14:28:01 +08:00
李通洲 3ece4e3b4d Presets: add a new example [ci skip] 2025-09-12 14:11:41 +08:00
Carter Li 6d72a32d1d 3rdparty: upgrade widecharwidth 2025-09-11 14:54:25 +08:00
Carter Li 45be29bad3 CPU (Linux): replaces HWCAP defines with explicit bitmasks for ARM 2025-09-11 14:02:41 +08:00
李通洲 6f5e618341 CPU (Linux): add new ARM part numbers 2025-09-10 14:32:07 +08:00
李通洲 1abfa70237 LocalIP: adds IPv6 type selection for local IP display
`{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`

Fixes #1459
2025-09-10 13:42:48 +08:00
李通洲 baaeef5ab5 Separator: uses widecharwidth for Unicode wcwidth and fixes issue that wchar_t on Windows is 2-byte length 2025-09-10 10:34:07 +08:00
李通洲 8eafec479e Separator: rename property length with times 2025-09-09 09:52:10 +08:00
李通洲 5f9e7c799a OpenGL (Windows): simplifies code by removing custom window proc
Adds more cleanups
2025-09-08 00:06:49 +08:00
Carter Li aeb1722eb9 Packaging: update debian stuff [ci skip] 2025-09-05 15:12:49 +08:00
Carter Li de18a07938 Release: v2.52.0 2025-09-05 13:04:53 +08:00
李通洲 88147f80ac Doc: update changelog 2025-09-05 12:38:14 +08:00
李通洲 505ff6ff65 Global: renames fractionTrailingZeros enum to always/never for consistance 2025-09-05 12:27:03 +08:00
李通洲 390549394d Fastfetch: removes redundant assignment in display config parsing
found by copilot
2025-09-05 11:08:37 +08:00
Carter Li f7e7d54c16 Release: v2.52.0 2025-09-05 10:46:30 +08:00
Carter Li 5e068d22c8 Btrfs (Linux): refactors Btrfs allocation to use profile string
Fixes #1941
2025-09-05 10:46:23 +08:00
李通洲 b77646f23e Btrfs (Linux): adds tracking of Btrfs data copy counts
Fixes(?) #1941
2025-09-05 00:18:00 +08:00
李通洲 aa40366a49 Terminal: ignores WSL2 unknown process for terminal detection 2025-09-04 22:31:59 +08:00
Carter Li a64a82f215 WMTheme (Linux): supports labwc on XFCE4 2025-09-04 18:50:23 +08:00
Qing Yun 0a4d6220e9 CPU (Linux): add cpu name detection for ia64 2025-09-04 18:34:14 +08:00
李通洲 6b037c595f Doc: update README 2025-09-04 16:36:55 +08:00
李通洲 f628f5c382 Settings: renames GNOME settings accessor for clarity 2025-09-04 16:17:01 +08:00
李通洲 cf713e32e1 Wallpaper (Linux): improves XFCE wallpaper detection via property enumeration 2025-09-04 13:54:49 +08:00
Carter Li 7d08f81075 Settings: removes direct XFConf support in favor of DBus backend 2025-09-04 09:43:57 +08:00
Carter Li 8822653335 DBus: adds function ffDBusGetInt 2025-09-04 09:35:52 +08:00
李通洲 75ff054255 Dbus: adds 2nd argument to ffDBusGetMethodReply 2025-09-04 08:45:09 +08:00
李通洲 c51cc8ce6b CI: bump dependencies 2025-09-03 16:01:09 +08:00
李通洲 44e23412b5 Doc: update changelog 2025-09-03 16:01:09 +08:00
李通洲 59742bca00 Fastfetch: improves frequency display config validation and schema 2025-09-03 16:01:09 +08:00
李通洲 303edb97ce Fastfetch: add option --faction-trailing-zeros 2025-09-03 14:20:23 +08:00
李通洲 37ab380a6f Logo (Chafa): fixes setting logo.width with chafa
Regression in v2.51.0

Fixes #1947
2025-09-03 10:49:58 +08:00
Carter Li a06e245c34 JsonSchema: update 2025-09-03 09:58:50 +08:00
Carter Li 5de432b083 Fastfetch: defaults display.fraction.ndigits to 2 2025-09-03 09:58:40 +08:00
Carter Li 817285ac01 Fastfetch: informs users that module-specific CLI options are no longer supported
... and provides guidance on transitioning to JSON config
2025-09-03 09:36:16 +08:00
李通洲 8687505505 LocalIP (Linux): skips interfaces without IPs unless MAC display is enabled 2025-09-02 15:00:35 +08:00
李通洲 34c34d25c4 JsonConfig: fixes fractionNdigits will be incorrectly set to 0 when specifying null 2025-09-02 14:44:15 +08:00
李通洲 21b15ee944 Display: rearranges default format; removes scaled resolution 2025-09-02 14:15:37 +08:00
李通洲 8e0a65126e LocalIP: honors fractionTrailingZeros 2025-09-02 14:13:37 +08:00
李通洲 54d8b0a95d Global: adds configurable trailing zeros for double formatting 2025-09-02 14:12:58 +08:00
李通洲 48fc72e95c DisplayServer: improves display size rounding and argument clarity 2025-09-02 09:36:19 +08:00
Carter Li e3d6a85888 Display (Linux): detect scale factor for X11 2025-09-01 21:20:34 +08:00
李通洲 7d92da8829 Global (Android): enable X11 related stuff 2025-09-01 16:28:13 +08:00
李通洲 2f3a361b1f CMake: enable zlib on all platforms 2025-09-01 09:59:06 +08:00
李通洲 ac71f21e6c DisplayServer (Android): update WM name accurately
See #1933
2025-08-30 14:14:48 +08:00
李通洲 8d5316f6aa CMake (Android): link to libm
Fix #1939
2025-08-30 13:31:37 +08:00
Carter Li 1242fda66f Merge pull request #1938 from fastfetch-cli/dev
Release: v2.51.1
2025-08-29 14:05:34 +08:00
李通洲 5a2b618d27 Release: v2.51.1 2025-08-29 13:55:52 +08:00
李通洲 d836d7569f CPU (macOS): removes reliance on unavailable ARM capability headers on macOS
Fixes https://github.com/Homebrew/homebrew-core/pull/235425
2025-08-29 13:45:16 +08:00
Carter Li 8a412e6823 Packaging: update debian stuff [ci skip] 2025-08-29 08:56:30 +08:00
96 changed files with 3948 additions and 1778 deletions
+97 -297
View File
@@ -38,7 +38,7 @@ jobs:
run: uname -a
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -61,12 +61,19 @@ jobs:
- name: run tests
run: ctest --output-on-failure
linux-amd64:
name: Linux-amd64
runs-on: ubuntu-22.04
linux-hosts:
name: Linux-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: amd64
runs-on: ubuntu-22.04
- arch: aarch64
runs-on: ubuntu-22.04-arm
outputs:
ffversion: ${{ steps.ffversion.outputs.ffversion }}
steps:
@@ -83,25 +90,27 @@ jobs:
run: cat /proc/cpuinfo
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
- name: Initialize CodeQL
if: matrix.arch == 'amd64'
uses: github/codeql-action/init@v3
with:
languages: c
- name: configure project
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
if: matrix.arch == 'amd64'
uses: github/codeql-action/analyze@v3
- name: list features
@@ -126,71 +135,19 @@ jobs:
id: ffversion
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-amd64
path: ./fastfetch-*.*
linux-aarch64:
name: Linux-aarch64
runs-on: ubuntu-22.04-arm
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: uname -a
run: uname -a
- name: cat /etc/os-release
run: cat /etc/os-release
- name: cat /proc/cpuinfo
run: cat /proc/cpuinfo
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
- name: install linuxbrew packages
- name: polyfill glibc
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
- name: configure project
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: ldd fastfetch
- name: run tests
run: ctest --output-on-failure
- name: get fastfetch version
id: ffversion
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
wget https://github.com/CarterLi/polyfill-glibc/releases/download/v0.0.1/polyfill-glibc-${{ matrix.arch }} -O polyfill-glibc
chmod +x polyfill-glibc
strip fastfetch && ./polyfill-glibc fastfetch --target-glibc=2.17
strip flashfetch && ./polyfill-glibc flashfetch --target-glibc=2.17
echo 'set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-polyfilled")' >> CPackConfig.cmake
cpack
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-aarch64
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
linux-armv7l:
@@ -212,11 +169,11 @@ jobs:
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y wget
# CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments`
wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb}
dpkg -i *.deb
apt-get install -y make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
apt-get update && apt-get install -y ca-certificates gpg curl
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -252,7 +209,7 @@ jobs:
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 ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -268,12 +225,18 @@ jobs:
name: fastfetch-linux-armv6l
path: ./fastfetch-*.*
linux-riscv64:
name: Linux-riscv64
runs-on: ubuntu-24.04
linux-vms:
name: Linux-${{ matrix.arch }}
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: riscv64
- arch: ppc64le
- arch: s390x
steps:
- name: checkout repository
uses: actions/checkout@v5
@@ -282,47 +245,12 @@ jobs:
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: riscv64
distro: ubuntu22.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 ocl-icd-opencl-dev libpulse-dev libdrm-dev libddcutil-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 --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-riscv64
path: ./fastfetch-*.*
linux-ppc64le:
name: Linux-ppc64le
runs-on: ubuntu-24.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: ppc64le
arch: ${{ matrix.arch }}
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 ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -335,42 +263,7 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-ppc64le
path: ./fastfetch-*.*
linux-s390x:
name: Linux-s390x
runs-on: ubuntu-24.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: s390x
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 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 --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-s390x
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
musl-amd64:
@@ -386,7 +279,7 @@ jobs:
run: |
cat /etc/alpine-release
uname -a
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
shell: alpine.sh --root {0}
- name: build
@@ -411,12 +304,19 @@ jobs:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
macos-amd64:
name: macOS-amd64
runs-on: macos-13
macos-hosts:
name: macOS-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: amd64
runs-on: macos-15-intel
- arch: aarch64
runs-on: macos-latest
steps:
- name: checkout repository
uses: actions/checkout@v5
@@ -455,54 +355,7 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-amd64
path: ./fastfetch-*.*
macos-aarch64:
name: macOS-aarch64
runs-on: macos-latest
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: uname -a
run: uname -a
- name: install required packages
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: otool -L fastfetch
- name: run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-aarch64
name: fastfetch-macos-${{ matrix.arch }}
path: ./fastfetch-*.*
sunos-amd64:
@@ -560,7 +413,7 @@ jobs:
run: |
uname -a
sudo pkg update
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -596,7 +449,7 @@ jobs:
version: '7.7'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -665,7 +518,7 @@ jobs:
prepare: |
uname -a
pkg update
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
@@ -718,12 +571,25 @@ jobs:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
windows-amd64:
name: Windows-amd64
runs-on: windows-latest
windows-hosts:
name: Windows-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: amd64
runs-on: windows-latest
msystem: CLANG64
msystem-lower: clang64
msys-arch: x86_64
- arch: aarch64
runs-on: windows-11-arm
msystem: CLANGARM64
msystem-lower: clangarm64
msys-arch: aarch64
defaults:
run:
shell: msys2 {0}
@@ -734,21 +600,21 @@ jobs:
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: CLANG64
msystem: ${{ matrix.msystem }}
update: true
install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd mingw-w64-clang-x86_64-opencl-headers mingw-w64-clang-x86_64-cppwinrt mingw-w64-clang-x86_64-imagemagick
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa
- name: print msys version
run: uname -a
- name: configure project
run: env PKG_CONFIG_PATH=/clang64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose -j4
- name: copy necessary dlls
run: cp /clang64/bin/{OpenCL,vulkan-1}.dll .
run: cp /${{ matrix.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll .
- name: list features
run: ./fastfetch --list-features
@@ -769,101 +635,35 @@ jobs:
run: ctest --output-on-failure
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-amd64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-amd64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-amd64
path: ./fastfetch-windows-amd64.*
windows-aarch64:
name: Windows-aarch64
runs-on: windows-11-arm
permissions:
security-events: write
contents: read
defaults:
run:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: CLANGARM64
update: true
install: git mingw-w64-clang-aarch64-7zip mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-vulkan-loader mingw-w64-clang-aarch64-vulkan-headers mingw-w64-clang-aarch64-opencl-icd mingw-w64-clang-aarch64-opencl-headers mingw-w64-clang-aarch64-cppwinrt mingw-w64-clang-aarch64-imagemagick
- name: print msys version
run: uname -a
- name: configure project
run: env PKG_CONFIG_PATH=/clangarm64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose -j4
- name: copy necessary dlls
run: cp /clangarm64/bin/{OpenCL,vulkan-1}.dll .
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: ldd fastfetch
- name: run tests
run: ctest --output-on-failure
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-aarch64
path: ./fastfetch-windows-aarch64.*
name: fastfetch-windows-${{ matrix.arch }}
path: ./fastfetch-windows-${{ matrix.arch }}.*
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
name: Release
runs-on: ubuntu-latest
needs:
- linux-amd64
- linux-aarch64
- linux-hosts
- linux-armv7l
- linux-armv6l
- linux-riscv64
- linux-ppc64le
- linux-s390x
- linux-vms
- musl-amd64
- macos-amd64
- macos-aarch64
- macos-hosts
- freebsd-amd64
- openbsd-amd64
- netbsd-amd64
- dragonfly-amd64
- sunos-amd64
- haiku-amd64
- windows-amd64
- windows-aarch64
- windows-hosts
permissions:
contents: write
steps:
@@ -874,29 +674,29 @@ jobs:
repository: ${{ github.repository }}
- name: download artifacts
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v4
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v5
- name: create release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux-amd64.outputs.ffversion }}
tag: ${{ needs.linux-hosts.outputs.ffversion }}
commit: ${{ github.sha }}
artifactErrorsFailBuild: true
artifacts: fastfetch-*/fastfetch-*
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details."
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details."
- name: download source tarballs
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
run: |
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-amd64.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-hosts.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
ls fastfetch-*/*
- name: generate release notes
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
run: |
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
@@ -905,10 +705,10 @@ jobs:
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
- name: update release body
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux-amd64.outputs.ffversion }}
tag: ${{ needs.linux-hosts.outputs.ffversion }}
commit: ${{ github.sha }}
bodyFile: fastfetch-release-notes.md
allowUpdates: true
+66
View File
@@ -1,3 +1,69 @@
# 2.53.0
Changes:
* JSON property `length` in `Separator` module has been renamed to `times` for clarity (Separator)
Features:
* Adds IPv6 type selection (#1459, LocalIP)
* For example: `{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`
* Adds more ARM CPU part IDs (CPU, Linux)
* Improves Ghostty font config parsing with fallback font detection (#1967, TerminalFont)
* Replaces statx(2) call with syscall(2) for better compatibility (Disk, Linux)
* Allows array input for disk folder and filesystem options (Disk)
* For example: `{ "type": "disk", "folders": ["/", "/home"] }`
* Adds support for ignoring input devices by name prefix (#1950, Keyboard / Mouse / Gamepad)
* For example: `{ "type": "keyboard", "ignores": ["Apple ", "Corsair "] }`
* Adds support for (B)SSID detection on macOS Tahoe (Wifi, macOS)
* Please don't expect it to work on later macOS versions
* Improves Ubuntu flavor detection (#1975, OS, Linux)
* Refines ARMv8.4-A detection to require LSE2 (CPU, Windows)
* Detects the latest Dimensity & Snapdragon SoC names (CPU, Android)
Bugfixes:
* Handles zero temperature data (#1960, CPU, Windows)
* Fixes `dlopen libzfs.so failed` error on Proxmox 9 (#1973, Zpool, Linux)
Logos:
* Removes Starry Linux
* Adds TempleOS
* Updates ObsidianOS
# 2.52.0
Changes:
* New optional build dependencies on Android
* main: chafa dbus glib imagemagick libelf libxcb libxrandr pulseaudio zlib
* x11: dconf (Optional)
* Dependency on `libxfconf` is removed. XFCE related detection now uses `libdbus` instead (Linux)
* The default format of `Display` module is updated to `{width}x{height} @ {scale-factor}x in {inch}", {refresh-rate} Hz`
* Replaced scaled resolution with scale factor for shorter texts and avoiding potential confusion.
Bugfixes:
* Fixes linking on 32-bit Android (#1939)
* Skips network interfaces without IPs unless MAC address is requested (#1949, LocalIP)
* Fixes unexpected padding when setting `logo.width` with chafa logos (#1947, Logo)
* Regression from v2.51.0
* Improves Wallpaper detection on XFCE4 (Wallpaper, Linux)
* Ignores process `Relay(xxx)` when detecting terminal on WSL2 (Terminal, Linux)
Features:
* Enables X11-related info (i.e., WM/DE) detection on Android (Global, Android)
* This requires many dependencies. See above.
* Adds scale factors detection for X11 (Display, Linux)
* X11 doesn't natively report scale factor as Wayland does. Instead, Fastfetch tries to detect `Xft.dpi` (DPI used by X FreeType for scaling fonts), which is usually set by the WM when DPI scaling is enabled.
* It's not always accurate. For example, XFCE4 has a separate config for text scaling, which is unaffected by the global DPI scaling setting.
* Adds `display.fraction.trailingZeros: [always|never]` option for fraction formatting
* The default value of `display.fraction.ndigits` is changed from `-1` (unlimited) to `2` for usability.
* Used for displaying scale factor in Display module mentioned above, alongside other places for printing raw fraction numbers.
* Informs users that module-specific CLI options are no longer supported and provide guidance for transitioning to JSON config
* Adds CPU name detection support for IA64 (CPU, Linux)
* Support Btrfs allocation profile detection (#1941, Btrfs, Linux)
# 2.51.1
Bugfixes:
* Fix building on macOS 14 or older; no functional changes (CPU, macOS)
# 2.51.0
Changes:
+37 -32
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.51.0
VERSION 2.53.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -60,25 +60,23 @@ include(CMakeDependentOption)
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR GNU" OFF)
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD OR GNU" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_XFCONF "Enable libxfconf-0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX OR GNU" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS OR GNU" 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 ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR GNU" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR ANDROID OR GNU" OFF)
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
@@ -86,6 +84,7 @@ cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND"
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
option(ENABLE_ZLIB "Enable zlib" ON)
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)
@@ -515,6 +514,7 @@ if(LINUX)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_linux.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -575,6 +575,7 @@ if(LINUX)
)
elseif(ANDROID)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_linux.c
src/common/networking/networking_linux.c
@@ -590,7 +591,7 @@ elseif(ANDROID)
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_linux.c
src/detection/cpucache/cpucache_linux.c
src/detection/cursor/cursor_nosupport.c
src/detection/cursor/cursor_linux.c
src/detection/cpuusage/cpuusage_linux.c
src/detection/disk/disk_linux.c
src/detection/dns/dns_linux.c
@@ -598,10 +599,16 @@ elseif(ANDROID)
src/detection/physicalmemory/physicalmemory_nosupport.c
src/detection/diskio/diskio_linux.c
src/detection/displayserver/displayserver_android.c
src/detection/font/font_nosupport.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/gtk_qt/gtk.c
src/detection/gtk_qt/qt.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_android.c
src/detection/host/host_android.c
src/detection/icons/icons_nosupport.c
src/detection/icons/icons_linux.c
src/detection/initsystem/initsystem_linux.c
src/detection/keyboard/keyboard_nosupport.c
src/detection/libc/libc_android.c
@@ -610,7 +617,7 @@ elseif(ANDROID)
src/detection/locale/locale_linux.c
src/detection/localip/localip_linux.c
src/detection/gamepad/gamepad_nosupport.c
src/detection/media/media_nosupport.c
src/detection/media/media_linux.c
src/detection/memory/memory_linux.c
src/detection/mouse/mouse_nosupport.c
src/detection/netio/netio_linux.c
@@ -620,20 +627,21 @@ elseif(ANDROID)
src/detection/packages/packages_nix.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/sound/sound_nosupport.c
src/detection/sound/sound_linux.c
src/detection/swap/swap_linux.c
src/detection/terminalfont/terminalfont_android.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_nosupport.c
src/detection/theme/theme_linux.c
src/detection/tpm/tpm_nosupport.c
src/detection/uptime/uptime_linux.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_nosupport.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_android.c
src/detection/wm/wm_nosupport.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_nosupport.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_android.c
src/detection/zpool/zpool_nosupport.c
src/util/platform/FFPlatform_unix.c
@@ -665,6 +673,7 @@ elseif(FreeBSD)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_bsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -759,6 +768,7 @@ elseif(NetBSD)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_nbsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -841,6 +851,7 @@ elseif(OpenBSD)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_obsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -1069,6 +1080,7 @@ elseif(SunOS)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_sunos.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -1220,6 +1232,7 @@ elseif(GNU)
src/detection/physicalmemory/physicalmemory_nosupport.c
src/detection/diskio/diskio_nosupport.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -1291,10 +1304,7 @@ endif()
include(CheckFunctionExists)
check_function_exists(wcwidth HAVE_WCWIDTH)
if(NOT HAVE_WCWIDTH)
list(APPEND LIBFASTFETCH_SRC src/3rdparty/mk_wcwidch/wcwidth.c)
endif()
if(LINUX)
check_function_exists(statx HAVE_STATX)
list(APPEND LIBFASTFETCH_SRC src/util/wcwidth.c)
endif()
if(NOT WIN32)
check_function_exists(pipe2 HAVE_PIPE2)
@@ -1411,10 +1421,6 @@ if(FreeBSD OR OpenBSD OR NetBSD)
unset(CMAKE_REQUIRED_DEFINITIONS)
endif()
if(HAVE_STATX)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_STATX)
endif()
if(HAVE_WCWIDTH)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WCWIDTH)
endif()
@@ -1525,10 +1531,6 @@ ff_lib_enable(DBUS
"dbus-1"
"DBus"
)
ff_lib_enable(XFCONF
"libxfconf-0"
"XFConf"
)
ff_lib_enable(SQLITE3
"sqlite3"
"SQLite3"
@@ -1728,6 +1730,9 @@ elseif(GNU)
PRIVATE "m"
)
elseif(ANDROID)
target_link_libraries(libfastfetch
PRIVATE "m"
)
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
if(HAVE_LIBANDROID_WORDEXP_STATIC)
target_link_libraries(libfastfetch
+18
View File
@@ -1,3 +1,21 @@
fastfetch (2.53.0) jammy; urgency=medium
* Update to 2.53.0
-- Carter Li <zhangsongcui@live.cn> Tue, 23 Sep 2025 09:58:48 +0800
fastfetch (2.52.0) jammy; urgency=medium
* Update to 2.52.0
-- Carter Li <zhangsongcui@live.cn> Fri, 05 Sep 2025 14:59:44 +0800
fastfetch (2.51.0) jammy; urgency=medium
* Update to 2.51.0
-- Carter Li <zhangsongcui@live.cn> Fri, 29 Aug 2025 08:55:03 +0800
fastfetch (2.50.2) jammy; urgency=medium
* Update to 2.50.2
+1 -1
View File
@@ -2,7 +2,7 @@ Source: fastfetch
Section: universe/utils
Priority: optional
Maintainer: Carter Li <zhangsongcui@live.cn>
Build-Depends: libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libxfconf-0-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
Standards-Version: 4.0.0
Homepage: https://github.com/fastfetch-cli/fastfetch
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.50.2_source.buildinfo universe/utils optional
fastfetch_2.53.0_source.buildinfo universe/utils optional
+139 -13
View File
@@ -1290,10 +1290,19 @@
"description": "Set how frequency values should be displayed",
"properties": {
"ndigits": {
"type": "integer",
"description": "Set the number of digits to keep after the decimal point when formatting frequency values\nA positive value will show the frequency in GHz with decimal\n-1 will show the frequency in MHz",
"minimum": -1,
"maximum": 9,
"description": "Set the number of decimal places to display when formatting frequency values",
"oneOf": [
{
"type": "integer",
"minimum": 0,
"maximum": 9,
"description": "Integer value displays the frequency in GHz with specified decimal places"
},
{
"type": "null",
"description": "Null value display the frequency as integer MHz"
}
],
"default": 2
},
"spaceBeforeUnit": {
@@ -1333,6 +1342,28 @@
"description": "The number of digits will be automatically determined based on the value"
}
],
"default": 2
},
"trailingZeros": {
"description": "Set when to keep trailing zeros",
"oneOf": [
{
"type": "null",
"description": "Same as `default`"
},
{
"const": "default",
"description": "Use the behavior defined internally"
},
{
"const": "always",
"description": "Always keep trailing zeros"
},
{
"const": "never",
"description": "Never keep trailing zeros"
}
],
"default": null
}
}
@@ -2276,17 +2307,60 @@
"const": "disk"
},
"folders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
"description": "A list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options",
"oneOf": [
{
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to get disk usage from",
"default": "/"
},
{
"type": "array",
"description": "An array of folder paths to get disk usage from",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"hideFolders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
"description": "A list of folder paths to hide from the disk output",
"oneOf": [
{
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output"
},
{
"type": "array",
"description": "An array of folder paths to hide from the disk output",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
],
"default": "/efi:/boot:/boot/efi:/boot/firmware"
},
"hideFS": {
"type": "string",
"description": "A colon separated file systems to hide from the disk output"
"description": "A list of file systems to hide from the disk output",
"oneOf": [
{
"type": "string",
"description": "A colon separated list of file systems to hide from the disk output"
},
{
"type": "array",
"description": "An array of file systems to hide from the disk output",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"showRegular": {
"type": "boolean",
@@ -2562,6 +2636,15 @@
"const": "gamepad",
"description": "List connected gamepads"
},
"ignores": {
"type": "array",
"description": "An array of case-insensitive device name prefixes to ignore",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"percent": {
"$ref": "#/$defs/percent"
},
@@ -2821,6 +2904,15 @@
"const": "keyboard",
"description": "List (connected) keyboards"
},
"ignores": {
"type": "array",
"description": "An array of case-insensitive device name prefixes to ignore",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"key": {
"$ref": "#/$defs/key"
},
@@ -2889,7 +2981,32 @@
},
"showIpv6": {
"description": "Show IPv6 addresses",
"type": "boolean",
"oneOf": [
{
"const": true,
"description": "Show the most useful IPv6 addresses"
},
{
"const": false,
"description": "Do not show IPv6 addresses"
},
{
"const": "gua",
"description": "Show only global unicast IPv6 addresses (2000::/3)"
},
{
"const": "ula",
"description": "Show only unique local IPv6 addresses (fc00::/7)"
},
{
"const": "lla",
"description": "Show only link-local IPv6 addresses (fe80::/10)"
},
{
"const": "unknown",
"description": "Show only IPv6 addresses that are not gua, ula or lla"
}
],
"default": false
},
"showSpeed": {
@@ -3119,6 +3236,15 @@
"const": "mouse",
"description": "List connected mouses"
},
"ignores": {
"type": "array",
"description": "An array of case-insensitive device name prefixes to ignore",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"key": {
"$ref": "#/$defs/key"
},
@@ -3656,8 +3782,8 @@
"description": "Set the color of the separator line",
"$ref": "#/$defs/outputColor"
},
"length": {
"description": "Set the length of the separator line, or 0 to auto-detect",
"times": {
"description": "Set the times of separator string to repeat, or 0 to auto-detect",
"type": "integer",
"minimum": 0,
"default": 0
+1 -1
View File
@@ -1,6 +1,6 @@
// #1887
{
"$schema": "file:///Users/carter/fastfetch/doc/json_schema.json",
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": null,
"display": {
"constants": [
+87
View File
@@ -0,0 +1,87 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": null,
"display": {
"key": {
"type": "both",
"paddingLeft": 6,
"width": 17
}
},
"modules": [
{
"type": "custom",
"format": "|---------------------: {#1}Hardware{#} : ---------------------|"
},
"break",
{
"keyColor": "green",
"type": "host"
},
{
"keyColor": "green",
"type": "cpu"
},
{
"keyColor": "yellow",
"type": "memory"
},
{
"keyColor": "yellow",
"type": "swap"
},
{
"type": "custom",
"keyIcon": "",
"key": "Disks"
},
{
"type": "disk",
"key": " ",
"format": " [{mountpoint}] - {size-used} / {size-total} ({size-percentage})"
},
"break",
{
"type": "title",
"format": "|-------------------------------------------------------|\u001b[40D: {#1}{user-name} @ {host-name}{#} :"
},
"break",
{
"type": "os",
"keyColor": "cyan"
},
{
"type": "kernel",
"keyColor": "cyan"
},
{
"type": "packages",
"keyColor": "red",
"key": "Pkgs"
},
{
"type": "shell",
"keyColor": "red"
},
{
"type": "terminal",
"key": "Term",
"keyColor": "red"
},
{
"type": "locale",
"keyColor": "magenta"
},
"break",
{
"type": "custom",
"format": "|---------------------: {#1}Software{#} : ---------------------|"
},
"break",
{
"type": "colors",
"symbol": "circle",
"paddingLeft": 8
}
]
}
-7
View File
@@ -1,7 +0,0 @@
{
"home": "https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c",
"license": "MIT compatible (embed in source)",
"version": "2007-05-26 (Unicode 5.0)",
"author": "Markus Kuhn",
"modified": "CarterLi"
}
-314
View File
@@ -1,314 +0,0 @@
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
#include <wchar.h>
struct interval {
int first;
int last;
};
/* auxiliary function for binary search in interval table */
static int bisearch(wchar_t ucs, const struct interval *table, int max) {
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that wchar_t characters are encoded
* in ISO 10646.
*/
int mk_wcwidth(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
#ifndef _WIN32 // sizeof(wchar_t) == 2
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd) ||
#endif
0
));
}
int mk_wcswidth(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
int mk_wcwidth_cjk(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
+6
View File
@@ -0,0 +1,6 @@
{
"home": "https://github.com/ridiculousfish/widecharwidth",
"license": "Public domain",
"version": "Unicode 17",
"author": "ridiculousfish"
}
File diff suppressed because it is too large Load Diff
+72 -20
View File
@@ -10,44 +10,96 @@
#include <ctype.h>
#include <inttypes.h>
bool ffParseModuleOptions(const char* key, const char* value)
{
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
if (value && !*value) value = NULL;
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
{
FFModuleBaseInfo* baseInfo = *modules;
const char* subKey = ffOptionTestPrefix(key, baseInfo->name);
if (subKey != NULL)
{
if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-'
{
fprintf(stderr, "Error: unknown module key %s\n", key);
exit(477);
}
FF_STRBUF_AUTO_DESTROY moduleName = ffStrbufCreateS(baseInfo->name);
ffStrbufLowerCase(&moduleName);
FF_STRBUF_AUTO_DESTROY jsonKey = ffStrbufCreate();
bool flag = false;
for (const char* p = subKey; *p; ++p)
{
if (*p == '-')
{
if (flag)
{
fprintf(stderr, "Error: invalid double `-` in module key %s\n", key);
exit(477);
}
flag = true;
}
else
{
if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p))
{
fprintf(stderr, "Error: invalid character `%c` in module key %s\n", *p, key);
exit(477);
}
if (flag)
{
flag = false;
ffStrbufAppendC(&jsonKey, (char) toupper((unsigned char) *p));
}
else
ffStrbufAppendC(&jsonKey, *p);
}
}
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr);
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ? value : "true", value ? "\"" : "");
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
exit(477);
}
}
return false;
}
void ffPrepareCommandOption(FFdata* data)
{
//If we don't have a custom structure, use the default one
if(data->structure.length == 0)
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
if(ffStrbufContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME, ':'))
ffPrepareCPUUsage();
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
if(instance.config.general.multithreading)
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME, ':'))
{
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
{
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
}
+1
View File
@@ -12,3 +12,4 @@ typedef struct FFdata
void ffPrepareCommandOption(FFdata* data);
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc);
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc);
bool ffParseModuleOptions(const char* key, const char* value);
+56 -3
View File
@@ -162,14 +162,67 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result)
return ffDBusGetUint(dbus, &subIter, result);
}
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg)
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result)
{
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
if(argType == DBUS_TYPE_INT16)
{
int16_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = value;
return true;
}
if(argType == DBUS_TYPE_INT32)
{
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
return true;
}
if(argType == DBUS_TYPE_BYTE)
{
uint8_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = value;
return true;
}
if(argType == DBUS_TYPE_UINT16)
{
uint16_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = (int16_t) value;
return true;
}
if(argType == DBUS_TYPE_UINT32)
{
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
return true;
}
if(argType != DBUS_TYPE_VARIANT)
return false;
DBusMessageIter subIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
return ffDBusGetInt(dbus, &subIter, result);
}
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2)
{
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
if(message == NULL)
return NULL;
if (arg)
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
if (arg1)
{
if (arg2)
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
else
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
}
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
+3 -2
View File
@@ -31,14 +31,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); //Returns an
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg);
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2);
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
{
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface);
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
}
#endif // FF_HAVE_DBUS
+2 -2
View File
@@ -32,10 +32,10 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_FLOAT:
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits);
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
break;
case FF_FORMAT_ARG_TYPE_DOUBLE:
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits);
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
break;
case FF_FORMAT_ARG_TYPE_BOOL:
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
+1 -1
View File
@@ -11,7 +11,7 @@ bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
if (ndigits >= 0)
{
ffStrbufAppendDouble(result, mhz / 1000., ndigits);
ffStrbufAppendDouble(result, mhz / 1000., ndigits, true);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
ffStrbufAppendS(result, "GHz");
}
-3
View File
@@ -208,9 +208,6 @@ void ffListFeatures(void)
#if FF_HAVE_ZLIB
"zlib\n"
#endif
#if FF_HAVE_XFCONF
"xfconf\n"
#endif
#if FF_HAVE_SQLITE3
"sqlite3\n"
#endif
+126 -52
View File
@@ -184,7 +184,7 @@ FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type)
}
#endif //FF_HAVE_DCONF
FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
{
FFvariant gsettings = ffSettingsGetGSettings(gsettingsSchemaName, gsettingsPath, gsettingsKey, type);
@@ -196,77 +196,151 @@ FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, c
return ffSettingsGetDConf(dconfKey, type);
}
#ifdef FF_HAVE_XFCONF
#include <xfconf/xfconf.h>
typedef struct XFConfData
{
FF_LIBRARY_SYMBOL(xfconf_channel_get)
FF_LIBRARY_SYMBOL(xfconf_channel_has_property)
FF_LIBRARY_SYMBOL(xfconf_channel_get_string)
FF_LIBRARY_SYMBOL(xfconf_channel_get_bool)
FF_LIBRARY_SYMBOL(xfconf_channel_get_int)
FF_LIBRARY_SYMBOL(xfconf_init)
bool inited;
} XFConfData;
static const XFConfData* getXFConfData(void)
{
static XFConfData data;
if (!data.inited)
{
data.inited = true;
FF_LIBRARY_LOAD(libxfconf, NULL, "libxfconf-0" FF_LIBRARY_EXTENSION, 4);
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_has_property, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_string, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_bool, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_int, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_init, NULL)
if(!data.ffxfconf_init(NULL))
data.ffxfconf_init = NULL;
else
libxfconf = NULL;
}
if(!data.ffxfconf_init)
return NULL;
return &data;
}
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
{
const XFConfData* data = getXFConfData();
if(data == NULL)
FFDBusData dbus;
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return FF_VARIANT_NULL;
XfconfChannel* channel = data->ffxfconf_channel_get(channelName); // Never fails according to documentation but rather returns an empty channel
if(!data->ffxfconf_channel_has_property(channel, propertyName))
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetProperty", channelName, propertyName);
if(!reply)
return FF_VARIANT_NULL;
DBusMessageIter rootIterator;
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
{
dbus.lib->ffdbus_message_unref(reply);
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_INT)
return (FFvariant) {.intValue = data->ffxfconf_channel_get_int(channel, propertyName, 0)};
{
int32_t value;
if (ffDBusGetInt(&dbus, &rootIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .intValue = value };
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_STRING)
return (FFvariant) {.strValue = data->ffxfconf_channel_get_string(channel, propertyName, NULL)};
{
FFstrbuf value = ffStrbufCreate();
if (ffDBusGetString(&dbus, &rootIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_BOOL)
return (FFvariant) {.boolValue = data->ffxfconf_channel_get_bool(channel, propertyName, false), .boolValueSet = true};
{
bool value;
if (ffDBusGetBool(&dbus, &rootIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .boolValue = value, .boolValueSet = true };
}
}
return FF_VARIANT_NULL;
}
#else //FF_HAVE_XFCONF
#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
{ \
if(!(dbus).lib->ffdbus_message_iter_next(iterator)) \
break; \
continue; \
}
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
{
FFDBusData dbus;
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return FF_VARIANT_NULL;
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetAllProperties", channelName, propertyPrefix);
if(!reply)
return FF_VARIANT_NULL;
DBusMessageIter rootIterator;
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
{
dbus.lib->ffdbus_message_unref(reply);
return FF_VARIANT_NULL;
}
DBusMessageIter arrayIterator;
dbus.lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
while(true)
{
if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
DBusMessageIter dictIterator;
dbus.lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
const char* key;
dbus.lib->ffdbus_message_iter_get_basic(&dictIterator, &key);
if (cb(data, key)) FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
dbus.lib->ffdbus_message_iter_next(&dictIterator);
if(type == FF_VARIANT_TYPE_INT)
{
int32_t value;
if (ffDBusGetInt(&dbus, &dictIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .intValue = value };
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_STRING)
{
FFstrbuf value = ffStrbufCreate();
if (ffDBusGetString(&dbus, &dictIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_BOOL)
{
bool value;
if (ffDBusGetBool(&dbus, &dictIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .boolValue = value, .boolValueSet = true };
}
}
return FF_VARIANT_NULL;
}
return FF_VARIANT_NULL;
}
#else //FF_HAVE_DBUS
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
{
FF_UNUSED(channelName, propertyName, type)
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_XFCONF
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
{
FF_UNUSED(channelName, propertyPrefix, type, data, cb);
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_DBUS
#ifdef FF_HAVE_SQLITE3
#include <sqlite3.h>
+3 -1
View File
@@ -24,8 +24,10 @@ typedef union FFvariant
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type);
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type);
FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type);
typedef bool FFTestXfconfPropCallback(void* data, const char* propertyName); // Return false to break loop
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb);
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query);
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result);
+1 -1
View File
@@ -17,7 +17,7 @@ static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const cha
if (counter == 0)
ffStrbufAppendUInt(result, bytes);
else
ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits);
ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits, true);
if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER)
ffStrbufAppendC(result, ' ');
ffStrbufAppendS(result, prefixes[counter]);
+12
View File
@@ -846,6 +846,18 @@
"default": -1
}
},
{
"long": "fraction-trailing-zeros",
"desc": "Set when to keep trailing zeros",
"arg": {
"type": "enum",
"enum": {
"default": "Use the behavior defined internally",
"always": "Always keep trailing zeros",
"never": "Never keep trailing zeros"
}
}
},
{
"long": "temp-unit",
"desc": "Set the temperature unit",
+1 -1
View File
@@ -196,7 +196,7 @@ static const char* detectBluetooth(FFlist* devices, int32_t connectedCount)
if(error)
return error;
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL);
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL, NULL);
if(!managedObjects)
return "Failed to call GetManagedObjects";
@@ -77,7 +77,7 @@ static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const cha
char objPath[300];
snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName);
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1");
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1", NULL);
if(!properties)
return "Failed to call org.freedesktop.DBus.Properties.GetAll";
+2 -1
View File
@@ -8,7 +8,8 @@ typedef struct FFBtrfsDiskUsage
uint64_t total;
uint64_t used;
const char* type;
bool dup;
const char* profile; // single / dup / raidx
uint8_t copies;
} FFBtrfsDiskUsage;
typedef struct FFBtrfsResult
+33 -13
View File
@@ -73,20 +73,40 @@ static const char* detectAllocation(FFBtrfsResult* item, int dfd, FFstrbuf* buff
item->globalReservationUsed = ffStrbufToUInt(buffer, 0);
item->globalReservationUsed = item->globalReservationTotal - item->globalReservationUsed;
#define FF_BTRFS_DETECT_TYPE(index, _type) \
if (ffReadFileBufferRelative(subfd, #_type "/total_bytes", buffer)) \
item->allocation[index].total = ffStrbufToUInt(buffer, 0); \
\
if (ffReadFileBufferRelative(subfd, #_type "/bytes_used", buffer)) \
item->allocation[index].used = ffStrbufToUInt(buffer, 0); \
\
item->allocation[index].dup = faccessat(subfd, #_type "/dup/", F_OK, 0) == 0; \
\
item->allocation[index].type = #_type;
#define FF_BTRFS_DETECT_PROFILE(_index, _type, _profile, _copies) \
else if (faccessat(subfd, _type "/" _profile "/", F_OK, 0) == 0) { \
item->allocation[_index].profile = _profile; \
item->allocation[_index].copies = _copies; \
}
FF_BTRFS_DETECT_TYPE(0, data);
FF_BTRFS_DETECT_TYPE(1, metadata);
FF_BTRFS_DETECT_TYPE(2, system);
#define FF_BTRFS_DETECT_TYPE(_index, _type) \
do { \
item->allocation[_index].type = _type; \
if (ffReadFileBufferRelative(subfd, _type "/total_bytes", buffer)) \
item->allocation[_index].total = ffStrbufToUInt(buffer, 0); \
\
if (ffReadFileBufferRelative(subfd, _type "/bytes_used", buffer)) \
item->allocation[_index].used = ffStrbufToUInt(buffer, 0); \
\
if (false) {} \
FF_BTRFS_DETECT_PROFILE(_index, _type, "single", 1) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "dup", 2) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid0", 1) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1", 2) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid10", 2) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c3", 3) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c4", 4) \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid5", 1) /* (n-1)/n */ \
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid6", 1) /* (n-2)/n */ \
else { \
item->allocation[_index].profile = "unknown"; \
item->allocation[_index].copies = 1; \
} \
} while (0)
FF_BTRFS_DETECT_TYPE(0, "data");
FF_BTRFS_DETECT_TYPE(1, "metadata");
FF_BTRFS_DETECT_TYPE(2, "system");
#undef FF_BTRFS_DETECT_TYPE
+64 -108
View File
@@ -132,35 +132,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
#ifdef __linux__
#include "common/io/io.h"
#include <elf.h>
#include <asm/hwcap.h>
#ifndef HWCAP2_SME
#define HWCAP2_SME (1UL << 23)
#endif
#ifndef HWCAP2_SME2
#define HWCAP2_SME2 (1UL << 37)
#endif
#ifndef HWCAP2_CSSC
#define HWCAP2_CSSC (1UL << 34)
#endif
#ifndef HWCAP2_SME2P1
#define HWCAP2_SME2P1 (1UL << 38)
#endif
#ifndef HWCAP2_MOPS
#define HWCAP2_MOPS (1UL << 43)
#endif
#ifndef HWCAP2_F8E4M3
#define HWCAP2_F8E4M3 (1UL << 55)
#endif
#ifndef HWCAP2_F8E5M2
#define HWCAP2_F8E5M2 (1UL << 56)
#endif
#ifndef HWCAP_CMPBR
#define HWCAP_CMPBR (1UL << 33)
#endif
#ifndef HWCAP_FPRCVT
#define HWCAP_FPRCVT (1UL << 34)
#endif
// #include <asm/hwcap.h>
void ffCPUDetectByCpuid(FFCPUResult* cpu)
{
@@ -188,69 +160,69 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
cpu->march = "unknown";
// ARMv8-A
bool has_fp = (hwcap & HWCAP_FP) != 0;
bool has_asimd = (hwcap & HWCAP_ASIMD) != 0;
bool has_fp = (hwcap & (1 << 0) /* HWCAP_FP */) != 0;
bool has_asimd = (hwcap & (1 << 1) /* HWCAP_ASIMD */) != 0;
// ARMv8.1-A
bool has_atomics = (hwcap & HWCAP_ATOMICS) != 0; // optional from v8.0
bool has_crc32 = (hwcap & HWCAP_CRC32) != 0; // optional from v8.0
bool has_asimdrdm = (hwcap & HWCAP_ASIMDRDM) != 0; // optional from v8.0
bool has_atomics = (hwcap & (1 << 8) /* HWCAP_ATOMICS */) != 0; // optional from v8.0
bool has_crc32 = (hwcap & (1 << 7) /* HWCAP_CRC32 */) != 0; // optional from v8.0
bool has_asimdrdm = (hwcap & (1 << 12) /* HWCAP_ASIMDRDM */) != 0; // optional from v8.0
// ARMv8.2-A
bool has_fphp = (hwcap & HWCAP_FPHP) != 0; // optional
bool has_dcpop = (hwcap & HWCAP_DCPOP) != 0; // DC CVAP, optional from v8.1
bool has_fphp = (hwcap & (1 << 9) /* HWCAP_FPHP */) != 0; // optional
bool has_dcpop = (hwcap & (1 << 16) /* HWCAP_DCPOP */) != 0; // DC CVAP, optional from v8.1
// ARMv8.3-A
bool has_paca = (hwcap & HWCAP_PACA) != 0; // optional from v8.2
bool has_lrcpc = (hwcap & HWCAP_LRCPC) != 0; // optional from v8.2
bool has_fcma = (hwcap & HWCAP_FCMA) != 0; // optional from v8.2
bool has_jscvt = (hwcap & HWCAP_JSCVT) != 0; // optional from v8.2
bool has_paca = (hwcap & (1 << 30) /* HWCAP_PACA */) != 0; // optional from v8.2
bool has_lrcpc = (hwcap & (1 << 15) /* HWCAP_LRCPC */) != 0; // optional from v8.2
bool has_fcma = (hwcap & (1 << 14) /* HWCAP_FCMA */) != 0; // optional from v8.2
bool has_jscvt = (hwcap & (1 << 13) /* HWCAP_JSCVT */) != 0; // optional from v8.2
// ARMv8.4-A
bool has_dit = (hwcap & HWCAP_DIT) != 0; // optional from v8.3
bool has_flagm = (hwcap & HWCAP_FLAGM) != 0; // optional from v8.1
bool has_ilrcpc = (hwcap & HWCAP_ILRCPC) != 0; // optional from v8.2
bool has_dit = (hwcap & (1 << 24) /* HWCAP_DIT */) != 0; // optional from v8.3
bool has_flagm = (hwcap & (1 << 27) /* HWCAP_FLAGM */) != 0; // optional from v8.1
bool has_ilrcpc = (hwcap & (1 << 26) /* HWCAP_ILRCPC */) != 0; // optional from v8.2
// ARMv8.5-A
bool has_bti = (hwcap2 & HWCAP2_BTI) != 0; // optional from v8.4
bool has_sb = (hwcap & HWCAP_SB) != 0; // optional from v8.0
bool has_dcpodp = (hwcap2 & HWCAP2_DCPODP) != 0; // optional from v8.1
bool has_flagm2 = (hwcap2 & HWCAP2_FLAGM2) != 0; // optional from v8.4
bool has_frint = (hwcap2 & HWCAP2_FRINT) != 0; // optional from v8.4
bool has_bti = (hwcap2 & (1 << 17) /* HWCAP2_BTI */) != 0; // optional from v8.4
bool has_sb = (hwcap & (1 << 29) /* HWCAP_SB */) != 0; // optional from v8.0
bool has_dcpodp = (hwcap2 & (1 << 0) /* HWCAP2_DCPODP */) != 0; // optional from v8.1
bool has_flagm2 = (hwcap2 & (1 << 7) /* HWCAP2_FLAGM2 */) != 0; // optional from v8.4
bool has_frint = (hwcap2 & (1 << 8) /* HWCAP2_FRINT */) != 0; // optional from v8.4
// ARMv9.0-A
bool has_sve2 = (hwcap2 & HWCAP2_SVE2) != 0;
bool has_sve2 = (hwcap2 & (1 << 1) /* HWCAP2_SVE2 */) != 0;
// ARMv9.1-A
// ARMv8.6-A
bool has_bf16 = (hwcap2 & HWCAP2_BF16) != 0; // optional from v8.2
bool has_i8mm = (hwcap2 & HWCAP2_I8MM) != 0; // optional from v8.1
bool has_bf16 = (hwcap2 & (1 << 14) /* HWCAP2_BF16 */) != 0; // optional from v8.2
bool has_i8mm = (hwcap2 & (1 << 13) /* HWCAP2_I8MM */) != 0; // optional from v8.1
// ARMv8.7-A
bool has_afp = (hwcap2 & HWCAP2_AFP) != 0; // optional from v8.6
bool has_afp = (hwcap2 & (1 << 20) /* HWCAP2_AFP */) != 0; // optional from v8.6
// ARMv9.2-A
bool has_sme = (hwcap2 & HWCAP2_SME) != 0;
bool has_sme = (hwcap2 & (1 << 23) /* HWCAP2_SME */) != 0;
// ARMv9.3-A
bool has_sme2 = (hwcap2 & HWCAP2_SME2) != 0; // optional from v9.2
bool has_sme2 = (hwcap2 & (1UL << 37) /* HWCAP2_SME2 */) != 0; // optional from v9.2
// ARMv8.8-A
bool has_mops = (hwcap2 & HWCAP2_MOPS) != 0; // optional from v8.7
bool has_mops = (hwcap2 & (1UL << 43) /* HWCAP2_MOPS */) != 0; // optional from v8.7
// ARMv8.9-A
bool has_cssc = (hwcap2 & HWCAP2_CSSC) != 0; // optional from v8.7
bool has_cssc = (hwcap2 & (1UL << 34) /* HWCAP2_CSSC */) != 0; // optional from v8.7
// ARMv9.4-A
bool has_sme2p1 = (hwcap2 & HWCAP2_SME2P1) != 0; // optional from v9.2
bool has_sme2p1 = (hwcap2 & (1UL << 38) /* HWCAP2_SME2P1 */) != 0; // optional from v9.2
// ARMv9.5-A
bool has_f8e4m3 = (hwcap2 & HWCAP2_F8E4M3) != 0; // optional from v9.2
bool has_f8e5m2 = (hwcap2 & HWCAP2_F8E5M2) != 0; // optional from v9.2
bool has_f8e4m3 = (hwcap2 & (1UL << 55) /* HWCAP2_F8E4M3 */) != 0; // optional from v9.2
bool has_f8e5m2 = (hwcap2 & (1UL << 56) /* HWCAP2_F8E5M2 */) != 0; // optional from v9.2
// ARMv9.6-A
bool has_cmpbr = (hwcap & HWCAP_CMPBR) != 0; // optional from v9.5
bool has_fprcvt = (hwcap & HWCAP_FPRCVT) != 0; // optional from v9.5
bool has_cmpbr = (hwcap & (1UL << 33) /* HWCAP_CMPBR */) != 0; // optional from v9.5
bool has_fprcvt = (hwcap & (1UL << 34) /* HWCAP_FPRCVT */) != 0; // optional from v9.5
if (has_sve2 || has_sme) {
// ARMv9
@@ -296,23 +268,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
}
#elif __APPLE__
#include <sys/sysctl.h>
#include <arm/cpu_capabilities_public.h>
#ifndef CAP_BIT_AdvSIMD
#define CAP_BIT_AdvSIMD 49
#endif
#ifndef CAP_BIT_AdvSIMD_HPFPCvt
#define CAP_BIT_AdvSIMD_HPFPCvt 50
#endif
#ifndef CAP_BIT_FEAT_CRC32
#define CAP_BIT_FEAT_CRC32 51
#endif
#ifndef CAP_BIT_FEAT_HBC
#define CAP_BIT_FEAT_HBC 64
#endif
#ifndef CAP_BIT_FEAT_CSSC
#define CAP_BIT_FEAT_CSSC 67
#endif
// #include <arm/cpu_capabilities_public.h> // Not available in macOS 14-
void ffCPUDetectByCpuid(FFCPUResult* cpu)
{
@@ -328,59 +284,59 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
cpu->march = "unknown";
// ARMv8-A
bool has_fp = FF_HAS_CAP(CAP_BIT_AdvSIMD_HPFPCvt); // Full FP16 support (implies FP/ASIMD)
bool has_asimd = FF_HAS_CAP(CAP_BIT_AdvSIMD); // Advanced SIMD (NEON)
bool has_fp = FF_HAS_CAP(50); /* CAP_BIT_AdvSIMD_HPFPCvt */ // Full FP16 support (implies FP/ASIMD)
bool has_asimd = FF_HAS_CAP(49); /* CAP_BIT_AdvSIMD */ // Advanced SIMD (NEON)
// ARMv8.1-A
bool has_lse = FF_HAS_CAP(CAP_BIT_FEAT_LSE); // Large System Extensions, optional in v8.0
bool has_crc32 = FF_HAS_CAP(CAP_BIT_FEAT_CRC32); // CRC32 instructions, optional in v8.0
bool has_rdm = FF_HAS_CAP(CAP_BIT_FEAT_RDM); // AdvSIMD rounding double multiply accumulate, optional in v8.0
bool has_lse = FF_HAS_CAP(6); /* CAP_BIT_FEAT_LSE */ // Large System Extensions, optional in v8.0
bool has_crc32 = FF_HAS_CAP(51); /* CAP_BIT_FEAT_CRC32 */ // CRC32 instructions, optional in v8.0
bool has_rdm = FF_HAS_CAP(5); /* CAP_BIT_FEAT_RDM */ // AdvSIMD rounding double multiply accumulate, optional in v8.0
// ARMv8.2-A
bool has_fp16 = FF_HAS_CAP(CAP_BIT_FEAT_FP16); // Half-precision FP support, optional
bool has_dpb = FF_HAS_CAP(CAP_BIT_FEAT_DPB); // DC CVAP, optional from v8.1
bool has_fp16 = FF_HAS_CAP(34); /* CAP_BIT_FEAT_FP16 */ // Half-precision FP support, optional
bool has_dpb = FF_HAS_CAP(22); /* CAP_BIT_FEAT_DPB */ // DC CVAP, optional from v8.1
// ARMv8.3-A
bool has_pauth = FF_HAS_CAP(CAP_BIT_FEAT_PAuth); // Pointer Authentication (PAC), optional from v8.2
bool has_lrcpc = FF_HAS_CAP(CAP_BIT_FEAT_LRCPC); // LDAPR/LR with RCPC semantics, optional from v8.2
bool has_fcma = FF_HAS_CAP(CAP_BIT_FEAT_FCMA); // Complex number multiply-add, optional from v8.2
bool has_jscvt = FF_HAS_CAP(CAP_BIT_FEAT_JSCVT); // JavaScript-style conversion (FJCVTZS), optional from v8.2
bool has_pauth = FF_HAS_CAP(19); /* CAP_BIT_FEAT_PAuth */ // Pointer Authentication (PAC), optional from v8.2
bool has_lrcpc = FF_HAS_CAP(15); /* CAP_BIT_FEAT_LRCPC */ // LDAPR/LR with RCPC semantics, optional from v8.2
bool has_fcma = FF_HAS_CAP(17); /* CAP_BIT_FEAT_FCMA */ // Complex number multiply-add, optional from v8.2
bool has_jscvt = FF_HAS_CAP(18); /* CAP_BIT_FEAT_JSCVT */ // JavaScript-style conversion (FJCVTZS), optional from v8.2
// ARMv8.4-A
bool has_lse2 = FF_HAS_CAP(CAP_BIT_FEAT_LSE2); // Large System Extensions version 2, optional from v8.2
bool has_dit = FF_HAS_CAP(CAP_BIT_FEAT_DIT); // Data Independent Timing, optional from v8.3
bool has_flagm = FF_HAS_CAP(CAP_BIT_FEAT_FlagM); // Flag manipulation (FMOV/FCVT), optional from v8.1
bool has_lrcpc2 = FF_HAS_CAP(CAP_BIT_FEAT_LRCPC2); // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2
bool has_lse2 = FF_HAS_CAP(30); /* CAP_BIT_FEAT_LSE2 */ // Large System Extensions version 2, optional from v8.2
bool has_dit = FF_HAS_CAP(33); /* CAP_BIT_FEAT_DIT */ // Data Independent Timing, optional from v8.3
bool has_flagm = FF_HAS_CAP(0); /* CAP_BIT_FEAT_FlagM */ // Flag manipulation (FMOV/FCVT), optional from v8.1
bool has_lrcpc2 = FF_HAS_CAP(16); /* CAP_BIT_FEAT_LRCPC2 */ // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2
// ARMv8.5-A
bool has_bti = FF_HAS_CAP(CAP_BIT_FEAT_BTI); // Branch Target Identification, optional from v8.4
bool has_sb = FF_HAS_CAP(CAP_BIT_FEAT_SB); // Speculative Barrier, optional from v8.0
bool has_dpb2 = FF_HAS_CAP(CAP_BIT_FEAT_DPB2); // DC CVADP (DPB2), optional from v8.1
bool has_flagm2 = FF_HAS_CAP(CAP_BIT_FEAT_FlagM2); // Enhanced FlagM, optional from v8.4
bool has_frintts = FF_HAS_CAP(CAP_BIT_FEAT_FRINTTS); // Floating-point to integer instructions, optional from v8.4
bool has_bti = FF_HAS_CAP(36); /* CAP_BIT_FEAT_BTI */ // Branch Target Identification, optional from v8.4
bool has_sb = FF_HAS_CAP(13); /* CAP_BIT_FEAT_SB */ // Speculative Barrier, optional from v8.0
bool has_dpb2 = FF_HAS_CAP(23); /* CAP_BIT_FEAT_DPB2 */ // DC CVADP (DPB2), optional from v8.1
bool has_flagm2 = FF_HAS_CAP(1); /* CAP_BIT_FEAT_FlagM2 */ // Enhanced FlagM, optional from v8.4
bool has_frintts = FF_HAS_CAP(14); /* CAP_BIT_FEAT_FRINTTS */ // Floating-point to integer instructions, optional from v8.4
// ARMv9.0-A
bool has_sve2 = false; // Not exposed and not supported by Apple M4
bool has_sve2 = false; // Not exposed and not supported by Apple M4
// ARMv9.1-A
// ARMv8.6-A
bool has_bf16 = FF_HAS_CAP(CAP_BIT_FEAT_BF16); // Brain float16, optional from v8.2
bool has_i8mm = FF_HAS_CAP(CAP_BIT_FEAT_I8MM); // Int8 Matrix Multiply, optional from v8.1
bool has_bf16 = FF_HAS_CAP(24); /* CAP_BIT_FEAT_BF16 */ // Brain float16, optional from v8.2
bool has_i8mm = FF_HAS_CAP(25); /* CAP_BIT_FEAT_I8MM */ // Int8 Matrix Multiply, optional from v8.1
// ARMv8.7-A
bool has_afp = FF_HAS_CAP(CAP_BIT_FEAT_AFP); // Alternate FP16 (FEXPA), optional from v8.6
bool has_afp = FF_HAS_CAP(29); /* CAP_BIT_FEAT_AFP */ // Alternate FP16 (FEXPA), optional from v8.6
// ARMv9.2-A
bool has_sme = FF_HAS_CAP(CAP_BIT_FEAT_SME); // Scalable Matrix Extension, optional from v9.2
bool has_sme = FF_HAS_CAP(40); /* CAP_BIT_FEAT_SME */ // Scalable Matrix Extension, optional from v9.2
// ARMv9.3-A
bool has_sme2 = FF_HAS_CAP(CAP_BIT_FEAT_SME2); // SME2, optional from v9.2
bool has_sme2 = FF_HAS_CAP(41); /* CAP_BIT_FEAT_SME2 */ // SME2, optional from v9.2
// ARMv8.8-A
bool has_hbc = FF_HAS_CAP(CAP_BIT_FEAT_HBC); // Hinted conditional branches, optional from v8.7
bool has_hbc = FF_HAS_CAP(64); /* CAP_BIT_FEAT_HBC */ // Hinted conditional branches, optional from v8.7
// ARMv8.9-A
bool has_cssc = FF_HAS_CAP(CAP_BIT_FEAT_CSSC); // Common Short String Compare, optional from v8.7
bool has_cssc = FF_HAS_CAP(67); /* CAP_BIT_FEAT_CSSC */ // Common Short String Compare, optional from v8.7
// ARMv9.4-A+ are not exposed yet
@@ -473,7 +429,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
// ARMv8.4-A
// My CPU (Apple M1 Pro in VM) does support LSE2, but Windows doesn't detect it for some reason
// bool has_lse2 = IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE); // Large System Extensions version 2, optional from v8.2
bool has_lse2 = IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE); // Large System Extensions version 2, optional from v8.2
bool has_dp = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE); // DotProd, optional from v8.1 (*)
// ARMv9.0-A
@@ -519,7 +475,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
cpu->march = "ARMv8.7-A";
} else if (has_i8mm && has_bf16) {
cpu->march = "ARMv8.6-A";
} else if (has_dp) {
} else if (has_dp && has_lse2) {
cpu->march = "ARMv8.4-A";
} else if (has_lrcpc && has_jscvt) {
cpu->march = "ARMv8.3-A";
+5
View File
@@ -112,8 +112,12 @@ static const char* armPartId2name(uint32_t partId)
case 0xd87: return "Cortex-A725";
case 0xd88: return "Cortex-A520AE";
case 0xd89: return "Cortex-A720AE";
case 0xd8a: return "C1-Nano";
case 0xd8b: return "C1-Pro";
case 0xd8c: return "C1-Ultra";
case 0xd8e: return "Neoverse-N3";
case 0xd8f: return "Cortex-A320";
case 0xd90: return "C1-Premium";
default: return NULL;
}
}
@@ -213,6 +217,7 @@ static const char* nvidiaPartId2name(uint32_t partId)
case 0x000: return "Denver";
case 0x003: return "Denver 2";
case 0x004: return "Carmel";
case 0x010: return "Olympus";
default: return NULL;
}
}
+7
View File
@@ -150,6 +150,8 @@ static void detectQualcomm(FFCPUResult* cpu)
switch (code)
{
case 8845: name = "8 Gen 5"; break; // ?
case 8850: name = "8 Elite Gen 5"; break;
case 8735: name = "8s Gen 4"; break;
case 8750: name = "8 Elite"; break;
case 8635: name = "8s Gen 3"; break;
@@ -192,6 +194,7 @@ static void detectMediaTek(FFCPUResult* cpu)
switch (code) // The SOC code of MTK Dimensity series is full of mess
{
case 6993: name = "9500"; break;
case 6991: name = "9400"; break;
case 6989:
case 8796: name = "9300"; break;
@@ -353,6 +356,10 @@ static const char* parseCpuInfo(
(cpu->name.length == 0 && ffParsePropLine(line, "processor 0:", &cpu->name)) ||
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) ||
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz static :", cpuMHz)) || // This one cannot be detected because of early return
#elif __ia64__
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor :", &cpu->vendor)) ||
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) ||
#else
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
(cpu->name.length == 0 && ffParsePropLine(line, "model :", &cpu->name)) ||
+8 -3
View File
@@ -102,12 +102,16 @@ const char* detectThermalTemp(double* result)
if (pCounterData->dwDataSize == sizeof(int32_t))
{
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
int32_t value = *(int32_t*)(pCounterData + 1);
if (value == 0)
return "Temperature data is zero";
switch (pCounterIds[iCounter]) {
case 0: // Temperature
*result = *(int32_t*)(pCounterData + 1) - 273;
*result = value - 273;
break;
case 3: // High Precision Temperature
*result = *(int32_t*)(pCounterData + 1) / 10.0 - 273;
*result = value / 10.0 - 273;
break;
}
}
@@ -238,7 +242,8 @@ static const char* detectByRegistry(FFCPUResult* cpu)
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL);
ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL);
if (ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL))
ffStrbufTrimRightSpace(&cpu->vendor);
if (cpu->coresLogical == 0)
{
-25
View File
@@ -1,30 +1,5 @@
#include "disk.h"
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
{
#ifdef _WIN32
const char separator = ';';
#else
const char separator = ':';
#endif
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
uint32_t startIndex = 0;
while(startIndex < folders->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
static int compareDisks(const FFDisk* disk1, const FFDisk* disk2)
{
return ffStrbufComp(&disk1->mountpoint, &disk2->mountpoint);
+6 -1
View File
@@ -3,6 +3,12 @@
#include "fastfetch.h"
#include "modules/disk/option.h"
#ifdef _WIN32
#define FF_DISK_FOLDER_SEPARATOR ';'
#else
#define FF_DISK_FOLDER_SEPARATOR ':'
#endif
typedef struct FFDisk
{
FFstrbuf mountFrom;
@@ -29,4 +35,3 @@ typedef struct FFDisk
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
+1 -1
View File
@@ -145,7 +145,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if(__builtin_expect(options->folders.length > 0, 0))
{
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
if(!ffStrbufSeparatedContainS(&options->folders, fs->f_mntonname, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
+1 -1
View File
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
if (!ffStrbufSeparatedContainS(&options->folders, path.Path(), FF_DISK_FOLDER_SEPARATOR))
continue;
}
+7 -3
View File
@@ -10,6 +10,10 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifdef STATX_BTIME
#include <sys/syscall.h>
#endif
#ifdef __USE_LARGEFILE64
#define stat stat64
#define statvfs statvfs64
@@ -263,9 +267,9 @@ static void detectStats(FFDisk* disk)
}
disk->createTime = 0;
#ifdef FF_HAVE_STATX
#ifdef SYS_statx
struct statx stx;
if (statx(0, disk->mountpoint.chars, 0, STATX_BTIME, &stx) == 0 && (stx.stx_mask & STATX_BTIME))
if (syscall(SYS_statx, 0, disk->mountpoint.chars, 0, STATX_BTIME, &stx) == 0 && (stx.stx_mask & STATX_BTIME) && stx.stx_btime.tv_sec > 685065600 /*birth of Linux*/)
disk->createTime = (uint64_t)((stx.stx_btime.tv_sec * 1000) + (stx.stx_btime.tv_nsec / 1000000));
#endif
@@ -287,7 +291,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length > 0, false))
{
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
if (!ffStrbufSeparatedContainS(&options->folders, device->mnt_dir, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(!isPhysicalDevice(device))
+1 -1
View File
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
if (!ffStrbufSeparatedContainS(&options->folders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(!isPhysicalDevice(&device))
+1 -1
View File
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect((long) options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
if (!ffStrbufSeparatedContain(&options->folders, &buffer, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(driveType == DRIVE_NO_ROOT_DIR)
@@ -44,6 +44,7 @@
#define FF_WM_PROTOCOL_TTY "TTY"
#define FF_WM_PROTOCOL_X11 "X11"
#define FF_WM_PROTOCOL_WAYLAND "Wayland"
#define FF_WM_PROTOCOL_SURFACEFLINGER "SurfaceFlinger"
typedef enum __attribute__((__packed__)) FFDisplayType {
FF_DISPLAY_TYPE_UNKNOWN,
@@ -1,6 +1,7 @@
#include "displayserver.h"
#include "common/settings.h"
#include "common/processing.h"
#include "linux/displayserver_linux.h"
#include <math.h>
@@ -82,13 +83,10 @@ static void detectWithDumpsys(FFDisplayServerResult* ds)
ffStrbufRecalculateLength(&name);
FFDisplayResult* display = ffdsAppendDisplay(ds,
(uint32_t)width,
(uint32_t)height,
(uint32_t)width, (uint32_t)height,
refreshRate,
0,
0,
0,
0,
0, 0,
0, 0,
0,
0,
&name,
@@ -121,13 +119,10 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
ffStrbufSubstrAfterFirstC(&buffer, ',');
double scaleFactor = (double) ffStrbufToUInt(&buffer, 0) / 160.;
FFDisplayResult* display = ffdsAppendDisplay(ds,
width,
height,
0,
(uint32_t) (width / scaleFactor + .5),
(uint32_t) (height / scaleFactor + .5),
0,
width, height,
0,
(uint32_t) (width / scaleFactor + .5), (uint32_t) (height / scaleFactor + .5),
0, 0,
0,
0,
NULL,
@@ -147,8 +142,19 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
{
ffStrbufSetStatic(&ds->wmProcessName, "surfaceflinger");
ffStrbufSetStatic(&ds->wmPrettyName, "SurfaceFlinger");
const char* error = ffdsConnectXcbRandr(ds);
if (error)
error = ffdsConnectXrandr(ds);
if (!error)
{
ffdsDetectWMDE(ds);
return;
}
// https://source.android.com/docs/core/graphics/surfaceflinger-windowmanager
ffStrbufSetStatic(&ds->wmProcessName, "system_server");
ffStrbufSetStatic(&ds->wmPrettyName, "WindowManager"); // A system service managed by system_server
ffStrbufSetStatic(&ds->wmProtocolName, FF_WM_PROTOCOL_SURFACEFLINGER);
if (!detectWithGetprop(ds))
detectWithDumpsys(ds);
@@ -0,0 +1,16 @@
#include "displayserver_linux.h"
#include "util/stringUtils.h"
FFDisplayType ffdsGetDisplayType(const char* name)
{
if(ffStrStartsWith(name, "eDP-") || ffStrStartsWith(name, "LVDS-"))
return FF_DISPLAY_TYPE_BUILTIN;
else if(ffStrStartsWith(name, "HDMI-") ||
ffStrStartsWith(name, "DP-") ||
ffStrStartsWith(name, "DisplayPort-") ||
ffStrStartsWith(name, "DVI-") ||
ffStrStartsWith(name, "VGA-"))
return FF_DISPLAY_TYPE_EXTERNAL;
return FF_DISPLAY_TYPE_UNKNOWN;
}
@@ -95,17 +95,3 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
ffdsDetectWMDE(ds);
}
}
FFDisplayType ffdsGetDisplayType(const char* name)
{
if(ffStrStartsWith(name, "eDP-") || ffStrStartsWith(name, "LVDS-"))
return FF_DISPLAY_TYPE_BUILTIN;
else if(ffStrStartsWith(name, "HDMI-") ||
ffStrStartsWith(name, "DP-") ||
ffStrStartsWith(name, "DisplayPort-") ||
ffStrStartsWith(name, "DVI-") ||
ffStrStartsWith(name, "VGA-"))
return FF_DISPLAY_TYPE_EXTERNAL;
return FF_DISPLAY_TYPE_UNKNOWN;
}
+3 -6
View File
@@ -396,13 +396,10 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result)
}
FFDisplayResult* item = ffdsAppendDisplay(result,
width,
height,
width, height,
refreshRate,
0,
0,
preferredWidth,
preferredHeight,
0, 0,
preferredWidth, preferredHeight,
preferredRefreshRate,
0,
&name,
@@ -128,8 +128,8 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale),
(uint32_t) (display.height / display.scale),
(uint32_t) (display.width / display.scale + .5),
(uint32_t) (display.height / display.scale + .5),
(uint32_t) display.preferredWidth,
(uint32_t) display.preferredHeight,
display.preferredRefreshRate / 1000.0,
@@ -220,8 +220,8 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale),
(uint32_t) (display.height / display.scale),
(uint32_t) (display.width / display.scale + .5),
(uint32_t) (display.height / display.scale + .5),
(uint32_t) display.preferredWidth,
(uint32_t) display.preferredHeight,
display.preferredRefreshRate / 1000.0,
+6 -1
View File
@@ -65,7 +65,7 @@ static const char* parseEnv(void)
if(getenv("SWAYSOCK") != NULL)
return "Sway";
#ifdef __linux__
#if __linux__ && !__ANDROID__
if(
getenv("WAYLAND_DISPLAY") != NULL &&
ffPathExists("/mnt/wslg/", FF_PATHTYPE_DIRECTORY)
@@ -433,6 +433,11 @@ static const char* getFromProcesses(FFDisplayServerResult* result)
void ffdsDetectWMDE(FFDisplayServerResult* result)
{
#if __ANDROID__
if(ffStrbufIgnCaseEqualS(&result->wmProtocolName, FF_WM_PROTOCOL_SURFACEFLINGER))
return; // Only supported when connected to X11
#endif
const char* env = parseEnv();
if(result->wmProcessName.length > 0)
+100 -100
View File
@@ -3,7 +3,7 @@
#ifdef FF_HAVE_XCB_RANDR
#include "common/library.h"
#include "common/time.h"
#include "common/properties.h"
#include "util/edidHelper.h"
#include "util/mallocHelper.h"
#include "util/stringUtils.h"
@@ -56,7 +56,7 @@ static void* xcbGetProperty(XcbPropertyData* data, xcb_connection_t* connection,
if(requestAtomReply == NULL)
return NULL;
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 64);
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 8 * 1024);
FF_AUTO_FREE xcb_get_property_reply_t* propertyReply = data->ffxcb_get_property_reply(connection, propertyCookie, NULL);
if(propertyReply == NULL)
@@ -138,86 +138,9 @@ typedef struct XcbRandrData
xcb_connection_t* connection;
FFDisplayServerResult* result;
XcbPropertyData propData;
//init per screen
xcb_randr_get_screen_resources_current_reply_t* screenResources;
} XcbRandrData;
static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrbuf* name, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength)
{
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME);
FF_AUTO_FREE xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL);
if(crtcInfoReply == NULL)
return false;
uint32_t rotation;
switch (crtcInfoReply->rotation)
{
case XCB_RANDR_ROTATION_ROTATE_90:
rotation = 90;
break;
case XCB_RANDR_ROTATION_ROTATE_180:
rotation = 180;
break;
case XCB_RANDR_ROTATION_ROTATE_270:
rotation = 270;
break;
default:
rotation = 0;
break;
}
xcb_randr_mode_info_t* currentMode = NULL;
xcb_randr_mode_info_t* preferredMode = NULL;
if(data->screenResources)
{
xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(data->screenResources);
if (output->num_preferred > 0)
preferredMode = modesIterator.data;
while (modesIterator.rem > 0)
{
if (modesIterator.data->id == crtcInfoReply->mode)
{
currentMode = modesIterator.data;
break;
}
data->ffxcb_randr_mode_info_next(&modesIterator);
}
}
FFDisplayResult* item = ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
preferredMode ? (uint32_t) preferredMode->width : 0,
preferredMode ? (uint32_t) preferredMode->height : 0,
preferredMode ? (double) preferredMode->dot_clock / (double) ((uint32_t) preferredMode->htotal * preferredMode->vtotal) : 0,
rotation,
name,
displayType,
primary,
0,
(uint32_t) output->mm_width,
(uint32_t) output->mm_height,
"xcb-randr-crtc"
);
if (item && edidLength)
{
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
}
return !!item;
}
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType)
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor)
{
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
FF_AUTO_FREE xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL);
@@ -246,12 +169,80 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
}
}
bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc, name, primary, outputInfoReply, displayType, edidData, edidLength);
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, outputInfoReply->crtc, XCB_CURRENT_TIME);
FF_AUTO_FREE xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL);
if(crtcInfoReply == NULL)
return false;
return res;
uint32_t rotation;
switch (crtcInfoReply->rotation)
{
case XCB_RANDR_ROTATION_ROTATE_90:
rotation = 90;
break;
case XCB_RANDR_ROTATION_ROTATE_180:
rotation = 180;
break;
case XCB_RANDR_ROTATION_ROTATE_270:
rotation = 270;
break;
default:
rotation = 0;
break;
}
xcb_randr_mode_info_t* currentMode = NULL;
xcb_randr_mode_info_t* preferredMode = NULL;
if(screenResources)
{
xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(screenResources);
if (outputInfoReply->num_preferred > 0)
preferredMode = modesIterator.data;
while (modesIterator.rem > 0)
{
if (modesIterator.data->id == crtcInfoReply->mode)
{
currentMode = modesIterator.data;
break;
}
data->ffxcb_randr_mode_info_next(&modesIterator);
}
}
FFDisplayResult* item = ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0,
(uint32_t) (crtcInfoReply->width / scaleFactor + .5),
(uint32_t) (crtcInfoReply->height / scaleFactor + .5),
preferredMode ? (uint32_t) preferredMode->width : 0,
preferredMode ? (uint32_t) preferredMode->height : 0,
preferredMode ? (double) preferredMode->dot_clock / (double) ((uint32_t) preferredMode->htotal * preferredMode->vtotal) : 0,
rotation,
name,
displayType,
primary,
0,
(uint32_t) outputInfoReply->mm_width,
(uint32_t) outputInfoReply->mm_height,
"xcb-randr-crtc"
);
if (item && edidLength)
{
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
item->bitDepth = bitDepth;
}
return !!item;
}
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor)
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor)
{
//for some reasons, we have to construct this our self
xcb_randr_output_iterator_t outputIterator = {
@@ -275,18 +266,20 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
while(outputIterator.rem > 0)
{
if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType))
if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType, screenResources, bitDepth, scaleFactor))
foundOutput = true;
data->ffxcb_randr_output_next(&outputIterator);
};
}
return foundOutput ? true : !!ffdsAppendDisplay(
if (foundOutput) return true;
FFDisplayResult* display = ffdsAppendDisplay(
data->result,
(uint32_t) monitor->width,
(uint32_t) monitor->height,
0,
(uint32_t) monitor->width,
(uint32_t) monitor->height,
(uint32_t) (monitor->width / scaleFactor + .5),
(uint32_t) (monitor->height / scaleFactor + .5),
0, 0, 0,
0,
&name,
@@ -297,6 +290,8 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
(uint32_t) monitor->height_in_millimeters,
"xcb-randr-monitor"
);
if (display) display->bitDepth = bitDepth;
return !!display;
}
static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
@@ -306,13 +301,27 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
if(monitorsReply == NULL)
return false;
//Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible.
xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root);
FF_AUTO_FREE struct xcb_randr_get_screen_resources_current_reply_t* screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL);
double scaleFactor = 1;
FF_AUTO_FREE const char* resourceManager = xcbGetProperty(&data->propData, data->connection, screen->root, "RESOURCE_MANAGER");
if (resourceManager)
{
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi))
scaleFactor = ffStrbufToDouble(&dpi, 96) / 96;
}
uint8_t bitDepth = (uint8_t) (screen->root_depth / 3);
xcb_randr_monitor_info_iterator_t monitorInfoIterator = data->ffxcb_randr_get_monitors_monitors_iterator(monitorsReply);
bool foundMonitor = false;
while(monitorInfoIterator.rem > 0)
{
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data))
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data, screenResources, bitDepth, scaleFactor))
foundMonitor = true;
data->ffxcb_randr_monitor_info_next(&monitorInfoIterator);
}
@@ -322,17 +331,8 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
{
//Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible.
xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root);
data->screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL);
//With all the initialisation done, start the detection
bool ret = xcbRandrHandleMonitors(data, screen);
free(data->screenResources);
if(ret)
if(xcbRandrHandleMonitors(data, screen))
return;
//If detetction failed, fallback to screen = monitor, like in the libxcb.so implementation
@@ -348,7 +348,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
NULL,
FF_DISPLAY_TYPE_UNKNOWN,
false,
0,
(uint64_t) screen->root,
(uint32_t) screen->width_in_millimeters,
(uint32_t) screen->height_in_millimeters,
"xcb-randr-screen"
+49 -40
View File
@@ -3,7 +3,7 @@
#ifdef FF_HAVE_XRANDR
#include "common/library.h"
#include "common/parsing.h"
#include "common/properties.h"
#include "util/edidHelper.h"
#include "util/stringUtils.h"
@@ -70,8 +70,6 @@ static void x11FetchServerVendor(X11PropertyData* data, Display* display, FFDisp
if (serverVendor && !ffStrEquals(serverVendor, "The X.Org Foundation")) {
ffStrbufSetS(&result->wmProtocolName, serverVendor);
}
}
typedef struct XrandrData
@@ -92,18 +90,16 @@ typedef struct XrandrData
//Init once
Display* display;
FFDisplayServerResult* result;
//Init per screen
XRRScreenResources* screenResources;
X11PropertyData* propData;
} XrandrData;
static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength)
static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor)
{
//We do the check here, because we want the best fallback display if this call failed
if(data->screenResources == NULL)
if(screenResources == NULL)
return false;
XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, output->crtc);
XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, screenResources, output->crtc);
if(crtcInfo == NULL)
return false;
@@ -125,27 +121,24 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
}
XRRModeInfo* currentMode = NULL;
if (data->screenResources)
for(int i = 0; i < screenResources->nmode; i++)
{
for(int i = 0; i < data->screenResources->nmode; i++)
if(screenResources->modes[i].id == crtcInfo->mode)
{
if(data->screenResources->modes[i].id == crtcInfo->mode)
{
currentMode = &data->screenResources->modes[i];
break;
}
currentMode = &screenResources->modes[i];
break;
}
}
XRRModeInfo* preferredMode = data->screenResources && output->npreferred > 0 ? &data->screenResources->modes[0] : NULL;
XRRModeInfo* preferredMode = output->npreferred > 0 ? &screenResources->modes[0] : NULL;
FFDisplayResult* item = ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfo->width,
(uint32_t) crtcInfo->height,
currentMode ? (double) currentMode->dotClock / (double) ((uint32_t) currentMode->hTotal * currentMode->vTotal) : 0,
(uint32_t) crtcInfo->width,
(uint32_t) crtcInfo->height,
(uint32_t) (crtcInfo->width / scaleFactor + .5),
(uint32_t) (crtcInfo->height / scaleFactor + .5),
preferredMode ? (uint32_t) preferredMode->width : 0,
preferredMode ? (uint32_t) preferredMode->height : 0,
preferredMode ? (double) preferredMode->dotClock / (double) ((uint32_t) preferredMode->hTotal * preferredMode->vTotal) : 0,
@@ -159,19 +152,23 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
"xlib-randr-crtc"
);
if (item && edidLength)
if (item)
{
item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
if (edidLength)
{
item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
}
item->bitDepth = bitDepth;
}
data->ffXRRFreeCrtcInfo(crtcInfo);
return !!item;
}
static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType)
static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor)
{
XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, data->screenResources, output);
XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, screenResources, output);
if(outputInfo == NULL)
return false;
@@ -195,7 +192,7 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name
}
}
bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength);
bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength, screenResources, bitDepth, scaleFactor);
if (edidData)
data->ffXFree(edidData);
@@ -204,7 +201,7 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name
return res;
}
static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo)
static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor)
{
bool foundOutput = false;
char* xname = data->ffXGetAtomName(data->display, monitorInfo->name);
@@ -213,17 +210,19 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo)
FFDisplayType displayType = ffdsGetDisplayType(name.chars);
for(int i = 0; i < monitorInfo->noutput; i++)
{
if(xrandrHandleOutput(data, monitorInfo->outputs[i], &name, monitorInfo->primary, displayType))
if(xrandrHandleOutput(data, monitorInfo->outputs[i], &name, monitorInfo->primary, displayType, screenResources, bitDepth, scaleFactor))
foundOutput = true;
}
return foundOutput ? true : !!ffdsAppendDisplay(
if (foundOutput) return true;
FFDisplayResult* display = ffdsAppendDisplay(
data->result,
(uint32_t) monitorInfo->width,
(uint32_t) monitorInfo->height,
0,
(uint32_t) monitorInfo->width,
(uint32_t) monitorInfo->height,
(uint32_t) (monitorInfo->width / scaleFactor + .5),
(uint32_t) (monitorInfo->height / scaleFactor + .5),
0, 0, 0,
0,
&name,
@@ -234,6 +233,8 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo)
(uint32_t) monitorInfo->mheight,
"xlib-randr-monitor"
);
if (display) display->bitDepth = bitDepth;
return !!display;
}
static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
@@ -243,29 +244,36 @@ static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
if(monitorInfos == NULL)
return false;
XRRScreenResources* screenResources = data->ffXRRGetScreenResourcesCurrent(data->display, RootWindowOfScreen(screen));
double scaleFactor = 1;
char* resourceManager = (char*) x11GetProperty(data->propData, data->display, screen->root, "RESOURCE_MANAGER");
if (resourceManager)
{
FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate();
if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi))
scaleFactor = ffStrbufToDouble(&dpi, 96) / 96;
data->ffXFree(resourceManager);
}
uint8_t bitDepth = (uint8_t) (screen->root_depth / 3);
bool foundAMonitor = false;
for(int i = 0; i < numberOfMonitors; i++)
{
if(xrandrHandleMonitor(data, &monitorInfos[i]))
if(xrandrHandleMonitor(data, &monitorInfos[i], screenResources, bitDepth, scaleFactor))
foundAMonitor = true;
}
data->ffXRRFreeMonitors(monitorInfos);
data->ffXRRFreeScreenResources(screenResources);
return foundAMonitor;
}
static void xrandrHandleScreen(XrandrData* data, Screen* screen)
{
//Init screen resources
data->screenResources = data->ffXRRGetScreenResourcesCurrent(data->display, RootWindowOfScreen(screen));
bool ret = xrandrHandleMonitors(data, screen);
data->ffXRRFreeScreenResources(data->screenResources);
if(ret)
if(xrandrHandleMonitors(data, screen))
return;
//Fallback to screen
@@ -281,7 +289,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
NULL,
FF_DISPLAY_TYPE_UNKNOWN,
false,
0,
RootWindowOfScreen(screen),
(uint32_t) WidthMMOfScreen(screen),
(uint32_t) HeightMMOfScreen(screen),
"xlib-randr-screen"
@@ -312,6 +320,7 @@ const char* ffdsConnectXrandr(FFDisplayServerResult* result)
X11PropertyData propertyData;
bool propertyDataInitialized = x11InitPropertyData(xrandr, &propertyData);
data.propData = &propertyData;
data.display = ffXOpenDisplay(NULL);
if(data.display == NULL)
+1 -1
View File
@@ -28,7 +28,7 @@ const char* ffDetectFontImpl(FFFontResult* result)
{
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0)
if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY))
return "Font isn't supported in TTY";
FFfont qt;
+33 -28
View File
@@ -34,6 +34,13 @@ static inline void applyGTKSettings(FFGTKResult* result, const char* themeName,
ffStrbufAppendS(&result->wallpaper, wallpaper);
}
static bool testXfconfWallpaperPropKey(FF_MAYBE_UNUSED void* data, const char* key)
{
int count = 0;
sscanf(key, "/backdrop/screen0/monitor%*[^/]/workspace0/last-image%n", &count);
return count == 0;
}
static void detectGTKFromSettings(FFGTKResult* result)
{
static const char* themeName = NULL;
@@ -55,47 +62,45 @@ static void detectGTKFromSettings(FFGTKResult* result)
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4) == 0)
if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4))
{
themeName = ffSettingsGetXFConf("xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetXFConf("xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetXFConf("xsettings", "/Gtk/FontName", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetXFConf("xfce4-desktop", "/backdrop/screen0/monitor0/workspace0/last-image", FF_VARIANT_TYPE_STRING).strValue;
if (!wallpaper) // FIXME: find a way to enumerate possible properties
wallpaper = ffSettingsGetXFConf("xfce4-desktop", "/backdrop/screen0/monitoreDP-1/workspace0/last-image", FF_VARIANT_TYPE_STRING).strValue;
wallpaper = ffSettingsGetXFConfFirstMatch("xfce4-desktop", "/backdrop/screen0", FF_VARIANT_TYPE_STRING, NULL, testXfconfWallpaperPropKey).strValue;
}
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON) == 0)
else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON))
{
themeName = ffSettingsGet("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGet("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGet("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGet("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
themeName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
}
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_MATE) == 0)
else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_MATE))
{
themeName = ffSettingsGet("/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet("/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet("/org/mate/interface/font-name", "org.mate.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGet("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGet("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGet("/org/mate/desktop/background", "org.mate.background", NULL, "picture-filename", FF_VARIANT_TYPE_STRING).strValue;
themeName = ffSettingsGetGnome("/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/mate/interface/font-name", "org.mate.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/mate/desktop/background", "org.mate.background", NULL, "picture-filename", FF_VARIANT_TYPE_STRING).strValue;
}
else if(
ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) == 0 ||
ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) == 0 ||
ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) == 0 ||
ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) == 0
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) ||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE)
) {
themeName = ffSettingsGet("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGet("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGet("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGet("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
themeName = ffSettingsGetGnome("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetGnome("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetGnome("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
wallpaper = ffSettingsGetGnome("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
}
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper);
+1 -1
View File
@@ -7,7 +7,7 @@ const char* ffDetectIcons(FFIconsResult* result)
{
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0)
if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY))
return "Icons aren't supported in TTY";
const FFstrbuf* plasma = &ffDetectQt()->icons;
+13
View File
@@ -3,6 +3,19 @@
#include "fastfetch.h"
#include "modules/localip/option.h"
#ifndef IN6_IS_ADDR_GLOBAL
#define IN6_IS_ADDR_GLOBAL(a) \
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
#endif
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
#endif
#ifndef IN6_IS_ADDR_LINKLOCAL
#define IN6_IS_ADDR_LINKLOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xffc00000)) == htonl(0xfe800000))
#endif
typedef struct FFLocalIpResult
{
FFstrbuf name;
+69 -58
View File
@@ -111,47 +111,32 @@ static const FFLocalIpNIFlag niFlagOptions[] = {
{},
};
typedef enum __attribute__((__packed__)) FFIPv6Type
{
FF_IPV6_Other,
FF_IPV6_GUA = 0b0001,
FF_IPV6_GUA_SECONDARY = 0b0101,
FF_IPV6_ULA = 0b0010,
FF_IPV6_ULA_SECONDARY = 0b0110,
FF_IPV6_TYPE_MASK = 0b0011,
FF_IPV6_SECONDARY_FLAG = 0b1100,
FF_IPV6_PREFERRED = UINT8_MAX,
} FFIPv6Type;
static FFIPv6Type getIpType(struct ifaddrs* ifa)
static FFLocalIpIpv6Type getIpv6Type(struct ifaddrs* ifa)
{
struct sockaddr_in6* addr = (struct sockaddr_in6*) ifa->ifa_addr;
FF_DEBUG("Checking IPv6 type for interface %s", ifa->ifa_name);
#ifndef IN6_IS_ADDR_GLOBAL
#define IN6_IS_ADDR_GLOBAL(a) \
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
#endif
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
#endif
FFIPv6Type result = FF_IPV6_Other;
FFLocalIpIpv6Type result = FF_LOCALIP_IPV6_TYPE_NONE;
if (IN6_IS_ADDR_GLOBAL(&addr->sin6_addr))
{
result = FF_IPV6_GUA;
result = FF_LOCALIP_IPV6_TYPE_GUA_BIT;
FF_DEBUG("Interface %s has Global Unicast Address", ifa->ifa_name);
}
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&addr->sin6_addr))
{
result = FF_IPV6_ULA;
result = FF_LOCALIP_IPV6_TYPE_ULA_BIT;
FF_DEBUG("Interface %s has Unique Local Address", ifa->ifa_name);
}
else if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
{
result = FF_LOCALIP_IPV6_TYPE_LLA_BIT;
FF_DEBUG("Interface %s has Link-Local Address", ifa->ifa_name);
}
else
{
FF_DEBUG("Interface %s has other IPv6 address type", ifa->ifa_name);
return FF_IPV6_Other;
FF_DEBUG("Interface %s has unknown IPv6 address type", ifa->ifa_name);
return FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT;
}
#ifdef SIOCGIFAFLAG_IN6
@@ -178,13 +163,13 @@ static FFIPv6Type getIpType(struct ifaddrs* ifa)
#ifdef IN6_IFF_PREFER_SOURCE
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PREFER_SOURCE)
return FF_IPV6_PREFERRED;
result |= FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT;
#endif
if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY | IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED
#ifdef IN6_IFF_OPTIMISTIC
| IN6_IFF_OPTIMISTIC
#endif
)) result |= FF_IPV6_SECONDARY_FLAG;
)) result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
return result;
#elif __linux__
static FFlist addresses = {};
@@ -220,13 +205,13 @@ static FFIPv6Type getIpType(struct ifaddrs* ifa)
if (memcmp(&addr->sin6_addr, entry, sizeof(struct in6_addr)) == 0)
return result;
}
result |= FF_IPV6_SECONDARY_FLAG;
result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
return result;
#elif __sun
if (ifa->ifa_flags & IFF_PREFERRED)
return FF_IPV6_PREFERRED;
result |= FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT;
if (ifa->ifa_flags & (IFF_DEPRECATED | IFF_TEMPORARY | IFF_DUPLICATE))
result |= FF_IPV6_SECONDARY_FLAG;
result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
return result;
#else
return result;
@@ -414,6 +399,13 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
FF_DEBUG("Processing adapter %s (IPv4 entries: %u, IPv6 entries: %u)",
adapter->mac->ifa_name, adapter->ipv4.length, adapter->ipv6.length);
if (adapter->ipv4.length == 0 && adapter->ipv6.length == 0 &&
!(options->showType & FF_LOCALIP_TYPE_MAC_BIT) )
{
FF_DEBUG("Skipping interface %s (no IP addresses)", adapter->mac->ifa_name);
continue;
}
FFLocalIpResult* item = FF_LIST_ADD(FFLocalIpResult, *results);
ffStrbufInitS(&item->name, adapter->mac->ifa_name);
ffStrbufInit(&item->ipv4);
@@ -502,46 +494,65 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
}
}
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
if (options->ipv6Type == FF_LOCALIP_IPV6_TYPE_AUTO)
{
struct ifaddrs* selected = NULL;
struct ifaddrs* secondary = NULL;
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
{
FFIPv6Type type = getIpType(*pifa);
if (type == FF_IPV6_PREFERRED)
struct ifaddrs* selected = NULL;
struct ifaddrs* secondary = NULL;
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
{
selected = *pifa;
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
break;
FFLocalIpIpv6Type type = getIpv6Type(*pifa);
if (type & FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT)
{
selected = *pifa;
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
break;
}
else if ((type & FF_LOCALIP_IPV6_TYPE_GUA_BIT) && !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT) && !selected)
{
selected = *pifa;
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
}
else if ((type & FF_LOCALIP_IPV6_TYPE_ULA_BIT) && !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT) && !secondary)
{
secondary = *pifa;
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
}
}
else if (type == FF_IPV6_GUA && !selected)
if (!selected) selected = secondary;
if (selected)
appendIpv6(options, &item->ipv6, selected);
else if (adapter->ipv6.length > 0)
{
selected = *pifa;
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
}
else if (type == FF_IPV6_ULA && !secondary)
{
secondary = *pifa;
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
}
}
if (!selected) selected = secondary;
if (selected)
appendIpv6(options, &item->ipv6, selected);
else if (adapter->ipv6.length > 0)
else
{
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
appendIpv6(options, &item->ipv6, *pifa);
}
}
else
{
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
appendIpv6(options, &item->ipv6, *pifa);
{
FFLocalIpIpv6Type type = getIpv6Type(*pifa);
if (type & options->ipv6Type)
{
if ((options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) || !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT))
{
appendIpv6(options, &item->ipv6, *pifa);
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
break;
}
}
}
}
}
mac:
+30 -6
View File
@@ -140,13 +140,24 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next)
{
FF_DEBUG("Processing unicast address: family=%d, DadState=%d",
ifa->Address.lpSockaddr->sa_family, ifa->DadState);
FF_DEBUG("Processing unicast address: prefix origin=%d, suffix origin=%d, family=%d, DadState=%d",
ifa->PrefixOrigin, ifa->SuffixOrigin, ifa->Address.lpSockaddr->sa_family, ifa->DadState);
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) && ifa->DadState != IpDadStatePreferred)
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
{
FF_DEBUG("Skipping address (DadState=%d, not preferred)", ifa->DadState);
continue;
if (ifa->DadState != IpDadStatePreferred)
{
FF_DEBUG("Skipping address (not preferred)");
continue;
}
if (ifa->SuffixOrigin == IpSuffixOriginRandom)
{
FF_DEBUG("Skipping temporary address (random suffix)");
continue;
}
// MIB_UNICASTIPADDRESS_ROW::SkipAsSource
}
if (ifa->Address.lpSockaddr->sa_family == AF_INET)
@@ -192,6 +203,20 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
continue;
}
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
FFLocalIpIpv6Type ipv6Type = FF_LOCALIP_IPV6_TYPE_NONE;
if (IN6_IS_ADDR_GLOBAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_GUA_BIT;
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_ULA_BIT;
else if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_LLA_BIT;
else ipv6Type |= FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT;
if (!(options->ipv6Type & ipv6Type))
{
FF_DEBUG("Skipping IPv6 address (doesn't match requested type 0x%X)", options->ipv6Type);
continue;
}
bool isDefaultRoute = ((options->showType & FF_LOCALIP_TYPE_IPV6_BIT) && ffNetifGetDefaultRouteV6()->ifIndex == adapter->IfIndex);
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
{
@@ -199,7 +224,6 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
continue;
}
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
char addressBuffer[INET6_ADDRSTRLEN + 6];
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
+1 -1
View File
@@ -191,7 +191,7 @@ static void getBestBus(FFDBusData* data, FFMediaResult* result)
getBusProperties(data, FF_DBUS_MPRIS_PREFIX "plasma-browser-integration", result)
) return;
DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", NULL);
DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", NULL, NULL);
if(reply == NULL)
return;
+48 -52
View File
@@ -7,9 +7,6 @@
typedef struct WGLData
{
FFOpenGLResult* result;
const char* error;
FF_LIBRARY_SYMBOL(glGetString)
FF_LIBRARY_SYMBOL(wglMakeCurrent)
FF_LIBRARY_SYMBOL(wglCreateContext)
@@ -18,82 +15,77 @@ typedef struct WGLData
void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString);
static const char* wglHandleContext(WGLData* wglData, HDC hdc, HGLRC context)
static const char* wglHandleContext(WGLData* wglData, FFOpenGLResult* result, HDC hdc, HGLRC context)
{
if(wglData->ffwglMakeCurrent(hdc, context) == FALSE)
return "wglMakeCurrent() failed";
ffOpenGLHandleResult(wglData->result, wglData->ffglGetString);
ffStrbufSetStatic(&wglData->result->library, "WGL 1.0");
ffOpenGLHandleResult(result, wglData->ffglGetString);
ffStrbufSetStatic(&result->library, "WGL 1.0");
if(wglData->ffwglMakeCurrent(NULL, NULL) == FALSE)
return "wglMakeCurrent(NULL, NULL) failed";
return NULL;
}
static const char* wglHandlePixelFormat(WGLData* wglData, HWND hWnd)
static const char* wglHandlePixelFormat(WGLData* wglData, FFOpenGLResult* result, HWND hWnd)
{
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(pfd),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
32, // Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, // Number of bits for the depthbuffer
8, // Number of bits for the stencilbuffer
0, // Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};
HDC hdc = GetDC(hWnd);
if(SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd) == FALSE)
if(hdc == NULL)
return "GetDC() failed";
PIXELFORMATDESCRIPTOR pfd = {
.nSize = sizeof(PIXELFORMATDESCRIPTOR),
.nVersion = 1,
.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
.iPixelType = PFD_TYPE_RGBA,
.cColorBits = 32,
.cDepthBits = 24,
.iLayerType = PFD_MAIN_PLANE
};
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
if(pixelFormat == 0)
{
ReleaseDC(hWnd, hdc);
return "ChoosePixelFormat() failed";
}
if(SetPixelFormat(hdc, pixelFormat, &pfd) == FALSE)
{
ReleaseDC(hWnd, hdc);
return "SetPixelFormat() failed";
}
HGLRC context = wglData->ffwglCreateContext(hdc);
if(context == NULL)
{
ReleaseDC(hWnd, hdc);
return "wglCreateContext() failed";
}
const char* error = wglHandleContext(wglData, hdc, context);
const char* error = wglHandleContext(wglData, result, hdc, context);
wglData->ffwglDeleteContext(context);
return error;
}
ReleaseDC(hWnd, hdc);
static LRESULT CALLBACK wglHandleWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CREATE: {
WGLData* wglData = (WGLData*)((CREATESTRUCT*)lParam)->lpCreateParams;
wglData->error = wglHandlePixelFormat(wglData, hWnd);
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
}
return error;
}
static const char* wglDetectOpenGL(FFOpenGLResult* result)
{
FF_LIBRARY_LOAD(opengl32, "dlopen opengl32" FF_LIBRARY_EXTENSION " failed", "opengl32" FF_LIBRARY_EXTENSION, 1);
WGLData data = { .result = result };
WGLData data = {};
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglMakeCurrent);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglCreateContext);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglDeleteContext);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, glGetString);
MSG msg = {0};
HINSTANCE hInstance = GetModuleHandleW(NULL);
WNDCLASSW wc = {
.lpfnWndProc = wglHandleWndProc,
.hInstance = NULL,
.lpfnWndProc = DefWindowProcW,
.hInstance = hInstance,
.hbrBackground = (HBRUSH)COLOR_BACKGROUND,
.lpszClassName = L"ogl_version_check",
.style = CS_OWNDC,
@@ -101,12 +93,16 @@ static const char* wglDetectOpenGL(FFOpenGLResult* result)
if(!RegisterClassW(&wc))
return "RegisterClassW() failed";
HWND hWnd = CreateWindowW(wc.lpszClassName, L"ogl_version_check", 0, 0, 0, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, NULL, NULL, NULL, &data);
HWND hWnd = CreateWindowW(wc.lpszClassName, L"ogl_version_check", 0, 0, 0, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, NULL, NULL, hInstance, NULL);
if(!hWnd)
return "CreateWindowW() failed";
while(GetMessageW(&msg, hWnd, 0, 0) > 0)
DispatchMessage(&msg);
const char* error = wglHandlePixelFormat(&data, result, hWnd);
return data.error;
DestroyWindow(hWnd);
UnregisterClassW(wc.lpszClassName, hInstance);
return error;
}
+4 -4
View File
@@ -61,10 +61,6 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
{
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if (detectArmbianVersion(result))
return;
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
@@ -104,6 +100,10 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
return;
}
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
{
ffStrbufSetStatic(&result->name, "Kubuntu");
+59 -14
View File
@@ -3,6 +3,8 @@
#include "common/properties.h"
#include "common/processing.h"
#include "detection/terminalshell/terminalshell.h"
#include "util/debug.h"
#include "util/stringUtils.h"
static void detectAlacritty(FFTerminalFontResult* terminalFont)
{
@@ -48,29 +50,72 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont)
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}
static void detectGhostty(FFTerminalFontResult* terminalFont)
static void detectGhostty(const FFstrbuf* exe, FFTerminalFontResult* terminalFont)
{
FF_DEBUG("detectGhostty: start");
FF_STRBUF_AUTO_DESTROY configPath = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontNameFallback = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
FFpropquery fontQueryToml[] = {
{"font-family =", &fontName},
{"font-size =", &fontSize},
};
// Try ghostty +show-config first
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
exe->chars,
"+show-config",
NULL,
});
if(error != NULL)
{
FF_DEBUG("`ghostty +show-config` failed: %s", error);
return;
}
#if __APPLE__
ffParsePropFileConfigValues("com.mitchellh.ghostty/config", 2, fontQueryToml);
#endif
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &buffer))
{
if (!fontName.length || !fontNameFallback.length)
{
if (ffStrStartsWith(line, "font-family = ")) {
FF_DEBUG("found %s", line);
ffStrbufSetNS(
!fontName.length ? &fontName : &fontNameFallback,
(uint32_t) (len - strlen("font-family = ")),
line + strlen("font-family = "));
continue;
}
}
if (!fontSize.length)
{
if (ffStrStartsWith(line, "font-size = ")) {
FF_DEBUG("found fallback %s", line);
ffStrbufSetNS(
&fontSize,
(uint32_t) (len - strlen("font-size = ")),
line + strlen("font-size = "));
continue;
}
}
}
ffParsePropFileConfigValues("ghostty/config", 2, fontQueryToml);
if(fontName.length == 0)
if (fontName.length == 0) {
ffStrbufAppendS(&fontName, "JetBrainsMono Nerd Font");
FF_DEBUG("using default family='%s'", fontName.chars);
}
if(fontSize.length == 0)
if (fontSize.length == 0) {
ffStrbufAppendS(&fontSize, "13");
FF_DEBUG("using default size='%s'", fontSize.chars);
}
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
if (fontNameFallback.length > 0) {
FF_DEBUG("applying fallback family='%s'", fontNameFallback.chars);
ffFontInitValues(&terminalFont->fallback, fontNameFallback.chars, NULL);
}
FF_DEBUG("result family='%s' size='%s'%s", fontName.chars, fontSize.chars, fontNameFallback.length ? " (with fallback)" : "");
FF_DEBUG("detectGhostty: end");
}
FF_MAYBE_UNUSED static void detectTTY(FFTerminalFontResult* terminalFont)
@@ -266,7 +311,7 @@ static bool detectRio(FFTerminalFontResult* terminalFont)
return true;
}
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont);
bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont);
static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
{
@@ -279,7 +324,7 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour"))
detectContour(&terminal->exe, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty"))
detectGhostty(terminalFont);
detectGhostty(&terminal->exe, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "rio"))
detectRio(terminalFont);
@@ -13,6 +13,12 @@
const char* detectTermux(FFTerminalFontResult* terminalFont)
{
if(!ffPathExists(FF_TERMUX_FONT_PATH, FF_PATHTYPE_FILE))
{
ffFontInitCopy(&terminalFont->font, "monospace");
return NULL;
}
#ifdef FF_HAVE_FREETYPE
FF_LIBRARY_LOAD(freetype, "dlopen libfreetype"FF_LIBRARY_EXTENSION " failed", "libfreetype"FF_LIBRARY_EXTENSION, 2)
@@ -53,19 +59,15 @@ exit:
#endif
}
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
{
if(ffStrbufCompS(&terminal->processName, "com.termux") != 0)
if(ffStrbufEqualS(&terminal->processName, "com.termux"))
ffStrbufSetS(&terminalFont->error, detectTermux(terminalFont));
else
{
ffStrbufSetS(&terminalFont->error, "Unsupported terminal");
return;
bool ffDetectTerminalFontPlatformLinux(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont);
return ffDetectTerminalFontPlatformLinux(terminal, terminalFont);
}
if(!ffPathExists(FF_TERMUX_FONT_PATH, FF_PATHTYPE_FILE))
{
ffFontInitCopy(&terminalFont->font, "monospace");
return;
}
ffStrbufSetS(&terminalFont->error, detectTermux(terminalFont));
return true;
}
@@ -91,7 +91,7 @@ static void detectWarpTerminal(FFTerminalFontResult* terminalFont)
ffFontInitValues(&terminalFont->font, fontName.UTF8String, fontSize.UTF8String);
}
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
{
if(ffStrbufIgnCaseEqualS(&terminal->processName, "iterm.app") ||
ffStrbufStartsWithIgnCaseS(&terminal->processName, "iTermServer-"))
@@ -100,4 +100,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo
detectAppleTerminal(terminalFont);
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal"))
detectWarpTerminal(terminalFont);
else
return false;
return true;
}
@@ -16,26 +16,26 @@ static const char* getSystemMonospaceFont(void)
if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, "Cinnamon"))
{
const char* systemMonospaceFont = ffSettingsGet("/org/cinnamon/desktop/interface/monospace-font-name", "org.cinnamon.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
const char* systemMonospaceFont = ffSettingsGetGnome("/org/cinnamon/desktop/interface/monospace-font-name", "org.cinnamon.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
if(ffStrSet(systemMonospaceFont))
return systemMonospaceFont;
}
else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, "Mate"))
{
const char* systemMonospaceFont = ffSettingsGet("/org/mate/interface/monospace-font-name", "org.mate.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
const char* systemMonospaceFont = ffSettingsGetGnome("/org/mate/interface/monospace-font-name", "org.mate.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
if(ffStrSet(systemMonospaceFont))
return systemMonospaceFont;
}
return ffSettingsGet("/org/gnome/desktop/interface/monospace-font-name", "org.gnome.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
return ffSettingsGetGnome("/org/gnome/desktop/interface/monospace-font-name", "org.gnome.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
}
static void detectKgx(FFTerminalFontResult* terminalFont)
{
// kgx (gnome console) doesn't support profiles
if(!ffSettingsGet("/org/gnome/Console/use-system-font", "org.gnome.Console", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue)
if(!ffSettingsGetGnome("/org/gnome/Console/use-system-font", "org.gnome.Console", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue)
{
FF_AUTO_FREE const char* fontName = ffSettingsGet("/org/gnome/Console/custom-font", "org.gnome.Console", NULL, "custom-font", FF_VARIANT_TYPE_STRING).strValue;
FF_AUTO_FREE const char* fontName = ffSettingsGetGnome("/org/gnome/Console/custom-font", "org.gnome.Console", NULL, "custom-font", FF_VARIANT_TYPE_STRING).strValue;
if(ffStrSet(fontName))
ffFontInitPango(&terminalFont->font, fontName);
else
@@ -53,9 +53,9 @@ static void detectKgx(FFTerminalFontResult* terminalFont)
static void detectPtyxis(FFTerminalFontResult* terminalFont)
{
if(!ffSettingsGet("/org/gnome/Ptyxis/use-system-font", "org.gnome.Ptyxis", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue)
if(!ffSettingsGetGnome("/org/gnome/Ptyxis/use-system-font", "org.gnome.Ptyxis", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue)
{
FF_AUTO_FREE const char* fontName = ffSettingsGet("/org/gnome/Ptyxis/font-name", "org.gnome.Ptyxis", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
FF_AUTO_FREE const char* fontName = ffSettingsGetGnome("/org/gnome/Ptyxis/font-name", "org.gnome.Ptyxis", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
if(ffStrSet(fontName))
ffFontInitPango(&terminalFont->font, fontName);
else
@@ -167,7 +167,7 @@ static void detectXFCETerminal(FFTerminalFontResult* terminalFont)
});
}
if(configFound && (useSysFont.length == 0 || ffStrbufIgnCaseCompS(&useSysFont, "false") == 0))
if(configFound && (useSysFont.length == 0 || ffStrbufIgnCaseEqualS(&useSysFont, "false")))
{
if(fontName.length == 0)
ffStrbufAppendF(&terminalFont->error, "Couldn't find FontName in %s", path);
@@ -433,7 +433,13 @@ static void detectHaikuTerminal(FFTerminalFontResult* terminalFont)
}
#endif
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
bool
#ifdef __ANDROID__
ffDetectTerminalFontPlatformLinux
#else
ffDetectTerminalFontPlatform
#endif
(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
{
if(ffStrbufIgnCaseEqualS(&terminal->processName, "konsole"))
detectKonsole(terminalFont, "konsolerc");
@@ -477,4 +483,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo
#endif
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "termite"))
detectFromConfigFile("termite/config", "font =", terminalFont);
else
return false;
return true;
}
@@ -274,7 +274,7 @@ static void detectWarp(FFTerminalFontResult* terminalFont)
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
{
if(ffStrbufIgnCaseEqualS(&terminal->processName, "Windows Terminal") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "WindowsTerminal.exe"))
@@ -287,4 +287,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo
detectConEmu(terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "warp"))
detectWarp(terminalFont);
else
return false;
return true;
}
@@ -111,6 +111,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
ffStrbufEqualS(&result->processName, "proot") ||
ffStrbufEqualS(&result->processName, "script") ||
#ifdef __linux__
ffStrbufStartsWithS(&result->processName, "Relay(") || // Unknown process in WSL2
ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707
#endif
ffStrbufEndsWithS(&result->processName, ".sh")
+1 -1
View File
@@ -7,7 +7,7 @@ const char* ffDetectTheme(FFThemeResult* result)
{
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0)
if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY))
return "Theme isn't supported in TTY";
const FFQtResult* plasma = ffDetectQt();
+10 -240
View File
@@ -9,227 +9,11 @@ static inline double rssiToSignalQuality(int rssi)
return (double) (rssi >= -50 ? 100 : rssi <= -100 ? 0 : (rssi + 100) * 2);
}
static bool queryIpconfig(const char* ifName, FFstrbuf* result)
{
if (@available(macOS 15.6, *))
{
// ipconfig reports <redacted> too
return false;
}
@interface CWNetworkProfile()
@property(readonly, retain, nullable) NSArray<NSDictionary *> *bssidList;
@end
return ffProcessAppendStdOut(result, (char* const[]) {
"/usr/sbin/ipconfig",
"getsummary",
(char* const) ifName,
NULL
}) == NULL;
}
static bool getWifiInfoByIpconfig(FFstrbuf* ipconfig, const char* prefix, FFstrbuf* result)
{
// `ipconfig getsummary <interface>` returns a string like this:
// <dictionary> {
// BSSID : <redacted>
// IPv4 : <array> {
// ...
// }
// IPv6 : <array> {
// ...
// }
// InterfaceType : WiFi
// LinkStatusActive : TRUE
// NetworkID : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// SSID : XXXXXX
// Security : WPA2_PSK
// }
const char* start = memmem(ipconfig->chars, ipconfig->length, prefix, strlen(prefix));
if (!start) return false;
start += strlen(prefix);
const char* end = strchr(start, '\n');
if (!end) return false;
ffStrbufSetNS(result, (uint32_t) (end - start), start);
return true;
}
static const char* detectByWdutil(FFlist* result)
{
FF_STRBUF_AUTO_DESTROY wdutil = ffStrbufCreate();
if (geteuid() != 0)
return "wdutil requires root privileges to run";
bool ok = ffProcessAppendStdOut(&wdutil, (char* const[]) {
"/usr/bin/wdutil",
"info",
NULL
}) == NULL;
if (!ok) return "Failed to run wdutil info command";
// ...
//
// WIFI
//
// <WIFI INFO>
//
// ...
{
// Remove unrelated lines
uint32_t start = ffStrbufFirstIndexS(&wdutil, "\nWIFI\n");
if (start >= wdutil.length)
return "wdutil info command did not return WIFI section (1)";
start += 6; // Skip "\nWIFI\n"
start = ffStrbufNextIndexC(&wdutil, start, '\n');
if (start >= wdutil.length)
return "wdutil info command did not return WIFI section (2)";
start++;
uint32_t end = ffStrbufNextIndexS(&wdutil, start, "\n——————————");
ffStrbufSubstr(&wdutil, start, end);
}
// `wdutil info <interface>` returns a string like this:
// MAC Address : xx:xx:xx:xx:xx:xx (hw=xx:xx:xx:xx:xx:xx)
// Interface Name : en0
// Power : On [On]
// Op Mode : STA
// SSID : XXX-XXX
// BSSID : xx:xx:xx:xx:xx:xx
// RSSI : -58 dBm
// CCA : 29 %
// Noise : -96 dBm
// Tx Rate : 173.0 Mbps
// Security : WPA2 Enterprise
// 802.1X Mode : User
// 802.1X Supplicant : Authenticated
// PHY Mode : 11ac
// MCS Index : 8
// Guard Interval : 400
// NSS : 2
// Channel : 5g165/20
// Country Code : CN
// Scan Cache Count : 28
// NetworkServiceID : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// IPv4 Config Method : DHCP
// IPv4 Address : xx.xx.xx.xx
// IPv4 Router : xx.xx.xx.x
// IPv6 Config Method : Automatic
// IPv6 Address : xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
// IPv6 Router : None
// DNS : xxx.xxx.xxx.xxx
// : xxx.xxx.xxx.xxx
// BTC Mode : Off
// Desense :
// Chain Ack : []
// BTC Profile 2.4GHz : Disabled
// BTC Profile 5GHz : Disabled
// Sniffer Supported : YES
// Supports 6e : No
// Supported Channels : 2g1/20,2g2/20,2g3/20,2g4/20,2g5/20,2g6/20,2g7/20,2g8/20,2g9/20,2g10/20,2g11/20,2g12/20,2g13/20,5g36/20,5g40/20,5g44/20,5g48/20,5g52/20,5g56/20,5g60/20,5g64/20,5g149/20,5g153/20,5g157/20,5g161/20,5g165/20,5g36/40,5g40/40,5g44/40,5g48/40,5g52/40,5g56/40,5g60/40,5g64/40,5g149/40,5g153/40,5g157/40,5g161/40,5g36/80,5g40/80,5g44/80,5g48/80,5g52/80,5g56/80,5g60/80,5g64/80,5g149/80,5g153/80,5g157/80,5g161/80
FFWifiResult* item = (FFWifiResult*) ffListAdd(result);
ffStrbufInit(&item->inf.description);
ffStrbufInit(&item->inf.status);
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.bssid);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = -DBL_MAX;
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.frequency = 0;
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &wdutil))
{
const char* key = line + 4; // Skip " "
const char* value = key + strlen("MAC Address : ");
switch (key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3])
{
case 'Inte': // Interface Name
ffStrbufAppendS(&item->inf.description, value);
break;
case 'Powe': // Power
if (ffStrStartsWith(value, "On "))
ffStrbufSetStatic(&item->inf.status, "Power On");
else
ffStrbufSetStatic(&item->inf.status, "Power Off");
break;
case 'SSID': // SSID
ffStrbufAppendS(&item->conn.ssid, value);
break;
case 'BSSI': // BSSID
if (ffStrEquals(value, "None") && ffStrbufEqualS(&item->conn.ssid, "None"))
{
ffStrbufSetStatic(&item->conn.status, "Inactive");
ffStrbufClear(&item->conn.ssid); // None
return NULL;
}
ffStrbufSetStatic(&item->conn.status, "Active");
ffStrbufAppendS(&item->conn.bssid, value);
break;
case 'RSSI': // RSSI
item->conn.signalQuality = rssiToSignalQuality((int) strtol(value, NULL, 10));
break;
case 'Tx R': // Tx Rate
item->conn.txRate = strtod(value, NULL);
break;
case 'Secu': // Security
if (ffStrEquals(value, "None"))
ffStrbufSetStatic(&item->conn.security, "Insecure");
else
ffStrbufAppendS(&item->conn.security, value);
break;
case 'PHY ': // PHY Mode
if (ffStrEquals(value, "None"))
ffStrbufSetStatic(&item->conn.protocol, "none");
else if (ffStrEquals(value, "11a"))
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
else if (ffStrEquals(value, "11b"))
ffStrbufSetStatic(&item->conn.protocol, "802.11b");
else if (ffStrEquals(value, "11g"))
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
else if (ffStrEquals(value, "11n"))
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
else if (ffStrEquals(value, "11ac"))
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
else if (ffStrEquals(value, "11ax"))
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
else if (ffStrEquals(value, "11be"))
ffStrbufSetStatic(&item->conn.protocol, "802.11be (Wi-Fi 7)");
else
ffStrbufAppendS(&item->conn.protocol, value);
break;
case 'Chan': // Channel
{
int band, channel;
if (sscanf(value, "%dg%d", &band, &channel) == 2)
{
item->conn.channel = (uint16_t) channel;
switch (band)
{
case 2: item->conn.frequency = 2400; break;
case 5: item->conn.frequency = 5400; break;
case 6: item->conn.frequency = 6400; break;
default: item->conn.frequency = 0; break;
}
}
break;
}
}
}
return NULL;
}
static const char* detectByCoreWlan(FFlist* result)
const char* ffDetectWifi(FFlist* result)
{
NSArray<CWInterface*>* interfaces = CWWiFiClient.sharedWiFiClient.interfaces;
if (!interfaces)
@@ -262,17 +46,19 @@ static const char* detectByCoreWlan(FFlist* result)
FF_STRBUF_AUTO_DESTROY ipconfig = ffStrbufCreate();
CWNetworkProfile* networkProfile = inf.configuration.networkProfiles.firstObject;
if (inf.ssid) // https://developer.apple.com/forums/thread/732431
ffStrbufAppendS(&item->conn.ssid, inf.ssid.UTF8String);
else if (ipconfig.length || (queryIpconfig(item->inf.description.chars, &ipconfig)))
getWifiInfoByIpconfig(&ipconfig, "\n SSID : ", &item->conn.ssid);
else if (networkProfile.ssid)
ffStrbufSetStatic(&item->conn.ssid, inf.configuration.networkProfiles.firstObject.ssid.UTF8String);
else
ffStrbufSetStatic(&item->conn.ssid, "<redacted>"); // https://developer.apple.com/forums/thread/732431
if (inf.bssid)
ffStrbufAppendS(&item->conn.bssid, inf.bssid.UTF8String);
else if (ipconfig.length || (queryIpconfig(item->inf.description.chars, &ipconfig)))
getWifiInfoByIpconfig(&ipconfig, "\n BSSID : ", &item->conn.bssid);
else if (networkProfile.bssidList)
ffStrbufSetStatic(&item->conn.bssid, [networkProfile.bssidList.firstObject[@"BSSID"] UTF8String]);
else
ffStrbufSetStatic(&item->conn.bssid, "<redacted>");
@@ -360,11 +146,6 @@ static const char* detectByCoreWlan(FFlist* result)
case 15 /*kCWSecurityOWETransition*/:
ffStrbufSetStatic(&item->conn.security, "OWE Transition");
break;
case kCWSecurityUnknown:
// Sonoma?
if (ipconfig.length || (queryIpconfig(item->inf.description.chars, &ipconfig)))
getWifiInfoByIpconfig(&ipconfig, "\n Security : ", &item->conn.security);
break;
default:
ffStrbufAppendF(&item->conn.security, "Unknown (%ld)", inf.security);
break;
@@ -382,14 +163,3 @@ static const char* detectByCoreWlan(FFlist* result)
return NULL;
}
const char* ffDetectWifi(FFlist* result)
{
if (@available(macOS 15.6, *))
{
if (detectByWdutil(result) == NULL)
return NULL;
}
return detectByCoreWlan(result);
}
+1 -1
View File
@@ -57,7 +57,7 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer)
{
FF_DEBUG("Getting device by IP interface name");
DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars);
DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars, NULL);
if(!device)
{
FF_DEBUG("GetDeviceByIpIface failed for interface %s", item->inf.description.chars);
+64 -53
View File
@@ -13,6 +13,17 @@ const char* ffDetectWMPlugin(FF_MAYBE_UNUSED FFstrbuf* pluginName)
return "Not supported on this platform";
}
static bool extractCommonWmVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
int count = 0;
sscanf(line, "%*d.%*d.%*d%n", &count);
if (count == 0) return true;
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
return false;
}
#if !__ANDROID__
static bool extractHyprlandVersion(const char* line, uint32_t len, void *userdata)
{
if (line[0] != 'v') return true;
@@ -128,6 +139,48 @@ static const char* getSway(FFstrbuf* result)
return "Failed to run command `sway --version`";
}
static const char* getLabwc(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("labwc", &path);
if (error) return "Failed to find labwc executable path";
ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0"));
if (result->length > 0) return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // labwc 0.9.0 (+xwayland +nls +rsvg +libsfdo)
ffStrbufSubstrAfterFirstC(result, ' ');
ffStrbufSubstrBeforeFirstC(result, ' ');
return NULL;
}
return "Failed to run command `labwc --version`";
}
#ifdef __linux__
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;
}
#endif
#endif // !__ANDROID__
static bool extractI3Version(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
int count = 0;
@@ -161,31 +214,6 @@ static const char* getI3(FFstrbuf* result)
return "Failed to run command `i3 --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;
}
static bool extractCommonWmVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
{
int count = 0;
sscanf(line, "%*d.%*d.%*d%n", &count);
if (count == 0) return true;
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
return false;
}
static const char* getCtwm(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
@@ -255,45 +283,31 @@ static const char* getOpenbox(FFstrbuf* result)
return "Failed to run command `openbox --version`";
}
static const char* getLabwc(FFstrbuf* result)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("labwc", &path);
if (error) return "Failed to find labwc executable path";
ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0"));
if (result->length > 0) return NULL;
if (ffProcessAppendStdOut(result, (char* const[]){
path.chars,
"--version",
NULL
}) == NULL)
{ // labwc 0.9.0 (+xwayland +nls +rsvg +libsfdo)
ffStrbufSubstrAfterFirstC(result, ' ');
ffStrbufSubstrBeforeFirstC(result, ' ');
return NULL;
}
return "Failed to run command `labwc --version`";
}
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
{
if (!wmName)
return "No WM detected";
#if !__ANDROID__
// Wayland compositors
if (ffStrbufIgnCaseEqualS(wmName, "Hyprland"))
return getHyprland(result);
if (ffStrbufEqualS(wmName, "sway"))
return getSway(result);
if (ffStrbufEqualS(wmName, "i3"))
return getI3(result);
if (ffStrbufEqualS(wmName, "labwc"))
return getLabwc(result);
#if __linux__
if (ffStrbufEqualS(wmName, "WSLg"))
return getWslg(result);
#endif
#endif
// X11 WMs
if (ffStrbufEqualS(wmName, "i3"))
return getI3(result);
if (ffStrbufEqualS(wmName, "ctwm"))
return getCtwm(result);
@@ -304,8 +318,5 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE
if (ffStrbufEqualS(wmName, "Openbox"))
return getOpenbox(result);
if (ffStrbufEqualS(wmName, "labwc"))
return getLabwc(result);
return "Unsupported WM";
}
+16 -13
View File
@@ -44,7 +44,7 @@ static bool detectWMThemeFromConfigFile(const char* configFile, const char* them
static bool detectWMThemeFromSettings(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFstrbuf* themeOrError)
{
const char* theme = ffSettingsGet(dconfKey, gsettingsSchemaName, gsettingsPath, gsettingsKey, FF_VARIANT_TYPE_STRING).strValue;
const char* theme = ffSettingsGetGnome(dconfKey, gsettingsSchemaName, gsettingsPath, gsettingsKey, FF_VARIANT_TYPE_STRING).strValue;
if(!ffStrSet(theme))
{
@@ -80,7 +80,7 @@ ok:
static bool detectMutter(FFstrbuf* themeOrError)
{
const char* theme = ffSettingsGet("/org/gnome/shell/extensions/user-theme/name", "org.gnome.shell.extensions.user-theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue;
const char* theme = ffSettingsGetGnome("/org/gnome/shell/extensions/user-theme/name", "org.gnome.shell.extensions.user-theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue;
if(ffStrSet(theme))
{
ffStrbufAppendS(themeOrError, theme);
@@ -92,8 +92,8 @@ static bool detectMutter(FFstrbuf* themeOrError)
static bool detectMuffin(FFstrbuf* themeOrError)
{
FF_AUTO_FREE const char* name = ffSettingsGet("/org/cinnamon/theme/name", "org.cinnamon.theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue;
FF_AUTO_FREE const char* theme = ffSettingsGet("/org/cinnamon/desktop/wm/preferences/theme", "org.cinnamon.desktop.wm.preferences", NULL, "theme", FF_VARIANT_TYPE_STRING).strValue;
FF_AUTO_FREE const char* name = ffSettingsGetGnome("/org/cinnamon/theme/name", "org.cinnamon.theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue;
FF_AUTO_FREE const char* theme = ffSettingsGetGnome("/org/cinnamon/desktop/wm/preferences/theme", "org.cinnamon.desktop.wm.preferences", NULL, "theme", FF_VARIANT_TYPE_STRING).strValue;
if(name == NULL && theme == NULL)
{
@@ -135,9 +135,9 @@ static bool detectOpenbox(const FFstrbuf* dePrettyName, FFstrbuf* themeOrError)
{
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(64);
const char *configFileSubpath = "openbox/rc.xml";
if (ffStrbufIgnCaseCompS(dePrettyName, "LXQt") == 0)
if (ffStrbufIgnCaseEqualS(dePrettyName, "LXQt"))
configFileSubpath = "openbox/lxqt-rc.xml";
else if (ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0)
else if (ffStrbufIgnCaseEqualS(dePrettyName, "LXDE"))
configFileSubpath = "openbox/lxde-rc.xml";
if (!ffSearchUserConfigFile(&instance.state.platform.configDirs, configFileSubpath, &absolutePath))
@@ -197,16 +197,19 @@ bool ffDetectWmTheme(FFstrbuf* themeOrError)
return false;
}
if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_KWIN) == 0)
if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_KWIN))
return detectWMThemeFromConfigFile("kwinrc", "theme =", "Breeze", themeOrError);
if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_XFWM4) == 0)
if(
ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_XFWM4) ||
(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, "labwc") && ffStrbufIgnCaseEqualS(&wm->dePrettyName, FF_DE_PRETTY_XFCE4))
)
return detectXFWM4(themeOrError);
if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MUTTER) == 0)
if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_MUTTER))
{
if(
ffStrbufIgnCaseCompS(&wm->dePrettyName, FF_DE_PRETTY_GNOME) == 0 ||
ffStrbufIgnCaseEqualS(&wm->dePrettyName, FF_DE_PRETTY_GNOME) ||
ffStrbufIgnCaseEqualS(&wm->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC)
)
return detectMutter(themeOrError);
@@ -214,13 +217,13 @@ bool ffDetectWmTheme(FFstrbuf* themeOrError)
return detectGTKThemeAsWMTheme(themeOrError);
}
if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MUFFIN) == 0)
if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_MUFFIN))
return detectMuffin(themeOrError);
if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MARCO) == 0)
if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_MARCO))
return detectWMThemeFromSettings("/org/mate/Marco/general/theme", "org.mate.Marco.general", NULL, "theme", themeOrError);
if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_OPENBOX) == 0)
if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_OPENBOX))
return detectOpenbox(&wm->dePrettyName, themeOrError);
ffStrbufAppendS(themeOrError, "Unknown WM: ");
+1 -1
View File
@@ -80,7 +80,7 @@ static int enumZpoolCallback(zpool_handle_t* zpool, void* param)
const char* ffDetectZpool(FFlist* result /* list of FFZpoolResult */)
{
FF_LIBRARY_LOAD(libzfs, "dlopen libzfs" FF_LIBRARY_EXTENSION " failed", "libzfs" FF_LIBRARY_EXTENSION, 4);
FF_LIBRARY_LOAD(libzfs, "dlopen libzfs" FF_LIBRARY_EXTENSION " failed", "libzfs" FF_LIBRARY_EXTENSION, 6);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, libzfs_init);
libzfs_handle_t* handle = fflibzfs_init();
+7 -1
View File
@@ -681,7 +681,8 @@ static void parseOption(FFdata* data, const char* key, const char* value)
else if(
ffOptionsParseGeneralCommandLine(&instance.config.general, key, value) ||
ffOptionsParseLogoCommandLine(&instance.config.logo, key, value) ||
ffOptionsParseDisplayCommandLine(&instance.config.display, key, value)
ffOptionsParseDisplayCommandLine(&instance.config.display, key, value) ||
ffParseModuleOptions(key, value)
) {}
else
@@ -748,7 +749,12 @@ static void run(FFdata* data)
if (useJsonConfig)
ffPrintJsonConfig(true /* prepare */, instance.state.resultDoc);
else
{
//If we don't have a custom structure, use the default one
if(data->structure.length == 0)
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
ffPrepareCommandOption(data);
}
ffStart();
+16 -19
View File
@@ -1,19 +1,16 @@
$1-`$2
.$1o+`$2
`o$1oo/$2
`+o$1ooo:$2
`+oo$1oooo:$2
-+oo$1oooo+:$2
`/:-:+$1+oooo+:$2
`/++++/$1+++++++:$2
`/++++++$1++++++++:$2
`/+++oooo$1ooooooooo/`$2
./ooosssso$1++osssssso+`$2
.oossssso-`$1```/ossssss+`$2
-osssssso. $1 :ssssssso.$2
:osssssss/ $1 osssso+++.$2
/ossssssss/ $1 +ssssooo/-$2
`/ossssso+/:- $1 -:/+osssso+-$2
`+sso+:-` $1 `.-/+oso:$2
`++:. $1 `-/+/$2
.` $1 `/$2
$2 *+++++++#
$2#*******###$3 @
$2#*******###$3 @
$2#*******###$3 @ @
$2#*******##%$3 @
$3@@@@@@@@@ @ @ @
@ @ @ @ @
@ @ @ @ @
@ @ @ @
@ @ @ @ @
@ @ @@@@@@@@@
@$1#*******##%$3
@$1 ##########%$3
@$1 ##########%$3
@$1 ##########%
########%
-14
View File
@@ -1,14 +0,0 @@
*/
*,*,*(
,,,,,,,,,,,,,,,,,,,,,,,,
,*,*,*,*,*,*,*,*,*,*,*,*
,,,,,,,,,,,,,,,,,,,,,,,,
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,*
,*,*,*,*,*,*,*,*,*,*,*,*,*,*
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
(*,*,*,*,*,*,*,*,*,*,*,*,*,
,,,,,,,,,,,,,,,,
&*,*,*#@@*,*,*,
+20
View File
@@ -0,0 +1,20 @@
$1aooooo$2,
$1aooooo$2``
$1aooooo$2``
$3(((((( $1aooooo$2``$3((((((
$1oooo$3@@ @C@*;,./k@@ @@ @$1oooo$2
$1oooooo$3@@ @@@@@@@@ @@k$1oooooo$2``
$1oooooooo$3\@ @/@@ @@$1ooooooooo$2``
`````````$3'*@*/'$2````````````
$3@@@( $1aooooo$2`` $3@@@@
@@ @ $1aooooo$2`` $3@ @@
@@@ $1aooooo$2`` $3@@@,
@@ $1aooooo$2`` $3 @@
@ $1aooooo$2`` $3 (@
$1aooooo$2``
$1aooooo$2``
$1aooooo$2``
$1aooooo$2``
$1aooooo$2``
```````
`````
+11 -10
View File
@@ -3408,6 +3408,7 @@ static const FFlogo O[] = {
.colors = {
FF_COLOR_FG_MAGENTA,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_LIGHT_BLUE,
},
},
// OmniOS
@@ -4615,16 +4616,6 @@ static const FFlogo S[] = {
FF_COLOR_FG_WHITE,
},
},
// Starry
{
.names = {"Starry"},
.lines = FASTFETCH_DATATEXT_LOGO_STARRY,
.colors = {
FF_COLOR_FG_GREEN,
},
.colorKeys = FF_COLOR_FG_GREEN,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
// StockLinux
{
.names = {"Stock Linux"},
@@ -4778,6 +4769,16 @@ static const FFlogo T[] = {
FF_COLOR_FG_WHITE,
},
},
// TempleOS
{
.names = {"TempleOS"},
.lines = FASTFETCH_DATATEXT_LOGO_TEMPLEOS,
.colors = {
FF_COLOR_FG_YELLOW,
FF_COLOR_FG_RED,
FF_COLOR_FG_CYAN,
},
},
// TileOS
{
.names = {"TileOS"},
+2 -2
View File
@@ -114,7 +114,7 @@ static bool ffLogoPrintCharsRaw(const char* data, size_t length, bool printError
static uint32_t logoAppendChars(const char* data, bool doColorReplacement, FFstrbuf* result)
{
FFOptionsLogo* options = &instance.config.logo;
uint32_t currentlineLength = options->width;
uint32_t currentlineLength = options->type == FF_LOGO_TYPE_IMAGE_CHAFA ? 0 : options->width; // For chafa, unit of options->width is pixels
uint32_t logoHeight = 0;
if (result)
@@ -260,7 +260,7 @@ static uint32_t logoAppendChars(const char* data, bool doColorReplacement, FFstr
if(currentlineLength > instance.state.logoWidth)
instance.state.logoWidth = currentlineLength;
return options->height > logoHeight ? options->height : logoHeight;
return options->type != FF_LOGO_TYPE_IMAGE_CHAFA && options->height > logoHeight ? options->height : logoHeight;
}
void ffLogoPrintChars(const char* data, bool doColorReplacement)
+5 -4
View File
@@ -27,9 +27,9 @@ static void printBtrfs(FFBtrfsOptions* options, FFBtrfsResult* result, uint8_t i
}
uint64_t used = 0, allocated = 0, total = result->totalSize;
for (int i = 0; i < 3; ++i)
for (uint32_t i = 0; i < ARRAY_SIZE(result->allocation); ++i)
{
uint64_t times = result->allocation[i].dup ? 2 : 1;
uint64_t times = result->allocation[i].copies;
used += result->allocation[i].used * times;
allocated += result->allocation[i].total * times;
}
@@ -180,11 +180,12 @@ bool ffGenerateBtrfsJsonResult(FF_MAYBE_UNUSED FFBtrfsOptions* options, yyjson_m
yyjson_mut_obj_add_uint(doc, obj, "sectorSize", btrfs->sectorSize);
yyjson_mut_obj_add_uint(doc, obj, "totalSize", btrfs->totalSize);
yyjson_mut_val* allocation = yyjson_mut_obj_add_arr(doc, obj, "allocation");
for (int i = 0; i < 3; ++i)
for (uint32_t i = 0; i < ARRAY_SIZE(btrfs->allocation); ++i)
{
yyjson_mut_val* item = yyjson_mut_arr_add_obj(doc, allocation);
yyjson_mut_obj_add_str(doc, item, "type", btrfs->allocation[i].type);
yyjson_mut_obj_add_bool(doc, item, "dup", btrfs->allocation[i].dup);
yyjson_mut_obj_add_str(doc, item, "profile", btrfs->allocation[i].profile);
yyjson_mut_obj_add_uint(doc, item, "copies", btrfs->allocation[i].copies);
yyjson_mut_obj_add_uint(doc, item, "used", btrfs->allocation[i].used);
yyjson_mut_obj_add_uint(doc, item, "total", btrfs->allocation[i].total);
}
+31 -5
View File
@@ -203,10 +203,10 @@ bool ffPrintDisk(FFDiskOptions* options)
if(__builtin_expect(options->folders.length == 0, 1) && (disk->type & ~options->showTypes))
continue;
if (options->hideFolders.length && ffDiskMatchMountpoint(&options->hideFolders, disk->mountpoint.chars))
if (options->hideFolders.length && ffStrbufSeparatedContain(&options->hideFolders, &disk->mountpoint, FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufMatchSeparated(&disk->filesystem, &options->hideFS, ':'))
if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &disk->filesystem, ':'))
continue;
printDisk(options, disk, ++index);
@@ -223,6 +223,32 @@ bool ffPrintDisk(FFDiskOptions* options)
return true;
}
static bool setSeparatedList(FFstrbuf* strbuf, yyjson_val* val, char separator)
{
if (yyjson_is_str(val))
{
ffStrbufSetJsonVal(strbuf, val);
return true;
}
if (yyjson_is_arr(val))
{
ffStrbufClear(strbuf);
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
if (strbuf->length > 0)
ffStrbufAppendC(strbuf, separator);
ffStrbufAppendJsonVal(strbuf, elem);
}
}
return true;
}
return false;
}
void ffParseDiskJsonObject(FFDiskOptions* options, yyjson_val* module)
{
yyjson_val *key, *val;
@@ -234,19 +260,19 @@ void ffParseDiskJsonObject(FFDiskOptions* options, yyjson_val* module)
if (unsafe_yyjson_equals_str(key, "folders"))
{
ffStrbufSetJsonVal(&options->folders, val);
setSeparatedList(&options->folders, val, FF_DISK_FOLDER_SEPARATOR);
continue;
}
if (unsafe_yyjson_equals_str(key, "hideFolders"))
{
ffStrbufSetJsonVal(&options->hideFolders, val);
setSeparatedList(&options->hideFolders, val, FF_DISK_FOLDER_SEPARATOR);
continue;
}
if (unsafe_yyjson_equals_str(key, "hideFS"))
{
ffStrbufSetJsonVal(&options->hideFS, val);
setSeparatedList(&options->hideFS, val, ':');
continue;
}
+16 -12
View File
@@ -101,6 +101,7 @@ bool ffPrintDisplay(FFDisplayOptions* options)
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
double inch = sqrt(result->physicalWidth * result->physicalWidth + result->physicalHeight * result->physicalHeight) / 25.4;
double scaleFactor = (double) result->height / (double) result->scaledHeight;
if(options->moduleArgs.outputFormat.length == 0)
{
@@ -108,23 +109,28 @@ bool ffPrintDisplay(FFDisplayOptions* options)
ffStrbufAppendF(&buffer, "%ix%i", result->width, result->height);
if(result->refreshRate > 0)
{
const char* space = instance.config.display.freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ";
if(options->preciseRefreshRate)
ffStrbufAppendF(&buffer, " @ %g%sHz", ((int) (result->refreshRate * 1000 + 0.5)) / 1000.0, space);
else
ffStrbufAppendF(&buffer, " @ %i%sHz", (uint32_t) (result->refreshRate + 0.5), space);
}
if(
result->scaledWidth > 0 && result->scaledWidth != result->width &&
result->scaledHeight > 0 && result->scaledHeight != result->height)
ffStrbufAppendF(&buffer, " (as %ix%i)", result->scaledWidth, result->scaledHeight);
{
ffStrbufAppendS(&buffer, " @ ");
ffStrbufAppendDouble(&buffer, scaleFactor, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS);
ffStrbufAppendC(&buffer, 'x');
}
if (inch > 1)
ffStrbufAppendF(&buffer, " in %i\"", (uint32_t) (inch + 0.5));
if(result->refreshRate > 0)
{
ffStrbufAppendS(&buffer, ", ");
if(options->preciseRefreshRate)
ffStrbufAppendDouble(&buffer, result->refreshRate, 3, false);
else
ffStrbufAppendSInt(&buffer, (int) (result->refreshRate + 0.5));
ffStrbufAppendS(&buffer, instance.config.display.freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "Hz" : " Hz");
}
bool flag = false;
if (result->type != FF_DISPLAY_TYPE_UNKNOWN)
{
@@ -185,8 +191,6 @@ bool ffPrintDisplay(FFDisplayOptions* options)
else
buf[0] = '\0';
double scaleFactor = (double) result->height / (double) result->scaledHeight;
FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
FF_FORMAT_ARG(result->width, "width"),
FF_FORMAT_ARG(result->height, "height"),
+76 -5
View File
@@ -68,15 +68,48 @@ bool ffPrintGamepad(FFGamepadOptions* options)
return false;
}
uint8_t index = 0;
FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFGamepadDevice*));
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
{
printDevice(options, device, result.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
if(!ignored)
{
FFGamepadDevice** ptr = ffListAdd(&filtered);
*ptr = device;
}
}
return true;
bool ret = true;
if(!filtered.length)
{
ffPrintError(FF_GAMEPAD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "All devices are ignored");
ret = false;
}
else
{
uint8_t index = 0;
FF_LIST_FOR_EACH(FFGamepadDevice*, pdevice, filtered)
{
FFGamepadDevice* device = *pdevice;
printDevice(options, device, filtered.length > 1 ? ++index : 0);
}
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
{
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
}
}
return ret;
}
void ffParseGamepadJsonObject(FFGamepadOptions* options, yyjson_val* module)
@@ -88,6 +121,21 @@ void ffParseGamepadJsonObject(FFGamepadOptions* options, yyjson_val* module)
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (unsafe_yyjson_equals_str(key, "ignores"))
{
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
FFstrbuf* strbuf = ffListAdd(&options->ignores);
ffStrbufInitJsonVal(strbuf, elem);
}
}
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
@@ -99,6 +147,12 @@ void ffGenerateGamepadJsonConfig(FFGamepadOptions* options, yyjson_mut_doc* doc,
{
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
if (options->ignores.length > 0)
{
yyjson_mut_val* ignores = yyjson_mut_obj_add_arr(doc, module, "ignores");
FF_LIST_FOR_EACH(FFstrbuf, strbuf, options->ignores)
yyjson_mut_arr_append(ignores, yyjson_mut_strncpy(doc, strbuf->chars, strbuf->length));
}
ffPercentGenerateJsonConfig(doc, module, options->percent);
}
@@ -120,6 +174,17 @@ bool ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
yyjson_mut_obj_add_bool(doc, obj, "ignored", ignored);
}
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
@@ -134,12 +199,18 @@ bool ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs
void ffInitGamepadOptions(FFGamepadOptions* options)
{
ffOptionInitModuleArg(&options->moduleArgs, "󰺵");
ffListInit(&options->ignores, sizeof(FFstrbuf));
options->percent = (FFPercentageModuleConfig) { 50, 20, 0 };
}
void ffDestroyGamepadOptions(FFGamepadOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
FF_LIST_FOR_EACH(FFstrbuf, str, options->ignores)
ffStrbufDestroy(str);
ffListDestroy(&options->ignores);
}
FFModuleBaseInfo ffGamepadModuleInfo = {
+2
View File
@@ -1,11 +1,13 @@
#pragma once
#include "common/option.h"
#include "util/FFlist.h"
typedef struct FFGamepadOptions
{
FFModuleArgs moduleArgs;
FFlist ignores; // List of FFstrbuf
FFPercentageModuleConfig percent;
} FFGamepadOptions;
+73 -5
View File
@@ -39,15 +39,44 @@ bool ffPrintKeyboard(FFKeyboardOptions* options)
return false;
}
uint8_t index = 0;
FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFKeyboardDevice*));
FF_LIST_FOR_EACH(FFKeyboardDevice, device, result)
{
printDevice(options, device, result.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
if(!ignored)
{
FFKeyboardDevice** ptr = ffListAdd(&filtered);
*ptr = device;
}
}
return true;
bool ret = true;
if(!filtered.length)
{
ffPrintError(FF_KEYBOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "All devices are ignored");
ret = false;
}
else
{
uint8_t index = 0;
FF_LIST_FOR_EACH(FFKeyboardDevice*, pdevice, filtered)
{
FFKeyboardDevice* device = *pdevice;
printDevice(options, device, filtered.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
}
}
return ret;
}
void ffParseKeyboardJsonObject(FFKeyboardOptions* options, yyjson_val* module)
@@ -59,6 +88,21 @@ void ffParseKeyboardJsonObject(FFKeyboardOptions* options, yyjson_val* module)
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (unsafe_yyjson_equals_str(key, "ignores"))
{
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
FFstrbuf* strbuf = ffListAdd(&options->ignores);
ffStrbufInitJsonVal(strbuf, elem);
}
}
continue;
}
ffPrintError(FF_KEYBOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -66,6 +110,13 @@ void ffParseKeyboardJsonObject(FFKeyboardOptions* options, yyjson_val* module)
void ffGenerateKeyboardJsonConfig(FFKeyboardOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
if (options->ignores.length > 0)
{
yyjson_mut_val* ignores = yyjson_mut_obj_add_arr(doc, module, "ignores");
FF_LIST_FOR_EACH(FFstrbuf, strbuf, options->ignores)
yyjson_mut_arr_append(ignores, yyjson_mut_strncpy(doc, strbuf->chars, strbuf->length));
}
}
bool ffGenerateKeyboardJsonResult(FF_MAYBE_UNUSED FFKeyboardOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -86,6 +137,17 @@ bool ffGenerateKeyboardJsonResult(FF_MAYBE_UNUSED FFKeyboardOptions* options, yy
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
yyjson_mut_obj_add_bool(doc, obj, "ignored", ignored);
}
FF_LIST_FOR_EACH(FFKeyboardDevice, device, result)
@@ -100,11 +162,17 @@ bool ffGenerateKeyboardJsonResult(FF_MAYBE_UNUSED FFKeyboardOptions* options, yy
void ffInitKeyboardOptions(FFKeyboardOptions* options)
{
ffOptionInitModuleArg(&options->moduleArgs, "");
ffListInit(&options->ignores, sizeof(FFstrbuf));
}
void ffDestroyKeyboardOptions(FFKeyboardOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
FF_LIST_FOR_EACH(FFstrbuf, str, options->ignores)
ffStrbufDestroy(str);
ffListDestroy(&options->ignores);
}
FFModuleBaseInfo ffKeyboardModuleInfo = {
+3
View File
@@ -1,10 +1,13 @@
#pragma once
#include "common/option.h"
#include "util/FFlist.h"
typedef struct FFKeyboardOptions
{
FFModuleArgs moduleArgs;
FFlist ignores; // List of FFstrbuf
} FFKeyboardOptions;
static_assert(sizeof(FFKeyboardOptions) <= FF_OPTION_MAX_SIZE, "FFKeyboardOptions size exceeds maximum allowed size");
+47 -13
View File
@@ -37,17 +37,13 @@ static void appendSpeed(FFLocalIpResult* ip, FFstrbuf* strbuf)
{
if (ip->speed >= 1000000)
{
if (instance.config.display.fractionNdigits >= 0)
ffStrbufAppendF(strbuf, "%.*f Tbps", instance.config.display.fractionNdigits, ip->speed / 1000000.0);
else
ffStrbufAppendF(strbuf, "%g Tbps", ip->speed / 1000000.0);
ffStrbufAppendDouble(strbuf, ip->speed / 1e6, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS);
ffStrbufAppendS(strbuf, " Tbps");
}
else if (ip->speed >= 1000)
{
if (instance.config.display.fractionNdigits >= 0)
ffStrbufAppendF(strbuf, "%.*f Gbps", instance.config.display.fractionNdigits, ip->speed / 1000.0);
else
ffStrbufAppendF(strbuf, "%g Gbps", ip->speed / 1000.0);
ffStrbufAppendDouble(strbuf, ip->speed / 1e3, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS);
ffStrbufAppendS(strbuf, " Gbps");
}
else
ffStrbufAppendF(strbuf, "%u Mbps", (unsigned) ip->speed);
@@ -202,10 +198,33 @@ void ffParseLocalIpJsonObject(FFLocalIpOptions* options, yyjson_val* module)
if (unsafe_yyjson_equals_str(key, "showIpv6"))
{
if (yyjson_get_bool(val))
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
else
options->showType &= ~FF_LOCALIP_TYPE_IPV6_BIT;
if (yyjson_is_bool(val))
{
options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
if (unsafe_yyjson_get_bool(val))
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
else
options->showType &= ~FF_LOCALIP_TYPE_IPV6_BIT;
}
else if (yyjson_is_str(val))
{
int value;
const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]) {
{ "auto", FF_LOCALIP_IPV6_TYPE_AUTO },
{ "gua", FF_LOCALIP_IPV6_TYPE_GUA_BIT },
{ "ula", FF_LOCALIP_IPV6_TYPE_ULA_BIT },
{ "lla", FF_LOCALIP_IPV6_TYPE_LLA_BIT },
{ "unknown", FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT },
{},
});
if (error)
ffPrintError(FF_LOCALIP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
else
{
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
options->ipv6Type = (FFLocalIpIpv6Type) value;
}
}
continue;
}
@@ -306,7 +325,21 @@ void ffGenerateLocalIpJsonConfig(FFLocalIpOptions* options, yyjson_mut_doc* doc,
yyjson_mut_obj_add_bool(doc, module, "showIpv4", !!(options->showType & FF_LOCALIP_TYPE_IPV4_BIT));
yyjson_mut_obj_add_bool(doc, module, "showIpv6", !!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT));
if (options->ipv6Type == FF_LOCALIP_IPV6_TYPE_AUTO)
yyjson_mut_obj_add_bool(doc, module, "showIpv6", !!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT));
else
{
const char* str = NULL;
switch (options->ipv6Type)
{
case FF_LOCALIP_IPV6_TYPE_GUA_BIT: str = "gua"; break;
case FF_LOCALIP_IPV6_TYPE_ULA_BIT: str = "ula"; break;
case FF_LOCALIP_IPV6_TYPE_LLA_BIT: str = "lla"; break;
case FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT: str = "unknown"; break;
default: str = "auto"; break;
}
yyjson_mut_obj_add_str(doc, module, "showIpv6", str);
}
yyjson_mut_obj_add_bool(doc, module, "showMac", !!(options->showType & FF_LOCALIP_TYPE_MAC_BIT));
@@ -389,6 +422,7 @@ void ffInitLocalIpOptions(FFLocalIpOptions* options)
| FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT
#endif
;
options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
ffStrbufInit(&options->namePrefix);
}
+15
View File
@@ -21,11 +21,26 @@ typedef enum __attribute__((__packed__)) FFLocalIpType
} FFLocalIpType;
static_assert(sizeof(FFLocalIpType) == sizeof(uint16_t), "");
typedef enum __attribute__((__packed__)) FFLocalIpIpv6Type
{
FF_LOCALIP_IPV6_TYPE_NONE = 0b00000000,
FF_LOCALIP_IPV6_TYPE_GUA_BIT = 0b00000001,
FF_LOCALIP_IPV6_TYPE_ULA_BIT = 0b00000010,
FF_LOCALIP_IPV6_TYPE_LLA_BIT = 0b00000100,
FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT = 0b00001000, // IPv4-mapped, loopback, etc.
FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT = 0b01000000, // Temporary, duplicated, etc.
FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT = 0b10000000, // PREFER_SOURCE (manually set)
FF_LOCALIP_IPV6_TYPE_TYPE_MASK = 0b00011111,
FF_LOCALIP_IPV6_TYPE_AUTO = 0b11111111, // Used for detect option
} FFLocalIpIpv6Type;
static_assert(sizeof(FFLocalIpIpv6Type) == sizeof(uint8_t), "");
typedef struct FFLocalIpOptions
{
FFModuleArgs moduleArgs;
FFLocalIpType showType;
FFLocalIpIpv6Type ipv6Type;
FFstrbuf namePrefix;
} FFLocalIpOptions;
+75 -3
View File
@@ -39,15 +39,48 @@ bool ffPrintMouse(FFMouseOptions* options)
return false;
}
uint8_t index = 0;
FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFMouseDevice*));
FF_LIST_FOR_EACH(FFMouseDevice, device, result)
{
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
if(!ignored)
{
FFMouseDevice** ptr = ffListAdd(&filtered);
*ptr = device;
}
}
bool ret = true;
if(!filtered.length)
{
ffPrintError(FF_MOUSE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "All devices are ignored");
ret = false;
}
else
{
uint8_t index = 0;
FF_LIST_FOR_EACH(FFMouseDevice*, pdevice, filtered)
{
FFMouseDevice* device = *pdevice;
printDevice(options, device, filtered.length > 1 ? ++index : 0);
}
}
FF_LIST_FOR_EACH(FFMouseDevice, device, result)
{
printDevice(options, device, result.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
}
return true;
return ret;
}
void ffParseMouseJsonObject(FFMouseOptions* options, yyjson_val* module)
@@ -59,6 +92,21 @@ void ffParseMouseJsonObject(FFMouseOptions* options, yyjson_val* module)
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (unsafe_yyjson_equals_str(key, "ignores"))
{
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
FFstrbuf* strbuf = ffListAdd(&options->ignores);
ffStrbufInitJsonVal(strbuf, elem);
}
}
continue;
}
ffPrintError(FF_MOUSE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -66,6 +114,13 @@ void ffParseMouseJsonObject(FFMouseOptions* options, yyjson_val* module)
void ffGenerateMouseJsonConfig(FFMouseOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
if (options->ignores.length > 0)
{
yyjson_mut_val* ignores = yyjson_mut_obj_add_arr(doc, module, "ignores");
FF_LIST_FOR_EACH(FFstrbuf, strbuf, options->ignores)
yyjson_mut_arr_append(ignores, yyjson_mut_strncpy(doc, strbuf->chars, strbuf->length));
}
}
bool ffGenerateMouseJsonResult(FF_MAYBE_UNUSED FFMouseOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -86,6 +141,17 @@ bool ffGenerateMouseJsonResult(FF_MAYBE_UNUSED FFMouseOptions* options, yyjson_m
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
yyjson_mut_obj_add_bool(doc, obj, "ignored", ignored);
}
FF_LIST_FOR_EACH(FFMouseDevice, device, result)
@@ -100,11 +166,17 @@ bool ffGenerateMouseJsonResult(FF_MAYBE_UNUSED FFMouseOptions* options, yyjson_m
void ffInitMouseOptions(FFMouseOptions* options)
{
ffOptionInitModuleArg(&options->moduleArgs, "󰍽");
ffListInit(&options->ignores, sizeof(FFstrbuf));
}
void ffDestroyMouseOptions(FFMouseOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
FF_LIST_FOR_EACH(FFstrbuf, str, options->ignores)
ffStrbufDestroy(str);
ffListDestroy(&options->ignores);
}
FFModuleBaseInfo ffMouseModuleInfo = {
+3
View File
@@ -1,10 +1,13 @@
#pragma once
#include "common/option.h"
#include "util/FFlist.h"
typedef struct FFMouseOptions
{
FFModuleArgs moduleArgs;
FFlist ignores; // List of FFstrbuf
} FFMouseOptions;
static_assert(sizeof(FFMouseOptions) <= FF_OPTION_MAX_SIZE, "FFMouseOptions size exceeds maximum allowed size");
+1 -1
View File
@@ -6,7 +6,7 @@ typedef struct FFSeparatorOptions
{
FFstrbuf string;
FFstrbuf outputColor;
uint32_t length;
uint32_t times;
} FFSeparatorOptions;
static_assert(sizeof(FFSeparatorOptions) <= FF_OPTION_MAX_SIZE, "FFSeparatorOptions size exceeds maximum allowed size");
+63 -41
View File
@@ -9,27 +9,52 @@
#include <locale.h>
static inline uint32_t max(uint32_t a, uint32_t b)
#if __SIZEOF_WCHAR_T__ == 4
static inline size_t mbrtoc32(uint32_t* restrict pc32, const char* restrict s, size_t n, mbstate_t* restrict ps)
{
return mbrtowc((wchar_t*) pc32, s, n, ps);
}
#else
#include <uchar.h>
#endif
static uint8_t getMbrWidth(const char* mbstr, uint32_t length, const char** next, mbstate_t* state)
{
return a > b ? a : b;
if (__builtin_expect((uint8_t) *mbstr < 0x80, true)) // ASCII fast path
{
if (next) *next = mbstr + 1;
return 1;
}
uint32_t c32;
uint32_t len = (uint32_t) mbrtoc32(&c32, mbstr, length, state);
if (len >= (uint32_t) -3)
{
// Invalid or incomplete multibyte sequence
if (next) *next = mbstr + 1;
return 1;
}
if (next) *next = mbstr + len;
int width = mk_wcwidth(c32);
return width < 0 ? 0 : (uint8_t) width;
}
static inline uint32_t getWcsWidth(const FFstrbuf* mbstr, wchar_t* wstr, mbstate_t* state)
static uint32_t getWcsWidth(const FFstrbuf* mbstr)
{
int result = 1;
for (uint32_t i = 0; i < mbstr->length; i++)
{
if (!isascii(mbstr->chars[i]))
{
result = 0;
break;
}
}
if (__builtin_expect(result, 1)) return mbstr->length;
mbstate_t state = {};
uint32_t remainLength = mbstr->length;
uint32_t result = 0;
const char* ptr = mbstr->chars;
while (remainLength > 0 && *ptr != '\0')
{
const char* lastPtr = NULL;
result += getMbrWidth(ptr, remainLength, &lastPtr, &state);
remainLength -= (uint32_t)(lastPtr - ptr);
ptr = lastPtr;
}
const char* str = mbstr->chars;
uint32_t wstrLength = (uint32_t) mbsrtowcs(wstr, &str, mbstr->length, state);
result = mk_wcswidth(wstr, wstrLength);
return result > 0 ? (uint32_t) result : mbstr->length;
}
@@ -40,13 +65,13 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
if(options->outputColor.length && !instance.config.display.pipe)
ffPrintColor(&options->outputColor);
if (options->length > 0)
if (options->times > 0)
{
if(__builtin_expect(options->string.length == 1, 1))
ffPrintCharTimes(options->string.chars[0], options->length);
ffPrintCharTimes(options->string.chars[0], options->times);
else
{
for (uint32_t i = 0; i < options->length; i++)
for (uint32_t i = 0; i < options->times; i++)
{
fputs(options->string.chars, stdout);
}
@@ -55,14 +80,10 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
else
{
setlocale(LC_CTYPE, "");
mbstate_t state = {};
const FFPlatform* platform = &instance.state.platform;
FF_AUTO_FREE wchar_t* wstr = malloc((max(
platform->userName.length, options->string.length) + 1) * sizeof(*wstr));
uint32_t titleLength = 1 // @
+ getWcsWidth(&platform->userName, wstr, &state) // user name
+ getWcsWidth(&platform->userName) // user name
+ (instance.state.titleFqdn ? platform->hostName.length : ffStrbufFirstIndexC(&platform->hostName, '.')); // host name
if(__builtin_expect(options->string.length == 1, 1))
@@ -71,7 +92,7 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
}
else
{
uint32_t wcsLength = getWcsWidth(&options->string, wstr, &state);
uint32_t wcsLength = getWcsWidth(&options->string);
int remaining = (int) titleLength;
//Write the whole separator as often as it fits fully into titleLength
@@ -84,24 +105,19 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
if (wcsLength != options->string.length)
{
// Unicode chars
for(int i = 0; remaining > 0; ++i)
const char* ptr = options->string.chars;
mbstate_t state = {};
const char* next = NULL;
while (remaining > 0 && *ptr != '\0')
{
#ifdef __linux__
// https://stackoverflow.com/questions/75126743/i-have-difficulties-with-putwchar-in-c#answer-75137784
char wch[16] = "";
uint32_t wchLength = (uint32_t) wcrtomb(wch, wstr[i], &state);
fwrite(wch, wchLength, 1, stdout);
#else
putwchar(wstr[i]);
#endif
int width = mk_wcwidth(wstr[i]);
remaining -= width < 0 ? 0 : width;
remaining -= (int) getMbrWidth(ptr, (uint32_t)(options->string.length - (ptr - options->string.chars)), &next, &state);
ptr = next;
}
fwrite(options->string.chars, (size_t) (ptr - options->string.chars), 1, stdout);
}
else
{
for(int i = 0; i < remaining; i++)
putchar(options->string.chars[i]);
fwrite(options->string.chars, (size_t) remaining, 1, stdout);
}
}
}
@@ -136,9 +152,15 @@ void ffParseSeparatorJsonObject(FFSeparatorOptions* options, yyjson_val* module)
continue;
}
if (unsafe_yyjson_equals_str(key, "times"))
{
options->times = (uint32_t) yyjson_get_uint(val);
continue;
}
if (unsafe_yyjson_equals_str(key, "length"))
{
options->length = (uint32_t) yyjson_get_uint(val);
ffPrintError(FF_SEPARATOR_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "The option length has been renamed to times.");
continue;
}
@@ -150,14 +172,14 @@ void ffGenerateSeparatorJsonConfig(FFSeparatorOptions* options, yyjson_mut_doc*
{
yyjson_mut_obj_add_strbuf(doc, module, "string", &options->string);
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &options->outputColor);
yyjson_mut_obj_add_uint(doc, module, "length", options->length);
yyjson_mut_obj_add_uint(doc, module, "times", options->times);
}
void ffInitSeparatorOptions(FFSeparatorOptions* options)
{
ffStrbufInitStatic(&options->string, "-");
ffStrbufInit(&options->outputColor);
options->length = 0;
options->times = 0;
}
void ffDestroySeparatorOptions(FFSeparatorOptions* options)
+79 -8
View File
@@ -136,7 +136,15 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va
}
yyjson_val* ndigits = yyjson_obj_get(val, "ndigits");
if (ndigits) options->sizeNdigits = (uint8_t) yyjson_get_uint(ndigits);
if (ndigits)
{
if (!yyjson_is_uint(ndigits))
return "display.size.ndigits must be an unsigned integer";
uint64_t val = yyjson_get_uint(ndigits);
if (val > 9)
return "display.size.ndigits must be between 0 and 9";
options->sizeNdigits = (uint8_t) val;
}
yyjson_val* spaceBeforeUnit = yyjson_obj_get(val, "spaceBeforeUnit");
if (spaceBeforeUnit)
@@ -177,7 +185,15 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va
}
yyjson_val* ndigits = yyjson_obj_get(val, "ndigits");
if (ndigits) options->tempNdigits = (uint8_t) yyjson_get_uint(ndigits);
if (ndigits)
{
if (!yyjson_is_uint(ndigits))
return "display.temperature.ndigits must be an unsigned integer";
uint64_t val = yyjson_get_uint(ndigits);
if (val > 9)
return "display.temperature.ndigits must be between 0 and 9";
options->tempNdigits = (uint8_t) val;
}
yyjson_val* color = yyjson_obj_get(val, "color");
if (color)
@@ -222,7 +238,15 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va
}
yyjson_val* ndigits = yyjson_obj_get(val, "ndigits");
if (ndigits) options->percentNdigits = (uint8_t) yyjson_get_uint(ndigits);
if (ndigits)
{
if (!yyjson_is_uint(ndigits))
return "display.percent.ndigits must be an unsigned integer";
uint64_t val = yyjson_get_uint(ndigits);
if (val > 9)
return "display.percent.ndigits must be between 0 and 9";
options->percentNdigits = (uint8_t) val;
}
yyjson_val* color = yyjson_obj_get(val, "color");
if (color)
@@ -376,9 +400,33 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va
{
if (yyjson_is_null(ndigits))
options->fractionNdigits = -1;
else if (!yyjson_is_int(ndigits))
return "display.fraction.ndigits must be an integer";
options->fractionNdigits = (int8_t) yyjson_get_int(ndigits);
else
{
if (!yyjson_is_int(ndigits))
return "display.fraction.ndigits must be an integer";
int64_t val = yyjson_get_int(ndigits);
if (val < -1 || val > 9)
return "display.fraction.ndigits must be between -1 and 9";
options->fractionNdigits = (int8_t) val;
}
}
yyjson_val* trailingZeros = yyjson_obj_get(val, "trailingZeros");
if (trailingZeros)
{
if (yyjson_is_null(trailingZeros))
options->fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT;
else
{
int value;
const char* error = ffJsonConfigParseEnum(trailingZeros, &value, (FFKeyValuePair[]) {
{ "default", FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT },
{ "always", FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS },
{ "never", FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER },
{},
});
if (error) return error;
options->fractionTrailingZeros = (FFFractionTrailingZerosType) value;
}
}
}
else
@@ -431,7 +479,20 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va
return "display.freq must be an object";
yyjson_val* ndigits = yyjson_obj_get(val, "ndigits");
if (ndigits) options->freqNdigits = (int8_t) yyjson_get_int(ndigits);
if (ndigits)
{
if (yyjson_is_null(ndigits))
options->freqNdigits = -1;
else
{
if (!yyjson_is_int(ndigits))
return "display.freq.ndigits must be an integer";
int64_t val = yyjson_get_int(ndigits);
if (val < -1 || val > 9)
return "display.freq.ndigits must be between -1 and 9";
options->freqNdigits = (int8_t) val;
}
}
yyjson_val* spaceBeforeUnit = yyjson_obj_get(val, "spaceBeforeUnit");
if (spaceBeforeUnit)
@@ -690,6 +751,15 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key
}
else if(ffStrEqualsIgnCase(key, "--fraction-ndigits"))
options->fractionNdigits = (int8_t) ffOptionParseInt32(key, value);
else if(ffStrEqualsIgnCase(key, "--fraction-trailing-zeros"))
{
options->fractionTrailingZeros = (FFFractionTrailingZerosType) ffOptionParseEnum(key, value, (FFKeyValuePair[]) {
{ "default", FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT },
{ "always", FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS },
{ "never", FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER },
{},
});
}
else if(ffStrEqualsIgnCase(key, "--no-buffer"))
options->noBuffer = ffOptionParseBoolean(value);
else if(ffStrStartsWithIgnCase(key, "--bar-"))
@@ -809,7 +879,8 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options)
options->freqNdigits = 2;
options->freqSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT;
options->fractionNdigits = -1;
options->fractionNdigits = 2;
options->fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT;
ffListInit(&options->constants, sizeof(FFstrbuf));
}
+8
View File
@@ -25,6 +25,13 @@ typedef enum __attribute__((__packed__)) FFSpaceBeforeUnitType
FF_SPACE_BEFORE_UNIT_NEVER,
} FFSpaceBeforeUnitType;
typedef enum __attribute__((__packed__)) FFFractionTrailingZerosType
{
FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT,
FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS,
FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER,
} FFFractionTrailingZerosType;
typedef struct FFOptionsDisplay
{
//If one of those is empty, ffLogoPrint will set them
@@ -81,6 +88,7 @@ typedef struct FFOptionsDisplay
int8_t freqNdigits;
FFSpaceBeforeUnitType freqSpaceBeforeUnit;
int8_t fractionNdigits;
FFFractionTrailingZerosType fractionTrailingZeros;
FFlist constants; // list of FFstrbuf
} FFOptionsDisplay;
+86 -11
View File
@@ -571,7 +571,7 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value)
strbuf->length += (uint32_t)(end - start);
}
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision)
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros)
{
assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point
@@ -598,18 +598,29 @@ void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision)
return;
}
if (precision > 1)
if (trailingZeros)
{
for (char* p = end - 1; *p != '.' && p > start; --p)
--precision;
if (precision > 0)
ffStrbufAppendNC(strbuf, (uint32_t) precision, '0');
if (precision > 1)
{
for (char* p = end - 1; *p != '.' && p > start; --p)
--precision;
if (precision > 0)
ffStrbufAppendNC(strbuf, (uint32_t) precision, '0');
}
else if (precision == 0 || (precision < 0 && end[-1] == '0'))
{
goto removeDecimalPoint;
}
}
else if (precision == 0 || (precision < 0 && end[-1] == '0'))
else
{
// yyjson always appends ".0", so we need to remove it
strbuf->length -= 2;
strbuf->chars[strbuf->length] = '\0';
if (end[-1] == '0')
{
removeDecimalPoint:
// yyjson always appends ".0" to make it a float point number. We need to remove it
strbuf->length -= 2;
strbuf->chars[strbuf->length] = '\0';
}
}
}
@@ -719,7 +730,7 @@ bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf)
return changed;
}
/// @brief Check if a separated string contains a substring.
/// @brief Check if a separated string (comp) contains a substring (strbuf).
/// @param strbuf The substring to check.
/// @param compLength The length of the separated string to check.
/// @param comp The separated string to check.
@@ -748,6 +759,31 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
return false;
}
/// @brief Case insensitive version of ffStrbufMatchSeparatedNS.
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
{
if (strbuf->length == 0)
return true;
if (compLength == 0)
return false;
for (const char* p = comp; p < comp + compLength;)
{
const char* colon = memchr(p, separator, compLength);
if (colon == NULL)
return strcasecmp(strbuf->chars, p) == 0;
uint32_t substrLength = (uint32_t) (colon - p);
if (strbuf->length == substrLength && strncasecmp(strbuf->chars, p, substrLength) == 0)
return true;
p = colon + 1;
}
return false;
}
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint)
{
if (codepoint <= 0x7F) {
@@ -779,3 +815,42 @@ int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint)
ffStrbufAppendS(strbuf, ""); // U+FFFD REPLACEMENT CHARACTER
return 1;
}
/// @brief Check if a separated string (strbuf) contains a substring (comp).
/// @param strbuf The separated to check.
/// @param compLength The length of the separated string to check.
/// @param comp The substring to check.
/// @param separator The separator character.
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
{
uint32_t startIndex = 0;
while(startIndex < strbuf->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(strbuf, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == compLength && memcmp(strbuf->chars + startIndex, comp, compLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
{
uint32_t startIndex = 0;
while(startIndex < strbuf->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(strbuf, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == compLength && strncasecmp(strbuf->chars + startIndex, comp, compLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
+34 -1
View File
@@ -100,6 +100,9 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer);
void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer);
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
@@ -107,7 +110,7 @@ void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value);
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
// Appends a double value to the string buffer with the specified precision (0~15).
// if `precision < 0`, let yyjson decide the precision
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision);
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros);
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
{
@@ -566,4 +569,34 @@ static inline bool ffStrbufMatchSeparated(const FFstrbuf* strbuf, const FFstrbuf
return ffStrbufMatchSeparatedNS(strbuf, comp->length, comp->chars, separator);
}
static inline bool ffStrbufMatchSeparatedIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
}
static inline bool ffStrbufMatchSeparatedIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
{
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
static inline bool ffStrbufSeparatedContainS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufSeparatedContainNS(strbuf, (uint32_t) strlen(comp), comp, separator);
}
static inline bool ffStrbufSeparatedContain(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
{
return ffStrbufSeparatedContainNS(strbuf, comp->length, comp->chars, separator);
}
static inline bool ffStrbufSeparatedContainIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufSeparatedContainIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
}
static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
{
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
#define FF_STRBUF_AUTO_DESTROY FFstrbuf __attribute__((__cleanup__(ffStrbufDestroy)))
+32
View File
@@ -0,0 +1,32 @@
#include "wcwidth.h"
#include "3rdparty/widecharwidth/widechar_width_c.h"
int mk_wcwidth(uint32_t wc)
{
// // We render U+1F6E1 (🛡) with a width of 2,
// // but widechar_width says it has a width of 1 because Unicode classifies it as "neutral".
// //
// // So we simply decide the width ourselves
// if (wc == 0x1F6E1) return 2;
//
// Well terminals do show it as width 1 after all
int width = widechar_wcwidth(wc);
switch (width) {
case widechar_ambiguous:
case widechar_private_use:
return 1;
case widechar_widened_in_9:
// Our renderer supports Unicode 9
return 2;
// case widechar_nonprint:
// case widechar_combining:
// case widechar_unassigned:
// case widechar_non_character:
// return -1;
default:
// Use the width widechar_width gave us.
return width;
}
}
+9 -9
View File
@@ -1,16 +1,16 @@
#pragma once
#include <wchar.h>
#include <stdint.h>
#ifdef FF_HAVE_WCWIDTH
static inline int mk_wcwidth(wchar_t ucs) {
return wcwidth(ucs);
}
static inline int mk_wcswidth(const wchar_t *pwcs, size_t n) {
return wcswidth(pwcs, n);
#include <wchar.h>
// Should be char32_t but it's not defined on macOS
static_assert(sizeof(wchar_t) == sizeof(uint32_t), "wcwidth implementation requires wchar_t to be 32 bits");
static inline int mk_wcwidth(uint32_t ucs) {
return wcwidth((wchar_t) ucs);
}
#else
// https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
int mk_wcwidth(wchar_t ucs);
int mk_wcswidth(const wchar_t *pwcs, size_t n);
int mk_wcwidth(uint32_t wc);
#endif
+185 -28
View File
@@ -663,6 +663,48 @@ int main(void)
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, "abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abc", ':') == true);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":ABC", ':') == false);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abcdef", ':') == false);
}
{
ffStrbufSetStatic(&strbuf, "ABC");
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:def:ghi", ' ') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:def:ghi", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def:ghi", ' ') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def:ghi", ':') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def", ':') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "", ' ') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abc", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":ABC", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abcdef", ':') == false);
}
{
ffStrbufSetStatic(&strbuf, "abc:def:ghi");
VERIFY(ffStrbufSeparatedContainS(&strbuf, "abc", ' ') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "abc", ':') == true);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "def", ' ') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "def", ':') == true);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "DEF", ':') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "a", ':') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "e", ':') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "i", ':') == false);
}
{
ffStrbufSetStatic(&strbuf, "ABC:DEF:GHI");
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "abc", ' ') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "abc", ':') == true);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "def", ' ') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "def", ':') == true);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "DEF", ':') == true);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "a", ':') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "e", ':') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "i", ':') == false);
}
{
@@ -744,115 +786,230 @@ int main(void)
}
{
ffStrbufAppendDouble(&strbuf, 120.0, 0);
ffStrbufAppendDouble(&strbuf, 120.0, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.0, 1);
ffStrbufAppendDouble(&strbuf, 120.0, 1, true);
VERIFY(ffStrbufEqualS(&strbuf, "120.0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.0, 5);
ffStrbufAppendDouble(&strbuf, 120.0, 5, true);
VERIFY(ffStrbufEqualS(&strbuf, "120.00000"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, 5);
ffStrbufAppendDouble(&strbuf, 120.123456789, 5, true);
VERIFY(ffStrbufEqualS(&strbuf, "120.12346"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.888888, 0);
ffStrbufAppendDouble(&strbuf, 120.888888, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "121"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.999999, 2);
ffStrbufAppendDouble(&strbuf, 120.999999, 2, true);
VERIFY(ffStrbufEqualS(&strbuf, "121.00"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, 0);
ffStrbufAppendDouble(&strbuf, 120.123456789, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, -1);
ffStrbufAppendDouble(&strbuf, 120.123456789, -1, true);
VERIFY(ffStrbufEqualS(&strbuf, "120.123456789"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123, 5);
ffStrbufAppendDouble(&strbuf, 120.123, 5, true);
VERIFY(ffStrbufEqualS(&strbuf, "120.12300"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 0);
ffStrbufAppendDouble(&strbuf, -120.0, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 1);
ffStrbufAppendDouble(&strbuf, -120.0, 1, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120.0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 5);
ffStrbufAppendDouble(&strbuf, -120.0, 5, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120.00000"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, 5);
ffStrbufAppendDouble(&strbuf, -120.123456789, 5, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120.12346"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, 0);
ffStrbufAppendDouble(&strbuf, -120.123456789, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, -1);
ffStrbufAppendDouble(&strbuf, -120.123456789, -1, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123, 5);
ffStrbufAppendDouble(&strbuf, -120.123, 5, true);
VERIFY(ffStrbufEqualS(&strbuf, "-120.12300"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.888888, 0);
ffStrbufAppendDouble(&strbuf, -120.888888, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "-121"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.999999, 2);
ffStrbufAppendDouble(&strbuf, -120.999999, 2, true);
VERIFY(ffStrbufEqualS(&strbuf, "-121.00"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 1);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, true);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 1);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, true);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 0);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 0);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, -1);
ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, true);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, -1);
ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, true);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e20, 1);
ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, true);
VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000.0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e20, 1);
ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, true);
VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000.0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, +0.0, 0);
ffStrbufAppendDouble(&strbuf, +0.0, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -0.0, 0);
ffStrbufAppendDouble(&strbuf, -0.0, 0, true);
VERIFY(ffStrbufEqualS(&strbuf, "-0"));
ffStrbufDestroy(&strbuf);
}
{
ffStrbufAppendDouble(&strbuf, 120.0, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.0, 1, false);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.0, 5, false);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, 5, false);
VERIFY(ffStrbufEqualS(&strbuf, "120.12346"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.888888, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "121"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.999999, 2, false);
VERIFY(ffStrbufEqualS(&strbuf, "121"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123456789, -1, false);
VERIFY(ffStrbufEqualS(&strbuf, "120.123456789"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 120.123, 5, false);
VERIFY(ffStrbufEqualS(&strbuf, "120.123"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 1, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.0, 5, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, 5, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120.12346"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123456789, -1, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.123, 5, false);
VERIFY(ffStrbufEqualS(&strbuf, "-120.123"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.888888, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "-121"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -120.999999, 2, false);
VERIFY(ffStrbufEqualS(&strbuf, "-121"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, false);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, false);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, false);
VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, false);
VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, false);
VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, false);
VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, +0.0, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "0"));
ffStrbufClear(&strbuf);
ffStrbufAppendDouble(&strbuf, -0.0, 0, false);
VERIFY(ffStrbufEqualS(&strbuf, "-0"));
ffStrbufDestroy(&strbuf);