Merge pull request #399 from LinusDierheimer/dev

Release 1.9.0
This commit is contained in:
Linus Dierheimer
2023-01-22 01:09:35 +01:00
committed by GitHub
126 changed files with 3331 additions and 1438 deletions
+12 -77
View File
@@ -18,7 +18,7 @@ jobs:
uses: actions/checkout@v3
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libcjson-dev
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libcjson-dev libnm-dev
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
@@ -34,6 +34,9 @@ jobs:
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v2
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all
@@ -80,6 +83,9 @@ jobs:
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v2
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all
@@ -113,6 +119,7 @@ jobs:
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
cmake --build . --target package
./fastfetch --list-features
time ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all
time ./flashfetch
ctest
@@ -179,6 +186,9 @@ jobs:
- name: copy necessary dlls
run: cp /clang64/bin/{libcjson,libOpenCL,vulkan-1}.dll .
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all
@@ -197,80 +207,6 @@ jobs:
name: fastfetch-windows
path: ./fastfetch-*-Windows.zip
win7:
name: Win7
runs-on: windows-latest
permissions:
security-events: write
contents: read
defaults:
run:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v3
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: git zip mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-cjson mingw-w64-x86_64-vulkan-loader mingw-w64-x86_64-opencl-icd
- name: print msys version
run: uname -a
# https://github.com/msys2/MINGW-packages/issues/13524#event-7555720785
- name: create OpenCL.pc
run: |
cat > /mingw64/lib/pkgconfig/OpenCL.pc << EOF
prefix=/mingw64
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: OpenCL
Description: Open Computing Language generic Installable Client Driver Loader
Version: 2022.09.30-1
Libs: -L${libdir} -lOpenCL.dll
Cflags: -I${includedir}
EOF
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: c, cpp
- name: configure project
run: env PKG_CONFIG_PATH=/mingw64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_BUFFER=Off .
- name: build project
run: cmake --build .
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v2
- name: copy necessary dlls
run: cp /mingw64/bin/{libcjson,libOpenCL,vulkan-1}.dll .
- name: run fastfetch
run: time ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all
- name: run flashfetch
run: time ./flashfetch
- name: run tests
run: ctest
- name: create zip archive
run: zip fastfetch-$(./fastfetch --version-raw)-Win7.zip *.dll fastfetch.exe flashfetch.exe
- name: upload artifacts
uses: actions/upload-artifact@v3
with:
name: fastfetch-win7
path: ./fastfetch-*-Win7.zip
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'LinusDierheimer/fastfetch'
name: Release
@@ -280,7 +216,6 @@ jobs:
- macos
- freebsd
- windows
- win7
permissions:
contents: write
steps:
@@ -300,4 +235,4 @@ jobs:
tag: ${{ needs.linux.outputs.ffversion }}
commit: ${{ github.sha }}
artifactErrorsFailBuild: true
artifacts: fastfetch-linux/*,fastfetch-macos/*,fastfetch-freebsd/*,fastfetch-windows/*,fastfetch-win7/*
artifacts: fastfetch-linux/*,fastfetch-macos/*,fastfetch-freebsd/*,fastfetch-windows/*
+47 -1
View File
@@ -1,3 +1,49 @@
# 1.9.0
Notable Changes:
* fastfetch no longer creates a sample config file silently. Use `--gen-config` to generate one.
* fastfetch now search for user config file in the order of `fastfetch --list-config-paths`
* Unknown disks are hidden by default.
* `Resolution` module is renamed to `Display`. (#393)
Features:
* `--logo-padding-top` option (@CarterLi, #372)
* Raw image file as logo support (@CarterLi)
* Look for config files in `$APPDATA` ([RoamingAppData](https://superuser.com/questions/21458/why-are-there-directories-called-local-locallow-and-roaming-under-users-user#answer-21462)) (Windows)
* Look for config files in `~/Library/Preferences` (macOS)
* Add `--list-config-paths` option which list search paths of config files
* Add `--list-data-paths` option which list search paths for presets and logos
* Add `Brightness` module support
* Add `Battery` module support for FreeBSD
* Add `--disk-show-unknown` option for Disk module
* Add `--disk-show-subvolumes` option for Disk module
* Add `--gpu-hide-integrated` option (#379)
* Add `--gpu-hide-discrete` option (#379)
* Detect terminal version when available
* Support `WezTerm` terminal font detection (requires [`wezterm` executable](https://wezfurlong.org/wezterm/cli/general.html) being available)
* Add `--shell-version` and `--terminal-version` options to disable shell / terminal version detection
* Enhance `--percent-type` to allow hiding other texts (#387)
* Add Wifi module support for Linux
* Detect scaled resolutions (Windows, macOS)
* Optimise font module printing (Windows)
* Detect pacman package count inside MSYS2 environment (Windows)
* Add Wifi / Battery module support for Android
* Disk name support for Linux
Logos:
* Raspbian (@IamNoRobot, #373)
Bugfixes:
* `--logo-type` now does accept `iterm` too (@CarterLi, #374)
* Fix mintty terminal font detection (Windows)
* Fix bug that line buffering doesn't work properly (Windows)
* Fix rpm package count detection (Linux)
* Fix cpu temp detection (Linux)
Other:
* Fixed a Typo in iterm error message (@jessebot, #376)
* Don't try to load config file in `/etc` (Windows)
# 1.8.2
Bugfixes:
@@ -112,7 +158,7 @@ Bugfixes:
* Don't segfault in GPU code on Intel Macs (@CarterLi, #236)
* Don't use hardcoded size units in presets (@dr460nf1r3, #255)
* Don't crash with some format strings (#252)
* --logo-none keeps key color now (#264)
* --logo none keeps key color now (#264)
# 1.7.2
+30 -9
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 1.8.2
VERSION 1.9.0
LANGUAGES C
DESCRIPTION "Fast system information tool"
HOMEPAGE_URL "https://github.com/LinusDierheimer/fastfetch"
@@ -68,6 +68,7 @@ cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR BSD" OFF)
cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR BSD" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" OFF)
cmake_dependent_option(ENABLE_LIBCJSON "Enable libcjson" ON "LINUX OR WIN32" OFF)
cmake_dependent_option(ENABLE_LIBNM "Enable libnm" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND AND NOT ANDROID" OFF)
cmake_dependent_option(ENABLE_BUFFER "Enable stdout buffer" ON "LINUX OR APPLE OR BSD OR WIN32 OR ANDROID" OFF)
@@ -102,6 +103,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wconversion")
if(WIN32)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wconversion -fno-exceptions -fno-rtti")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id -Wl,--subsystem,console:6.1,--major-os-version,6,--minor-os-version,1")
endif()
# Used for dlopen finding dylibs installed by homebrew
@@ -244,7 +246,6 @@ set(LIBFASTFETCH_SRC
src/detection/packages/packages.c
src/detection/terminalfont/terminalfont.c
src/detection/terminalshell/terminalshell.c
src/detection/title.c
src/detection/vulkan.c
src/logo/builtin.c
src/logo/image/im6.c
@@ -254,6 +255,7 @@ set(LIBFASTFETCH_SRC
src/modules/battery.c
src/modules/bios.c
src/modules/board.c
src/modules/brightness.c
src/modules/break.c
src/modules/chassis.c
src/modules/colors.c
@@ -261,6 +263,7 @@ set(LIBFASTFETCH_SRC
src/modules/cpuUsage.c
src/modules/cursor.c
src/modules/custom.c
src/modules/command.c
src/modules/date.c
src/modules/datetime.c
src/modules/de.c
@@ -281,7 +284,7 @@ set(LIBFASTFETCH_SRC
src/modules/poweradapter.c
src/modules/processes.c
src/modules/publicip.c
src/modules/resolution.c
src/modules/display.c
src/modules/separator.c
src/modules/shell.c
src/modules/media.c
@@ -300,6 +303,7 @@ set(LIBFASTFETCH_SRC
src/util/FFlist.c
src/util/FFstrbuf.c
src/util/FFvaluestore.c
src/util/platform/FFPlatform.c
)
if(LINUX)
@@ -309,6 +313,7 @@ if(LINUX)
src/detection/battery/battery_linux.c
src/detection/bios/bios_linux.c
src/detection/board/board_linux.c
src/detection/brightness/brightness_linux.c
src/detection/chassis/chassis_linux.c
src/detection/cpu/cpu_linux.c
src/detection/cpuUsage/cpuUsage_linux.c
@@ -340,14 +345,16 @@ if(LINUX)
src/detection/users/users_linux.c
src/detection/wifi/wifi_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/util/platform/FFPlatform_unix.c
)
elseif(ANDROID)
list(APPEND LIBFASTFETCH_SRC
src/common/networking_linux.c
src/common/processing_linux.c
src/detection/battery/battery_nosupport.c
src/detection/battery/battery_android.c
src/detection/bios/bios_nosupport.c
src/detection/board/board_nosupport.c
src/detection/brightness/brightness_nosupport.c
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_linux.c
src/detection/cursor/cursor_nosupport.c
@@ -371,17 +378,19 @@ elseif(ANDROID)
src/detection/terminalshell/terminalshell_linux.c
src/detection/uptime/uptime_linux.c
src/detection/users/users_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wifi/wifi_android.c
src/detection/wmtheme/wmtheme_nosupport.c
src/util/platform/FFPlatform_unix.c
)
elseif(BSD)
list(APPEND LIBFASTFETCH_SRC
src/common/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_nosupport.c
src/detection/battery/battery_bsd.c
src/detection/bios/bios_bsd.c
src/detection/board/board_nosupport.c
src/detection/brightness/brightness_nosupport.c
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_bsd.c
src/detection/cpuUsage/cpuUsage_bsd.c
@@ -413,6 +422,7 @@ elseif(BSD)
src/detection/users/users_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wmtheme/wmtheme_linux.c
src/util/platform/FFPlatform_unix.c
)
elseif(APPLE)
list(APPEND LIBFASTFETCH_SRC
@@ -422,6 +432,7 @@ elseif(APPLE)
src/detection/battery/battery_apple.c
src/detection/bios/bios_apple.c
src/detection/board/board_nosupport.c
src/detection/brightness/brightness_apple.c
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_apple.c
src/detection/cpuUsage/cpuUsage_apple.c
@@ -450,6 +461,7 @@ elseif(APPLE)
src/detection/wmtheme/wmtheme_apple.m
src/util/apple/cf_helpers.c
src/util/apple/osascript.m
src/util/platform/FFPlatform_unix.c
)
elseif(WIN32)
list(APPEND LIBFASTFETCH_SRC
@@ -458,6 +470,7 @@ elseif(WIN32)
src/detection/battery/battery_windows.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
src/detection/brightness/brightness_windows.cpp
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_windows.c
src/detection/cpuUsage/cpuUsage_windows.c
@@ -483,11 +496,10 @@ elseif(WIN32)
src/detection/wifi/wifi_windows.c
src/detection/wmtheme/wmtheme_windows.c
src/util/windows/getline.c
src/util/windows/pwd.c
src/util/windows/registry.c
src/util/windows/unicode.c
src/util/windows/utsname.c
src/util/windows/wmi.cpp
src/util/platform/FFPlatform_windows.c
)
endif()
@@ -626,6 +638,10 @@ ff_lib_enable(LIBCJSON
"libcjson"
"CJson"
)
ff_lib_enable(LIBNM
"libnm"
"libnm"
)
ff_lib_enable(FREETYPE
"freetype2"
"FreeType2"
@@ -638,7 +654,6 @@ if(ENABLE_THREADS)
endif()
endif()
if(ENABLE_BUFFER)
target_compile_definitions(libfastfetch PRIVATE FF_ENABLE_BUFFER)
endif()
@@ -652,6 +667,7 @@ if(APPLE)
PRIVATE "-framework Cocoa"
PRIVATE "-framework CoreWLAN"
PRIVATE "-weak_framework MediaRemote -F /System/Library/PrivateFrameworks"
PRIVATE "-weak_framework DisplayServices -F /System/Library/PrivateFrameworks"
)
elseif(WIN32)
target_compile_definitions(libfastfetch PRIVATE -D_WIN32_WINNT=0x0601)
@@ -712,6 +728,11 @@ target_link_libraries(flashfetch
PRIVATE libfastfetch
)
if(ENABLE_BUFFER) # FF_ENABLE_BUFFER is used in fastfetch.c
target_compile_definitions(fastfetch PRIVATE FF_ENABLE_BUFFER)
target_compile_definitions(flashfetch PRIVATE FF_ENABLE_BUFFER)
endif()
if(WIN32)
set(TARGET_NAME fastfetch)
target_sources(fastfetch
+22 -22
View File
@@ -1,6 +1,6 @@
# Fastfetch
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying them in a pretty way. It is written in pure c, with performance and customizability in mind. Currently, Linux, Android, FreeBSD, MacOS and Windows 7+ are supported.
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying them in a pretty way. It is written mainly in C, with performance and customizability in mind. Currently, Linux, Android, FreeBSD, MacOS and Windows 7+ are supported.
<img src="screenshots/example1.png" width="49%" align="left" />
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
@@ -10,17 +10,21 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
<img src="screenshots/example3.png" width="48%" align="top" />
<img src="screenshots/example5.png" height="15%" align="top" />
There are [screenshots on different platforms](https://github.com/LinusDierheimer/fastfetch/wiki)
## Customization
With customization and speed being two competing goals, this project actually builds two executables.
* The main one being `fastfetch`, which can be very greatly configured via flags. These flags can be made persistent in `~/.config/fastfetch/config.conf`. To view the available options run `fastfetch --help`.
* The main one being `fastfetch`, which can be very greatly configured via flags. These flags can be made persistent in `$XDG_CONFIG_HOME/fastfetch/config.conf`. To view the available options run `fastfetch --help`.
* The second executable being built is called `flashfetch`, which is configured at compile time to eliminate any possible overhead. Configuration of it can be very easily done in [`src/flashfetch.c`](src/flashfetch.c).
At the moment the performance difference is measurable, but too small to be human recognizable. But the leap will get bigger with more and more options coming, and on slow machines this might actually make a difference.
There are some premade config files in [`presets`](presets), including the ones used for the screenshots above. You can load them using `--load-config <filename>`. They may also serve as a good example for format arguments.
Logos can be heavily customized to. See the [logo documentation](doc/logo.md) for more information.
## Dependencies
Fastfetch dynamically loads needed libraries if they are available. On Linux, its only hard dependencies are `libc` (any implementation of the c standard library), `libdl` and [`libpthread`](https://man7.org/linux/man-pages/man7/pthreads.7.html) (if built with multithreading support). They are all shipped with [`glibc`](https://www.gnu.org/software/libc/), which is already installed on most linux distributions.
@@ -34,8 +38,8 @@ The following libraries are used if present at runtime:
* [`libxcb-randr`](https://xcb.freedesktop.org/),
[`libXrandr`](https://gitlab.freedesktop.org/xorg/lib/libxrandr),
[`libxcb`](https://xcb.freedesktop.org/),
[`libX11`](https://gitlab.freedesktop.org/xorg/lib/libx11): At least one of them sould be present in X11 sessions for better resolution detection and faster WM detection. The `*randr` ones provide multi monitor support The `libxcb*` ones usually have better performance.
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance and output in wayland sessions. Supports different refresh rates per monitor.
[`libX11`](https://gitlab.freedesktop.org/xorg/lib/libx11): At least one of them sould be present in X11 sessions for better display detection and faster WM detection. The `*randr` ones provide multi monitor support The `libxcb*` ones usually have better performance.
* [`libwayland-client`](https://wayland.freedesktop.org/): Better display performance and output in wayland sessions. Supports different refresh rates per monitor.
* [`libGIO`](https://developer.gnome.org/gio/unstable/): Needed for values that are only stored GSettings.
* [`libDConf`](https://developer.gnome.org/dconf/unstable/): Needed for values that are only stored in DConf + Fallback for GSettings.
* [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel or kitty graphics protocol.
@@ -50,10 +54,12 @@ The following libraries are used if present at runtime:
* [`libsqlite3`](https://www.sqlite.org/index.html): Needed for pkg & rpm package count.
* [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE.
* [`libcJSON`](https://github.com/DaveGamble/cJSON): Needed for Windows Terminal font ( WSL ).
* [`libnm`](https://networkmanager.dev/docs/libnm/latest/): Used for Wifi detection on Linux.
### macOS
* [`MediaRemote`](https://iphonedev.wiki/index.php/MediaRemote.framework): Need for Media detection. It's a private framework provided by newer macOS system.
* [`DisplayServices`](https://developer.apple.com/forums/thread/666383#663154022): Need for screen brightness detection. It's a private framework provided by newer macOS system.
* [`MoltenVK`](https://github.com/KhronosGroup/MoltenVK): Vulkan driver for macOS. [`molten-vk`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/molten-vk.rb)
* [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel graphics protocol. [`imagemagick`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/imagemagick.rb)
* [`libchafa`](https://github.com/hpjansson/chafa): Image output as ascii art. [`chafa`](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/chafa.rb)
@@ -67,10 +73,7 @@ For the image logo, iTerm with iterm image protocol should work. Apple Terminal
* [`libvulkan`](https://www.vulkan.org/): Vulkan module. Usually has been provided by GPU drivers. [`vulkan-loader`](https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-vulkan-loader) [`vulkan-headers`](https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-vulkan-headers)
* [`libOpenCL`](https://www.khronos.org/opencl/): OpenCL module. [`opencl-icd`](https://github.com/msys2/MINGW-packages/tree/master/mingw-w64-opencl-icd)
Note: In Windows 7, 8 and 8.1, [ConEmu](https://conemu.github.io/en/AnsiEscapeCodes.html) is required to run fastfetch due to [the lack of ASCII escape code native support](https://en.wikipedia.org/wiki/ANSI_escape_code#DOS,_OS/2,_and_Windows). In addition, special build `fastfetch-win7` is provided to support these old systems, which
1. Build with the ancient [MSVCRT](https://en.wikipedia.org/wiki/Microsoft_Windows_library_files#MSVCRT.DLL,_MSVCP*.DLL_and_CRTDLL.DLL) C runtime library, instead of the modern [UCRT](https://learn.microsoft.com/en-us/cpp/windows/universal-crt-deployment) C runtime library
2. Disable stdout application buffer, which seems to problematic for ConEmu.
Note: In Windows 7, 8 and 8.1, [ConEmu](https://conemu.github.io/en/AnsiEscapeCodes.html) is required to run fastfetch due to [the lack of ASCII escape code native support](https://en.wikipedia.org/wiki/ANSI_escape_code#DOS,_OS/2,_and_Windows). In addition, as fastfetch for Windows targets [UCRT](https://learn.microsoft.com/en-us/cpp/windows/universal-crt-deployment) C runtime library, [it must be installed manually](https://support.microsoft.com/en-us/topic/update-for-universal-c-runtime-in-windows-c0514201-7fe6-95a3-b0a5-287930f3560c) as UCRT is only pre-installed in Windows 10 and later.
For the image logo, only chafa is supported due to [the design flaw of ConPTY](https://github.com/microsoft/terminal/issues/1173). In addition, chafa support is not built by default due to the massive dependencies of imagemagick. You must built it yourself.
@@ -78,43 +81,39 @@ For the image logo, only chafa is supported due to [the design flaw of ConPTY](h
* [`freetype`](https://www.freetype.org/): Used for Termux font detection. [`freetype`](https://github.com/termux/termux-packages/tree/master/packages/freetype)
* [`libvulkan`](https://www.vulkan.org/): Vulkan module, also used for GPU detection. Usually has been provided by Android system. [`vulkan-loader-android`](https://github.com/termux/termux-packages/tree/master/packages/vulkan-loader-android) [`vulkan-headers`](https://github.com/termux/termux-packages/tree/master/packages/vulkan-headers)
* [`termux-api`](https://github.com/termux/termux-api-package): Used for Wifi / Battery detection. Read [the official doc](https://wiki.termux.com/wiki/Termux:API) for detail or if you hang on these modules (IMPORTANT). [`termux-api`](https://github.com/termux/termux-packages/tree/master/packages/termux-api)
## Support status
All categories not listed here should work without needing a specific implementation.
##### Available Modules
```
Title, Separator, OS, Host, Bios, Board, Kernel, Uptime, Processes, Packages, Shell, Resolution, DE, WM, WMTheme, Theme, Icons, Font, Cursor, Terminal, Terminal Font, CPU, CPUUsage, GPU, Memory, Swap, Disk, Battery, Power Adapter, Player, Media, Vulkan, OpenGL, OpenCL, LocalIP, PublicIP, Wifi, DateTime, Date, Time, Locale, Colors, Break, Custom
Battery, Bios, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, GPU, Host, Icons, Kernel, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator OS, Shell, Swap, Terminal, Terminal Font, Theme, Time, Title, Uptime, Vulkan, Wifi, WM, WMTheme
```
##### Logos
##### Builtin logos
```
AlmaLinux, Alpine, Android, Arch, Arco, Artix, Bedrock, CachyOS, CentOS, CRUX, Crystal, Debian, Devuan, Deepin, Endeavour, Enso, Fedora, FreeBSD, Garuda, Gentoo, KDE Neon, KISS, Kubuntu, LangitKetujuh, Linux, MacOS, Manjaro, Mint, MSYS2, NixOS, Nobara, OpenSUSE, OpenSUSE Tumbleweed, OpenSUSE LEAP, Parabola, Pop!_OS, RebornOS, RedstarOS, Rocky, Rosa, Slackware, Solus, Ubuntu, Vanilla, Void, Windows 11, Windows 8, Windows, Zorin
AlmaLinux, Alpine, Android, Arch, Arco, Artix, Bedrock, CachyOS, CentOS, CRUX, Crystal, Debian, Deepin, Devuan, Endeavour, Enso, Fedora, FreeBSD, Garuda, Gentoo, KDE Neon, KISS, Kubuntu, LangitKetujuh, Linux, MacOS, Manjaro, Mint, MSYS2, NixOS, Nobara, OpenSUSE, OpenSUSE LEAP, OpenSUSE Tumbleweed, Parabola, Pop!_OS, Raspbian, RebornOS, RedstarOS, Rocky, Rosa, Slackware, Solus, Ubuntu, Vanilla, Void, Windows, Windows 11, Windows 8, Zorin
```
* Most of the logos have a small variant. Access it by appending _small to the logo name.
* Some logos have an old variant. Access it by appending _old to the logo name.
* To disable the logo, use `--logo none`.
* Get a list of all available logos with `fastfetch --print-logos`.
* Printing images as logo is supported using Sixel / Kitty / iTerm graphics protocol or chafas image to text conversion.
##### Package managers
```
Pacman, dpkg, rpm, emerge, eopkg, xbps, nix, Flatpak, Snap, apk, pkg, brew, MacPorts, scoop, Chocolatey
apk, brew, Chocolatey, dpkg, emerge, eopkg, Flatpak, MacPorts, nix, Pacman, pkg, rpm, scoop, Snap, xbps
```
##### WM themes
```
KWin, Mutter, Muffin, Marco, XFWM, Openbox (LXDE, LXQT & without DE), Quartz Compositor (macOS), DWM (Windows)
DWM (Windows), KWin, Marco, Muffin, Mutter, Openbox (LXDE, LXQT & without DE), Quartz Compositor (macOS), XFWM
```
##### DE versions
```
KDE Plasma, Gnome, Cinnamon, Mate, XFCE4, LXQt
Budgie, Cinnamon, Gnome, KDE Plasma, LXQt, Mate, XFCE4
```
##### Terminal fonts
```
Konsole, Gnome Terminal, Tilix, XFCE4 Terminal, Alacritty, Kitty, LXTerminal, Deepin Terminal, iTerm2, Apple Terminal, Warp, TTY, Windows Terminal, Termux, mintty, ConEmu
Alacritty, Apple Terminal, ConEmu, Deepin Terminal, Gnome Terminal, iTerm2, Kitty, Konsole, LXTerminal, mintty, Termux, Tilix, TTY, Warp, WezTerm, Windows Terminal, XFCE4 Terminal
```
## Building
@@ -134,12 +133,13 @@ If the build process fails to find the headers for a library listed in [dependen
Currently GCC or clang is required (MSVC is not supported). MSYS2 with CLANG64 subsystem (or CLANGARM64 if needed) is suggested (and tested) to build fastfetch. If you need Windows 7 / 8.x support, using MINGW64 is suggested.
1. Install [MSYS2](https://www.msys2.org/#installation)
1. Open `MSYS2 CLANG64` (not `MSYS2 / MSYS`, which targets cygwin C runtime)
1. Open `MSYS2 / CLANG64` (not `MSYS2 / MSYS`, which targets cygwin C runtime)
1. Install dependencies
```bash
pacman -Syu mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-pkgconf mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-cjson mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-opencl-icd
```
1. Follow building instructions of Linux
Follow the building instructions of Linux next.
## Packaging
+14 -4
View File
@@ -13,7 +13,7 @@ __fastfetch_complete_help()
"processes-format"
"packages-format"
"shell-format"
"resolution-format"
"display-format"
"de-format"
"wm-format"
"wm-theme-format"
@@ -160,6 +160,8 @@ __fastfetch_completion()
"--print-config-system"
"--print-config-user"
"--print-structure"
"--gen-config"
"--gen-config-force"
)
local FF_OPTIONS_HELP=(
@@ -187,8 +189,15 @@ __fastfetch_completion()
"--pipe"
"--title-fqdn"
"--escape-bedrock"
"--shell-version"
"--terminal-version"
"--disk-folders"
"--disk-show-removable"
"--disk-show-hidden"
"--disk-show-subvolumes"
"--gpu-hide-integrated"
"--gpu-hide-discrete"
"--disk-show-unknown"
)
local FF_OPTIONS_STRING=(
@@ -196,6 +205,7 @@ __fastfetch_completion()
"--logo-padding"
"--logo-padding-left"
"--logo-padding-right"
"--logo-padding-top"
"--logo-color-1"
"--logo-color-2"
"--logo-color-3"
@@ -243,9 +253,9 @@ __fastfetch_completion()
"--shell-key"
"--shell-format"
"--shell-error"
"--resolution-key"
"--resolution-format"
"--resolution-error"
"--display-key"
"--display-format"
"--display-error"
"--de-key"
"--de-format"
"--de-error"
+116
View File
@@ -0,0 +1,116 @@
# Logo options
## General
| Option | Default | Description |
|--------|---------|-------------|
| `--logo`, `-l` | `""` | The logo source, interpreted depending on type |
| `--logo-type` | `auto` | The logo type. See the following categories for possible values |
| `--<type>` | `""` | Short for `--logo-type <type> --logo <value>` |
| `--logo-padding` | `""` | Sets the padding left and right of the logo |
| `--logo-padding-left` | `0` | Sets the padding left of the logo |
| `--logo-padding-right` | `4` | Sets the padding right of the logo |
| `--logo-padding-top` | `0` | Sets the padding top of the logo |
All filesytem paths can be:
* Absolute
* Relative to the current working directory
* Relative to any of the directories listed by `fastfetch --list-data-paths` + `/logos`
For example, the file `~/.local/share/fastfetch/logos/shrek` can simply be referenced as `shrek`.
## Text
| Option | Default | Description |
|--------|---------|-------------|
| `--logo-color-[1-9]` | `""` | Overrides a color for logos that support it |
| `--logo-print-remaining` | `true` | Print the remaining logo, if it is higher than the keys |
* Color placeholders are in the form `$[1-9]`. To print a `$`, use `$$`.
* If a color placeholder value is not set, the placeholder is simply discarded.
## Image
| Option | Default | Description |
|--------|---------|-------------|
| `--logo-width` | `""` | Sets the width of the logo for logos that support it |
| `--logo-height` | `""` | Sets the height of the logo for logos that support it |
* If one of the height / width options is set, but the other not, the aspect ratio is preserved.
* If neither height nor width is set, the original size is used.
# Logo types
## auto
Trys to detect the logo type depending on the value of `--logo`, in the following order:
* If the value is empty / not set, an autodected builtin logo is displayed.
* If the value is the name of a builtin logo, it is displayed.
* If the value is the path to an image file, and the terminal emulator is known to support an image protocol, the image is displayed.
* If the value is the path to a text file, the content is displayed.
* The autodetected builtin logo is displayed.
## builtin
The value of `--logo` is interpreted as the name of a builtin logo.
* If the value is empty / not set, it is autodetected.
* Use `--list-logos` to get a list of all available logos.
* Use `--print-logos` to see all available logos.
* All builtin logos set default values for `--logo-color-[1-9]`.
* Use `none` to disable the logo, but keep key colors from the detected logo.
## file
The value of `--logo` is interpreted as the path to a file. The content of the file is displayed.
* If the file can't be read, the autodetected builtin logo is displayed.
## file-raw
The value of `--logo` is interpreted as the path to a file. The content of the file is displayed.
* No color placeholder replacement is done.
* If the file can't be read, the autodetected builtin logo is displayed.
## data
The value of `--logo` is interpreted as the logo and directly displayed.
* If the value is empty / not set, the autodetected builtin logo is displayed.
## data-raw
The value of `--logo` is interpreted as the logo and directly displayed.
* No color placeholder replacement is done.
* If the value is empty / not set, the autodetected builtin logo is displayed.
## sixel
The value of `--logo` is interpreted as the path to an image file. It is displayed using the sixel graphics protocol.
* `fastfetch` must be compiled with the `imagemagick6` or `imagemagick7` feature.
## kitty
The value of `--logo` is interpreted as the path to an image file. It is displayed using the kitty graphics protocol.
* If the file is a png file, and both `--logo-width` and `--logo-height` are specified, the image is directly send to the terminal emulator.
* Otherwise `fastfetch` must be compiled with the `imagemagick6` or `imagemagick7` feature.
## iterm
The value of `--logo` is interpreted as the path to an image file. It is displayed using the iTerm graphics protocol.
* Both `--logo-width` and `--logo-height` must be specified.
## chafa
The value of `--logo` is interpreted as the path to an image file. It is converted to an ascii logo using `libchafa`.
* `fastfetch` must be compiled with the `chafa` feature.
* `fastfetch` must be compiled with the `imagemagick6` or `imagemagick7` feature.
* Use `--chafa-fg-only` to set weather to render foreground only.
* Use `--chafa-symbols` to set the symbols.
* Use `--chafa-canvas-mode` to set the canvas mode.
* Use `--chafa-color-space` to set the color space.
* Use `--chafa-dither-mode` to set the dither mode.
* See the [chafa documentation](https://hpjansson.org/chafa/man/) for more information.
## raw
The value of `--logo` is interpreted as the path to a binary file. It is printed as-is.
* Both `--logo-width` and `--logo-height` must be specified.
* Use this to display a pre converted image file.
* If the file can't be read, the autodetected builtin logo is displayed.
+1 -1
View File
@@ -1 +1 @@
--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Weather:Break:Colors
--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Weather:Break:Colors
+1 -1
View File
@@ -1,4 +1,4 @@
--structure Host:Resolution:CPU:GPU:Memory:Disk:Battery
--structure Host:Display:CPU:GPU:Memory:Disk:Battery
--memory-format "{?2}{2}{?}"
--disk-format "{?2}{2}{?}"
--battery-format "{?1}{1} {?}{?2}{2} {?}{?3}({3}){?}"
+3 -3
View File
@@ -1,10 +1,10 @@
--structure "Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Terminal:TerminalFont:CPU:GPU:Memory:Break:Colors"
--structure "Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Display:DE:WM:WMTheme:Theme:Icons:Terminal:TerminalFont:CPU:GPU:Memory:Break:Colors"
--host-format "{/2}{-}{/}{2}{?3} {3}{?}"
--os-format "{3} {12}"
--resolution-format "{}x{}"
--display-format "{}x{}"
--de-format "{2} {3}"
--theme-format "{?1}{1}{?3} {3}{?} [Plasma], {?}{7}"
--terminal-font-format "{/2}{-}{/}{2}{?3} {3}{?}"
--memory-format "{/1}{-}{/}{/2}{-}{/}{} / {}"
--gpu-key "GPU"
--resolution-key "Resolution"
--display-key "Display"
+2 -2
View File
@@ -1,5 +1,5 @@
--structure Title:Separator:OS:Host:Kernel:Uptime:Battery:Break:Packages:Shell:Resolution:Terminal:Break:CPU:GPU:Memory:Break:Colors
--structure Title:Separator:OS:Host:Kernel:Uptime:Battery:Break:Packages:Shell:Display:Terminal:Break:CPU:GPU:Memory:Break:Colors
--host-format "{/2}{-}{/}{2}{?3} {3}{?}"
--battery-format "{/4}{-}{/}{4}%{?5} [{5}]{?}"
--resolution-key "Resolution"
--display-key "Display"
--gpu-key "GPU"
+1 -1
View File
@@ -5,7 +5,7 @@
--processes-format Count: {}
--packages-format All: {}; pacman: {}; pacman branch: {}; dpkg: {}; rpm: {}; emerge: {}; eopkg: {}; xbps: {}; apk: {}; flatpak: {}; snap: {}; brew: {}; brew-cask: {}; port: {}; scoop: {}; choco: {}
--shell-format Process name: {}; Process path: {}; Process exe: {}; Process version: {}; User path: {}; User exe: {}; User version: {}
--resolution-format Width: {}; Height: {}; Refresh rate: {}
--display-format Width: {}; Height: {}; Refresh rate: {}
--de-format Process name: {}; Pretty name: {}; Version: {}
--wm-format Process name: {}; Pretty name: {}; Protocol: {}
--wm-theme-format Name: {}
+1
View File
@@ -9,6 +9,7 @@ enum
{
FF_PERCENTAGE_TYPE_NUM_BIT = 1,
FF_PERCENTAGE_TYPE_BAR_BIT = 2,
FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 4,
};
void ffAppendPercentBar(FFinstance* instance, FFstrbuf* buffer, uint8_t percent, uint8_t green, uint8_t yellow, uint8_t red);
+2
View File
@@ -19,6 +19,8 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
ffStrbufAppendS(buffer, (const char*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_STRBUF)
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_FLOAT)
ffStrbufAppendF(buffer, "%f", *(float*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_DOUBLE)
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_BOOL)
+1
View File
@@ -12,6 +12,7 @@ typedef enum FFformatargtype
FF_FORMAT_ARG_TYPE_INT,
FF_FORMAT_ARG_TYPE_STRING,
FF_FORMAT_ARG_TYPE_STRBUF,
FF_FORMAT_ARG_TYPE_FLOAT,
FF_FORMAT_ARG_TYPE_DOUBLE,
FF_FORMAT_ARG_TYPE_LIST,
FF_FORMAT_ARG_TYPE_BOOL
+51 -97
View File
@@ -12,107 +12,19 @@
#ifdef _WIN32
#include <wincon.h>
#include <locale.h>
#include <shlobj.h>
#include "util/windows/unicode.h"
#else
#include <signal.h>
#endif
static void initConfigDirs(FFstate* state)
{
ffListInit(&state->configDirs, sizeof(FFstrbuf));
#if !(defined(_WIN32) || defined(__APPLE__) || defined(__ANDROID__))
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
if(ffStrSet(xdgConfigHome))
{
FFstrbuf* buffer = (FFstrbuf*) ffListAdd(&state->configDirs);
ffStrbufInitA(buffer, 64);
ffStrbufAppendS(buffer, xdgConfigHome);
ffStrbufEnsureEndsWithC(buffer, '/');
}
#endif
#define FF_ENSURE_ONLY_ONCE_IN_LIST(element) \
if(ffListFirstIndexComp(&state->configDirs, element, (bool(*)(const void*, const void*))ffStrbufEqual) < state->configDirs.length - 1) \
{ \
ffStrbufDestroy(ffListGet(&state->configDirs, state->configDirs.length - 1)); \
--state->configDirs.length; \
}
FFstrbuf* userConfigHome = ffListAdd(&state->configDirs);
ffStrbufInitA(userConfigHome, 64);
ffStrbufAppendS(userConfigHome, state->passwd->pw_dir);
ffStrbufAppendS(userConfigHome, "/.config/");
FF_ENSURE_ONLY_ONCE_IN_LIST(userConfigHome)
FFstrbuf* userHome = ffListAdd(&state->configDirs);
ffStrbufInitA(userHome, 64);
ffStrbufAppendS(userHome, state->passwd->pw_dir);
ffStrbufEnsureEndsWithC(userHome, '/');
FF_ENSURE_ONLY_ONCE_IN_LIST(userHome)
#if !(defined(_WIN32) || defined(__APPLE__) || defined(__ANDROID__))
FFstrbuf xdgConfigDirs;
ffStrbufInitA(&xdgConfigDirs, 64);
ffStrbufAppendS(&xdgConfigDirs, getenv("XDG_CONFIG_DIRS"));
uint32_t startIndex = 0;
while (startIndex < xdgConfigDirs.length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&xdgConfigDirs, startIndex, ':');
xdgConfigDirs.chars[colonIndex] = '\0';
if(!ffStrSet(xdgConfigDirs.chars + startIndex))
{
startIndex = colonIndex + 1;
continue;
}
FFstrbuf* buffer = (FFstrbuf*) ffListAdd(&state->configDirs);
ffStrbufInitA(buffer, 64);
ffStrbufAppendS(buffer, xdgConfigDirs.chars + startIndex);
ffStrbufEnsureEndsWithC(buffer, '/');
FF_ENSURE_ONLY_ONCE_IN_LIST(buffer);
startIndex = colonIndex + 1;
}
ffStrbufDestroy(&xdgConfigDirs);
FFstrbuf* systemConfigHome = ffListAdd(&state->configDirs);
ffStrbufInitA(systemConfigHome, 64);
ffStrbufAppendS(systemConfigHome, FASTFETCH_TARGET_DIR_ETC"/xdg/");
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfigHome)
#endif
FFstrbuf* systemConfig = ffListAdd(&state->configDirs);
ffStrbufInitA(systemConfig, 64);
ffStrbufAppendS(systemConfig, FASTFETCH_TARGET_DIR_ETC"/");
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfig)
#undef FF_ENSURE_ONLY_ONCE_IN_LIST
}
static void initState(FFstate* state)
{
#ifdef WIN32
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
setlocale(LC_ALL, ".UTF8");
#endif
state->logoWidth = 0;
state->logoHeight = 0;
state->keysHeight = 0;
#ifndef WIN32
state->passwd = getpwuid(getuid());
#else
state->passwd = ffGetPasswd();
#endif
uname(&state->utsname);
initConfigDirs(state);
ffPlatformInit(&state->platform);
}
static void initModuleArg(FFModuleArgs* args)
@@ -130,6 +42,7 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInit(&instance->config.logo.colors[i]);
instance->config.logo.width = 0;
instance->config.logo.height = 0; //preserve aspect ratio
instance->config.logo.paddingTop = 0;
instance->config.logo.paddingLeft = 0;
instance->config.logo.paddingRight = 4;
instance->config.logo.printRemaining = true;
@@ -163,13 +76,14 @@ static void defaultConfig(FFinstance* instance)
initModuleArg(&instance->config.host);
initModuleArg(&instance->config.bios);
initModuleArg(&instance->config.board);
initModuleArg(&instance->config.brightness);
initModuleArg(&instance->config.chassis);
initModuleArg(&instance->config.kernel);
initModuleArg(&instance->config.uptime);
initModuleArg(&instance->config.processes);
initModuleArg(&instance->config.packages);
initModuleArg(&instance->config.shell);
initModuleArg(&instance->config.resolution);
initModuleArg(&instance->config.display);
initModuleArg(&instance->config.de);
initModuleArg(&instance->config.wm);
initModuleArg(&instance->config.wmTheme);
@@ -225,16 +139,25 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.libcJSON, 0);
ffStrbufInitA(&instance->config.libfreetype, 0);
ffStrbufInit(&instance->config.libwlanapi);
ffStrbufInit(&instance->config.libnm);
instance->config.cpuTemp = false;
instance->config.gpuTemp = false;
instance->config.batteryTemp = false;
instance->config.gpuHideIntegrated = false;
instance->config.gpuHideDiscrete = false;
instance->config.shellVersion = true;
instance->config.terminalVersion = true;
instance->config.titleFQDN = false;
ffStrbufInitA(&instance->config.diskFolders, 0);
instance->config.diskShowRemovable = true;
instance->config.diskShowHidden = false;
instance->config.diskShowUnknown = false;
instance->config.diskShowSubvolumes = false;
ffStrbufInitA(&instance->config.batteryDir, 0);
@@ -256,10 +179,27 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.playerName, 0);
instance->config.percentType = 1;
ffStrbufInitS(&instance->config.commandShell,
#ifdef _WIN32
"cmd"
#elif defined(__FreeBSD__)
"csh"
#else
"bash"
#endif
);
ffListInit(&instance->config.commandKeys, sizeof(FFstrbuf));
ffListInit(&instance->config.commandTexts, sizeof(FFstrbuf));
}
void ffInitInstance(FFinstance* instance)
{
#ifdef WIN32
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
setlocale(LC_ALL, ".UTF8");
#endif
initState(&instance->state);
defaultConfig(instance);
}
@@ -308,6 +248,10 @@ static void resetConsole()
if(ffHideCursor)
fputs("\033[?25h", stdout);
#if defined(_WIN32) && defined(FF_ENABLE_BUFFER)
fflush(stdout);
#endif
}
#ifdef _WIN32
@@ -401,7 +345,7 @@ static void destroyConfig(FFinstance* instance)
destroyModuleArg(&instance->config.processes);
destroyModuleArg(&instance->config.packages);
destroyModuleArg(&instance->config.shell);
destroyModuleArg(&instance->config.resolution);
destroyModuleArg(&instance->config.display);
destroyModuleArg(&instance->config.de);
destroyModuleArg(&instance->config.wm);
destroyModuleArg(&instance->config.wmTheme);
@@ -457,6 +401,7 @@ static void destroyConfig(FFinstance* instance)
ffStrbufDestroy(&instance->config.libcJSON);
ffStrbufDestroy(&instance->config.libfreetype);
ffStrbufDestroy(&instance->config.libwlanapi);
ffStrbufDestroy(&instance->config.libnm);
ffStrbufDestroy(&instance->config.diskFolders);
ffStrbufDestroy(&instance->config.batteryDir);
@@ -466,13 +411,19 @@ static void destroyConfig(FFinstance* instance)
ffStrbufDestroy(&instance->config.weatherOutputFormat);
ffStrbufDestroy(&instance->config.osFile);
ffStrbufDestroy(&instance->config.playerName);
ffStrbufDestroy(&instance->config.commandShell);
FF_LIST_FOR_EACH(FFstrbuf, item, instance->config.commandKeys)
ffStrbufDestroy(item);
ffListDestroy(&instance->config.commandKeys);
FF_LIST_FOR_EACH(FFstrbuf, item, instance->config.commandTexts)
ffStrbufDestroy(item);
ffListDestroy(&instance->config.commandTexts);
}
static void destroyState(FFinstance* instance)
{
for(uint32_t i = 0; i < instance->state.configDirs.length; ++i)
ffStrbufDestroy((FFstrbuf*)ffListGet(&instance->state.configDirs, i));
ffListDestroy(&instance->state.configDirs);
ffPlatformDestroy(&instance->state.platform);
}
void ffDestroyInstance(FFinstance* instance)
@@ -552,7 +503,10 @@ void ffListFeatures()
"libcjson\n"
#endif
#ifdef FF_HAVE_FREETYPE
"freetype"
"freetype\n"
#endif
#ifdef FF_HAVE_LIBNM
"libnm\n"
#endif
""
, stdout);
-11
View File
@@ -3,17 +3,6 @@
#include <ctype.h>
#include <inttypes.h>
bool ffStrSet(const char* str)
{
if(str == NULL)
return false;
while(isspace(*str))
str++;
return *str != '\0';
}
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch)
{
if(major->length > 0)
-1
View File
@@ -14,7 +14,6 @@ typedef struct FFVersion
#define FF_VERSION_INIT ((FFVersion) {0})
bool ffStrSet(const char* str);
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
+4 -1
View File
@@ -130,9 +130,12 @@ void ffPrintColor(const FFstrbuf* colorValue)
void ffPrintCharTimes(char c, uint32_t times)
{
if(times == 0)
return;
char str[32];
memset(str, c, sizeof(str)); //2 instructions when compiling with AVX2 enabled
for(uint32_t i = sizeof(str); i <= times; i += sizeof(str))
for(uint32_t i = sizeof(str); i <= times; i += (uint32_t)sizeof(str))
fwrite(str, 1, sizeof(str), stdout);
uint32_t remaining = times % sizeof(str);
if(remaining > 0)
+2 -2
View File
@@ -31,8 +31,8 @@ const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
//Parent
close(pipes[1]);
waitpid(childPid, NULL, 0);
ffAppendFDBuffer(pipes[0], buffer);
bool ok = ffAppendFDBuffer(pipes[0], buffer);
close(pipes[0]);
return NULL;
return ok ? NULL : "ffAppendFDBuffer() failed";
}
-1
View File
@@ -4,7 +4,6 @@
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
//We can't use this native version yet because we still use POSIX path ( eg /usr/bin/fish ) at a lot of places.
const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
{
SECURITY_ATTRIBUTES saAttr = {
+5 -20
View File
@@ -144,16 +144,11 @@ done:
return true;
}
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
}
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
FFstrbuf absolutePath;
ffStrbufInitA(&absolutePath, 64);
ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir);
ffStrbufAppend(&absolutePath, &instance->state.platform.homeDir);
ffStrbufAppendC(&absolutePath, '/');
ffStrbufAppendS(&absolutePath, relativeFile);
@@ -164,22 +159,17 @@ bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeF
return result;
}
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileHomeValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
bool foundAFile = false;
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
for(uint32_t i = 0; i < list->length; i++)
{
//We need to copy the config dir each time, because it used by multiple threads, so we can't directly write to it.
ffStrbufSet(&baseDir, ffListGet(&instance->state.configDirs, i));
//We need to copy the dir each time, because it used by multiple threads, so we can't directly write to it.
ffStrbufSet(&baseDir, ffListGet(list, i));
ffStrbufAppendS(&baseDir, relativeFile);
if(ffParsePropFileValues(baseDir.chars, numQueries, queries))
@@ -203,8 +193,3 @@ bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativ
return foundAFile;
}
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
+36 -4
View File
@@ -14,10 +14,42 @@ typedef struct FFpropquery
bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer);
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer);
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer);
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer);
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer);
bool ffParsePropFileListValues(const FFlist* list, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
static inline bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
}
static inline bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileHomeValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
static inline bool ffParsePropFileList(const FFlist* list, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileListValues(list, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
static inline bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
return ffParsePropFileListValues(&instance->state.platform.configDirs, relativeFile, numQueries, queries);
}
static inline bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
static inline bool ffParsePropFileDataValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
return ffParsePropFileListValues(&instance->state.platform.dataDirs, relativeFile, numQueries, queries);
}
static inline bool ffParsePropFileData(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileDataValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
#endif
+50 -6
View File
@@ -6,7 +6,7 @@
# Empty lines or lines starting with # are ignored.
# This file was shipped with $" FASTFETCH_PROJECT_VERSION $".
# Use fastfetch --print-config-user > ~/.config/fastfetch/config.conf to overwrite this file with the current defaults
# Use fastfetch --gen-config-force to overwrite this file with the current defaults
# Below some often usefull options are listed. Uncomment and modify them so they take affect.
# Note that there are a lot more options than the ones listed here, take a look at "fastfetch --help".
@@ -16,7 +16,7 @@
# Load additional config files.
# Some are shipped with fastfetch, list them with "fastfetch --list-presets".
# Must be a path to a config file or the name of a shipped preset.
# The config file is completly loaded before continuing in the current file, so the placement of this option matters, as later options overwrite already set ones.
# The config file is completely loaded before continuing in the current file, so the placement of this option matters, as later options overwrite already set ones.
# Can be used multiple times to load multiple config files / presets.
#--load-config /path/to/config.txt
@@ -114,6 +114,12 @@
# Default is 0.
#--logo-padding-right 0
# Logo padding top option:
# Adds a padding to the top side of the logo.
# Must be a positive integer.
# Default is 0.
#--logo-padding-top 0
# Logo print remaining option:
# Sets if the remaining logo should be printed, it is has more lines than modules to show.
# Must be true or false.
@@ -206,10 +212,45 @@
# Default is auto.
#--gl auto
# GPU hide options
# Sets weather to hide certain gpu types
# Must be either true or false
# Default is false.
#--gpu-hide-integrated
#--gpu-hide-discrete
# Shell option
# Sets if shell version should be detected and printed
# Must be either true or false
# Default is true.
#--shell-version true
# Terminal option
# Sets if terminal version should be detected and printed
# Must be either true or false
# Default is true.
#--terminal-version true
# Disk show options
# Sets if certain types of disk should be printed
# Must be either true or false
# Default is false except for --disk-show-removable.
#--disk-show-removable true
#--disk-show-hidden false
#--disk-show-subvolumes false
#--disk-show-unknown false
# Disk option
# A colon (semicolon on Windows) separated list of folder paths for the disk output
# This option override `--disk-show-*` options above
# Must be a string
# Default is "/:/home" ("C:\\;D:\\ ..." on Windows).
#--disk-folders /:/home
# Percentage output type option
# Applies to all modules that prints percentage values. Currently memory, swap, disk, battery and CPU usage are supported.
# Only works with default format ( without --module-format option ).
# 0: prints none; 1: prints percent number only; 2: prints bar only; 3: prints both percent number and bar
# 0: prints none; 1: prints percent number only; 2: prints bar only; 3: prints both percent number and bar; 6: prints bar and hide other texts
#--percent-type 1
# Key options:
@@ -223,7 +264,8 @@
#--processes-key Processes
#--packages-key Packages
#--shell-key Shell
#--resolution-key Resolution {1}
#--display-key Display {1}
#--brightness-key Brightness ({1})
#--de-key DE
#--wm-key WM
#--wm-theme-key WM Theme
@@ -267,7 +309,8 @@
#--processes-format
#--packages-format
#--shell-format
#--resolution-format
#--display-format
#--brightness-format
#--de-format
#--wm-format
#--wm-theme-format
@@ -310,7 +353,8 @@
#--processes-error
#--packages-error
#--shell-error
#--resolution-error
#--display-error
#--brightness-error
#--de-error
#--wm-error
#--wm-theme-error
+35 -21
View File
@@ -4,6 +4,8 @@ Informative options:
-h,--help: Show this message
-h,--help <command>: Show help for a specific command
-v,--version: Show the version of fastfetch
--list-config-paths: List search paths of config files
--list-data-paths: List search paths of presets and logos
--list-logos: List available logos
--list-modules: List available modules
--list-presets: List presets fastfetch knows about; they can be loaded with --load-config (+)
@@ -12,6 +14,8 @@ Informative options:
--print-config-system: Print the default system config
--print-config-user: Print the default user config
--print-structure: Print the default structure
--gen-config: Generate a sample config file in the default path
--gen-config-force: Generate a sample config file in the default path. Overwrite the existing one
General options:
--load-config <file>: Load a config file or preset (+)
@@ -31,6 +35,7 @@ Logo options:
--logo-padding <padding>: Set the padding on the left and the right of the logo
--logo-padding-left <padding>: Set the padding on the left of the logo
--logo-padding-right <padding>: Set the padding on the right of the logo
--logo-padding-top <padding>: Set the padding on the top of the logo
--logo-print-remaining <?value>: Whether to print the remaining logo, if it has more lines than modules to display
--file <file>: Short for --logo-type file --logo <file>
--file-raw <file>: Short for --logo-type file-raw --logo <file>
@@ -95,27 +100,36 @@ Library options: Set the path of a library to load
--lib-cjson <path>
Module specific options:
--title-fqdn <?value>: Set if the title should use fully qualified domain name. Default is false
--separator-string <str>: Set the string printed by the separator module
--os-file <path>: Set the path to the file containing OS information
--disk-folders <folders>: A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows)
--disk-show-removable <?value>: Set if removable volume should be printed. Default is true
--disk-show-hidden <?value>: Set if hidden volumes should be printed. Default is false
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
--cpu-temp <?value>: Detect and display CPU temperature if supported. Default is false
--gpu-temp <?value>: Detect and display GPU temperature if supported. Default is false
--battery-temp <?value>: Detect and display Battery temperature if supported. Default is false
--localip-show-ipv4 <?value>: Show IPv4 addresses in local ip module. Default is true
--localip-show-ipv6 <?value>: Show IPv6 addresses in local ip module. Default is false
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
--localip-name-prefix <str>: Show IPs with given name prefix only. Default is empty
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
--public-ip-url: The URL of public IP detection server to be used.
--weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0)
--weather-output-format: The output weather format to be used. It must be URI encoded.
--player-name: The name of the player to use
--gl <value>: Set the OpenGL context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
--percent-type <value>: Set the percentage output type. 1 for percentage number, 2 for bar, 3 for both. Default is 1
--title-fqdn <?value>: Set if the title should use fully qualified domain name. Default is false
--separator-string <str>: Set the string printed by the separator module
--os-file <path>: Set the path to the file containing OS information
--shell-version <?value>: Set if shell version should be detected and printed
--terminal-version <?value>: Set if terminal version should be detected and printed
--disk-folders <folders>: A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows)
--disk-show-removable <?value>: Set if removable volume should be printed. Default is true
--disk-show-hidden <?value>: Set if hidden volumes should be printed. Default is false
--disk-show-subvolumes <?value>: Set if subvolumes should be printed. Default is false
--disk-show-unknown <?value>: Set if unknown (unable to detect sizes) volumes should be printed. Default is false
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
--cpu-temp <?value>: Detect and display CPU temperature if supported. Default is false
--gpu-temp <?value>: Detect and display GPU temperature if supported. Default is false
--gpu-hide-integrated <?value>: Hide integrated GPU if supported. Default is false
--gpu-hide-discrete <?value>: Hide discrete GPU if supported. Default is false
--battery-temp <?value>: Detect and display Battery temperature if supported. Default is false
--localip-show-ipv4 <?value>: Show IPv4 addresses in local ip module. Default is true
--localip-show-ipv6 <?value>: Show IPv6 addresses in local ip module. Default is false
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
--localip-name-prefix <str>: Show IPs with given name prefix only. Default is empty
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
--public-ip-url: The URL of public IP detection server to be used.
--weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0)
--weather-output-format: The output weather format to be used. It must be URI encoded.
--player-name: The name of the player to use
--gl <value>: Set the OpenGL context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
--percent-type <value>: Set the percentage output type. 1 for percentage number, 2 for bar, 3 for both, 6 for bar only. Default is 1
--command-shell <str>: Set the shell program to execute the command text. Default is cmd for Windows, csh for FreeBSD, bash for others
--command-key <str>: Set the module key to display, can be specified mulitple times
--command-text <str>: Set the command text to be executed, can be specified mulitple times
Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci"
If a value starts with a ?, it is optional. "true" will be used if not set.
+1 -1
View File
@@ -33,4 +33,4 @@ You can therefore use --host-format " " to disable host output.
Note that --host-format "" would evaluate as not set, and therefore use the built-in host format
Format string is also the way to go to set a fixed value - just use one without placeholders.
For example when running in headless mode, you could use "--resolution-format "Preferred".
For example when running in headless mode, you could use "--display-format Preferred".
+1 -1
View File
@@ -11,6 +11,7 @@ Date
Datetime
DE
Disk
Display
Font
GPU
Host
@@ -27,7 +28,6 @@ Player
PowerAdapter
Processes
PublicIP
Resolution
Separator
Shell
Swap
+1 -1
View File
@@ -1 +1 @@
Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:PowerAdapter:Locale:Break:Colors
Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Display:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:PowerAdapter:Locale:Break:Colors
+38
View File
@@ -0,0 +1,38 @@
#include "fastfetch.h"
#include "battery.h"
#include "common/processing.h"
#include "common/properties.h"
const char* ffDetectBatteryImpl(FF_MAYBE_UNUSED FFinstance* instance, FFlist* results)
{
FF_STRBUF_AUTO_DESTROY buffer;
ffStrbufInit(&buffer);
if(ffProcessAppendStdOut(&buffer, (char* const[]){
FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api",
"BatteryStatus"
}))
return "Starting `" FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api" " BatteryStatus` failed";
BatteryResult* battery = ffListAdd(results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
if(ffParsePropLines(buffer.chars, "\"percentage\": ", &battery->status))
{
battery->capacity = ffStrbufToDouble(&battery->status);
ffStrbufClear(&battery->status);
}
if(ffParsePropLines(buffer.chars, "\"status\": ", &battery->status))
{
ffStrbufTrimRight(&battery->status, ',');
ffStrbufTrim(&battery->status, '"');
}
return NULL;
}
+59
View File
@@ -0,0 +1,59 @@
#include "fastfetch.h"
#include "battery.h"
#include <dev/acpica/acpiio.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <unistd.h>
const char* ffDetectBatteryImpl(FF_MAYBE_UNUSED FFinstance* instance, FFlist* results)
{
//https://www.freebsd.org/cgi/man.cgi?acpi_battery(4)
//https://gitlab.xfce.org/panel-plugins/xfce4-battery-plugin/-/blob/master/panel-plugin/libacpi.c
int acpifd = open("/dev/acpi", O_RDONLY);
if(acpifd < 0)
return "open(\"/dev/acpi\", O_RDONLY) failed";
int units = ioctl(acpifd, ACPIIO_BATT_GET_UNITS, 0);
if(units < 0)
{
close(acpifd);
return "No acpiio battery units found";
}
for(int i = 0; i < units; ++i)
{
union acpi_battery_ioctl_arg battio;
battio.unit = i;
if(ioctl(acpifd, ACPIIO_BATT_GET_BATTINFO, &battio) < 0 || (battio.battinfo.state & ACPI_BATT_STAT_NOT_PRESENT))
continue;
BatteryResult* battery = ffListAdd(results);
battery->temperature = FF_BATTERY_TEMP_UNSET;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->technology);
battery->capacity = battio.battinfo.cap;
if(battio.battinfo.state & ACPI_BATT_STAT_INVALID)
{
ffStrbufAppendS(&battery->status, "Invalid");
}
else
{
if(battio.battinfo.state & ACPI_BATT_STAT_DISCHARG)
ffStrbufAppendS(&battery->status, "Discharging, ");
else if(battio.battinfo.state & ACPI_BATT_STAT_CHARGING)
ffStrbufAppendS(&battery->status, "Charging, ");
if(battio.battinfo.state & ACPI_BATT_STAT_CRITICAL)
ffStrbufAppendS(&battery->status, "Ctritical");
ffStrbufTrimRight(&battery->status, ' ');
ffStrbufTrimRight(&battery->status, ',');
}
}
close(acpifd);
return NULL;
}
+3
View File
@@ -99,6 +99,9 @@ const char* ffDetectBatteryImpl(FFinstance* instance, FFlist* results) {
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
ffStrbufAppendS(&baseDir, entry->d_name);
parseBattery(&baseDir, results);
ffStrbufSubstrBefore(&baseDir, baseDirLength);
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#ifndef FF_INCLUDED_detection_brightness_brightness
#define FF_INCLUDED_detection_brightness_brightness
#include "fastfetch.h"
#include "util/FFlist.h"
typedef struct FFBrightnessResult
{
FFstrbuf name;
float value;
} FFBrightnessResult;
const char* ffDetectBrightness(FFlist* result); // list of FFBrightnessResult
#endif
@@ -0,0 +1,33 @@
#include "brightness.h"
#include <CoreGraphics/CoreGraphics.h>
extern int DisplayServicesGetBrightness(CGDirectDisplayID display, float *brightness) __attribute__((weak_import));
const char* ffDetectBrightness(FFlist* result)
{
if(DisplayServicesGetBrightness == NULL)
return "DisplayServices function DisplayServicesGetBrightness is not available";
CGDirectDisplayID screens[128];
uint32_t screenCount;
if(CGGetOnlineDisplayList(sizeof(screens) / sizeof(screens[0]), screens, &screenCount) != kCGErrorSuccess)
return "CGGetOnlineDisplayList() failed";
for(uint32_t i = 0; i < screenCount; i++)
{
CGDirectDisplayID screen = screens[i];
float brightness;
if(DisplayServicesGetBrightness(screen, &brightness) != kCGErrorSuccess)
continue;
FFBrightnessResult* display = (FFBrightnessResult*) ffListAdd(result);
if(CGDisplayIsBuiltin(screen))
ffStrbufInitS(&display->name, "built-in");
else
ffStrbufInitF(&display->name, "external-%u", (unsigned) screen);
display->value = brightness * 100;
}
return NULL;
}
@@ -0,0 +1,55 @@
#include "brightness.h"
#include "common/io.h"
#include <dirent.h>
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFlist* result)
{
//https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight
const char* backlightDirPath = "/sys/class/backlight/";
DIR* dirp = opendir(backlightDirPath);
if(dirp == NULL)
return "Failed to open `/sys/class/backlight/`";
FFstrbuf backlightDir;
ffStrbufInitA(&backlightDir, 64);
ffStrbufAppendS(&backlightDir, backlightDirPath);
uint32_t backlightDirLength = backlightDir.length;
FFstrbuf buffer;
ffStrbufInit(&buffer);
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
ffStrbufAppendS(&backlightDir, entry->d_name);
ffStrbufAppendS(&backlightDir, "/actual_brightness");
if(ffReadFileBuffer(backlightDir.chars, &buffer))
{
double actualBrightness = ffStrbufToDouble(&buffer);
ffStrbufSubstrBefore(&backlightDir, backlightDirLength);
ffStrbufAppendS(&backlightDir, entry->d_name);
ffStrbufAppendS(&backlightDir, "/max_brightness");
if(ffReadFileBuffer(backlightDir.chars, &buffer))
{
FFBrightnessResult* display = (FFBrightnessResult*) ffListAdd(result);
ffStrbufInitS(&display->name, entry->d_name);
double maxBrightness = ffStrbufToDouble(&buffer);
display->value = (float) (actualBrightness * 100 / maxBrightness);
}
break;
}
}
closedir(dirp);
ffStrbufDestroy(&backlightDir);
ffStrbufDestroy(&buffer);
return NULL;
}
@@ -0,0 +1,6 @@
#include "brightness.h"
const char* ffDetectBrightness(FF_MAYBE_UNUSED FFlist* result)
{
return "Not supported on this platform";
}
@@ -0,0 +1,27 @@
extern "C"
{
#include "brightness.h"
}
#include "util/windows/wmi.hpp"
extern "C"
const char* ffDetectBrightness(FFlist* result)
{
FFWmiQuery query(L"SELECT CurrentBrightness, InstanceName FROM WmiMonitorBrightness WHERE Active = true", nullptr, FFWmiNamespace::WMI);
if(!query)
return "Query WMI service failed";
while(FFWmiRecord record = query.next())
{
FFBrightnessResult* display = (FFBrightnessResult*) ffListAdd(result);
ffStrbufInit(&display->name);
record.getString(L"InstanceName", &display->name);
ffStrbufSubstrAfterFirstC(&display->name, '\\');
ffStrbufSubstrBeforeFirstC(&display->name, '\\');
uint64_t brightness;
record.getUnsigned(L"CurrentBrightness", &brightness);
display->value = (float) brightness;
}
return NULL;
}
+50 -6
View File
@@ -7,7 +7,7 @@
#include <stdlib.h>
#include <unistd.h>
static void parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer, FFstrbuf* cpuMHz)
static void parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer, FFstrbuf* cpuMHz, FFstrbuf* cpuIsa, FFstrbuf* cpuUarch)
{
FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
if(cpuinfo == NULL)
@@ -19,7 +19,7 @@ static void parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer, FFstrb
while(getline(&line, &len, cpuinfo) != -1)
{
//Stop after the first CPU
if(cpu->name.length > 0 && (*line == '\0' || *line == '\n'))
if(*line == '\0' || *line == '\n')
break;
(void)(
@@ -27,6 +27,8 @@ static void parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer, FFstrb
ffParsePropLine(line, "vendor_id :", &cpu->vendor) ||
ffParsePropLine(line, "cpu cores :", physicalCoresBuffer) ||
ffParsePropLine(line, "cpu MHz :", cpuMHz) ||
ffParsePropLine(line, "isa :", cpuIsa) ||
ffParsePropLine(line, "uarch :", cpuUarch) ||
(cpu->name.length == 0 && ffParsePropLine(line, "Hardware :", &cpu->name)) //For Android devices
);
}
@@ -65,9 +67,9 @@ static double getFrequency(const char* info, const char* scaling)
return getGHz(scaling);
}
static double detectCPUTemp(const FFinstance* instance)
static double detectCPUTemp(void)
{
const FFTempsResult* temps = ffDetectTemps(instance);
const FFTempsResult* temps = ffDetectTemps();
for(uint32_t i = 0; i < temps->values.length; i++)
{
@@ -83,10 +85,29 @@ static double detectCPUTemp(const FFinstance* instance)
return FF_CPU_TEMP_UNSET;
}
static void parseIsa(FFstrbuf* cpuIsa)
{
if(ffStrbufStartsWithS(cpuIsa, "rv"))
{
// RISC-V ISA string example: "rv64imafdch_zicsr_zifencei".
// The _z parts are not important for CPU showcasing, so we remove them.
if(ffStrbufContainC(cpuIsa, '_'))
ffStrbufSubstrBeforeFirstC(cpuIsa, '_');
// Then we replace "imafd" with "g" since "g" is a shorthand.
if(ffStrbufContainS(cpuIsa, "imafd"))
{
// Remove 4 of the 5 characters and replace the remaining one with "g".
ffStrbufRemoveSubstr(cpuIsa, 4, 8);
cpuIsa->chars[4] = 'g';
}
// The final ISA output of the above example is "rv64gch".
}
}
void ffDetectCPUImpl(const FFinstance* instance, FFCPUResult* cpu)
{
if(instance->config.cpuTemp)
cpu->temperature = detectCPUTemp(instance);
cpu->temperature = detectCPUTemp();
else
cpu->temperature = FF_CPU_TEMP_UNSET;
@@ -96,7 +117,13 @@ void ffDetectCPUImpl(const FFinstance* instance, FFCPUResult* cpu)
FFstrbuf cpuMHz;
ffStrbufInit(&cpuMHz);
parseCpuInfo(cpu, &physicalCoresBuffer, &cpuMHz);
FFstrbuf cpuIsa;
ffStrbufInit(&cpuIsa);
FFstrbuf cpuUarch;
ffStrbufInit(&cpuUarch);
parseCpuInfo(cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch);
cpu->coresPhysical = ffStrbufToUInt16(&physicalCoresBuffer, 1);
@@ -114,6 +141,23 @@ void ffDetectCPUImpl(const FFinstance* instance, FFCPUResult* cpu)
cpu->frequencyMin = cpu->frequencyMax = ffStrbufToDouble(&cpuMHz) / 1000;
}
if(cpuUarch.length > 0)
{
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuUarch);
}
if(cpuIsa.length > 0)
{
parseIsa(&cpuIsa);
if(cpu->name.length > 0)
ffStrbufAppendC(&cpu->name, ' ');
ffStrbufAppend(&cpu->name, &cpuIsa);
}
ffStrbufDestroy(&physicalCoresBuffer);
ffStrbufDestroy(&cpuMHz);
ffStrbufDestroy(&cpuIsa);
ffStrbufDestroy(&cpuUarch);
}
+15 -56
View File
@@ -8,7 +8,7 @@
#include <stdlib.h>
static void detectCursorGTK(const FFinstance* instance, FFCursorResult* result)
static bool detectCursorGTK(const FFinstance* instance, FFCursorResult* result)
{
const FFGTKResult* gtk = ffDetectGTK4(instance);
@@ -19,25 +19,11 @@ static void detectCursorGTK(const FFinstance* instance, FFCursorResult* result)
gtk = ffDetectGTK2(instance);
if(gtk->cursor.length == 0)
{
ffStrbufAppendS(&result->error, "Couldn't detect GTK Cursor");
return;
}
return false;
ffStrbufAppend(&result->theme, &gtk->cursor);
ffStrbufAppend(&result->size, &gtk->cursorSize);
}
static void detectCursorXFCE(const FFinstance* instance, FFCursorResult* result)
{
ffStrbufAppendS(&result->theme, ffSettingsGetXFConf(instance, "xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue);
if(result->theme.length == 0)
ffStrbufAppendS(&result->error, "Couldn't find xfce cursor in xfconf (xsettings::/Gtk/CursorThemeName)");
int cursorSizeVal = ffSettingsGetXFConf(instance, "xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue;
if(cursorSizeVal > 0)
ffStrbufAppendF(&result->size, "%i", cursorSizeVal);
return true;
}
static void detectCursorFromConfigFile(const FFinstance* instance, const char* relativeFilePath, const char* themeStart, const char* themeDefault, const char* sizeStart, const char* sizeDefault, FFCursorResult* result)
@@ -68,16 +54,6 @@ static bool detectCursorFromXResources(const FFinstance* instance, FFCursorResul
return result->theme.length > 0;
}
static bool detectCursorFromXDG(const FFinstance* instance, bool user, FFCursorResult* result)
{
if(user)
ffParsePropFileHome(instance, ".icons/default/index.theme", "Inherits =", &result->theme);
else
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/icons/default/index.theme", "Inherits =", &result->theme);
return result->theme.length > 0;
}
static bool detectCursorFromEnv(const FFinstance* instance, FFCursorResult* result)
{
FF_UNUSED(instance);
@@ -97,35 +73,18 @@ void ffDetectCursor(const FFinstance* instance, FFCursorResult* result)
const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance);
if(ffStrbufCompS(&wmde->wmPrettyName, "WSLg") == 0)
{
ffStrbufAppendS(&result->error, "WSLg uses native windows cursor");
return;
}
if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0)
{
else if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0)
ffStrbufAppendS(&result->error, "Cursor isn't supported in TTY");
return;
}
if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "KDE Plasma") == 0)
return detectCursorFromConfigFile(instance, "kcminputrc", "cursorTheme =", "Breeze", "cursorSize =", "24", result);
if(ffStrbufStartsWithIgnCaseS(&wmde->dePrettyName, "XFCE"))
return detectCursorXFCE(instance, result);
if(ffStrbufStartsWithIgnCaseS(&wmde->dePrettyName, "LXQt"))
return detectCursorFromConfigFile(instance, "lxqt/session.conf", "cursor_theme =", "Adwaita", "cursor_size =", "24", result);
if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Gnome") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Cinnamon") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Mate") == 0)
return detectCursorGTK(instance, result);
if(
detectCursorFromEnv(instance, result) ||
detectCursorFromXDG(instance, true, result) ||
detectCursorFromXResources(instance, result) ||
detectCursorFromXDG(instance, false, result)
) return;
detectCursorGTK(instance, result);
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "KDE Plasma") == 0)
detectCursorFromConfigFile(instance, "kcminputrc", "cursorTheme =", "Breeze", "cursorSize =", "24", result);
else if(ffStrbufStartsWithIgnCaseS(&wmde->dePrettyName, "LXQt"))
detectCursorFromConfigFile(instance, "lxqt/session.conf", "cursor_theme =", "Adwaita", "cursor_size =", "24", result);
else if(
!detectCursorGTK(instance, result) &&
!detectCursorFromEnv(instance, result) &&
!ffParsePropFileHome(instance, ".icons/default/index.theme", "Inherits =", &result->theme) &&
!detectCursorFromXResources(instance, result) &&
!ffParsePropFileData(instance, "icons/default/index.theme", "Inherits =", &result->theme)
) ffStrbufAppendS(&result->error, "Couldn't find cursor");
}
+2 -1
View File
@@ -9,7 +9,8 @@ typedef enum FFDiskType
{
FF_DISK_TYPE_REGULAR,
FF_DISK_TYPE_HIDDEN,
FF_DISK_TYPE_EXTERNAL
FF_DISK_TYPE_EXTERNAL,
FF_DISK_TYPE_SUBVOLUME
} FFDiskType;
typedef struct FFDisk
+188 -72
View File
@@ -2,30 +2,181 @@
#include <limits.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
static void strbufAppendMountPoint(FFstrbuf* mountpoint, const char* source)
#ifdef __USE_LARGEFILE64
#define stat stat64
#define statvfs statvfs64
#define dirent dirent64
#define readdir readdir64
#endif
static bool isPhysicalDevice(const char* device)
{
while(*source != '\0' && !isspace(*source))
//DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
if(strcmp(device, "drvfs") == 0)
return true;
//Pseudo filesystems don't have a device in /dev
const char* devPrefix = "/dev/";
if(strncmp(device, devPrefix, strlen(devPrefix)) != 0)
return false;
//Skip /dev/ prefix
device += strlen(devPrefix);
if(
strncmp(device, "loop", 4) == 0 || //Ignore loop devices
strncmp(device, "ram", 3) == 0 || //Ignore ram devices
strncmp(device, "fd", 2) == 0 //Ignore fd devices
) return false;
return true;
}
static void appendNextEntry(FFstrbuf* buffer, char** source)
{
//Read the current entry into the buffer
while(**source != '\0' && !isspace(**source))
{
//After a backslash the next 3 characters are octal ascii codes
if(*source == '\\' && strnlen(source, 4) == 4)
if(**source == '\\' && strnlen(*source, 4) == 4)
{
char octal[4] = {0};
strncpy(octal, source + 1, 3);
strncpy(octal, *source + 1, 3);
long value = strtol(octal, NULL, 8); //Returns 0 on error, so no need to check endptr
if(value > 0 && value < CHAR_MAX)
{
ffStrbufAppendC(mountpoint, (char) value);
source += 4;
ffStrbufAppendC(buffer, (char) value);
*source += 4;
continue;
}
}
ffStrbufAppendC(mountpoint, *source);
++source;
ffStrbufAppendC(buffer, **source);
++*source;
}
//Skip whitespace
while(isspace(**source))
++*source;
}
static void detectNameFromPath(FFDisk* disk, const struct stat* deviceStat, FFstrbuf* basePath)
{
DIR* dir = opendir(basePath->chars);
if(dir == NULL)
return;
uint32_t basePathLength = basePath->length;
struct dirent* entry;
while((entry = readdir(dir)) != NULL)
{
if(entry->d_name[0] == '.')
continue;
ffStrbufAppendS(basePath, entry->d_name);
struct stat entryStat;
bool ret = stat(basePath->chars, &entryStat) == 0;
ffStrbufSubstrBefore(basePath, basePathLength);
if(!ret || deviceStat->st_ino != entryStat.st_ino)
continue;
ffStrbufAppendS(&disk->name, entry->d_name);
break;
}
closedir(dir);
}
static void detectName(FFDisk* disk, const FFstrbuf* device)
{
struct stat deviceStat;
if(stat(device->chars, &deviceStat) != 0)
return;
FFstrbuf basePath;
ffStrbufInit(&basePath);
//Try partlabel first
ffStrbufSetS(&basePath, "/dev/disk/by-partlabel/");
detectNameFromPath(disk, &deviceStat, &basePath);
//Try label second
if(disk->name.length == 0)
{
ffStrbufSetS(&basePath, "/dev/disk/by-label/");
detectNameFromPath(disk, &deviceStat, &basePath);
}
//Use the mountpoint as a last resort
if(disk->name.length == 0)
ffStrbufAppend(&disk->name, &disk->mountpoint);
ffStrbufDestroy(&basePath);
}
#ifdef __ANDROID__
static void detectType(FF_MAYBE_UNUSED const FFlist* devices, FFDisk* currentDisk, FF_MAYBE_UNUSED const char* options)
{
if(ffStrbufEqualS(&currentDisk->mountpoint, "/") || ffStrbufEqualS(&currentDisk->mountpoint, "/storage/emulated"))
currentDisk->type = FF_DISK_TYPE_REGULAR;
else if(ffStrbufStartsWithS(&currentDisk->mountpoint, "/mnt/media_rw/"))
currentDisk->type = FF_DISK_TYPE_EXTERNAL;
else
currentDisk->type = FF_DISK_TYPE_HIDDEN;
}
#else
static bool isSubvolume(const FFlist* devices)
{
const FFstrbuf* currentDevie = ffListGet(devices, devices->length - 1);
for(uint32_t i = 0; i < devices->length - 1; i++)
{
const FFstrbuf* otherDevice = ffListGet(devices, i);
if(ffStrbufEqual(currentDevie, otherDevice))
return true;
}
return false;
}
static void detectType(const FFlist* devices, FFDisk* currentDisk, const char* options)
{
if(isSubvolume(devices))
currentDisk->type = FF_DISK_TYPE_SUBVOLUME;
else if(strstr(options, "nosuid") != NULL || strstr(options, "nodev") != NULL)
currentDisk->type = FF_DISK_TYPE_EXTERNAL;
else if(ffStrbufStartsWithS(&currentDisk->mountpoint, "/boot") || ffStrbufStartsWithS(&currentDisk->mountpoint, "/efi"))
currentDisk->type = FF_DISK_TYPE_HIDDEN;
else
currentDisk->type = FF_DISK_TYPE_REGULAR;
}
#endif
static void detectStats(FFDisk* disk)
{
struct statvfs fs;
if(statvfs(disk->mountpoint.chars, &fs) != 0)
memset(&fs, 0, sizeof(struct statvfs)); //Set all values to 0, so our values get initialized to 0 too
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
disk->bytesUsed = disk->bytesTotal - (fs.f_bavail * fs.f_frsize);
disk->filesTotal = (uint32_t) fs.f_files;
disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
}
void ffDetectDisksImpl(FFDiskResult* disks)
@@ -37,88 +188,53 @@ void ffDetectDisksImpl(FFDiskResult* disks)
return;
}
FFlist devices;
ffListInit(&devices, sizeof(FFstrbuf));
char* line = NULL;
size_t len = 0;
while(getline(&line, &len, mountsFile) != EOF)
{
if(!isPhysicalDevice(line))
continue;
//We have a valid device, add it to the list
FFDisk* disk = ffListAdd(&disks->disks);
//Format of the file: "<device> <mountpoint> <filesystem> <options> ..." (Same as fstab)
char* currentPos = line;
//Non pseudo filesystems have their device in /dev/
//DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
if(strncmp(currentPos, "/dev/", 5) != 0 && strncmp(currentPos, "drvfs", 5) != 0)
continue;
//detect device
FFstrbuf* device = ffListAdd(&devices);
ffStrbufInit(device);
appendNextEntry(device, &currentPos);
//Skip /dev/ or drvfs
currentPos += 5;
//detect mountpoint
ffStrbufInit(&disk->mountpoint);
appendNextEntry(&disk->mountpoint, &currentPos);
//Don't show loop file systems
if(strncasecmp(currentPos, "loop", 4) == 0)
continue;
//detect filesystem
ffStrbufInit(&disk->filesystem);
appendNextEntry(&disk->filesystem, &currentPos);
FFDisk* disk = ffListAdd(&disks->disks);
//detect name
ffStrbufInit(&disk->name);
detectName(disk, device);
//Go to mountpoint
while(!isspace(*currentPos) && *currentPos != '\0')
++currentPos;
while(isspace(*currentPos))
++currentPos;
ffStrbufInitA(&disk->mountpoint, 16);
strbufAppendMountPoint(&disk->mountpoint, currentPos);
//Go to filesystem
currentPos += disk->mountpoint.length;
while(isspace(*currentPos))
++currentPos;
ffStrbufInitA(&disk->filesystem, 16);
ffStrbufAppendSUntilC(&disk->filesystem, currentPos, ' ');
//Go to options, detect type
currentPos += disk->filesystem.length;
while(isspace(*currentPos))
++currentPos;
#ifdef __ANDROID__
if(ffStrbufEqualS(&disk->mountpoint, "/") || ffStrbufEqualS(&disk->mountpoint, "/storage/emulated"))
disk->type = FF_DISK_TYPE_REGULAR;
else if(ffStrbufStartsWithS(&disk->mountpoint, "/mnt/media_rw/"))
disk->type = FF_DISK_TYPE_EXTERNAL;
else
disk->type = FF_DISK_TYPE_HIDDEN;
#else
if(strstr(currentPos, "nosuid") != NULL || strstr(currentPos, "nodev") != NULL)
disk->type = FF_DISK_TYPE_EXTERNAL;
else if(ffStrbufStartsWithS(&disk->mountpoint, "/boot") || ffStrbufStartsWithS(&disk->mountpoint, "/efi"))
disk->type = FF_DISK_TYPE_HIDDEN;
else
disk->type = FF_DISK_TYPE_REGULAR;
#endif
//detect type
detectType(&devices, disk, currentPos);
//Detects stats
#ifdef __USE_LARGEFILE64
struct statvfs64 fs;
if(statvfs64(disk->mountpoint.chars, &fs) != 0)
memset(&fs, 0, sizeof(struct statvfs64)); //Set all values to 0, so our values get initialized to 0 too
#else
struct statvfs fs;
if(statvfs(disk->mountpoint.chars, &fs) != 0)
memset(&fs, 0, sizeof(struct statvfs)); //Set all values to 0, so our values get initialized to 0 too
#endif
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
disk->bytesUsed = disk->bytesTotal - (fs.f_bavail * fs.f_frsize);
disk->filesTotal = (uint32_t) fs.f_files;
disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
ffStrbufInit(&disk->name); //TODO: implement this
detectStats(disk);
}
if(line != NULL)
free(line);
FF_LIST_FOR_EACH(FFstrbuf, device, devices)
ffStrbufDestroy(device);
ffListDestroy(&devices);
fclose(mountsFile);
}
+7 -5
View File
@@ -19,15 +19,17 @@ uint32_t ffdsParseRefreshRate(int32_t refreshRate)
return (uint32_t) refreshRate;
}
bool ffdsAppendResolution(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate)
bool ffdsAppendDisplay(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate, uint32_t scaledWidth, uint32_t scaledHeight)
{
if(width == 0 || height == 0)
return false;
FFResolutionResult* resolution = ffListAdd(&result->resolutions);
resolution->width = width;
resolution->height = height;
resolution->refreshRate = refreshRate;
FFDisplayResult* display = ffListAdd(&result->displays);
display->width = width;
display->height = height;
display->refreshRate = refreshRate;
display->scaledWidth = scaledWidth;
display->scaledHeight = scaledHeight;
return true;
}
+6 -4
View File
@@ -5,12 +5,14 @@
#include "fastfetch.h"
typedef struct FFResolutionResult
typedef struct FFDisplayResult
{
uint32_t width;
uint32_t height;
uint32_t refreshRate;
} FFResolutionResult;
uint32_t scaledWidth;
uint32_t scaledHeight;
} FFDisplayResult;
typedef struct FFDisplayServerResult
{
@@ -20,13 +22,13 @@ typedef struct FFDisplayServerResult
FFstrbuf deProcessName;
FFstrbuf dePrettyName;
FFstrbuf deVersion;
FFlist resolutions; //List of FFResolutionResult
FFlist displays; //List of FFDisplayResult
} FFDisplayServerResult;
const FFDisplayServerResult* ffConnectDisplayServer(const FFinstance* instance);
//Used internal
uint32_t ffdsParseRefreshRate(int32_t refreshRate);
bool ffdsAppendResolution(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate);
bool ffdsAppendDisplay(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate, uint32_t scaledWidth, uint32_t scaledHeight);
#endif
@@ -7,7 +7,7 @@
#include <assert.h>
#include <CoreGraphics/CGDirectDisplay.h>
static void detectResolution(FFDisplayServerResult* ds)
static void detectDisplays(FFDisplayServerResult* ds)
{
CGDirectDisplayID screens[128];
uint32_t screenCount;
@@ -20,10 +20,12 @@ static void detectResolution(FFDisplayServerResult* ds)
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(screen);
if(mode)
{
ffdsAppendResolution(ds,
ffdsAppendDisplay(ds,
(uint32_t)CGDisplayModeGetPixelWidth(mode),
(uint32_t)CGDisplayModeGetPixelHeight(mode),
(uint32_t)CGDisplayModeGetRefreshRate(mode),
(uint32_t)CGDisplayModeGetWidth(mode),
(uint32_t)CGDisplayModeGetHeight(mode),
(uint32_t)CGDisplayModeGetRefreshRate(mode)
(uint32_t)CGDisplayModeGetHeight(mode)
);
CGDisplayModeRelease(mode);
}
@@ -84,6 +86,6 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* ins
ffStrbufAppendS(&ds->deProcessName, "aqua");
ffStrbufAppendS(&ds->dePrettyName, "Aqua");
ffListInitA(&ds->resolutions, sizeof(FFResolutionResult), 4);
detectResolution(ds);
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 4);
detectDisplays(ds);
}
@@ -10,5 +10,5 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* ins
ffStrbufInitA(&ds->deProcessName, 0);
ffStrbufInitA(&ds->dePrettyName, 0);
ffStrbufInitA(&ds->deVersion, 0);
ffListInitA(&ds->resolutions, sizeof(FFResolutionResult), 0);
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 0);
}
@@ -4,6 +4,26 @@
#include <dwmapi.h>
#include <WinUser.h>
typedef struct
{
WCHAR* deviceName;
uint32_t width;
uint32_t height;
} DataBundle;
static CALLBACK WINBOOL enumMonitorProc(HMONITOR hMonitor, FF_MAYBE_UNUSED HDC hDC, FF_MAYBE_UNUSED LPRECT rc, LPARAM lparam)
{
MONITORINFOEXW mi = { .cbSize = sizeof(mi) };
DataBundle* data = (DataBundle*) lparam;
if(GetMonitorInfoW(hMonitor, (MONITORINFO *)&mi) && wcscmp(mi.szDevice, data->deviceName) == 0)
{
data->width = (uint32_t) mi.rcMonitor.right;
data->height = (uint32_t) mi.rcMonitor.bottom;
return FALSE;
}
return TRUE;
}
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* instance)
{
FF_UNUSED(instance);
@@ -23,7 +43,7 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* ins
ffStrbufInit(&ds->deProcessName);
ffStrbufInit(&ds->dePrettyName);
ffStrbufInit(&ds->deVersion);
ffListInit(&ds->resolutions, sizeof(FFResolutionResult));
ffListInit(&ds->displays, sizeof(FFDisplayResult));
DISPLAY_DEVICEW displayDevice = { .cb = sizeof(DISPLAY_DEVICEW) };
for(DWORD devNum = 0; EnumDisplayDevicesW(NULL, devNum, &displayDevice, 0) != 0; ++devNum)
@@ -34,7 +54,13 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* ins
if(EnumDisplaySettingsW(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode) == 0)
continue;
ffdsAppendResolution(ds, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmDisplayFrequency);
DataBundle data = {
.deviceName = displayDevice.DeviceName,
.width = 0,
.height = 0,
};
EnumDisplayMonitors(NULL, NULL, enumMonitorProc, (LPARAM)&data);
ffdsAppendDisplay(ds, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmDisplayFrequency, data.width, data.height);
}
//https://github.com/hykilpikonna/hyfetch/blob/master/neofetch#L2067
@@ -19,6 +19,9 @@ static void parseDRM(FFDisplayServerResult* result)
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
ffStrbufAppendS(&drmDir, entry->d_name);
ffStrbufAppendS(&drmDir, "/modes");
@@ -29,14 +32,16 @@ static void parseDRM(FFDisplayServerResult* result)
continue;
}
FFResolutionResult* resolution = ffListAdd(&result->resolutions);
resolution->width = 0;
resolution->height = 0;
resolution->refreshRate = 0;
FFDisplayResult* display = ffListAdd(&result->displays);
display->width = 0;
display->height = 0;
display->refreshRate = 0;
display->scaledWidth = 0;
display->scaledHeight = 0;
int scanned = fscanf(modeFile, "%ux%u", &resolution->width, &resolution->height);
if(scanned < 2 || resolution->width == 0 || resolution->height == 0)
--result->resolutions.length;
int scanned = fscanf(modeFile, "%ux%u", &display->width, &display->height);
if(scanned < 2 || display->width == 0 || display->height == 0)
--result->displays.length;
fclose(modeFile);
ffStrbufSubstrBefore(&drmDir, drmDirLength);
@@ -54,31 +59,31 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* ins
ffStrbufInit(&ds->deProcessName);
ffStrbufInit(&ds->dePrettyName);
ffStrbufInit(&ds->deVersion);
ffListInitA(&ds->resolutions, sizeof(FFResolutionResult), 4);
ffListInitA(&ds->displays, sizeof(FFDisplayResult), 4);
//We try wayland as our prefered display server, as it supports the most features.
//This method can't detect the name of our WM / DE
ffdsConnectWayland(instance, ds);
//Try the x11 libs, from most feature rich to least.
//We use the resolution list to detect if a connection is needed.
//They respect wmProtocolName, and only detect resolution if it is set.
//We use the display list to detect if a connection is needed.
//They respect wmProtocolName, and only detect display if it is set.
if(ds->resolutions.length == 0)
if(ds->displays.length == 0)
ffdsConnectXcbRandr(instance, ds);
if(ds->resolutions.length == 0)
if(ds->displays.length == 0)
ffdsConnectXrandr(instance, ds);
if(ds->resolutions.length == 0)
if(ds->displays.length == 0)
ffdsConnectXcb(instance, ds);
if(ds->resolutions.length == 0)
if(ds->displays.length == 0)
ffdsConnectXlib(instance, ds);
//This resolution detection method is display server independent.
//This display detection method is display server independent.
//Use it if all connections failed
if(ds->resolutions.length == 0)
if(ds->displays.length == 0)
parseDRM(ds);
//This fills in missing information about WM / DE by using env vars and iterating processes
+5 -3
View File
@@ -59,13 +59,15 @@ static void waylandOutputModeListener(void* data, struct wl_output* output, uint
static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER;
ffThreadMutexLock(&mutex);
FFResolutionResult* result = ffListAdd(wldata->results);
FFDisplayResult* result = ffListAdd(wldata->results);
ffThreadMutexUnlock(&mutex);
result->width = (uint32_t) width;
result->height = (uint32_t) height;
result->refreshRate = ffdsParseRefreshRate(refreshRate / 1000);
result->scaledWidth = 0;
result->scaledHeight = 0;
}
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
@@ -136,7 +138,7 @@ bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result)
return false;
}
data.results = &result->resolutions;
data.results = &result->displays;
struct wl_registry_listener registry_listener = {
.global = waylandGlobalAddListener,
@@ -151,7 +153,7 @@ bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result)
ffwl_display_disconnect(display);
dlclose(wayland);
//We successfully connected to wayland and detected the resolution.
//We successfully connected to wayland and detected the display.
//So we can set set the session type to wayland.
//This is used as an indicator that we are running wayland by the x11 backends.
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND);
+31 -21
View File
@@ -116,38 +116,34 @@ static void applyBetterWM(FFDisplayServerResult* result, const char* processName
ffStrbufAppend(&result->wmPrettyName, &result->wmProcessName);
}
static void getKDE(FFDisplayServerResult* result)
static void getKDE(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "plasmashell");
ffStrbufSetS(&result->dePrettyName, "KDE Plasma");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
ffParsePropFileData(instance, "xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/xsessions/plasma5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
ffParsePropFileData(instance, "xsessions/plasma5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/wayland-sessions/plasmawayland.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
ffParsePropFileData(instance, "wayland-sessions/plasmawayland.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/wayland-sessions/plasmawayland5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/local/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/local/share/wayland-sessions/plasmawayland.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
ffParsePropFileData(instance, "wayland-sessions/plasmawayland5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
applyBetterWM(result, getenv("KDEWM"));
}
static void getGnome(FFDisplayServerResult* result)
static void getGnome(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "gnome-shell");
ffStrbufSetS(&result->dePrettyName, "GNOME");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
ffParsePropFileData(instance, "gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
}
static void getCinnamon(FFDisplayServerResult* result)
static void getCinnamon(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "cinnamon");
ffStrbufSetS(&result->dePrettyName, "Cinnamon");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
ffParsePropFileData(instance, "applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
}
static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
@@ -164,7 +160,7 @@ static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
FFstrbuf micro;
ffStrbufInit(&micro);
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR"/share/mate-about/mate-version.xml", 3, (FFpropquery[]) {
ffParsePropFileDataValues(instance, "mate-about/mate-version.xml", 3, (FFpropquery[]) {
{"<platform>", &major},
{"<minor>", &minor},
{"<micro>", &micro}
@@ -193,7 +189,7 @@ static void getXFCE4(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "xfce4-session");
ffStrbufSetS(&result->dePrettyName, "Xfce4");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
ffParsePropFileData(instance, "gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
@@ -214,12 +210,12 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "lxqt-session");
ffStrbufSetS(&result->dePrettyName, "LXQt");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/lib/pkgconfig/lxqt.pc", "Version:", &result->deVersion);
ffParsePropFileData(instance, "gconfig/lxqt.pc", "Version:", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
ffParsePropFileData(instance, "cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
ffParsePropFileData(instance, "cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
@@ -243,6 +239,13 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
ffStrbufDestroy(&wmProcessNameBuffer);
}
static void getBudgie(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->dePrettyName, "Budgie");
ffStrbufSetS(&result->deProcessName, "budgie-desktop");
ffParsePropFileData(instance, "budgie/budgie-version.xml", "<str>", &result->deVersion);
}
static void applyPrettyNameIfDE(const FFinstance* instance, FFDisplayServerResult* result, const char* name)
{
if(!ffStrSet(name))
@@ -253,19 +256,19 @@ static void applyPrettyNameIfDE(const FFinstance* instance, FFDisplayServerResul
strcasecmp(name, "plasma") == 0 ||
strcasecmp(name, "plasmashell") == 0 ||
strcasecmp(name, "plasmawayland") == 0
) getKDE(result);
) getKDE(instance, result);
else if(
strcasecmp(name, "Gnome") == 0 ||
strcasecmp(name, "ubuntu:GNOME") == 0 ||
strcasecmp(name, "ubuntu") == 0 ||
strcasecmp(name, "gnome-shell") == 0
) getGnome(result);
) getGnome(instance, result);
else if(
strcasecmp(name, "X-Cinnamon") == 0 ||
strcasecmp(name, "Cinnamon") == 0
) getCinnamon(result);
) getCinnamon(instance, result);
else if(
strcasecmp(name, "XFCE") == 0 ||
@@ -286,6 +289,13 @@ static void applyPrettyNameIfDE(const FFinstance* instance, FFDisplayServerResul
strcasecmp(name, "X-LXQT") == 0 ||
strcasecmp(name, "lxqt-session") == 0
) getLXQt(instance, result);
else if(
strcasecmp(name, "Budgie") == 0 ||
strcasecmp(name, "X-Budgie") == 0 ||
strcasecmp(name, "budgie-desktop") == 0 ||
strcasecmp(name, "Budgie:GNOME") == 0
) getBudgie(instance, result);
}
static void getWMProtocolNameFromEnv(FFDisplayServerResult* result)
+20 -10
View File
@@ -115,10 +115,12 @@ void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
while(iterator.rem > 0)
{
ffdsAppendResolution(
ffdsAppendDisplay(
result,
(uint32_t) iterator.data->width_in_pixels,
(uint32_t) iterator.data->height_in_pixels,
0,
0,
0
);
ffxcb_screen_next(&iterator);
@@ -180,17 +182,19 @@ static bool xcbRandrHandleModeInfo(XcbRandrData* data, xcb_randr_mode_info_t* mo
modeInfo->dot_clock / (uint32_t) (modeInfo->htotal * modeInfo->vtotal)
));
return ffdsAppendResolution(
return ffdsAppendDisplay(
data->result,
(uint32_t) modeInfo->width,
(uint32_t) modeInfo->height,
refreshRate == 0 ? data->defaultRefreshRate : refreshRate
refreshRate == 0 ? data->defaultRefreshRate : refreshRate,
0,
0
);
}
static bool xcbRandrHandleMode(XcbRandrData* data, xcb_randr_mode_t mode)
{
//We do the check here, because we want the best fallback resolution if this call failed
//We do the check here, because we want the best fallback display if this call failed
if(data->screenResources == NULL)
return false;
@@ -215,11 +219,13 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc)
return false;
bool res = xcbRandrHandleMode(data, crtcInfoReply->mode);
res = res ? true : ffdsAppendResolution(
res = res ? true : ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
data->defaultRefreshRate
data->defaultRefreshRate,
0,
0
);
free(crtcInfoReply);
@@ -258,11 +264,13 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t*
data->ffxcb_randr_output_next(&outputIterator);
};
return foundOutput ? true : ffdsAppendResolution(
return foundOutput ? true : ffdsAppendDisplay(
data->result,
(uint32_t) monitor->width,
(uint32_t) monitor->height,
data->defaultRefreshRate
data->defaultRefreshRate,
0,
0
);
}
@@ -316,11 +324,13 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
return;
//If detetction failed, fallback to screen = monitor, like in the libxcb.so implementation
ffdsAppendResolution(
ffdsAppendDisplay(
data->result,
(uint32_t) screen->width_in_pixels,
(uint32_t) screen->height_in_pixels,
data->defaultRefreshRate
data->defaultRefreshRate,
0,
0
);
}
+20 -10
View File
@@ -79,10 +79,12 @@ void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
for(int i = 0; i < ScreenCount(display); i++)
{
Screen* screen = ScreenOfDisplay(display, i);
ffdsAppendResolution(
ffdsAppendDisplay(
result,
(uint32_t) screen->width,
(uint32_t) screen->height,
0,
0,
0
);
}
@@ -138,11 +140,13 @@ static bool xrandrHandleModeInfo(XrandrData* data, XRRModeInfo* modeInfo)
modeInfo->dotClock / (modeInfo->hTotal * modeInfo->vTotal)
));
return ffdsAppendResolution(
return ffdsAppendDisplay(
data->result,
(uint32_t) modeInfo->width,
(uint32_t) modeInfo->height,
refreshRate == 0 ? data->defaultRefreshRate : refreshRate
refreshRate == 0 ? data->defaultRefreshRate : refreshRate,
0,
0
);
}
@@ -158,7 +162,7 @@ static bool xrandrHandleMode(XrandrData* data, RRMode mode)
static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc)
{
//We do the check here, because we want the best fallback resolution if this call failed
//We do the check here, because we want the best fallback display if this call failed
if(data->screenResources == NULL)
return false;
@@ -167,11 +171,13 @@ static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc)
return false;
bool res = xrandrHandleMode(data, crtcInfo->mode);
res = res ? true : ffdsAppendResolution(
res = res ? true : ffdsAppendDisplay(
data->result,
(uint32_t) crtcInfo->width,
(uint32_t) crtcInfo->height,
data->defaultRefreshRate
data->defaultRefreshRate,
0,
0
);
data->ffXRRFreeCrtcInfo(crtcInfo);
@@ -201,11 +207,13 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo)
foundOutput = true;
}
return foundOutput ? true : ffdsAppendResolution(
return foundOutput ? true : ffdsAppendDisplay(
data->result,
(uint32_t) monitorInfo->width,
(uint32_t) monitorInfo->height,
data->defaultRefreshRate
data->defaultRefreshRate,
0,
0
);
}
@@ -253,11 +261,13 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
return;
//Fallback to screen
ffdsAppendResolution(
ffdsAppendDisplay(
data->result,
(uint32_t) WidthOfScreen(screen),
(uint32_t) HeightOfScreen(screen),
data->defaultRefreshRate
data->defaultRefreshRate,
0,
0
);
}
+9
View File
@@ -8,12 +8,21 @@
#define FF_GPU_TEMP_UNSET (0/0.0)
#define FF_GPU_CORE_COUNT_UNSET -1
#define FF_GPU_VENDOR_NAME_APPLE "Apple"
#define FF_GPU_VENDOR_NAME_AMD "AMD"
#define FF_GPU_VENDOR_NAME_INTEL "Intel"
#define FF_GPU_VENDOR_NAME_NVIDIA "NVIDIA"
typedef enum FFGpuType
{
FF_GPU_TYPE_INTEGRATED,
FF_GPU_TYPE_DISCRETE,
FF_GPU_TYPE_UNKNOWN
} FFGpuType;
typedef struct FFGPUResult
{
FFGpuType type;
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
+28 -1
View File
@@ -5,6 +5,7 @@
#include "util/apple/cf_helpers.h"
#include <IOKit/graphics/IOGraphicsLib.h>
#include <wchar.h>
static double detectGpuTemp(const FFstrbuf* gpuName)
{
@@ -59,7 +60,33 @@ const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance)
FFGPUResult* gpu = ffListAdd(gpus);
ffStrbufInitA(&gpu->vendor, 0);
gpu->type = FF_GPU_TYPE_UNKNOWN;
ffStrbufInit(&gpu->vendor);
int vendorId;
if(!ffCfDictGetInt(properties, CFSTR("vendor-id"), &vendorId))
{
if(vendorId == 0x106b)
{
ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
else if(wmemchr((const wchar_t[]) {0x1002, 0x1022}, (wchar_t)vendorId, 2))
{
ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
gpu->type = FF_GPU_TYPE_DISCRETE; // Apple never used AMD CPUs
}
else if(wmemchr((const wchar_t[]) {0x03e7, 0x8086, 0x8087}, (wchar_t)vendorId, 3))
{
ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
else if(wmemchr((const wchar_t[]) {0x0955, 0x10de, 0x12d2}, (wchar_t)vendorId, 3))
{
ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
gpu->type = FF_GPU_TYPE_DISCRETE;
}
}
ffStrbufInit(&gpu->driver);
ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver);
+46 -14
View File
@@ -58,10 +58,10 @@ static void pciDetectVendorName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
ffStrbufSetS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
}
static void drmDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
static void drmDetectDeviceName(const FFinstance* instance, FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
{
u8 revId;
bool revIdSet = false;;
bool revIdSet = false;
#if PCI_LIB_VERSION >= 0x030800
revIdSet = pci->ffpci_fill_info(device, PCI_FILL_CLASS_EXT) & PCI_FILL_CLASS_EXT;
@@ -82,7 +82,7 @@ static void drmDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
ffStrbufInit(&query);
ffStrbufAppendF(&query, "%X, %X,", device->device_id, revId);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/libdrm/amdgpu.ids", query.chars, &gpu->name);
ffParsePropFileData(instance, "libdrm/amdgpu.ids", query.chars, &gpu->name);
ffStrbufDestroy(&query);
@@ -94,11 +94,11 @@ static void drmDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
ffStrbufRemoveStringsA(&gpu->name, sizeof(removeStrings) / sizeof(removeStrings[0]), removeStrings);
}
static void pciDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
static void pciDetectDeviceName(const FFinstance* instance, FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
{
if(ffStrbufCompS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD) == 0)
{
drmDetectDeviceName(gpu, pci, device);
drmDetectDeviceName(instance, gpu, pci, device);
if(gpu->name.length > 0)
return;
}
@@ -146,20 +146,16 @@ static void pciDetectDriverName(FFGPUResult* gpu, PCIData* pci, struct pci_dev*
ffStrbufDestroy(&path);
}
static void pciDetectTemperatur(const FFinstance* instance, FFGPUResult* gpu, struct pci_dev* device)
static void pciDetectTemperatur(FFGPUResult* gpu, struct pci_dev* device)
{
const FFTempsResult* tempsResult = ffDetectTemps(instance);
const FFTempsResult* tempsResult = ffDetectTemps();
for(uint32_t i = 0; i < tempsResult->values.length; i++)
{
FFTempValue* tempValue = ffListGet(&tempsResult->values, i);
uint32_t tempClass;
if(sscanf(tempValue->deviceClass.chars, "%x", &tempClass) != 1)
continue;
//The kernel exposes the device class multiplied by 256 for some reason
if(tempClass == device->device_class * 256)
if(tempValue->deviceClass == device->device_class * 256)
{
gpu->temperature = tempValue->value;
return;
@@ -167,6 +163,38 @@ static void pciDetectTemperatur(const FFinstance* instance, FFGPUResult* gpu, st
}
}
static void detectType(FFGPUResult* gpu, const PCIData* pci, struct pci_dev* device)
{
//There is no straightforward way to detect the type of a GPU.
//The approach taken here is to look at the memory sizes of the device.
//Since integrated GPUs usually use the system ram, they don't have expansive ROMs
//and their memory sizes are usually smaller than 1GB.
if(!(pci->ffpci_fill_info(device, PCI_FILL_SIZES) & PCI_FILL_SIZES))
{
gpu->type = FF_GPU_TYPE_UNKNOWN;
return;
}
if(device->rom_size > 0)
{
gpu->type = FF_GPU_TYPE_DISCRETE;
return;
}
uint32_t numSizes = sizeof(device->size) / sizeof(device->size[0]);
for(uint32_t i = 0; i < numSizes; i++)
{
if(device->size[i] >= 1024 * 1024 * 1024) //1GB
{
gpu->type = FF_GPU_TYPE_DISCRETE;
return;
}
}
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
static void pciHandleDevice(const FFinstance* instance, FFlist* results, PCIData* pci, struct pci_dev* device)
{
pci->ffpci_fill_info(device, PCI_FILL_CLASS);
@@ -175,7 +203,9 @@ static void pciHandleDevice(const FFinstance* instance, FFlist* results, PCIData
pci->ffpci_lookup_name(pci->access, class, sizeof(class) - 1, PCI_LOOKUP_CLASS, device->device_class);
if(
//https://pci-ids.ucw.cz/read/PD/03
strcasecmp("VGA compatible controller", class) != 0 &&
strcasecmp("XGA compatible controller", class) != 0 &&
strcasecmp("3D controller", class) != 0 &&
strcasecmp("Display controller", class) != 0
) return;
@@ -188,16 +218,18 @@ static void pciHandleDevice(const FFinstance* instance, FFlist* results, PCIData
pciDetectVendorName(gpu, pci, device);
ffStrbufInit(&gpu->name);
pciDetectDeviceName(gpu, pci, device);
pciDetectDeviceName(instance, gpu, pci, device);
ffStrbufInit(&gpu->driver);
pciDetectDriverName(gpu, pci, device);
detectType(gpu, pci, device);
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
if(instance->config.gpuTemp)
pciDetectTemperatur(instance, gpu, device);
pciDetectTemperatur(gpu, device);
}
static const char* pciDetectGPUs(const FFinstance* instance, FFlist* gpus)
+4
View File
@@ -40,6 +40,8 @@ static const char* detectWithDxgi(FFlist* gpus)
ffStrbufInit(&gpu->driver);
gpu->type = desc.DedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
adapter->Release();
gpu->temperature = FF_GPU_TEMP_UNSET;
@@ -65,6 +67,8 @@ static const char* detectWithWmi(FFlist* gpus)
{
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
gpu->type = FF_GPU_TYPE_UNKNOWN;
ffStrbufInit(&gpu->vendor);
record.getString(L"AdapterCompatibility", &gpu->vendor);
if(ffStrbufStartsWithS(&gpu->vendor, "Intel "))
+8 -5
View File
@@ -80,8 +80,11 @@ static void detectGTKFromSettings(const FFinstance* instance, FFGTKResult* resul
cursorTheme = ffSettingsGet(instance, "/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGet(instance, "/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
}
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Gnome") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Unity") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Budgie") == 0)
{
else if(
ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Gnome") == 0 ||
ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Unity") == 0 ||
ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Budgie") == 0
) {
themeName = ffSettingsGet(instance, "/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet(instance, "/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet(instance, "/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
@@ -145,7 +148,7 @@ static void detectGTKFromConfigDir(FFstrbuf* configDir, const char* version, FFG
static void detectGTK(const FFinstance* instance, const char* version, FFGTKResult* result)
{
//Mate, Cinnamon and Gnome use dconf to save theme config
//Mate, Cinnamon, Gnome, Unity, Budgie use dconf to save theme config
//On other DEs, this will do nothing
detectGTKFromSettings(instance, result);
if(allPropertiesSet(result))
@@ -155,9 +158,9 @@ static void detectGTK(const FFinstance* instance, const char* version, FFGTKResu
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
FF_LIST_FOR_EACH(FFstrbuf, configDir, instance->state.platform.configDirs)
{
ffStrbufSet(&baseDir, ffListGet(&instance->state.configDirs, i));
ffStrbufSet(&baseDir, configDir);
detectGTKFromConfigDir(&baseDir, version, result);
if(allPropertiesSet(result))
break;
-2
View File
@@ -17,8 +17,6 @@ typedef struct FFOSResult
FFstrbuf versionID;
FFstrbuf codename;
FFstrbuf buildID;
FFstrbuf systemName;
FFstrbuf architecture;
} FFOSResult;
const FFOSResult* ffDetectOS(const FFinstance* instance);
-4
View File
@@ -23,10 +23,6 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
ffStrbufInit(&os->buildID);
ffSettingsGetAndroidProperty("ro.build.id", &os->buildID);
ffStrbufInitS(&os->systemName, instance->state.utsname.sysname);
ffStrbufInitS(&os->architecture, instance->state.utsname.machine);
ffStrbufInit(&os->idLike);
ffStrbufInit(&os->variant);
ffStrbufInit(&os->variantID);
-4
View File
@@ -61,8 +61,6 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
ffStrbufInit(&os->id);
ffStrbufInit(&os->prettyName);
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->systemName);
ffStrbufInit(&os->architecture);
ffStrbufInitA(&os->codename, 0);
ffStrbufInitA(&os->idLike, 0);
@@ -82,8 +80,6 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
ffStrbufAppend(&os->prettyName, &os->name);
ffStrbufAppend(&os->versionID, &os->version);
ffSysctlGetString("kern.ostype", &os->systemName);
ffSysctlGetString("hw.machine", &os->architecture);
parseOSXSoftwareLicense(os);
}
-5
View File
@@ -138,11 +138,6 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->codename);
ffStrbufInit(&os->buildID);
ffStrbufInit(&os->systemName);
ffStrbufInit(&os->architecture);
ffStrbufSetS(&os->systemName, instance->state.utsname.sysname);
ffStrbufSetS(&os->architecture, instance->state.utsname.machine);
detectOS(os, instance);
+2 -5
View File
@@ -46,6 +46,8 @@ static const char* getOsNameByWinbrand(FFstrbuf* osName)
extern "C"
void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
{
FF_UNUSED(instance);
ffStrbufInit(&os->name);
ffStrbufInit(&os->prettyName);
ffStrbufInit(&os->id);
@@ -56,8 +58,6 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->codename);
ffStrbufInit(&os->buildID);
ffStrbufInit(&os->systemName);
ffStrbufInit(&os->architecture);
if(getOsNameByWinbrand(&os->variant) && getOsNameByWmi(&os->variant))
return;
@@ -106,7 +106,4 @@ void ffDetectOSImpl(FFOSResult* os, const FFinstance* instance)
}
ffStrbufAppendF(&os->id, "%*s %*s", os->prettyName.length, os->prettyName.chars, os->version.length, os->version.chars);
ffStrbufSetS(&os->architecture, instance->state.utsname.machine);
ffStrbufSetS(&os->systemName, instance->state.utsname.sysname);
}
+9 -8
View File
@@ -140,7 +140,7 @@ static uint32_t getNixPackagesImpl(char* path)
ffStrbufInitA(&command, 255);
ffStrbufAppendS(&command, "for x in $(nix-store --query --requisites ");
ffStrbufAppendS(&command, path);
ffStrbufAppendS(&command, "); do if [ -d $x ]; then echo $x ; fi ; done | cut -d- -f2- | egrep '([0-9]{1,}\\.)+[0-9]{1,}' | egrep -v '\\-doc$|\\-man$|\\-info$|\\-dev$|\\-bin$|^nixos-system-nixos-' | uniq");
ffStrbufAppendS(&command, "); do if [ -d $x ]; then echo $x ; fi ; done | cut -d- -f2- | egrep '([0-9]{1,}\\.)+[0-9]{1,}' | egrep -v '\\-doc$|\\-man$|\\-info$|\\-dev$|\\-bin$|^nixos-system-nixos-' | uniq | wc -l");
ffProcessAppendStdOut(&output, (char* const[]) {
"sh",
@@ -149,13 +149,12 @@ static uint32_t getNixPackagesImpl(char* path)
NULL
});
//Each package is a new line in the output. If at least one line is found, add 1 for the last line.
uint32_t result = ffStrbufCountC(&output, '\n');
if(result > 0)
result++;
int result = (int) strtol(output.chars, NULL, 10);
ffStrbufDestroy(&command);
ffStrbufDestroy(&output);
return result;
return (uint32_t) result;
}
static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname)
@@ -272,7 +271,7 @@ static void getPackageCounts(const FFinstance* instance, FFstrbuf* baseDir, FFPa
packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system");
packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", DT_DIR);
packageCounts->pkg += getSQLite3Int(instance, baseDir, "/var/db/pkg/local.sqlite", "SELECT count(id) FROM packages");
packageCounts->rpm += getSQLite3Int(instance, baseDir, "/var/lib/rpm/rmpdb.sqlite", "SELECT count(blob) FROM Packages");
packageCounts->rpm += getSQLite3Int(instance, baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(blob) FROM Packages");
packageCounts->snap += getSnap(baseDir);
packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
}
@@ -309,6 +308,8 @@ static void getPackageCountsBedrock(const FFinstance* instance, FFstrbuf* baseDi
{
if(entry->d_type != DT_DIR)
continue;
if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
ffStrbufAppendS(baseDir, entry->d_name);
getPackageCounts(instance, baseDir, packageCounts);
@@ -338,7 +339,7 @@ void ffDetectPackagesImpl(const FFinstance* instance, FFPackagesResult* result)
result->rpm = getRpmFromLibrpm(instance);
#endif
ffStrbufSetS(&baseDir, instance->state.passwd->pw_dir);
ffStrbufSet(&baseDir, &instance->state.platform.homeDir);
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
ffStrbufDestroy(&baseDir);
+19 -7
View File
@@ -17,10 +17,10 @@ static uint32_t getNumElements(const char* searchPath /* including `\*` suffix *
counter++;
} while (FindNextFileA(hFind, &wfd));
FindClose(hFind);
}
if(type == FILE_ATTRIBUTE_DIRECTORY && counter >= 2)
counter -= 2; // accounting for . and ..
if(type == FILE_ATTRIBUTE_DIRECTORY && counter >= 2)
counter -= 2; // accounting for . and ..
}
return counter;
}
@@ -28,17 +28,15 @@ static uint32_t getNumElements(const char* searchPath /* including `\*` suffix *
static void detectScoop(const FFinstance* instance, FFPackagesResult* result)
{
char scoopPath[MAX_PATH + 3];
strcpy(scoopPath, instance->state.passwd->pw_dir);
strcpy(scoopPath, instance->state.platform.homeDir.chars);
strncat(scoopPath, "/scoop/apps/*", sizeof(scoopPath) - 1 - strlen(scoopPath));
result->scoop = getNumElements(scoopPath, FILE_ATTRIBUTE_DIRECTORY);
if(result->scoop > 0)
result->scoop--; // scoop
}
static void detectChoco(const FFinstance* instance, FFPackagesResult* result)
static void detectChoco(FF_MAYBE_UNUSED const FFinstance* instance, FFPackagesResult* result)
{
FF_UNUSED(instance);
const char* chocoInstall = getenv("ChocolateyInstall");
if(!chocoInstall || chocoInstall[0] == '\0')
return;
@@ -51,8 +49,22 @@ static void detectChoco(const FFinstance* instance, FFPackagesResult* result)
result->choco--; // choco
}
static void detectPacman(FF_MAYBE_UNUSED const FFinstance* instance, FFPackagesResult* result)
{
const char* msystemPrefix = getenv("MSYSTEM_PREFIX");
if(!msystemPrefix)
return;
// MSYS2
char pacmanPath[MAX_PATH + 3];
strcpy(pacmanPath, msystemPrefix);
strncat(pacmanPath, "/../var/lib/pacman/local/*", sizeof(pacmanPath) - 1 - strlen(pacmanPath));
result->pacman = getNumElements(pacmanPath, FILE_ATTRIBUTE_DIRECTORY);
}
void ffDetectPackagesImpl(const FFinstance* instance, FFPackagesResult* result)
{
detectScoop(instance, result);
detectChoco(instance, result);
detectPacman(instance, result);
}
+2 -2
View File
@@ -88,9 +88,9 @@ static void detectPlasma(const FFinstance* instance, FFQtResult* result)
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
FF_LIST_FOR_EACH(FFstrbuf, configDir, instance->state.platform.configDirs)
{
ffStrbufSet(&baseDir, ffListGet(&instance->state.configDirs, i));
ffStrbufSet(&baseDir, configDir);
ffStrbufAppendS(&baseDir, "kdeglobals");
if(detectPlasmaFromFile(baseDir.chars, result))
+17 -18
View File
@@ -8,18 +8,19 @@
static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
{
//https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
uint32_t dirLength = dir->length;
FFstrbuf valueBuffer;
FF_STRBUF_AUTO_DESTROY valueBuffer;
ffStrbufInit(&valueBuffer);
ffStrbufAppendS(dir, "temp1_input");
ffReadFileBuffer(dir->chars, &valueBuffer);
if(!ffReadFileBuffer(dir->chars, &valueBuffer))
return false;
ffStrbufSubstrBefore(dir, dirLength);
value->value = ffStrbufToDouble(&valueBuffer);
ffStrbufDestroy(&valueBuffer);
value->value = ffStrbufToDouble(&valueBuffer) / 1000; // valueBuffer is millidegree Celsius
if(value->value != value->value)
return false;
@@ -29,13 +30,19 @@ static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufAppendS(dir, "device/class");
ffReadFileBuffer(dir->chars, &value->deviceClass);
ffStrbufSubstrBefore(dir, dirLength);
if(!ffReadFileBuffer(dir->chars, &valueBuffer))
{
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufAppendS(dir, "device/device/class");
ffReadFileBuffer(dir->chars, &valueBuffer);
}
if(valueBuffer.length)
value->deviceClass = (uint32_t) strtoul(valueBuffer.chars, NULL, 16);
return value->name.length > 0 || value->deviceClass.length > 0;
return value->name.length > 0 || value->deviceClass > 0;
}
const FFTempsResult* ffDetectTemps(const FFinstance* instance)
const FFTempsResult* ffDetectTemps()
{
static FFTempsResult result;
static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER;
@@ -49,13 +56,6 @@ const FFTempsResult* ffDetectTemps(const FFinstance* instance)
}
init = true;
if(!instance->config.allowSlowOperations)
{
ffListInitA(&result.values, sizeof(FFTempValue), 0);
ffThreadMutexUnlock(&mutex);
return &result;
}
ffListInitA(&result.values, sizeof(FFTempValue), 16);
FFstrbuf baseDir;
@@ -83,11 +83,10 @@ const FFTempsResult* ffDetectTemps(const FFinstance* instance)
FFTempValue* temp = ffListAdd(&result.values);
ffStrbufInit(&temp->name);
ffStrbufInit(&temp->deviceClass);
temp->deviceClass = 0;
if(!parseHwmonDir(&baseDir, temp))
{
ffStrbufDestroy(&temp->name);
ffStrbufDestroy(&temp->deviceClass);
--result.values.length;
}
+2 -2
View File
@@ -8,7 +8,7 @@
typedef struct FFTempValue
{
FFstrbuf name;
FFstrbuf deviceClass;
uint32_t deviceClass;
double value;
} FFTempValue;
@@ -17,6 +17,6 @@ typedef struct FFTempsResult
FFlist values; //List of FFTempValue
} FFTempsResult;
const FFTempsResult* ffDetectTemps(const FFinstance* instance);
const FFTempsResult* ffDetectTemps();
#endif
+39 -6
View File
@@ -37,7 +37,7 @@ static void detectAlacritty(const FFinstance* instance, FFTerminalFontResult* te
ffStrbufDestroy(&fontSize);
}
static void detectTTY(FFTerminalFontResult* terminalFont)
FF_MAYBE_UNUSED static void detectTTY(FFTerminalFontResult* terminalFont)
{
FFstrbuf fontName;
ffStrbufInit(&fontName);
@@ -291,7 +291,7 @@ static void detectFromWindowsTeriminal(const FFinstance* instance, const FFstrbu
#endif
#endif //defined(_WIN32) || defined(__linux__)
static bool detectKitty(const FFinstance* instance, FFTerminalFontResult* result)
FF_MAYBE_UNUSED static bool detectKitty(const FFinstance* instance, FFTerminalFontResult* result)
{
FFstrbuf fontName;
ffStrbufInit(&fontName);
@@ -320,21 +320,54 @@ static bool detectKitty(const FFinstance* instance, FFTerminalFontResult* result
return true;
}
static bool detectWezterm(FF_MAYBE_UNUSED const FFinstance* instance, FFTerminalFontResult* result)
{
FF_STRBUF_AUTO_DESTROY fontName;
ffStrbufInit(&fontName);
ffStrbufSetS(&result->error, ffProcessAppendStdOut(&fontName, (char* const[]){
"wezterm",
"ls-fonts",
"--text",
"a",
NULL
}));
if(result->error.length)
return false;
//LeftToRight
// 0 a \u{61} x_adv=7 cells=1 glyph=a,180 wezterm.font("JetBrains Mono", {weight="Regular", stretch="Normal", style="Normal"})
// <built-in>, BuiltIn
ffStrbufSubstrAfterFirstC(&fontName, '"');
ffStrbufSubstrBeforeFirstC(&fontName, '"');
if(!fontName.length)
return false;
ffFontInitCopy(&result->font, fontName.chars);
return true;
}
void ffDetectTerminalFontPlatform(const FFinstance* instance, const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont);
static bool detectTerminalFontCommon(const FFinstance* instance, const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
{
if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "alacritty") == 0)
if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "alacritty"))
detectAlacritty(instance, terminalFont);
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0)
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "wezterm-gui"))
detectWezterm(instance, terminalFont);
#ifndef _WIN32
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "kitty"))
detectKitty(instance, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalExe, "/dev/tty"))
detectTTY(terminalFont);
#endif
#if defined(_WIN32) || defined(__linux__)
//Used by both Linux (WSL) and Windows
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "Windows Terminal") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "WindowsTerminal.exe") == 0)
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "Windows Terminal") ||
ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "WindowsTerminal.exe"))
detectFromWindowsTeriminal(instance, &terminalShell->terminalExe, terminalFont);
#endif
@@ -17,7 +17,7 @@ static void detectIterm2(const FFinstance* instance, FFTerminalFontResult* termi
}
NSError* error;
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/com.googlecode.iterm2.plist", instance->state.passwd->pw_dir];
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/com.googlecode.iterm2.plist", instance->state.platform.homeDir.chars];
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
error:&error];
if(error)
@@ -62,7 +62,7 @@ static void detectAppleTerminal(FFTerminalFontResult* terminalFont)
static void detectWarpTerminal(const FFinstance* instance, FFTerminalFontResult* terminalFont)
{
NSError* error;
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/dev.warp.Warp-Stable.plist", instance->state.passwd->pw_dir];
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/dev.warp.Warp-Stable.plist", instance->state.platform.homeDir.chars];
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
error:&error];
if(error)
@@ -88,15 +88,15 @@ static void detectKonsole(const FFinstance* instance, FFTerminalFontResult* term
}
FFstrbuf profilePath;
ffStrbufInitA(&profilePath, 64);
ffStrbufAppendS(&profilePath, ".local/share/konsole/");
ffStrbufInitA(&profilePath, 32);
ffStrbufAppendS(&profilePath, "konsole/");
ffStrbufAppend(&profilePath, &profile);
ffStrbufDestroy(&profile);
FFstrbuf fontName;
ffStrbufInit(&fontName);
ffParsePropFileHome(instance, profilePath.chars, "Font =", &fontName);
ffParsePropFileData(instance, profilePath.chars, "Font =", &fontName);
if(fontName.length == 0)
ffStrbufAppendF(&terminalFont->error, "Couldn't find \"Font=%%[^\\n]\" in \"%s\"", profilePath.chars);
@@ -149,7 +149,9 @@ static void detectDeepinTerminal(const FFinstance* instance, FFTerminalFontResul
ffStrbufInit(&fontSize);
FFstrbuf profile;
ffStrbufInitF(&profile, "%s/.config/deepin/deepin-terminal/config.conf", instance->state.passwd->pw_dir);
ffStrbufInit(&profile);
ffStrbufAppend(&profile, &instance->state.platform.homeDir);
ffStrbufAppendS(&profile, ".config/deepin/deepin-terminal/config.conf"); //TODO: Use config dirs
FILE* file = fopen(profile.chars, "r");
if(file)
@@ -14,10 +14,14 @@ static void detectMintty(const FFinstance* instance, FFTerminalFontResult* termi
FF_STRBUF_AUTO_DESTROY fontSize;
ffStrbufInit(&fontSize);
ffParsePropFileHomeValues(instance, ".minttyrc", 2, (FFpropquery[]) {
if(!ffParsePropFileConfigValues(instance, "mintty/config", 2, (FFpropquery[]) {
{"Font=", &fontName},
{"FontHeight=", &fontSize}
});
}))
ffParsePropFileConfigValues(instance, ".minttyrc", 2, (FFpropquery[]) {
{"Font=", &fontName},
{"FontHeight=", &fontSize}
});
if(fontName.length == 0)
ffStrbufAppendS(&fontName, "Lucida Console");
if(fontSize.length == 0)
+202 -70
View File
@@ -1,5 +1,7 @@
#include "fastfetch.h"
#include "common/io.h"
#include "common/processing.h"
#include "common/properties.h"
#ifdef _WIN32
@@ -36,122 +38,252 @@ static bool getFileVersion(const char* exePath, FFstrbuf* version)
#endif
static void getShellVersionBash(FFstrbuf* exe, FFstrbuf* version)
static bool getExeVersionRaw(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
return ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
}); // GNU bash, version 5.1.16(1)-release (x86_64-pc-msys)\nCopyright...
}) == NULL;
}
static bool getExeVersionGeneral(FFstrbuf* exe, FFstrbuf* version)
{
if(!getExeVersionRaw(exe, version))
return false;
ffStrbufSubstrAfterFirstC(version, ' ');
ffStrbufSubstrBeforeFirstC(version, ' ');
return true;
}
static bool getShellVersionBash(FFstrbuf* exe, FFstrbuf* version)
{
if(!getExeVersionRaw(exe, version))
return false;
// GNU bash, version 5.1.16(1)-release (x86_64-pc-msys)\nCopyright...
ffStrbufSubstrBeforeFirstC(version, '\n'); // GNU bash, version 5.1.16(1)-release (x86_64-pc-msys)
ffStrbufSubstrBeforeLastC(version, ' '); // GNU bash, version 5.1.16(1)-release
ffStrbufSubstrAfterLastC(version, ' '); // 5.1.16(1)-release
ffStrbufSubstrBeforeFirstC(version, '('); // 5.1.16
return true;
}
static void getShellVersionZsh(FFstrbuf* exe, FFstrbuf* version)
static bool getShellVersionFish(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
});
ffStrbufSubstrBeforeLastC(version, ' ');
ffStrbufSubstrAfterFirstC(version, ' ');
}
if(!getExeVersionRaw(exe, version))
return false;
static void getShellVersionFish(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
});
//fish, version 3.6.0
ffStrbufTrimRight(version, '\n');
ffStrbufSubstrAfterLastC(version, ' ');
return true;
}
static void getShellVersionTcsh(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
}); // tcsh 6.24.01 (Astron) 2022-05-12 (aarch64-apple-darwin) options wide,nls,dl,al,kan,sm,rh,color,filec
ffStrbufSubstrAfterFirstC(version, ' '); // 6.24.01 (Astron) 2022-05-12 (aarch64-apple-darwin) options wide,nls,dl,al,kan,sm,rh,color,filec
ffStrbufSubstrBeforeFirstC(version, ' '); // 6.24.01
}
static void getShellVersionPwsh(FFstrbuf* exe, FFstrbuf* version)
static bool getShellVersionPwsh(FFstrbuf* exe, FFstrbuf* version)
{
#ifdef _WIN32
if(getFileVersion(exe->chars, version))
return;
{
ffStrbufSubstrBeforeLastC(version, '.');
return true;
}
#endif
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
});
if(!getExeVersionRaw(exe, version))
return false;
ffStrbufTrimRight(version, '\n');
ffStrbufSubstrAfterLastC(version, ' ');
return true;
}
#ifdef _WIN32
static void getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version)
static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
if(ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"-NoLogo",
"-NoProfile",
"-Command",
"$PSVersionTable.PSVersion.ToString()",
NULL
});
})) return false;
ffStrbufTrimRight(version, '\n');
ffStrbufSubstrAfterLastC(version, ' ');
return true;
}
static void getShellVersionCmd(FFstrbuf* exe, FFstrbuf* version)
static bool getShellVersionCmd(FFstrbuf* exe, FFstrbuf* version)
{
getFileVersion(exe->chars, version);
return getFileVersion(exe->chars, version);
}
#endif
static void getShellVersionNu(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
});
}
bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
{
bool ok = true;
if(strcasecmp(exeName, "bash") == 0 || strcasecmp(exeName, "sh") == 0)
getShellVersionBash(exe, version);
else if(strcasecmp(exeName, "zsh") == 0)
getShellVersionZsh(exe, version);
else if(strcasecmp(exeName, "fish") == 0)
getShellVersionFish(exe, version);
else if(strcasecmp(exeName, "pwsh") == 0)
getShellVersionPwsh(exe, version);
else if(strcasecmp(exeName, "csh") == 0 || strcasecmp(exeName, "tcsh") == 0)
getShellVersionTcsh(exe, version);
else if(strcasecmp(exeName, "nu") == 0)
getShellVersionNu(exe, version);
return getShellVersionBash(exe, version);
if(strcasecmp(exeName, "zsh") == 0)
return getExeVersionGeneral(exe, version); //zsh 5.9 (arm-apple-darwin21.3.0)
if(strcasecmp(exeName, "fish") == 0)
return getShellVersionFish(exe, version);
if(strcasecmp(exeName, "pwsh") == 0)
return getShellVersionPwsh(exe, version);
if(strcasecmp(exeName, "csh") == 0 || strcasecmp(exeName, "tcsh") == 0)
return getExeVersionGeneral(exe, version); //tcsh 6.24.07 (Astron) 2022-12-21 (aarch64-apple-darwin) options wide,nls,dl,al,kan,sm,rh,color,filec
if(strcasecmp(exeName, "nu") == 0)
return getExeVersionRaw(exe, version); //0.73.0
#ifdef _WIN32
else if(strcasecmp(exeName, "powershell") == 0 || strcasecmp(exeName, "powershell_ise") == 0)
getShellVersionWinPowerShell(exe, version);
else if(strcasecmp(exeName, "cmd") == 0)
getShellVersionCmd(exe, version);
if(strcasecmp(exeName, "powershell") == 0 || strcasecmp(exeName, "powershell_ise") == 0)
return getShellVersionWinPowerShell(exe, version);
if(strcasecmp(exeName, "cmd") == 0)
return getShellVersionCmd(exe, version);
#endif
else
ok = false;
return ok;
return false;
}
FF_MAYBE_UNUSED static bool getTerminalVersionTermux(FFstrbuf* version)
{
ffStrbufSetS(version, getenv("TERMUX_VERSION"));
return version->length > 0;
}
FF_MAYBE_UNUSED static bool getTerminalVersionGnome(FFstrbuf* version)
{
if(ffProcessAppendStdOut(version, (char* const[]){
"gnome-terminal",
"--version",
NULL
})) return false;
//# GNOME Terminal 3.46.7 using VTE 0.70.2 +BIDI +GNUTLS +ICU +SYSTEMD
ffStrbufSubstrAfterFirstS(version, "Terminal ");
ffStrbufSubstrBeforeFirstC(version, ' ');
return true;
}
FF_MAYBE_UNUSED static bool getTerminalVersionKonsole(FFstrbuf* exe, FFstrbuf* version)
{
const char* konsoleVersion = getenv("KONSOLE_VERSION");
if(konsoleVersion)
{
//221201
long major = strtol(konsoleVersion, NULL, 10);
if (major >= 0)
{
long patch = major % 100;
major /= 100;
long minor = major % 100;
major /= 100;
ffStrbufSetF(version, "%ld.%ld.%ld", major, minor, patch);
return true;
}
}
return getExeVersionGeneral(exe, version);
}
#ifdef _WIN32
static bool getTerminalVersionWindowsTerminal(FFstrbuf* exe, FFstrbuf* version)
{
FF_STRBUF_AUTO_DESTROY buildInfoPath;
ffStrbufInitNS(&buildInfoPath, ffStrbufLastIndexC(exe, '\\') + 1, exe->chars);
ffStrbufAppendS(&buildInfoPath, "BuildInfo.xml");
if(ffParsePropFile(buildInfoPath.chars, "StoreVersion=\"", version))
{
ffStrbufTrimRight(version, '"');
return true;
}
return getFileVersion(exe->chars, version);
}
static bool getTerminalVersionConEmu(FFstrbuf* exe, FFstrbuf* version)
{
ffStrbufSetS(version, getenv("ConEmuBuild"));
if(version->length)
return true;
return getFileVersion(exe->chars, version);
}
#endif
bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
{
#ifdef __ANDROID__
if(ffStrbufEqualS(processName, "Termux"))
return getTerminalVersionTermux(version);
#endif
#if defined(__linux__) || defined(__FreeBSD__)
if(ffStrbufIgnCaseEqualS(processName, "gnome-terminal-"))
return getTerminalVersionGnome(version);
if(ffStrbufIgnCaseEqualS(processName, "konsole"))
return getTerminalVersionKonsole(exe, version);
if(ffStrbufIgnCaseEqualS(processName, "xfce4-terminal"))
return getExeVersionGeneral(exe, version);//xfce4-terminal 1.0.4 (Xfce 4.18)...
if(ffStrbufIgnCaseEqualS(processName, "deepin-terminal"))
return getExeVersionGeneral(exe, version);//deepin-terminal 5.4.36
#endif
#ifdef _WIN32
if(ffStrbufIgnCaseEqualS(processName, "WindowsTerminal.exe"))
return getTerminalVersionWindowsTerminal(exe, version);
if(ffStrbufStartsWithIgnCaseS(processName, "ConEmuC"))
return getTerminalVersionConEmu(exe, version);
#endif
#ifndef _WIN32
if(ffStrbufIgnCaseEqualS(processName, "kitty"))
return getExeVersionGeneral(exe, version); //kitty 0.21.2 created by Kovid Goyal
#endif
if(ffStrbufStartsWithIgnCaseS(processName, "alacritty"))
return getExeVersionGeneral(exe, version);
const char* termProgramVersion = getenv("TERM_PROGRAM_VERSION");
if(termProgramVersion)
{
const char* termProgram = getenv("TERM_PROGRAM");
if(termProgram)
{
if(ffStrbufStartsWithIgnCaseS(processName, termProgram) || // processName ends with `.exe` on Windows
(strcmp(termProgram, "vscode") == 0 && ffStrbufStartsWithIgnCaseS(processName, "code"))
) {
ffStrbufSetS(version, termProgramVersion);
return true;
}
}
}
#ifdef _WIN32
return getFileVersion(exe->chars, version);
#else
return false;
#endif
}
@@ -17,6 +17,7 @@ typedef struct FFTerminalShellResult
FFstrbuf terminalExe;
FFstrbuf terminalPrettyName;
const char* terminalExeName; //pointer to a char in terminalExe
FFstrbuf terminalVersion;
FFstrbuf userShellExe;
const char* userShellExeName; //pointer to a char in userShellExe
@@ -261,10 +261,7 @@ static void getTerminalFromEnv(FFTerminalShellResult* result)
static void getUserShellFromEnv(const FFinstance* instance, FFTerminalShellResult* result)
{
if(instance->state.passwd->pw_shell[0] != '\0')
ffStrbufAppendS(&result->userShellExe, instance->state.passwd->pw_shell);
else
ffStrbufAppendS(&result->userShellExe, getenv("SHELL"));
ffStrbufSet(&result->userShellExe, &instance->state.platform.userShell);
if(result->userShellExe.length == 0)
return;
@@ -310,6 +307,8 @@ static void getShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* versio
getShellVersionGeneric(exe, exeName, version);
}
bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version);
const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
{
FF_UNUSED(instance);
@@ -350,12 +349,17 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
getTerminalFromEnv(&result);
getUserShellFromEnv(instance, &result);
getShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion);
if(strcasecmp(result.shellExeName, result.userShellExeName) != 0)
getShellVersion(&result.userShellExe, result.userShellExeName, &result.userShellVersion);
else
ffStrbufSet(&result.userShellVersion, &result.shellVersion);
ffStrbufClear(&result.shellVersion);
if(instance->config.shellVersion)
{
getShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion);
if(strcasecmp(result.shellExeName, result.userShellExeName) != 0)
getShellVersion(&result.userShellExe, result.userShellExeName, &result.userShellVersion);
else
ffStrbufSet(&result.userShellVersion, &result.shellVersion);
}
if(ffStrbufEqualS(&result.shellProcessName, "pwsh"))
ffStrbufInitS(&result.shellPrettyName, "PowerShell");
@@ -373,11 +377,18 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
ffStrbufInitS(&result.terminalPrettyName, "Apple Terminal");
else if(ffStrbufEqualS(&result.terminalProcessName, "WarpTerminal"))
ffStrbufInitS(&result.terminalPrettyName, "Warp");
else if(ffStrbufEqualS(&result.terminalProcessName, "wezterm-gui"))
ffStrbufInitS(&result.terminalPrettyName, "WezTerm");
else if(strncmp(result.terminalExeName, result.terminalProcessName.chars, result.terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName
ffStrbufInitS(&result.terminalPrettyName, result.terminalExeName);
else
ffStrbufInitCopy(&result.terminalPrettyName, &result.terminalProcessName);
ffStrbufInit(&result.terminalVersion);
if(instance->config.terminalVersion)
fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion);
ffThreadMutexUnlock(&mutex);
return &result;
}
@@ -99,7 +99,7 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb
extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid)
static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* result, uint32_t pid)
{
uint32_t ppid;
@@ -128,11 +128,12 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid)
ffStrbufClear(&result->shellPrettyName);
ffStrbufClear(&result->shellExe);
result->shellExeName = nullptr;
return getShellInfo(result, ppid);
return getShellInfo(instance, result, ppid);
}
ffStrbufClear(&result->shellVersion);
fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion);
if(instance->config.shellVersion)
fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion);
if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh"))
ffStrbufSetS(&result->shellPrettyName, "PowerShell");
@@ -175,7 +176,7 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid)
return ppid;
}
static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid)
static uint32_t getTerminalInfo(const FFinstance* instance, FFTerminalShellResult* result, uint32_t pid)
{
uint32_t ppid;
@@ -201,7 +202,7 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid)
ffStrbufClear(&result->terminalPrettyName);
ffStrbufClear(&result->terminalExe);
result->terminalExeName = "";
return getTerminalInfo(result, ppid);
return getTerminalInfo(instance, result, ppid);
}
if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal"))
@@ -217,6 +218,8 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid)
ffStrbufSetS(&result->terminalPrettyName, "Windows Explorer");
else if(ffStrbufStartsWithIgnCaseS(&result->terminalPrettyName, "ConEmuC"))
ffStrbufSetS(&result->terminalPrettyName, "ConEmu");
else if(ffStrbufEqualS(&result->terminalPrettyName, "wezterm-gui"))
ffStrbufInitS(&result->terminalPrettyName, "WezTerm");
return ppid;
}
@@ -263,6 +266,8 @@ static void getTerminalFromEnv(FFTerminalShellResult* result)
}
}
extern "C" bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version);
const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
{
FF_UNUSED(instance);
@@ -297,11 +302,15 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
if(!getProcessInfo(0, &ppid, nullptr, nullptr, nullptr))
goto exit;
ppid = getShellInfo(&result, ppid);
getTerminalInfo(&result, ppid);
ppid = getShellInfo(instance, &result, ppid);
getTerminalInfo(instance, &result, ppid);
if(result.terminalProcessName.length == 0)
getTerminalFromEnv(&result);
ffStrbufInit(&result.terminalVersion);
if(instance->config.terminalVersion)
fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion);
exit:
ffThreadMutexUnlock(&mutex);
return &result;
-66
View File
@@ -1,66 +0,0 @@
#include "fastfetch.h"
#include "detection/title.h"
#include "common/thread.h"
#include <limits.h>
#include <unistd.h>
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 64
#endif
#ifdef __linux__
#include <netdb.h>
static void detectFQDN(FFTitleResult* title)
{
struct addrinfo hints = {0};
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
struct addrinfo* info = NULL;
if(getaddrinfo(title->hostname.chars, "80", &hints, &info) == 0)
{
struct addrinfo* current = info;
while(title->fqdn.length == 0 && current != NULL)
{
ffStrbufAppendS(&title->fqdn, current->ai_canonname);
current = current->ai_next;
}
freeaddrinfo(info);
}
}
#endif
const FFTitleResult* ffDetectTitle(const FFinstance* instance)
{
static FFTitleResult result;
static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER;
static bool init = false;
ffThreadMutexLock(&mutex);
if(init)
{
ffThreadMutexUnlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.userName);
ffStrbufAppendS(&result.userName, instance->state.passwd->pw_name);
ffStrbufInitA(&result.hostname, HOST_NAME_MAX);
ffStrbufAppendS(&result.hostname, instance->state.utsname.nodename);
ffStrbufInitA(&result.fqdn, HOST_NAME_MAX);
#ifdef __linux__
detectFQDN(&result);
#endif
if(result.fqdn.length == 0)
ffStrbufAppend(&result.fqdn, &result.hostname);
ffThreadMutexUnlock(&mutex);
return &result;
}
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#ifndef FF_INCLUDED_detection_title
#define FF_INCLUDED_detection_title
#include "fastfetch.h"
typedef struct FFTitleResult
{
FFstrbuf userName;
FFstrbuf hostname;
FFstrbuf fqdn; //Fully qualified domain name
} FFTitleResult;
const FFTitleResult* ffDetectTitle(const FFinstance* instance);
#endif
-1
View File
@@ -2,7 +2,6 @@
#include "util/windows/unicode.h"
#include <wtsapi32.h>
#include "wtsapi32_extend.h"
void ffDetectUsers(FFlist* users, FFstrbuf* error)
{
-45
View File
@@ -1,45 +0,0 @@
#pragma once
//at the time of writing, <wtsapi32.h> of MinGW doesn't have the definition of WTSEnumerateSessionsExW and friends
#if (_WIN32_WINNT >= 0x0601)
typedef struct _WTS_SESSION_INFO_1A {
DWORD ExecEnvId;
WTS_CONNECTSTATE_CLASS State;
DWORD SessionId;
LPSTR pSessionName;
LPSTR pHostName;
LPSTR pUserName;
LPSTR pDomainName;
LPSTR pFarmName;
} WTS_SESSION_INFO_1A, *PWTS_SESSION_INFO_1A;
typedef struct _WTS_SESSION_INFO_1W {
DWORD ExecEnvId;
WTS_CONNECTSTATE_CLASS State;
DWORD SessionId;
LPWSTR pSessionName;
LPWSTR pHostName;
LPWSTR pUserName;
LPWSTR pDomainName;
LPWSTR pFarmName;
} WTS_SESSION_INFO_1W, * PWTS_SESSION_INFO_1W;
#define WTS_SESSION_INFO_1 __MINGW_NAME_AW(WTS_SESSION_INFO_1)
#define PWTS_SESSION_INFO_1 __MINGW_NAME_AW(PWTS_SESSION_INFO_1)
WINBOOL WINAPI WTSEnumerateSessionsExA(HANDLE hServer,DWORD* pLevel,DWORD Filter,PWTS_SESSION_INFO_1A* ppSessionInfo,DWORD* pCount);
WINBOOL WINAPI WTSEnumerateSessionsExW(HANDLE hServer,DWORD* pLevel,DWORD Filter,PWTS_SESSION_INFO_1W* ppSessionInfo,DWORD* pCount);
#define WTSEnumerateSessionsEx __MINGW_NAME_AW(WTSEnumerateSessionsEx)
typedef enum _WTS_TYPE_CLASS {
WTSTypeProcessInfoLevel0,
WTSTypeProcessInfoLevel1,
WTSTypeSessionInfoLevel1
} WTS_TYPE_CLASS;
BOOL WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass,PVOID pMemory,ULONG NumberOfEntries);
BOOL WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass,PVOID pMemory,ULONG NumberOfEntries);
#define WTSFreeMemoryEx __MINGW_NAME_AW(WTSFreeMemoryEx)
#endif /*(_WIN32_WINNT >= 0x0601)*/
+5
View File
@@ -190,6 +190,11 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu
ffStrbufInit(&gpu->name);
ffStrbufAppendS(&gpu->name, physicalDeviceProperties.properties.deviceName);
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
gpu->type = FF_GPU_TYPE_INTEGRATED;
else
gpu->type = FF_GPU_TYPE_DISCRETE;
//No way to detect those using vulkan
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->driver);
+2 -9
View File
@@ -16,24 +16,17 @@ struct FFWifiConnection
FFstrbuf status;
FFstrbuf ssid;
FFstrbuf macAddress;
FFstrbuf phyType;
FFstrbuf protocol;
FFstrbuf security;
double signalQuality; // Percentage
double rxRate;
double txRate;
};
struct FFWifiSecurity
{
bool enabled;
bool oneXEnabled;
FFstrbuf algorithm;
};
typedef struct FFWifiResult
{
struct FFWifiInterface inf;
struct FFWifiConnection conn;
struct FFWifiSecurity security;
} FFWifiResult;
const char* ffDetectWifi(const FFinstance* instance, FFlist* result /*list of FFWifiItem*/);
+62
View File
@@ -0,0 +1,62 @@
#include "wifi.h"
#include "common/processing.h"
#include "common/properties.h"
const char* ffDetectWifi(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* result)
{
FF_STRBUF_AUTO_DESTROY buffer;
ffStrbufInit(&buffer);
if(ffProcessAppendStdOut(&buffer, (char* const[]){
FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api",
"WifiConnectionInfo"
}))
return "Starting `" FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api" " WifiConnectionInfo` failed";
FFWifiResult* item = (FFWifiResult*)ffListAdd(result);
ffStrbufInit(&item->inf.description);
ffStrbufInit(&item->inf.status);
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.macAddress);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = 0.0/0.0;
item->conn.rxRate = 0.0/0.0;
item->conn.txRate = 0.0/0.0;
if(!ffParsePropLines(buffer.chars, "\"supplicant_state\": ", &item->inf.status))
ffStrbufAppendS(&item->inf.status, "Unknown");
{
ffStrbufTrimRight(&item->inf.status, ',');
ffStrbufTrim(&item->inf.status, '"');
if(!ffStrbufEqualS(&item->inf.status, "COMPLETED"))
return NULL;
}
if(ffParsePropLines(buffer.chars, "\"rssi\": ", &item->inf.description))
{
double rssi = ffStrbufToDouble(&item->inf.description);
item->conn.signalQuality = rssi >= -50 ? 100 : rssi <= -100 ? 0 : (rssi + 100) * 2;
ffStrbufClear(&item->inf.description);
}
if(ffParsePropLines(buffer.chars, "\"network_id\": ", &item->inf.description))
ffStrbufTrimRight(&item->inf.description, ',');
if(ffParsePropLines(buffer.chars, "\"bssid\": ", &item->conn.macAddress))
{
ffStrbufTrimRight(&item->conn.macAddress, ',');
ffStrbufTrim(&item->conn.macAddress, '"');
}
if(ffParsePropLines(buffer.chars, "\"ssid\": ", &item->conn.ssid))
{
ffStrbufTrimRight(&item->conn.ssid, ',');
ffStrbufTrim(&item->conn.ssid, '"');
}
return NULL;
}
+29 -34
View File
@@ -10,9 +10,6 @@ const char* ffDetectWifi(const FFinstance* instance, FFlist* result)
if(!interfaces)
return "CWWiFiClient.sharedWiFiClient.interfaces is nil";
if(interfaces.count == 0)
return "No wifi interfaces found";
for(CWInterface* inf in interfaces)
{
FFWifiResult* item = (FFWifiResult*)ffListAdd(result);
@@ -21,13 +18,11 @@ const char* ffDetectWifi(const FFinstance* instance, FFlist* result)
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.macAddress);
ffStrbufInit(&item->conn.phyType);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = 0.0/0.0;
item->conn.rxRate = 0.0/0.0;
item->conn.txRate = 0.0/0.0;
item->security.enabled = false;
item->security.oneXEnabled = false;
ffStrbufInit(&item->security.algorithm);
ffStrbufAppendS(&item->inf.description, inf.interfaceName.UTF8String);
ffStrbufAppendS(&item->inf.status, inf.powerOn ? "Power On" : "Power Off");
@@ -43,88 +38,88 @@ const char* ffDetectWifi(const FFinstance* instance, FFlist* result)
switch(inf.activePHYMode)
{
case kCWPHYModeNone:
ffStrbufAppendS(&item->conn.phyType, "none");
ffStrbufAppendS(&item->conn.protocol, "none");
break;
case kCWPHYMode11a:
ffStrbufAppendS(&item->conn.phyType, "802.11a");
ffStrbufAppendS(&item->conn.protocol, "802.11a");
break;
case kCWPHYMode11b:
ffStrbufAppendS(&item->conn.phyType, "802.11b");
ffStrbufAppendS(&item->conn.protocol, "802.11b");
break;
case kCWPHYMode11g:
ffStrbufAppendS(&item->conn.phyType, "802.11g");
ffStrbufAppendS(&item->conn.protocol, "802.11g");
break;
case kCWPHYMode11n:
ffStrbufAppendS(&item->conn.phyType, "802.11n (Wi-Fi 4)");
ffStrbufAppendS(&item->conn.protocol, "802.11n (Wi-Fi 4)");
break;
case kCWPHYMode11ac:
ffStrbufAppendS(&item->conn.phyType, "802.11ac (Wi-Fi 5)");
ffStrbufAppendS(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
break;
case 6 /*kCWPHYMode11ax*/:
ffStrbufAppendS(&item->conn.phyType, "802.11ax (Wi-Fi 6)");
ffStrbufAppendS(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
break;
case 7 /*kCWPHYMode11be?*/:
ffStrbufAppendS(&item->conn.phyType, "802.11be (Wi-Fi 7)");
ffStrbufAppendS(&item->conn.protocol, "802.11be (Wi-Fi 7)");
break;
default:
ffStrbufAppendF(&item->conn.phyType, "Unknown (%ld)", inf.activePHYMode);
ffStrbufAppendF(&item->conn.protocol, "Unknown (%ld)", inf.activePHYMode);
break;
}
item->conn.signalQuality = inf.rssiValue >= -50 ? 100 : inf.rssiValue <= -100 ? 0 : (inf.rssiValue + 100) * 2;
item->conn.txRate = inf.transmitRate;
item->security.enabled = inf.security != kCWSecurityNone;
switch(inf.security)
{
case kCWSecurityNone:
ffStrbufAppendS(&item->security.algorithm, "None");
ffStrbufAppendS(&item->conn.security, "Insecure");
break;
case kCWSecurityWEP:
ffStrbufAppendS(&item->security.algorithm, "WEP");
ffStrbufAppendS(&item->conn.security, "WEP");
break;
case kCWSecurityWPAPersonal:
ffStrbufAppendS(&item->security.algorithm, "WPA Personal");
ffStrbufAppendS(&item->conn.security, "WPA Personal");
break;
case kCWSecurityWPAPersonalMixed:
ffStrbufAppendS(&item->security.algorithm, "WPA Persional Mixed");
ffStrbufAppendS(&item->conn.security, "WPA Persional Mixed");
break;
case kCWSecurityWPA2Personal:
ffStrbufAppendS(&item->security.algorithm, "WPA2 Personal");
ffStrbufAppendS(&item->conn.security, "WPA2 Personal");
break;
case kCWSecurityPersonal:
ffStrbufAppendS(&item->security.algorithm, "Personal");
ffStrbufAppendS(&item->conn.security, "Personal");
break;
case kCWSecurityDynamicWEP:
ffStrbufAppendS(&item->security.algorithm, "Dynamic WEP");
ffStrbufAppendS(&item->conn.security, "Dynamic WEP");
break;
case kCWSecurityWPAEnterprise:
ffStrbufAppendS(&item->security.algorithm, "WPA Enterprise");
ffStrbufAppendS(&item->conn.security, "WPA Enterprise");
break;
case kCWSecurityWPAEnterpriseMixed:
ffStrbufAppendS(&item->security.algorithm, "WPA Enterprise Mixed");
ffStrbufAppendS(&item->conn.security, "WPA Enterprise Mixed");
break;
case kCWSecurityWPA2Enterprise:
ffStrbufAppendS(&item->security.algorithm, "WPA2 Enterprise");
ffStrbufAppendS(&item->conn.security, "WPA2 Enterprise");
break;
case kCWSecurityEnterprise:
ffStrbufAppendS(&item->security.algorithm, "Enterprise");
ffStrbufAppendS(&item->conn.security, "Enterprise");
break;
case kCWSecurityWPA3Personal:
ffStrbufAppendS(&item->security.algorithm, "WPA3 Personal");
ffStrbufAppendS(&item->conn.security, "WPA3 Personal");
break;
case kCWSecurityWPA3Enterprise:
ffStrbufAppendS(&item->security.algorithm, "WPA3 Enterprise");
ffStrbufAppendS(&item->conn.security, "WPA3 Enterprise");
break;
case kCWSecurityWPA3Transition:
ffStrbufAppendS(&item->security.algorithm, "WPA3 Transition");
ffStrbufAppendS(&item->conn.security, "WPA3 Transition");
break;
case 14 /*kCWSecurityOWE*/:
ffStrbufAppendS(&item->security.algorithm, "OWE");
ffStrbufAppendS(&item->conn.security, "OWE");
break;
case 15 /*kCWSecurityOWETransition*/:
ffStrbufAppendS(&item->security.algorithm, "OWE Transition");
ffStrbufAppendS(&item->conn.security, "OWE Transition");
break;
default:
ffStrbufAppendF(&item->security.algorithm, "Unknown (%ld)", inf.security);
ffStrbufAppendF(&item->conn.security, "Unknown (%ld)", inf.security);
break;
}
}
+279 -20
View File
@@ -1,20 +1,214 @@
#include "wifi.h"
#include "common/io.h"
#include <linux/nl80211.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
static const char* detectInf(uint32_t ifIndex, FFWifiResult* wifi)
#ifdef FF_HAVE_LIBNM
#include "common/processing.h"
#include "common/properties.h"
#include "common/library.h"
#include <glib.h>
#define NM_NO_INCLUDE_EXTRA_HEADERS 1
#include <NetworkManager.h>
static const char* detectWifiWithLibnm(const FFinstance* instance, FFlist* result)
{
//TODO: play with netlink
FF_UNUSED(ifIndex, wifi);
return "Unimplemented";
FF_LIBRARY_LOAD(nm, &instance->config.libnm, "dlopen libnm failed", "libnm" FF_LIBRARY_EXTENSION, 0);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_client_new);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_client_get_devices);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_device_get_iface);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_device_get_state);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_device_wifi_get_type);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_device_wifi_get_active_access_point);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_ssid);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_utils_ssid_to_utf8);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_bssid);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_strength);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_max_bitrate);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_flags);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_wpa_flags);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, nm_access_point_get_rsn_flags);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, g_type_check_instance_is_a);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, g_bytes_get_size);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, g_bytes_get_data);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, g_free);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(nm, g_object_unref);
NMClient* client = ffnm_client_new(NULL, NULL);
if(!client)
{
dlclose(nm);
return "Could not create NMClient";
}
/* Get all devices managed by NetworkManager */
const GPtrArray* devices = ffnm_client_get_devices(client);
/* Go through the array and process Wi-Fi devices */
for (guint i = 0; i < devices->len; i++)
{
NMDevice *device = g_ptr_array_index(devices, i);
if (!({
GTypeInstance *__inst = (GTypeInstance*) device; GType __t = ffnm_device_wifi_get_type(); gboolean __r;
if (!__inst)
__r = FALSE;
else if (__inst->g_class && __inst->g_class->g_type == __t)
__r = TRUE;
else
__r = ffg_type_check_instance_is_a (__inst, __t);
__r;
}) //NM_IS_DEVICE_WIFI(device)
)
continue;
FFWifiResult* item = (FFWifiResult*) ffListAdd(result);
ffStrbufInit(&item->inf.description);
ffStrbufInit(&item->inf.status);
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.macAddress);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = 0.0/0.0;
item->conn.rxRate = 0.0/0.0;
item->conn.txRate = 0.0/0.0;
ffStrbufAppendS(&item->inf.description, ffnm_device_get_iface(device));
NMDeviceState state = ffnm_device_get_state(device);
switch(state)
{
case NM_DEVICE_STATE_UNKNOWN:
ffStrbufAppendS(&item->inf.status, "Unknown");
break;
case NM_DEVICE_STATE_UNMANAGED:
ffStrbufAppendS(&item->inf.status, "Unmanaged");
break;
case NM_DEVICE_STATE_UNAVAILABLE:
ffStrbufAppendS(&item->inf.status, "Unavailable");
break;
case NM_DEVICE_STATE_DISCONNECTED:
ffStrbufAppendS(&item->inf.status, "Disconnected");
break;
case NM_DEVICE_STATE_PREPARE:
ffStrbufAppendS(&item->inf.status, "Prepare");
break;
case NM_DEVICE_STATE_CONFIG:
ffStrbufAppendS(&item->inf.status, "Config");
break;
case NM_DEVICE_STATE_NEED_AUTH:
ffStrbufAppendS(&item->inf.status, "Need auth");
break;
case NM_DEVICE_STATE_IP_CONFIG:
ffStrbufAppendS(&item->inf.status, "IP config");
break;
case NM_DEVICE_STATE_IP_CHECK:
ffStrbufAppendS(&item->inf.status, "IP check");
break;
case NM_DEVICE_STATE_SECONDARIES:
ffStrbufAppendS(&item->inf.status, "Secondaries");
break;
case NM_DEVICE_STATE_ACTIVATED:
ffStrbufAppendS(&item->inf.status, "Activated");
break;
case NM_DEVICE_STATE_DEACTIVATING:
ffStrbufAppendS(&item->inf.status, "Deactivating");
break;
case NM_DEVICE_STATE_FAILED:
ffStrbufAppendS(&item->inf.status, "Failed");
break;
}
if(state != NM_DEVICE_STATE_ACTIVATED)
continue;
NMAccessPoint* ap = ffnm_device_wifi_get_active_access_point((NMDeviceWifi *) device);
if (!ap)
continue;
GBytes* activeSsid = ffnm_access_point_get_ssid(ap);
if (activeSsid)
{
char* ssid = ffnm_utils_ssid_to_utf8(ffg_bytes_get_data(activeSsid, NULL), ffg_bytes_get_size(activeSsid));
ffStrbufAppendS(&item->conn.ssid, ssid);
ffg_free(ssid);
}
ffStrbufAppendS(&item->conn.macAddress, ffnm_access_point_get_bssid(ap));
item->conn.signalQuality = ffnm_access_point_get_strength(ap);
item->conn.rxRate = ffnm_access_point_get_max_bitrate(ap);
if(instance->config.allowSlowOperations)
{
FF_STRBUF_AUTO_DESTROY output;
ffStrbufInit(&output);
if(!ffProcessAppendStdOut(&output, (char* const[]){
"iw",
"dev",
item->inf.description.chars,
"link",
NULL
}) && ffParsePropLines(output.chars, "tx bitrate: ", &item->conn.protocol))
{
if(ffStrbufContainS(&item->conn.protocol, " HE-MCS "))
ffStrbufSetS(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
else if(ffStrbufContainS(&item->conn.protocol, " VHT-MCS "))
ffStrbufSetS(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
else if(ffStrbufContainS(&item->conn.protocol, " MCS "))
ffStrbufSetS(&item->conn.protocol, "802.11n (Wi-Fi 4)");
else
ffStrbufSetS(&item->conn.protocol, "802.11a/b/g");
}
}
NM80211ApFlags flags = ffnm_access_point_get_flags(ap);
NM80211ApSecurityFlags wpaFlags = ffnm_access_point_get_wpa_flags(ap);
NM80211ApSecurityFlags rsnFlags = ffnm_access_point_get_rsn_flags(ap);
if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpaFlags == NM_802_11_AP_SEC_NONE)
&& (rsnFlags == NM_802_11_AP_SEC_NONE))
ffStrbufAppendS(&item->conn.security, "WEP ");
if (wpaFlags != NM_802_11_AP_SEC_NONE)
ffStrbufAppendS(&item->conn.security, "WPA ");
if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
|| (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
ffStrbufAppendS(&item->conn.security, "WPA2 ");
}
if (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
ffStrbufAppendS(&item->conn.security, "WPA3 ");
}
if ((rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE)
|| (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) {
ffStrbufAppendS(&item->conn.security, "OWE ");
}
if ((wpaFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
|| (rsnFlags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
ffStrbufAppendS(&item->conn.security, "802.1X ");
}
if (!item->conn.security.length)
ffStrbufAppendS(&item->conn.security, "Insecure");
else
ffStrbufTrimRight(&item->conn.security, ' ');
}
ffg_object_unref(client);
dlclose(nm);
return NULL;
}
const char* ffDetectWifi(const FFinstance* instance, FFlist* result)
{
FF_UNUSED(instance);
#endif
#include "common/io.h"
#include <net/if.h>
#include <linux/wireless.h>
#include <sys/ioctl.h>
#include <unistd.h>
static const char* detectWifiWithIoctls(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* result)
{
struct if_nameindex* infs = if_nameindex();
if(!infs)
return "if_nameindex() failed";
@@ -34,28 +228,93 @@ const char* ffDetectWifi(const FFinstance* instance, FFlist* result)
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.macAddress);
ffStrbufInit(&item->conn.phyType);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = 0.0/0.0;
item->conn.rxRate = 0.0/0.0;
item->conn.txRate = 0.0/0.0;
item->security.enabled = false;
item->security.oneXEnabled = false;
ffStrbufInit(&item->security.algorithm);
ffStrbufSetF(&path, "/sys/class/net/%s/operstate", i->if_name);
if(!ffAppendFileBuffer(path.chars, &item->inf.status) || !ffStrbufEqualS(&item->inf.status, "up"))
continue;
ffStrbufSetF(&path, "/sys/class/net/%s/address", i->if_name);
ffAppendFileBuffer(path.chars, &item->conn.macAddress);
int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if(sock < 0)
continue;
detectInf(i->if_index, item);
struct iwreq iwr;
strncpy(iwr.ifr_name, i->if_name, IFNAMSIZ);
ffStrbufEnsureFree(&item->conn.ssid, IW_ESSID_MAX_SIZE);
iwr.u.essid.pointer = (caddr_t) item->conn.ssid.chars;
iwr.u.essid.length = IW_ESSID_MAX_SIZE + 1;
iwr.u.essid.flags = 0;
if(ioctl(sock, SIOCGIWESSID, &iwr) >= 0)
ffStrbufRecalculateLength(&item->conn.ssid);
if(ioctl(sock, SIOCGIWNAME, &iwr) >= 0)
{
if(strncasecmp(iwr.u.name, "IEEE ", 5) == 0)
ffStrbufSetS(&item->conn.protocol, iwr.u.name + 5);
else
ffStrbufSetS(&item->conn.protocol, iwr.u.name);
}
if(ioctl(sock, SIOCGIWAP, &iwr) >= 0)
{
for(int i = 0; i < 6; ++i)
ffStrbufAppendF(&item->conn.macAddress, "%.2X-", (uint8_t) iwr.u.ap_addr.sa_data[i]);
ffStrbufTrimRight(&item->conn.macAddress, '-');
}
//FIXME: doesn't work
if(ioctl(sock, SIOCGIWSPY, &iwr) >= 0)
item->conn.signalQuality = iwr.u.qual.level;
//FIXME: doesn't work
struct iw_encode_ext iwe;
iwr.u.data.pointer = &iwe;
iwr.u.data.length = sizeof(iwe);
iwr.u.data.flags = 0;
if(ioctl(sock, SIOCGIWENCODEEXT, &iwr) >= 0)
{
struct iw_encode_ext* iwe = iwr.u.data.pointer;
switch(iwe->alg)
{
case IW_ENCODE_ALG_WEP:
ffStrbufAppendS(&item->conn.security, "WEP");
break;
case IW_ENCODE_ALG_TKIP:
ffStrbufAppendS(&item->conn.security, "TKIP");
break;
case IW_ENCODE_ALG_CCMP:
ffStrbufAppendS(&item->conn.security, "CCMP");
break;
case IW_ENCODE_ALG_PMK:
ffStrbufAppendS(&item->conn.security, "PMK");
break;
case IW_ENCODE_ALG_AES_CMAC:
ffStrbufAppendS(&item->conn.security, "CMAC");
break;
default:
ffStrbufAppendF(&item->conn.security, "Unknown (%d)", (int) iwe->alg);
break;
}
}
close(sock);
}
if_freenameindex(infs);
ffStrbufDestroy(&path);
if(result->length == 0)
return "No wifi interfaces found";
return NULL;
}
const char* ffDetectWifi(const FFinstance* instance, FFlist* result)
{
#ifdef FF_HAVE_LIBNM
if(!detectWifiWithLibnm(instance, result))
return NULL;
#endif
return detectWifiWithIoctls(instance, result);
}
+60 -108
View File
@@ -40,7 +40,7 @@ static void convertIfStateToString(WLAN_INTERFACE_STATE state, FFstrbuf* result)
}
}
const char* ffDetectWifi(FF_UNUSED_PARAM const FFinstance* instance, FFlist* result)
const char* ffDetectWifi(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* result)
{
FF_LIBRARY_LOAD(wlanapi, NULL, "dlopen wlanapi"FF_LIBRARY_EXTENSION" failed", "wlanapi"FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wlanapi, WlanOpenHandle)
@@ -66,12 +66,6 @@ const char* ffDetectWifi(FF_UNUSED_PARAM const FFinstance* instance, FFlist* res
goto exit;
}
if(ifList->dwNumberOfItems == 0)
{
error = "No wifi interfaces found";
goto exit;
}
for(uint32_t index = 0; index < ifList->dwNumberOfItems; ++index)
{
WLAN_INTERFACE_INFO* ifInfo = (WLAN_INTERFACE_INFO*)&ifList->InterfaceInfo[index];
@@ -82,13 +76,11 @@ const char* ffDetectWifi(FF_UNUSED_PARAM const FFinstance* instance, FFlist* res
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.macAddress);
ffStrbufInit(&item->conn.phyType);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = 0.0/0.0;
item->conn.rxRate = 0.0/0.0;
item->conn.txRate = 0.0/0.0;
item->security.enabled = false;
item->security.oneXEnabled = false;
ffStrbufInit(&item->security.algorithm);
ffStrbufSetWS(&item->inf.description, ifInfo->strInterfaceDescription);
convertIfStateToString(ifInfo->isState, &item->inf.status);
@@ -121,40 +113,40 @@ const char* ffDetectWifi(FF_UNUSED_PARAM const FFinstance* instance, FFlist* res
switch (connInfo->wlanAssociationAttributes.dot11PhyType)
{
case dot11_phy_type_fhss:
ffStrbufAppendS(&item->conn.phyType, "802.11 (FHSS)");
ffStrbufAppendS(&item->conn.protocol, "802.11 (FHSS)");
break;
case dot11_phy_type_dsss:
ffStrbufAppendS(&item->conn.phyType, "802.11 (DSSS)");
ffStrbufAppendS(&item->conn.protocol, "802.11 (DSSS)");
break;
case dot11_phy_type_irbaseband:
ffStrbufAppendS(&item->conn.phyType, "802.11 (IR)");
ffStrbufAppendS(&item->conn.protocol, "802.11 (IR)");
break;
case dot11_phy_type_ofdm:
ffStrbufAppendS(&item->conn.phyType, "802.11a");
ffStrbufAppendS(&item->conn.protocol, "802.11a");
break;
case dot11_phy_type_hrdsss:
ffStrbufAppendS(&item->conn.phyType, "802.11b");
ffStrbufAppendS(&item->conn.protocol, "802.11b");
break;
case dot11_phy_type_erp:
ffStrbufAppendS(&item->conn.phyType, "802.11g");
ffStrbufAppendS(&item->conn.protocol, "802.11g");
break;
case dot11_phy_type_ht:
ffStrbufAppendS(&item->conn.phyType, "802.11n (Wi-Fi 4)");
ffStrbufAppendS(&item->conn.protocol, "802.11n (Wi-Fi 4)");
break;
case 8 /*dot11_phy_type_vht*/:
ffStrbufAppendS(&item->conn.phyType, "802.11ac (Wi-Fi 5)");
ffStrbufAppendS(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
break;
case 9 /*dot11_phy_type_dmg*/:
ffStrbufAppendS(&item->conn.phyType, "802.11ad (WiGig)");
ffStrbufAppendS(&item->conn.protocol, "802.11ad (WiGig)");
break;
case 10 /*dot11_phy_type_he*/:
ffStrbufAppendS(&item->conn.phyType, "802.11ax (Wi-Fi 6)");
ffStrbufAppendS(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
break;
case 11 /*dot11_phy_type_eht*/:
ffStrbufAppendS(&item->conn.phyType, "802.11be (Wi-Fi 7)");
ffStrbufAppendS(&item->conn.protocol, "802.11be (Wi-Fi 7)");
break;
default:
ffStrbufAppendF(&item->conn.phyType, "Unknown (%u)", (unsigned)connInfo->wlanAssociationAttributes.dot11PhyType);
ffStrbufAppendF(&item->conn.protocol, "Unknown (%u)", (unsigned)connInfo->wlanAssociationAttributes.dot11PhyType);
break;
}
@@ -162,93 +154,53 @@ const char* ffDetectWifi(FF_UNUSED_PARAM const FFinstance* instance, FFlist* res
item->conn.rxRate = connInfo->wlanAssociationAttributes.ulRxRate;
item->conn.txRate = connInfo->wlanAssociationAttributes.ulTxRate;
item->security.enabled = connInfo->wlanSecurityAttributes.bSecurityEnabled;
item->security.oneXEnabled = connInfo->wlanSecurityAttributes.bOneXEnabled;
switch (connInfo->wlanSecurityAttributes.dot11AuthAlgorithm)
if(connInfo->wlanSecurityAttributes.bSecurityEnabled)
{
case DOT11_AUTH_ALGO_80211_OPEN:
ffStrbufAppendS(&item->security.algorithm, "802.11 Open");
break;
case DOT11_AUTH_ALGO_80211_SHARED_KEY:
ffStrbufAppendS(&item->security.algorithm, "802.11 Shared");
break;
case DOT11_AUTH_ALGO_WPA:
ffStrbufAppendS(&item->security.algorithm, "WPA");
break;
case DOT11_AUTH_ALGO_WPA_PSK:
ffStrbufAppendS(&item->security.algorithm, "WPA-PSK");
break;
case DOT11_AUTH_ALGO_WPA_NONE:
ffStrbufAppendS(&item->security.algorithm, "WPA-None");
break;
case DOT11_AUTH_ALGO_RSNA:
ffStrbufAppendS(&item->security.algorithm, "RSNA");
break;
case DOT11_AUTH_ALGO_RSNA_PSK:
ffStrbufAppendS(&item->security.algorithm, "RSNA with PSK");
break;
case 8 /* DOT11_AUTH_ALGO_WPA3 */:
ffStrbufAppendS(&item->security.algorithm, "WPA3");
break;
case 9 /* DOT11_AUTH_ALGO_WPA3_SAE */:
ffStrbufAppendS(&item->security.algorithm, "WPA3-SAE");
break;
case 10 /* DOT11_AUTH_ALGO_OWE */:
ffStrbufAppendS(&item->security.algorithm, "OWE");
break;
case 11 /* DOT11_AUTH_ALGO_WPA3_ENT */:
ffStrbufAppendS(&item->security.algorithm, "OWE-ENT");
break;
default:
ffStrbufAppendF(&item->security.algorithm, "Unknown (%u)", (unsigned)connInfo->wlanSecurityAttributes.dot11AuthAlgorithm);
break;
}
ffStrbufAppendS(&item->security.algorithm, " - ");
switch (connInfo->wlanSecurityAttributes.dot11CipherAlgorithm)
{
case DOT11_CIPHER_ALGO_NONE:
ffStrbufAppendS(&item->security.algorithm, "None");
break;
case DOT11_CIPHER_ALGO_WEP40:
ffStrbufAppendS(&item->security.algorithm, "WEP-40");
break;
case DOT11_CIPHER_ALGO_TKIP:
ffStrbufAppendS(&item->security.algorithm, "TKIP");
break;
case DOT11_CIPHER_ALGO_CCMP:
ffStrbufAppendS(&item->security.algorithm, "CCMP");
break;
case DOT11_CIPHER_ALGO_WEP104:
ffStrbufAppendS(&item->security.algorithm, "WEP-104");
break;
case 0x06 /* DOT11_CIPHER_ALGO_BIP */:
ffStrbufAppendS(&item->security.algorithm, "BIP-CMAC-128");
break;
case 0x08 /* DOT11_CIPHER_ALGO_GCMP */:
ffStrbufAppendS(&item->security.algorithm, "GCMP-128");
break;
case 0x09 /* DOT11_CIPHER_ALGO_GCMP_256 */:
ffStrbufAppendS(&item->security.algorithm, "GCMP-256");
break;
case 0x0a /* DOT11_CIPHER_ALGO_CCMP_256 */:
ffStrbufAppendS(&item->security.algorithm, "CCMP-256");
break;
case 0x0b /* DOT11_CIPHER_ALGO_BIP_GMAC_128 */:
ffStrbufAppendS(&item->security.algorithm, "BIP-GMAC-128");
break;
case 0x0c /* DOT11_CIPHER_ALGO_BIP_GMAC_256 */:
ffStrbufAppendS(&item->security.algorithm, "BIP-GMAC-256");
break;
case 0x0d /* DOT11_CIPHER_ALGO_BIP_CMAC_256 */:
ffStrbufAppendS(&item->security.algorithm, "BIP-CMAC-256");
break;
case DOT11_CIPHER_ALGO_WEP:
ffStrbufAppendS(&item->security.algorithm, "WEP");
break;
default:
ffStrbufAppendF(&item->security.algorithm, "Unknown (%u)", (unsigned)connInfo->wlanSecurityAttributes.dot11CipherAlgorithm);
break;
switch (connInfo->wlanSecurityAttributes.dot11AuthAlgorithm)
{
case DOT11_AUTH_ALGO_80211_OPEN:
ffStrbufAppendS(&item->conn.security, "802.11 Open");
break;
case DOT11_AUTH_ALGO_80211_SHARED_KEY:
ffStrbufAppendS(&item->conn.security, "802.11 Shared");
break;
case DOT11_AUTH_ALGO_WPA:
ffStrbufAppendS(&item->conn.security, "WPA");
break;
case DOT11_AUTH_ALGO_WPA_PSK:
ffStrbufAppendS(&item->conn.security, "WPA-PSK");
break;
case DOT11_AUTH_ALGO_WPA_NONE:
ffStrbufAppendS(&item->conn.security, "WPA-None");
break;
case DOT11_AUTH_ALGO_RSNA:
ffStrbufAppendS(&item->conn.security, "WPA2");
break;
case DOT11_AUTH_ALGO_RSNA_PSK:
ffStrbufAppendS(&item->conn.security, "WPA2-PSK");
break;
case 8 /* DOT11_AUTH_ALGO_WPA3 */:
ffStrbufAppendS(&item->conn.security, "WPA3");
break;
case 9 /* DOT11_AUTH_ALGO_WPA3_SAE */:
ffStrbufAppendS(&item->conn.security, "WPA3-SAE");
break;
case 10 /* DOT11_AUTH_ALGO_OWE */:
ffStrbufAppendS(&item->conn.security, "OWE");
break;
case 11 /* DOT11_AUTH_ALGO_WPA3_ENT */:
ffStrbufAppendS(&item->conn.security, "OWE-ENT");
break;
default:
ffStrbufAppendF(&item->conn.security, "Unknown (%u)", (unsigned)connInfo->wlanSecurityAttributes.dot11AuthAlgorithm);
break;
}
if(connInfo->wlanSecurityAttributes.bOneXEnabled)
ffStrbufAppendS(&item->conn.security, " 802.11X");
}
else
ffStrbufAppendS(&item->conn.security, "Insecure");
ffWlanFreeMemory(connInfo);
}
+1 -1
View File
@@ -9,7 +9,7 @@ static bool detectQuartzCompositor(FFinstance* instance, FFstrbuf* themeOrError)
FF_UNUSED(instance);
NSError* error;
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/.GlobalPreferences.plist", instance->state.passwd->pw_dir];
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Preferences/.GlobalPreferences.plist", instance->state.platform.homeDir.chars];
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
error:&error];
if(error)
+2 -2
View File
@@ -131,9 +131,9 @@ static bool detectOpenbox(FFinstance* instance, const FFstrbuf* dePrettyName, FF
{
FFstrbuf absolutePath;
ffStrbufInitA(&absolutePath, 64);
ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir);
ffStrbufAppendC(&absolutePath, '/');
ffStrbufAppend(&absolutePath, &instance->state.platform.homeDir);
//TODO: use config dirs
if(ffStrbufIgnCaseCompS(dePrettyName, "LXQT") == 0)
ffStrbufAppendS(&absolutePath, ".config/openbox/lxqt-rc.xml");
else if(ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0)
+171 -62
View File
@@ -174,12 +174,13 @@ static inline void printCommandHelp(const char* command)
"User shell version"
);
}
else if(strcasecmp(command, "resolution-format") == 0)
else if(strcasecmp(command, "display-format") == 0)
{
constructAndPrintCommandHelpFormat("resolution", "{}x{} @ {}Hz", 3,
constructAndPrintCommandHelpFormat("display", "{}x{} @ {}Hz", 4,
"Screen width",
"Screen height",
"Screen refresh rate"
"Screen refresh rate",
"Screen brightness"
);
}
else if(strcasecmp(command, "de-format") == 0)
@@ -287,12 +288,13 @@ static inline void printCommandHelp(const char* command)
}
else if(strcasecmp(command, "gpu-format") == 0)
{
constructAndPrintCommandHelpFormat("gpu", "{} {}", 5,
constructAndPrintCommandHelpFormat("gpu", "{} {}", 6,
"GPU vendor",
"GPU name",
"GPU driver",
"GPU temperature",
"GPU core count"
"GPU core count",
"GPU type"
);
}
else if(strcasecmp(command, "memory-format") == 0)
@@ -371,13 +373,11 @@ static inline void printCommandHelp(const char* command)
"Connection status",
"Connection SSID",
"Connection mac address",
"Connection PHY type",
"Connection protocol",
"Connection signal quality (percentage)",
"Connection RX rate",
"Connection TX rate",
"Security enabled",
"Security 802.1X enabled",
"Security algorithm"
"Connection Security algorithm"
);
}
else if(strcasecmp(command, "player-format") == 0)
@@ -525,17 +525,29 @@ static inline void listAvailablePresetsFromFolder(FFstrbuf* folder, uint8_t inde
static inline void listAvailablePresets(FFinstance* instance)
{
FFstrbuf folder;
ffStrbufInitA(&folder, 64);
FF_LIST_FOR_EACH(FFstrbuf, path, instance->state.platform.dataDirs)
{
ffStrbufAppendS(path, "fastfetch/presets/");
listAvailablePresetsFromFolder(path, 0, NULL);
}
}
ffStrbufSetS(&folder, instance->state.passwd->pw_dir);
ffStrbufAppendS(&folder, "/.local/share/fastfetch/presets/");
listAvailablePresetsFromFolder(&folder, 0, NULL);
static void listConfigPaths(FFinstance* instance)
{
FF_LIST_FOR_EACH(FFstrbuf, folder, instance->state.platform.configDirs)
{
ffStrbufAppendS(folder, "fastfetch/config.conf");
printf("%s%s\n", folder->chars, ffFileExists(folder->chars, S_IFREG) ? " (*)" : "");
}
}
ffStrbufSetS(&folder, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
listAvailablePresetsFromFolder(&folder, 0, NULL);
ffStrbufDestroy(&folder);
static void listDataPaths(FFinstance* instance)
{
FF_LIST_FOR_EACH(FFstrbuf, folder, instance->state.platform.dataDirs)
{
ffStrbufAppendS(folder, "fastfetch/");
puts(folder->chars);
}
}
static void parseOption(FFinstance* instance, FFdata* data, const char* key, const char* value);
@@ -603,6 +615,25 @@ static bool parseConfigFile(FFinstance* instance, FFdata* data, const char* path
return true;
}
static void generateConfigFile(FFinstance* instance, bool force)
{
FFstrbuf* filename = (FFstrbuf*) ffListGet(&instance->state.platform.configDirs, 0);
// Paths generated in `init.c/initConfigDirs` end with `/`
ffStrbufAppendS(filename, "fastfetch/config.conf");
if (!force && ffFileExists(filename->chars, S_IFREG))
{
fprintf(stderr, "Config file exists in `%s`, use `--gen-config-force` to overwrite\n", filename->chars);
exit(1);
}
else
{
ffWriteFileData(filename->chars, sizeof(FASTFETCH_DATATEXT_CONFIG_USER), FASTFETCH_DATATEXT_CONFIG_USER);
printf("A sample config file has been written in `%s`\n", filename->chars);
exit(0);
}
}
static void optionParseConfigFile(FFinstance* instance, FFdata* data, const char* key, const char* value)
{
if(value == NULL)
@@ -616,37 +647,29 @@ static void optionParseConfigFile(FFinstance* instance, FFdata* data, const char
if(parseConfigFile(instance, data, value))
return;
//Try to load as an user preset
//Try to load as a relative path
FFstrbuf filename;
ffStrbufInitA(&filename, 64);
FFstrbuf absolutePath;
ffStrbufInitA(&absolutePath, 128);
ffStrbufAppendS(&filename, instance->state.passwd->pw_dir);
ffStrbufAppendS(&filename, "/.local/share/fastfetch/presets/");
ffStrbufAppendS(&filename, value);
if(parseConfigFile(instance, data, filename.chars))
FF_LIST_FOR_EACH(FFstrbuf, path, instance->state.platform.dataDirs)
{
ffStrbufDestroy(&filename);
return;
//We need to copy it, because if a config file loads a config file, the value of path must be unchanged
ffStrbufSet(&absolutePath, path);
ffStrbufAppendS(&absolutePath, "fastfetch/presets/");
ffStrbufAppendS(&absolutePath, value);
bool success = parseConfigFile(instance, data, absolutePath.chars);
if(success)
return;
}
//Try to load as a system preset
ffStrbufSetS(&filename, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
ffStrbufAppendS(&filename, value);
if(parseConfigFile(instance, data, filename.chars))
{
ffStrbufDestroy(&filename);
return;
}
ffStrbufDestroy(&absolutePath);
//File not found
fprintf(stderr, "Error: couldn't find config: %s\n", value);
ffStrbufDestroy(&filename);
exit(414);
}
@@ -836,7 +859,35 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
}
else if(strcasecmp(key, "-v") == 0 || strcasecmp(key, "--version") == 0)
{
puts("fastfetch "FASTFETCH_PROJECT_VERSION""FASTFETCH_PROJECT_VERSION_TWEAK);
#ifndef NDEBUG
#define FF_BUILD_TYPE "-debug"
#else
#define FF_BUILD_TYPE
#endif
#if defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64)
#define FF_ARCHITECTURE "x86_64"
#elif defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(__i586__) || defined(__i586) || defined(__i686__) || defined(__i686)
#define FF_ARCHITECTURE "i386"
#elif defined(__aarch64__)
#define FF_ARCHITECTURE "aarch64"
#elif defined(__arm__)
#define FF_ARCHITECTURE "arm"
#elif defined(__mips__)
#define FF_ARCHITECTURE "mips"
#elif defined(__powerpc__) || defined(__powerpc)
#define FF_ARCHITECTURE "powerpc"
#elif defined(__riscv__) || defined(__riscv)
#define FF_ARCHITECTURE "riscv"
#elif
#define FF_ARCHITECTURE "unknown"
#endif
puts("fastfetch " FASTFETCH_PROJECT_VERSION FASTFETCH_PROJECT_VERSION_TWEAK FF_BUILD_TYPE " (" FF_ARCHITECTURE ")");
#undef FF_ARCHITECTURE
#undef FF_BUILD_TYPE
exit(0);
}
else if(strcasecmp(key, "--version-raw") == 0)
@@ -883,6 +934,16 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
listAvailablePresets(instance);
exit(0);
}
else if(strcasecmp(subkey, "-config-paths") == 0)
{
listConfigPaths(instance);
exit(0);
}
else if(strcasecmp(subkey, "-data-paths") == 0)
{
listDataPaths(instance);
exit(0);
}
else if(strcasecmp(subkey, "-features") == 0)
{
ffListFeatures();
@@ -912,6 +973,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
fputs("`--nocache` are obsoleted. Caching functions other than image caching are removed.\n\n", stderr);
else if(strcasecmp(key, "--load-config") == 0)
optionParseConfigFile(instance, data, key, value);
else if(strcasecmp(key, "--gen-config") == 0)
generateConfigFile(instance, false);
else if(strcasecmp(key, "--gen-config-force") == 0)
generateConfigFile(instance, true);
else if(strcasecmp(key, "--thread") == 0 || strcasecmp(key, "--multithreading") == 0)
instance->config.multithreading = optionParseBoolean(value);
else if(strcasecmp(key, "--stat") == 0)
@@ -939,8 +1004,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
//this is usally wanted when using the none logo
if(strcasecmp(value, "none") == 0)
{
instance->config.logo.paddingTop = 0;
instance->config.logo.paddingRight = 0;
instance->config.logo.paddingLeft = 0;
instance->config.logo.type = FF_LOGO_TYPE_NONE;
}
}
else if(startsWith(key, "--logo"))
@@ -957,7 +1024,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
"data-raw", FF_LOGO_TYPE_DATA_RAW,
"sixel", FF_LOGO_TYPE_IMAGE_SIXEL,
"kitty", FF_LOGO_TYPE_IMAGE_KITTY,
"iterm", FF_LOGO_TYPE_IMAGE_ITERM,
"chafa", FF_LOGO_TYPE_IMAGE_CHAFA,
"raw", FF_LOGO_TYPE_IMAGE_RAW,
"none", FF_LOGO_TYPE_NONE,
NULL
);
}
@@ -985,6 +1055,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
instance->config.logo.paddingLeft = padding;
instance->config.logo.paddingRight = padding;
}
else if(strcasecmp(subkey, "-padding-top") == 0)
instance->config.logo.paddingTop = optionParseUInt32(key, value);
else if(strcasecmp(subkey, "-padding-left") == 0)
instance->config.logo.paddingLeft = optionParseUInt32(key, value);
else if(strcasecmp(subkey, "-padding-right") == 0)
@@ -1036,6 +1108,11 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.logo.source);
instance->config.logo.type = FF_LOGO_TYPE_IMAGE_ITERM;
}
else if(strcasecmp(key, "--raw") == 0)
{
optionParseString(key, value, &instance->config.logo.source);
instance->config.logo.type = FF_LOGO_TYPE_IMAGE_RAW;
}
else if(strcasecmp(key, "--chafa-fg-only") == 0)
instance->config.logo.chafaFgOnly = optionParseBoolean(value);
else if(strcasecmp(key, "--chafa-symbols") == 0)
@@ -1098,7 +1175,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
else if(optionParseModuleArgs(key, value, "processes", &instance->config.processes)) {}
else if(optionParseModuleArgs(key, value, "packages", &instance->config.packages)) {}
else if(optionParseModuleArgs(key, value, "shell", &instance->config.shell)) {}
else if(optionParseModuleArgs(key, value, "resolution", &instance->config.resolution)) {}
else if(optionParseModuleArgs(key, value, "display", &instance->config.display)) {}
else if(optionParseModuleArgs(key, value, "brightness", &instance->config.brightness)) {}
else if(optionParseModuleArgs(key, value, "de", &instance->config.de)) {}
else if(optionParseModuleArgs(key, value, "wifi", &instance->config.wifi)) {}
else if(optionParseModuleArgs(key, value, "wm", &instance->config.wm)) {}
@@ -1184,6 +1262,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.libcJSON);
else if(strcasecmp(subkey, "-wlanapi") == 0)
optionParseString(key, value, &instance->config.libwlanapi);
else if(strcasecmp(subkey, "-nm") == 0)
optionParseString(key, value, &instance->config.libnm);
else
goto error;
}
@@ -1198,14 +1278,26 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
instance->config.gpuTemp = optionParseBoolean(value);
else if(strcasecmp(key, "--battery-temp") == 0)
instance->config.batteryTemp = optionParseBoolean(value);
else if(strcasecmp(key, "--gpu-hide-integrated") == 0)
instance->config.gpuHideIntegrated = optionParseBoolean(value);
else if(strcasecmp(key, "--gpu-hide-discrete") == 0)
instance->config.gpuHideDiscrete = optionParseBoolean(value);
else if(strcasecmp(key, "--title-fqdn") == 0)
instance->config.titleFQDN = optionParseBoolean(value);
else if(strcasecmp(key, "--shell-version") == 0)
instance->config.shellVersion = optionParseBoolean(value);
else if(strcasecmp(key, "--terminal-version") == 0)
instance->config.terminalVersion = optionParseBoolean(value);
else if(strcasecmp(key, "--disk-folders") == 0)
optionParseString(key, value, &instance->config.diskFolders);
else if(strcasecmp(key, "--disk-show-removable") == 0)
instance->config.diskShowRemovable = optionParseBoolean(value);
else if(strcasecmp(key, "--disk-show-hidden") == 0)
instance->config.diskShowHidden = optionParseBoolean(value);
else if(strcasecmp(key, "--disk-show-subvolumes") == 0)
instance->config.diskShowSubvolumes = optionParseBoolean(value);
else if(strcasecmp(key, "--disk-show-unknown") == 0)
instance->config.diskShowUnknown = optionParseBoolean(value);
else if(strcasecmp(key, "--battery-dir") == 0)
optionParseString(key, value, &instance->config.batteryDir);
else if(strcasecmp(key, "--separator-string") == 0)
@@ -1242,6 +1334,20 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
}
else if(strcasecmp(key, "--percent-type") == 0)
instance->config.percentType = optionParseUInt32(key, value);
else if(strcasecmp(key, "--command-shell") == 0)
optionParseString(key, value, &instance->config.commandShell);
else if(strcasecmp(key, "--command-key") == 0)
{
FFstrbuf* result = (FFstrbuf*) ffListAdd(&instance->config.commandKeys);
ffStrbufInit(result);
optionParseString(key, value, result);
}
else if(strcasecmp(key, "--command-text") == 0)
{
FFstrbuf* result = (FFstrbuf*) ffListAdd(&instance->config.commandTexts);
ffStrbufInit(result);
optionParseString(key, value, result);
}
//////////////////
//Unknown option//
@@ -1255,25 +1361,20 @@ error:
}
}
static void parseConfigFileSystem(FFinstance* instance, FFdata* data)
static void parseConfigFiles(FFinstance* instance, FFdata* data)
{
parseConfigFile(instance, data, FASTFETCH_TARGET_DIR_INSTALL_SYSCONF"/fastfetch/config.conf");
}
for(uint32_t i = instance->state.platform.configDirs.length; i > 0; --i)
{
if(!data->loadUserConfig)
return;
static void parseConfigFileUser(FFinstance* instance, FFdata* data)
{
if(!data->loadUserConfig)
return;
FFstrbuf* dir = ffListGet(&instance->state.platform.configDirs, i - 1);
uint32_t dirLength = dir->length;
FFstrbuf* filename = ffListGet(&instance->state.configDirs, 0);
uint32_t filenameLength = filename->length;
ffStrbufAppendS(filename, "/fastfetch/config.conf");
if(!parseConfigFile(instance, data, filename->chars))
ffWriteFileData(filename->chars, sizeof(FASTFETCH_DATATEXT_CONFIG_USER), FASTFETCH_DATATEXT_CONFIG_USER);
ffStrbufSubstrBefore(filename, filenameLength);
ffStrbufAppendS(dir, "fastfetch/config.conf");
parseConfigFile(instance, data, dir->chars);
ffStrbufSubstrBefore(dir, dirLength);
}
}
static void parseArguments(FFinstance* instance, FFdata* data, int argc, const char** argv)
@@ -1320,6 +1421,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char
ffPrintBios(instance);
else if(strcasecmp(line, "board") == 0)
ffPrintBoard(instance);
else if(strcasecmp(line, "brightness") == 0)
ffPrintBrightness(instance);
else if(strcasecmp(line, "chassis") == 0)
ffPrintChassis(instance);
else if(strcasecmp(line, "kernel") == 0)
@@ -1332,8 +1435,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char
ffPrintPackages(instance);
else if(strcasecmp(line, "shell") == 0)
ffPrintShell(instance);
else if(strcasecmp(line, "resolution") == 0)
ffPrintResolution(instance);
else if(strcasecmp(line, "display") == 0)
ffPrintDisplay(instance);
else if(strcasecmp(line, "desktopenvironment") == 0 || strcasecmp(line, "de") == 0)
ffPrintDesktopEnvironment(instance);
else if(strcasecmp(line, "windowmanager") == 0 || strcasecmp(line, "wm") == 0)
@@ -1398,6 +1501,8 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char
ffPrintOpenCL(instance);
else if(strcasecmp(line, "users") == 0)
ffPrintUsers(instance);
else if(strcasecmp(line, "command") == 0)
ffPrintCommand(instance);
else
ffPrintErrorString(instance, line, 0, NULL, NULL, "<no implementation provided>");
}
@@ -1413,8 +1518,8 @@ int main(int argc, const char** argv)
ffStrbufInitA(&data.structure, 256);
data.loadUserConfig = true;
parseConfigFileSystem(&instance, &data);
parseConfigFileUser(&instance, &data);
if(!getenv("NO_CONFIG"))
parseConfigFiles(&instance, &data);
parseArguments(&instance, &data, argc, argv);
//If we don't have a custom structure, use the default one
@@ -1432,6 +1537,10 @@ int main(int argc, const char** argv)
ffStart(&instance);
#if defined(_WIN32) && defined(FF_ENABLE_BUFFER)
fflush(stdout);
#endif
//Parse the structure and call the modules
uint32_t startIndex = 0;
while (startIndex < data.structure.length)
+25 -16
View File
@@ -8,20 +8,13 @@
#include <stdint.h>
#include <stdbool.h>
#ifndef _WIN32
#include <pwd.h>
#include <sys/utsname.h>
#else
#include "util/windows/pwd.h"
#include "util/windows/utsname.h"
#endif
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
#include "util/platform/FFPlatform.h"
static inline void ffUnused(int dummy, ...) { (void) dummy; }
#define FF_UNUSED(...) ffUnused(0, __VA_ARGS__);
#define FF_UNUSED_PARAM __attribute__ ((__unused__))
#define FF_MAYBE_UNUSED __attribute__ ((__unused__))
#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9)
@@ -37,6 +30,8 @@ typedef enum FFLogoType
FF_LOGO_TYPE_IMAGE_KITTY, //image file, printed as kitty graphics protocol
FF_LOGO_TYPE_IMAGE_ITERM, //image file, printed as iterm graphics protocol
FF_LOGO_TYPE_IMAGE_CHAFA, //image file, printed as ascii art using libchafa
FF_LOGO_TYPE_IMAGE_RAW, //image file, printed as raw binary string
FF_LOGO_TYPE_NONE, //--logo none
} FFLogoType;
typedef enum FFBinaryPrefixType
@@ -70,6 +65,7 @@ typedef struct FFconfig
FFstrbuf colors[FASTFETCH_LOGO_MAX_COLORS];
uint32_t width;
uint32_t height;
uint32_t paddingTop;
uint32_t paddingLeft;
uint32_t paddingRight;
bool printRemaining;
@@ -103,14 +99,15 @@ typedef struct FFconfig
FFModuleArgs os;
FFModuleArgs host;
FFModuleArgs bios;
FFModuleArgs chassis;
FFModuleArgs board;
FFModuleArgs brightness;
FFModuleArgs chassis;
FFModuleArgs kernel;
FFModuleArgs uptime;
FFModuleArgs processes;
FFModuleArgs packages;
FFModuleArgs shell;
FFModuleArgs resolution;
FFModuleArgs display;
FFModuleArgs de;
FFModuleArgs wifi;
FFModuleArgs wm;
@@ -166,16 +163,25 @@ typedef struct FFconfig
FFstrbuf libcJSON;
FFstrbuf libfreetype;
FFstrbuf libwlanapi;
FFstrbuf libnm;
bool cpuTemp;
bool gpuTemp;
bool batteryTemp;
bool gpuHideIntegrated;
bool gpuHideDiscrete;
bool titleFQDN;
bool shellVersion;
bool terminalVersion;
FFstrbuf diskFolders;
bool diskShowRemovable;
bool diskShowHidden;
bool diskShowUnknown;
bool diskShowSubvolumes;
FFstrbuf batteryDir;
@@ -197,6 +203,10 @@ typedef struct FFconfig
FFstrbuf playerName;
uint32_t percentType;
FFstrbuf commandShell;
FFlist commandKeys;
FFlist commandTexts;
} FFconfig;
typedef struct FFstate
@@ -205,10 +215,7 @@ typedef struct FFstate
uint32_t logoHeight;
uint32_t keysHeight;
struct passwd* passwd;
struct utsname utsname;
FFlist configDirs;
FFPlatform platform;
} FFstate;
typedef struct FFinstance
@@ -268,7 +275,8 @@ void ffPrintUptime(FFinstance* instance);
void ffPrintProcesses(FFinstance* instance);
void ffPrintPackages(FFinstance* instance);
void ffPrintShell(FFinstance* instance);
void ffPrintResolution(FFinstance* instance);
void ffPrintDisplay(FFinstance* instance);
void ffPrintBrightness(FFinstance* instance);
void ffPrintDesktopEnvironment(FFinstance* instance);
void ffPrintWM(FFinstance* instance);
void ffPrintWMTheme(FFinstance* instance);
@@ -301,5 +309,6 @@ void ffPrintVulkan(FFinstance* instance);
void ffPrintOpenGL(FFinstance* instance);
void ffPrintOpenCL(FFinstance* instance);
void ffPrintUsers(FFinstance* instance);
void ffPrintCommand(FFinstance* instance);
#endif
+2 -1
View File
@@ -30,7 +30,8 @@ int main(int argc, char** argv)
//ffPrintProcesses(&instance);
ffPrintPackages(&instance);
ffPrintShell(&instance);
ffPrintResolution(&instance);
ffPrintDisplay(&instance);
// ffPrintBrightness(&instance);
ffPrintDesktopEnvironment(&instance);
ffPrintWM(&instance);
ffPrintWMTheme(&instance);
+64
View File
@@ -1871,6 +1871,68 @@ static const FFlogo* getLogoPopSmall()
FF_LOGO_COLOR_TITLE("36"); //cyan
FF_LOGO_RETURN
}
static const FFlogo* getLogoRaspbian()
{
FF_LOGO_INIT
FF_LOGO_NAMES("raspbian", "raspi", "raspberrypi" "raspberrypios" "pios")
FF_LOGO_LINES(
" $2`.::///+:/-. --///+//-:`\n"
" `+oooooooooooo: `+oooooooooooo:\n"
" /oooo++//ooooo: ooooo+//+ooooo.\n"
" `+ooooooo:-:oo- +o+::/ooooooo:\n"
" `:oooooooo+`` `.oooooooo+-\n"
" `:++ooo/. :+ooo+/.`$1\n"
" ...` `.----.` ``..\n"
" .::::-``:::::::::.`-:::-`\n"
" -:::-` .:::::::-` `-:::-\n"
" `::. `.--.` `` `.---.``.::`\n"
" .::::::::` -::::::::` `\n"
" .::` .:::::::::- `::::::::::``::.\n"
"-:::` ::::::::::. ::::::::::.`:::-\n"
":::: -::::::::. `-:::::::: ::::\n"
"-::- .-:::-.``....``.-::-. -::-\n"
" .. `` .::::::::. `..`..\n"
" -:::-` -::::::::::` .:::::`\n"
" :::::::` -::::::::::` :::::::.\n"
" .::::::: -::::::::. ::::::::\n"
" `-:::::` ..--.` ::::::.\n"
" `...` `...--..` `...`\n"
" .::::::::::\n"
" `.-::::-`"
)
FF_LOGO_COLORS(
"31", //red
"32" //green
)
FF_LOGO_COLOR_KEYS("31"); //red
FF_LOGO_COLOR_TITLE("32"); //green
FF_LOGO_RETURN
}
static const FFlogo* getLogoRaspbianSmall()
{
FF_LOGO_INIT
FF_LOGO_NAMES("raspbian_small", "raspi_small", "raspberrypi_small" "raspberrypios_small" "pios_small")
FF_LOGO_LINES(
" $2.~~. .~~.\n"
" '. \\ ' ' / .'$1\n"
" .~ .~~~..~.\n"
" : .~.'~'.~. :\n"
" ~ ( ) ( ) ~\n"
"( : '~'.~.'~' : )\n"
" ~ .~ ( ) ~. ~\n"
" ( : '~' : )\n"
" '~ .~~~. ~'\n"
" '~'"
)
FF_LOGO_COLORS(
"31", //red
"32" //green
)
FF_LOGO_COLOR_KEYS("31"); //red
FF_LOGO_COLOR_TITLE("32"); //green
FF_LOGO_RETURN
}
static const FFlogo* getLogoReborn()
{
@@ -2430,6 +2492,8 @@ GetLogoMethod* ffLogoBuiltinGetAll()
getLogoPopSmall,
getLogoParabola,
getLogoParabolaSmall,
getLogoRaspbian,
getLogoRaspbianSmall,
getLogoReborn,
getLogoRebornSmall,
getLogoRedHatEnterpriseLinux,
+23 -20
View File
@@ -2,6 +2,10 @@
#include "common/io.h"
#include "common/printing.h"
#ifdef __APPLE__
#include <sys/syslimits.h>
#endif
static FFstrbuf base64Encode(FFstrbuf* in)
{
const char* base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -30,24 +34,31 @@ static FFstrbuf base64Encode(FFstrbuf* in)
static bool printImageIterm(FFinstance* instance)
{
if(instance->config.logo.width == 0 || instance->config.logo.height == 0)
{
fputs("Logo: `iterm` protocol only works when both `--logo-width` and `--logo-height` being specified\n", stderr);
return false;
}
FFstrbuf buf;
ffStrbufInit(&buf);
if(!ffAppendFileBuffer(instance->config.logo.source.chars, &buf))
{
fputs("Logo: Failed to load image file\n", stderr);
return false;
}
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
ffPrintCharTimes('\n', instance->config.logo.paddingTop);
FFstrbuf base64 = base64Encode(&buf);
instance->state.logoWidth = instance->config.logo.width + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
instance->state.logoHeight = instance->config.logo.paddingTop + instance->config.logo.height;
printf("\033]1337;File=inline=1;width=%u;height=%u;preserveAspectRatio=%u:%s\a\033[9999999D\n\033[%uA",
(unsigned) instance->config.logo.width,
(unsigned) instance->config.logo.height,
(unsigned) instance->config.logo.preserveAspectRadio,
base64.chars,
(unsigned) instance->config.logo.height
(unsigned) instance->state.logoHeight
);
instance->state.logoWidth = instance->config.logo.width + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
instance->state.logoHeight = instance->config.logo.height;
ffStrbufDestroy(&buf);
ffStrbufDestroy(&base64);
@@ -58,6 +69,7 @@ static bool printImageIterm(FFinstance* instance)
static bool printImageKittyDirect(FFinstance* instance)
{
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
ffPrintCharTimes('\n', instance->config.logo.paddingTop);
FFstrbuf base64 = base64Encode(&instance->config.logo.source);
printf("\033_Ga=T,f=100,t=f,c=%u,r=%u,C=1;%s\033\\\033[9999999D",
(unsigned) instance->config.logo.width,
@@ -66,7 +78,7 @@ static bool printImageKittyDirect(FFinstance* instance)
);
instance->state.logoWidth = instance->config.logo.width + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
instance->state.logoHeight = instance->config.logo.height;
instance->state.logoHeight = instance->config.logo.paddingTop + instance->config.logo.height;
ffStrbufDestroy(&base64);
@@ -101,6 +113,7 @@ static inline char* realpath(const char* restrict file_name, char* restrict reso
resolved_name[1] = resolved_name[0]; // Drive Name
resolved_name[0] = '/';
}
return result;
}
#endif
@@ -199,7 +212,7 @@ static void printImagePixels(FFinstance* instance, FFLogoRequestData* requestDat
//Calculate character dimensions
instance->state.logoWidth = requestData->logoCharacterWidth + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
instance->state.logoHeight = requestData->logoCharacterHeight;
instance->state.logoHeight = requestData->logoCharacterHeight + instance->config.logo.paddingTop;
if(requestData->type == FF_LOGO_TYPE_IMAGE_KITTY)
instance->state.logoHeight -= 1;
@@ -213,6 +226,7 @@ static void printImagePixels(FFinstance* instance, FFLogoRequestData* requestDat
writeCacheUint32(requestData, instance->state.logoHeight, FF_CACHE_FILE_HEIGHT);
//Write result to stdout
ffPrintCharTimes('\n', instance->config.logo.paddingTop);
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
fflush(stdout);
ffWriteFDBuffer(STDOUT_FILENO, result);
@@ -594,6 +608,7 @@ static bool printCachedPixel(FFinstance* instance, FFLogoRequestData* requestDat
if(fd == -1)
return false;
ffPrintCharTimes('\n', instance->config.logo.paddingTop);
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
fflush(stdout);
@@ -605,7 +620,7 @@ static bool printCachedPixel(FFinstance* instance, FFLogoRequestData* requestDat
close(fd);
instance->state.logoWidth = requestData->logoCharacterWidth + instance->config.logo.paddingLeft + instance->config.logo.paddingRight;
instance->state.logoHeight = requestData->logoCharacterHeight;
instance->state.logoHeight = requestData->logoCharacterHeight + instance->config.logo.paddingTop;
//Go to upper left corner
fputs("\033[9999999D", stdout);
@@ -676,20 +691,8 @@ static bool printImageIfExistsSlowPath(FFinstance* instance, FFLogoType type)
requestData.logoPixelWidth = simpleCeil((double) instance->config.logo.width * requestData.characterPixelWidth);
requestData.logoPixelHeight = simpleCeil((double) instance->config.logo.height * requestData.characterPixelHeight);
ffStrbufInitA(&requestData.cacheDir, PATH_MAX * 2);
#if !(defined(_WIN32) || defined(__APPLE__) || defined(__ANDROID__))
ffStrbufAppendS(&requestData.cacheDir, getenv("XDG_CACHE_HOME"));
#endif
if(requestData.cacheDir.length == 0)
{
ffStrbufAppendS(&requestData.cacheDir, instance->state.passwd->pw_dir);
ffStrbufAppendS(&requestData.cacheDir, "/.cache/");
}
else
ffStrbufEnsureEndsWithC(&requestData.cacheDir, '/');
ffStrbufInit(&requestData.cacheDir);
ffStrbufAppend(&requestData.cacheDir, &instance->state.platform.cacheDir);
ffStrbufAppendS(&requestData.cacheDir, "fastfetch");
ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX);
+65 -9
View File
@@ -8,13 +8,27 @@
#include <ctype.h>
#include <string.h>
static void ffLogoPrintCharsRaw(FFinstance* instance, const char* data, size_t length)
{
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintCharTimes('\n', instance->config.logo.paddingTop);
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
fwrite(data, length, 1, stdout);
instance->state.logoHeight = instance->config.logo.paddingTop + instance->config.logo.height;
instance->state.logoWidth = instance->config.logo.paddingLeft + instance->config.logo.width + instance->config.logo.paddingRight;
printf("\033[9999999D\n\033[%uA", instance->state.logoHeight);
}
void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplacement)
{
uint32_t currentlineLength = 0;
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintCharTimes('\n', instance->config.logo.paddingTop);
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
instance->state.logoHeight = instance->config.logo.paddingTop;
//Use logoColor[0] as the default color
if(doColorReplacement)
ffPrintColor(&instance->config.logo.colors[0]);
@@ -191,7 +205,7 @@ static const FFlogo* logoGetBuiltin(const char* name)
return NULL;
}
static const FFlogo* logoGetBuiltinDetected(FFinstance* instance)
static const FFlogo* logoGetBuiltinDetected(const FFinstance* instance)
{
const FFOSResult* os = ffDetectOS(instance);
@@ -211,7 +225,7 @@ static const FFlogo* logoGetBuiltinDetected(FFinstance* instance)
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->systemName.chars);
logo = logoGetBuiltin(instance->state.platform.systemName.chars);
if(logo != NULL)
return logo;
@@ -271,19 +285,49 @@ static void logoPrintData(FFinstance* instance, bool doColorReplacement) {
logoApplyColorsDetected(instance);
}
static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement)
static bool loadLogoFile(const FFinstance* instance, FFstrbuf* buffer)
{
if(ffAppendFileBuffer(instance->config.logo.source.chars, buffer))
return true;
FFstrbuf fullPath;
ffStrbufInit(&fullPath);
FF_LIST_FOR_EACH(FFstrbuf, dataDir, instance->state.platform.dataDirs)
{
//We need to copy it, because multiple threads might be using dataDirs at the same time
ffStrbufSet(&fullPath, dataDir);
ffStrbufAppendS(&fullPath, "fastfetch/logos/");
ffStrbufAppend(&fullPath, &instance->config.logo.source);
if(ffAppendFileBuffer(fullPath.chars, buffer))
{
ffStrbufDestroy(&fullPath);
return true;
}
}
ffStrbufDestroy(&fullPath);
return false;
}
static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement, bool raw)
{
FFstrbuf content;
ffStrbufInitA(&content, 2047);
ffStrbufInit(&content);
if(!ffAppendFileBuffer(instance->config.logo.source.chars, &content))
if(!loadLogoFile(instance, &content))
{
ffStrbufDestroy(&content);
fputs("Logo: Failed to load file content from logo source\n", stderr);
return false;
}
logoApplyColorsDetected(instance);
ffLogoPrintChars(instance, content.chars, doColorReplacement);
if(raw)
ffLogoPrintCharsRaw(instance, content.chars, content.length);
else
ffLogoPrintChars(instance, content.chars, doColorReplacement);
ffStrbufDestroy(&content);
return true;
}
@@ -304,13 +348,25 @@ static void logoPrintKnownType(FFinstance* instance)
if(instance->config.logo.type == FF_LOGO_TYPE_BUILTIN)
successfull = logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars);
else if(instance->config.logo.type == FF_LOGO_TYPE_FILE)
successfull = logoPrintFileIfExists(instance, true);
successfull = logoPrintFileIfExists(instance, true, false);
else if(instance->config.logo.type == FF_LOGO_TYPE_FILE_RAW)
successfull = logoPrintFileIfExists(instance, false);
successfull = logoPrintFileIfExists(instance, false, false);
else if(instance->config.logo.type == FF_LOGO_TYPE_DATA)
logoPrintData(instance, true);
else if(instance->config.logo.type == FF_LOGO_TYPE_DATA_RAW)
logoPrintData(instance, false);
else if(instance->config.logo.type == FF_LOGO_TYPE_IMAGE_RAW)
{
if(instance->config.logo.width == 0 || instance->config.logo.height == 0)
{
fputs("both `--logo-width` and `--logo-height` must be specified\n", stderr);
successfull = false;
}
else
successfull = logoPrintFileIfExists(instance, false, true);
}
else if(instance->config.logo.type == FF_LOGO_TYPE_NONE)
logoApplyColorsDetected(instance);
else //image
successfull = logoPrintImageIfExists(instance, instance->config.logo.type);
@@ -362,7 +418,7 @@ void ffLogoPrint(FFinstance* instance)
return;
//Try to load the logo as a file. If it succeeds, print it and return.
if(logoPrintFileIfExists(instance, true))
if(logoPrintFileIfExists(instance, true, false))
return;
logoPrintDetected(instance);
+2 -1
View File
@@ -13,6 +13,7 @@ static void printBattery(FFinstance* instance, BatteryResult* result, uint8_t in
ffPrintLogoAndKey(instance, FF_BATTERY_MODULE_NAME, index, &instance->config.battery.key);
bool showStatus =
!(instance->config.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT) &&
result->status.length > 0 &&
ffStrbufIgnCaseCompS(&result->status, "Unknown") != 0;
@@ -35,7 +36,7 @@ static void printBattery(FFinstance* instance, BatteryResult* result, uint8_t in
{
if(str.length > 0)
ffStrbufAppendC(&str, ' ');
ffStrbufAppendF(&str, "%.0f%%", result->capacity);
ffStrbufAppendF(&str, str.length > 0 ? "(%u%%)" : "%u%%", (unsigned) result->capacity);
}
}
+62
View File
@@ -0,0 +1,62 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "detection/brightness/brightness.h"
#define FF_BRIGHTNESS_MODULE_NAME "Brightness"
#define FF_BRIGHTNESS_NUM_FORMAT_ARGS 2
void ffPrintBrightness(FFinstance* instance)
{
FFlist result;
ffListInit(&result, sizeof(FFBrightnessResult));
const char* error = ffDetectBrightness(&result);
if(error)
{
ffPrintError(instance, FF_BRIGHTNESS_MODULE_NAME, 0, &instance->config.brightness, "%s", error);
goto exit;
}
if(result.length == 0)
{
ffPrintError(instance, FF_BRIGHTNESS_MODULE_NAME, 0, &instance->config.brightness, "No result is detected.");
goto exit;
}
FFstrbuf key;
ffStrbufInit(&key);
FF_LIST_FOR_EACH(FFBrightnessResult, item, result)
{
if(instance->config.brightness.key.length == 0)
{
ffStrbufAppendF(&key, "%s (%s)", FF_BRIGHTNESS_MODULE_NAME, item->name.chars);
}
else
{
ffParseFormatString(&key, &instance->config.brightness.key, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &item->name}
});
}
if(instance->config.brightness.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, key.chars, 0, NULL);
printf("%.0f%%\n", item->value);
}
else
{
ffPrintFormatString(instance, key.chars, 0, NULL, &instance->config.brightness.outputFormat, FF_BRIGHTNESS_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &item->value},
{FF_FORMAT_ARG_TYPE_FLOAT, &item->name}
});
}
ffStrbufDestroy(&item->name);
}
ffStrbufDestroy(&key);
exit:
ffListDestroy(&result);
}
+67
View File
@@ -0,0 +1,67 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "common/processing.h"
#include "util/textModifier.h"
#define FF_COMMAND_MODULE_NAME "Command"
static void printError(FFinstance* instance, const char* key, const char* error)
{
ffPrintLogoAndKey(instance, key, 0, NULL);
if(instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
fputs(error, stdout);
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
putchar('\n');
}
void ffPrintCommand(FFinstance* instance)
{
FF_STRBUF_AUTO_DESTROY key;
ffStrbufInit(&key);
if(!ffListShift(&instance->config.commandKeys, &key))
ffStrbufInitS(&key, FF_COMMAND_MODULE_NAME);
FF_STRBUF_AUTO_DESTROY text;
ffStrbufInit(&text);
if(!ffListShift(&instance->config.commandTexts, &text))
{
printError(instance, key.chars, "No command text left");
return;
}
FF_STRBUF_AUTO_DESTROY result;
ffStrbufInit(&result);
const char* error = ffProcessAppendStdOut(&result, (char* const[]){
instance->config.commandShell.chars,
#ifdef _WIN32
"/c",
#else
"-c",
#endif
text.chars,
NULL
});
if(error)
{
printError(instance, key.chars, error);
return;
}
if(!result.length)
{
printError(instance, key.chars, "No result printed");
return;
}
ffPrintLogoAndKey(instance, key.chars, 0, NULL);
puts(result.chars);
}
+16 -5
View File
@@ -47,17 +47,22 @@ static void printDisk(FFinstance* instance, const FFDisk* disk)
ffAppendPercentBar(instance, &str, bytesPercentage, 0, 5, 8);
ffStrbufAppendC(&str, ' ');
}
ffStrbufAppendF(&str, "%s / %s", usedPretty.chars, totalPretty.chars);
if(!(instance->config.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT))
ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars);
if(instance->config.percentType & FF_PERCENTAGE_TYPE_NUM_BIT)
ffStrbufAppendF(&str, " (%u%%)", bytesPercentage);
{
ffStrbufAppendF(&str, str.length > 0 ? "(%u%%) " : "%u%% ", bytesPercentage);
}
}
else
ffStrbufAppendS(&str, "Unknown");
ffStrbufAppendS(&str, "Unknown ");
if(disk->type == FF_DISK_TYPE_EXTERNAL)
ffStrbufAppendS(&str, " [Removable]");
if(disk->type == FF_DISK_TYPE_EXTERNAL && !(instance->config.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT))
ffStrbufAppendS(&str, "[Removable]");
ffStrbufTrimRight(&str, ' ');
ffStrbufPutTo(&str, stdout);
ffStrbufDestroy(&str);
}
@@ -132,9 +137,15 @@ static void printAutodetected(FFinstance* instance, const FFlist* disks)
if(disk->type == FF_DISK_TYPE_EXTERNAL && !instance->config.diskShowRemovable)
continue;
if(disk->type == FF_DISK_TYPE_SUBVOLUME && !instance->config.diskShowSubvolumes)
continue;
if(disk->type == FF_DISK_TYPE_HIDDEN && !instance->config.diskShowHidden)
continue;
if(disk->bytesTotal == 0 && !instance->config.diskShowUnknown)
continue;
printDisk(instance, disk);
}
}
+51
View File
@@ -0,0 +1,51 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "detection/displayserver/displayserver.h"
#define FF_RESOLUTION_MODULE_NAME "Display"
#define FF_RESOLUTION_NUM_FORMAT_ARGS 3
void ffPrintDisplay(FFinstance* instance)
{
#ifdef __ANDROID__
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.display, "Display detection is not supported on Android");
return;
#endif
const FFDisplayServerResult* dsResult = ffConnectDisplayServer(instance);
for(uint32_t i = 0; i < dsResult->displays.length; i++)
{
FFDisplayResult* result = ffListGet(&dsResult->displays, i);
uint8_t moduleIndex = dsResult->displays.length == 1 ? 0 : (uint8_t) (i + 1);
if(instance->config.display.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_RESOLUTION_MODULE_NAME, moduleIndex, &instance->config.display.key);
printf("%ix%i", result->width, result->height);
if(result->refreshRate > 0)
printf(" @ %iHz", result->refreshRate);
if(
result->scaledWidth > 0 && result->scaledWidth != result->width &&
result->scaledHeight > 0 && result->scaledHeight != result->height)
printf(" (as %ix%i)", result->scaledWidth, result->scaledHeight);
putchar('\n');
}
else
{
ffPrintFormat(instance, FF_RESOLUTION_MODULE_NAME, moduleIndex, &instance->config.display, FF_RESOLUTION_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_UINT, &result->width},
{FF_FORMAT_ARG_TYPE_UINT, &result->height},
{FF_FORMAT_ARG_TYPE_UINT, &result->refreshRate},
{FF_FORMAT_ARG_TYPE_UINT, &result->scaledWidth},
{FF_FORMAT_ARG_TYPE_UINT, &result->scaledHeight}
});
}
}
if(dsResult->displays.length == 0)
ffPrintError(instance, FF_RESOLUTION_MODULE_NAME, 0, &instance->config.display, "Couldn't detect display");
}
+9 -3
View File
@@ -48,12 +48,18 @@ static void printFont(const FFFontResult* font)
const char* types[] = { "Caption", "Menu", "Message", "Status" };
for(uint32_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i)
{
if(font->fonts[i].length > 0)
if(i == 0 || !ffStrbufEqual(&font->fonts[i - 1], &font->fonts[i]))
{
printf("%s [%s]", font->fonts[i].chars, types[i]);
break;
if(i > 0)
fputs("], ", stdout);
printf("%s [%s", font->fonts[i].chars, types[i]);
}
else
{
printf(" / %s", types[i]);
}
}
putchar(']');
}
#else
+32 -8
View File
@@ -6,13 +6,13 @@
#include <stdlib.h>
#define FF_GPU_MODULE_NAME "GPU"
#define FF_GPU_NUM_FORMAT_ARGS 5
#define FF_GPU_NUM_FORMAT_ARGS 6
static void printGPUResult(FFinstance* instance, uint8_t index, FFGPUResult* gpu)
static void printGPUResult(FFinstance* instance, uint8_t index, const FFGPUResult* gpu)
{
if(instance->config.gpu.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpu.key);
ffPrintLogoAndKey(instance, FF_GPU_MODULE_NAME, index, &instance->config.gpu.key);
FFstrbuf output;
ffStrbufInitA(&output, gpu->vendor.length + 1 + gpu->name.length);
@@ -37,12 +37,21 @@ static void printGPUResult(FFinstance* instance, uint8_t index, FFGPUResult* gpu
}
else
{
const char* type;
if(gpu->type == FF_GPU_TYPE_INTEGRATED)
type = "Integrated";
else if(gpu->type == FF_GPU_TYPE_DISCRETE)
type = "Discrete";
else
type = "Unknown";
ffPrintFormat(instance, FF_GPU_MODULE_NAME, index, &instance->config.gpu, FF_GPU_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &gpu->vendor},
{FF_FORMAT_ARG_TYPE_STRBUF, &gpu->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &gpu->driver},
{FF_FORMAT_ARG_TYPE_DOUBLE, &gpu->temperature},
{FF_FORMAT_ARG_TYPE_INT, &gpu->coreCount},
{FF_FORMAT_ARG_TYPE_STRING, type},
});
}
}
@@ -51,12 +60,27 @@ void ffPrintGPU(FFinstance* instance)
{
const FFlist* gpus = ffDetectGPU(instance);
if(gpus->length == 0)
FFlist selectedGpus;
ffListInitA(&selectedGpus, sizeof(const FFGPUResult*), gpus->length);
for(uint32_t i = 0; i < gpus->length; i++)
{
ffPrintError(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpu, "No GPUs found");
return;
const FFGPUResult* gpu = ffListGet(gpus, i);
if(gpu->type == FF_GPU_TYPE_INTEGRATED && instance->config.gpuHideIntegrated)
continue;
if(gpu->type == FF_GPU_TYPE_DISCRETE && instance->config.gpuHideDiscrete)
continue;
* (const FFGPUResult**) ffListAdd(&selectedGpus) = gpu;
}
for(uint8_t i = 0; i < (uint8_t) gpus->length; i++)
printGPUResult(instance, gpus->length == 1 ? 0 : (uint8_t) (i + 1), ffListGet(gpus, i));
for(uint32_t i = 0; i < selectedGpus.length; i++)
printGPUResult(instance, selectedGpus.length == 1 ? 0 : (uint8_t) (i + 1), * (const FFGPUResult**) ffListGet(&selectedGpus, i));
if(selectedGpus.length == 0)
ffPrintError(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpu, "No GPUs found");
ffListDestroy(&selectedGpus);
}
+1 -1
View File
@@ -33,7 +33,7 @@ void ffPrintHost(FFinstance* instance)
else
ffStrbufAppend(&output, &host->productFamily);
if(host->productVersion.length > 0)
if(host->productVersion.length > 0 && !ffStrbufIgnCaseEqualS(&host->productVersion, "none"))
{
ffStrbufAppendF(&output, " (%s)", host->productVersion.chars);
}
+10 -10
View File
@@ -2,29 +2,29 @@
#include "common/printing.h"
#define FF_KERNEL_MODULE_NAME "Kernel"
#define FF_KERNEL_NUM_FORMAT_ARGS 3
#define FF_KERNEL_NUM_FORMAT_ARGS 4
void ffPrintKernel(FFinstance* instance)
{
if(instance->config.kernel.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_KERNEL_MODULE_NAME, 0, &instance->config.kernel.key);
ffStrbufWriteTo(&instance->state.platform.systemRelease, stdout);
#ifdef _WIN32
if(instance->state.utsname.version[0] != '\0')
printf("%s (%s)\n", instance->state.utsname.release, instance->state.utsname.version);
else
puts(instance->state.utsname.release);
#else
puts(instance->state.utsname.release);
if(instance->state.platform.systemVersion.length > 0)
printf(" (%s)", instance->state.platform.systemVersion.chars);
#endif
putchar('\n');
}
else
{
ffPrintFormat(instance, FF_KERNEL_MODULE_NAME, 0, &instance->config.kernel, FF_KERNEL_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRING, instance->state.utsname.sysname},
{FF_FORMAT_ARG_TYPE_STRING, instance->state.utsname.release},
{FF_FORMAT_ARG_TYPE_STRING, instance->state.utsname.version}
{FF_FORMAT_ARG_TYPE_STRBUF, &instance->state.platform.systemName},
{FF_FORMAT_ARG_TYPE_STRBUF, &instance->state.platform.systemRelease},
{FF_FORMAT_ARG_TYPE_STRBUF, &instance->state.platform.systemVersion},
{FF_FORMAT_ARG_TYPE_STRBUF, &instance->state.platform.systemArchitecture}
});
}
}
+4 -2
View File
@@ -52,11 +52,13 @@ static void printMemory(FFinstance* instance, const char* name, const FFModuleAr
ffStrbufAppendC(&str, ' ');
}
ffStrbufAppendF(&str, "%s / %s", usedPretty.chars, totalPretty.chars);
if(!(instance->config.percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT))
ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars);
if(instance->config.percentType & FF_PERCENTAGE_TYPE_NUM_BIT)
ffStrbufAppendF(&str, " (%u%%)", percentage);
ffStrbufAppendF(&str, str.length > 0 ? "(%u%%)" : "%u%%", percentage);
ffStrbufTrimRight(&str, ' ');
ffStrbufPutTo(&str, stdout);
ffStrbufDestroy(&str);
}

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