Compare commits

...

76 Commits

Author SHA1 Message Date
Linus Dierheimer 2d0ffb55b7 Release 1.5.3
Enable LTO by default
Fix compile bug when LTO enabled
2022-06-08 17:18:02 +02:00
Linus Dierheimer 22a8cfdcfe Remove obsolete strbuf function 2022-06-08 17:14:11 +02:00
Linus Dierheimer 63041aa24b Enable link time optimization 2022-06-08 16:25:14 +02:00
Linus Dierheimer 242df5f2f0 Explicitly set c standard to 11 2022-06-08 15:52:55 +02:00
Linus Dierheimer ec1bbd118f Update README.md 2022-06-08 12:11:00 +02:00
Linus Dierheimer fe624123dc Merge pull request #168 from Yureien/master
Fix build if ImageMagick is not installed
2022-06-08 12:08:10 +02:00
Linus Dierheimer 8577be3d6d Update packaging section in README 2022-06-08 12:07:06 +02:00
Soham Sen d185dc74b8 Bumped version to 1.5.2 2022-06-08 15:32:52 +05:30
Soham Sen 54c09cab18 Fix build if ImageMagick is not installed 2022-06-08 15:22:34 +05:30
Linus Dierheimer dbe24c7508 Fix --print-logos 2022-06-08 11:28:26 +02:00
Linus Dierheimer d23d4ef5a0 Relase 1.5.0
Module: Vulkan
Module: OpenGL
Module: OpenCL
Feature: Detect Bedrock linux
Feature: Detect packages on Bedrock linux
Feature: --pipe option
Logo: Bedrock linux
Bugfix: Locale detection on Ubuntu and deriviates
Bugfix: bolt keys and title, if main color is not set
2022-06-08 11:17:08 +02:00
Linus Dierheimer daac1b783c Refactored logo choosing logic 2022-06-08 10:59:33 +02:00
Linus Dierheimer 2e98dd7710 Move ffPrintLogoAndKey to printing.c 2022-06-06 14:30:06 +02:00
Linus Dierheimer 9d6d2ca5a4 Add osmesa to help texts 2022-06-06 14:24:14 +02:00
Linus Dierheimer e4a1a836fe Fix keys not being bolt if main color is not set 2022-06-06 14:20:05 +02:00
Linus Dierheimer 1e3cabff2d --pipe option 2022-06-06 14:02:21 +02:00
Linus Dierheimer 008cf3b83d OpenCL module 2022-06-05 00:18:40 +02:00
Linus Dierheimer 3daede53eb Don't cache OS 2022-06-04 22:43:57 +02:00
Linus Dierheimer 36d9b5a9bd Finish OpenGL module 2022-06-04 19:30:26 +02:00
Linus Dierheimer 1826e23c29 OpenGL module 2022-06-04 15:21:34 +02:00
Linus Dierheimer 43b3998b9d Fix bedrock linux detection 2022-06-03 01:48:50 +02:00
Linus Dierheimer c55cc9c732 ffParsePropFileValues: only allocate storage on the heap if numQuerys > 4 2022-06-03 00:24:53 +02:00
Linus Dierheimer 0244e5ebd7 removed unused code 2022-06-02 23:24:50 +02:00
Linus Dierheimer ea6805de82 Escape bedrock option 2022-06-02 23:06:49 +02:00
Linus Dierheimer 9aba57cdea Bedrock package support 2022-06-02 22:58:19 +02:00
Linus Dierheimer 0dffd8debf Vulkan module 2022-06-01 00:04:58 +02:00
Linus Dierheimer 032ba375b6 Enable chafa only if ImageMagick is found 2022-05-29 16:23:56 +02:00
Linus Dierheimer 743bc07bad Correctly detect locale on ubuntu systems 2022-05-29 16:17:36 +02:00
Linus Dierheimer 044e5496fd Fix bedrock logo 2022-05-25 14:28:08 +02:00
Linus Dierheimer 102b2d33c7 Bedrock linux detection 2022-05-25 14:06:59 +02:00
Linus Dierheimer afc144fa01 Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2022-05-25 14:00:36 +02:00
Linus Dierheimer ededa4d6dd Bedrock linux logo 2022-05-25 14:00:18 +02:00
Linus Dierheimer af4596b666 Bedrock linux 2022-05-25 13:59:40 +02:00
Linus Dierheimer 8c910089cc Detect KDE plasma version more reliable 2022-05-24 13:58:38 +02:00
Linus Dierheimer e79af7ba79 Relase 1.4.2
Bugfix: RPM package count on SUSE platforms
Bugfix: Prepend /var with TARGET_DIR_ROOT
2022-05-24 13:41:23 +02:00
Linus Dierheimer 960364bd47 Use librpm as rpm fallback 2022-05-24 13:36:33 +02:00
Linus Dierheimer ea44231c78 Don't prepend proc with TARGET_DIR_ROOT
Should make future packaging for termux simpler
2022-05-23 20:01:18 +02:00
Linus Dierheimer 60af0b9e39 Release 1.4.0
Feature: Display images converted to ascii art as logo, using chafa
Feature: Stretch images by using the --logo-height option
Logo: RedstarOS
Logo: Devuan
Logo: Rocky
Bugfix: Better calculation of image dimensions
Bugfix: Better rpm package detection
Bugfix: Format uptime right, when hours > 0 and minutes = 0
Bugfix: Only detect themes for installed gtk versions
2022-05-23 19:39:49 +02:00
Linus Dierheimer e4ecb9d069 Use sqlite to get rpm package count 2022-05-23 19:30:02 +02:00
Linus Dierheimer 3c648d84db Better GTK detection 2022-05-23 16:19:58 +02:00
Linus Dierheimer 45db4a5c3d Fix possible use after free 2022-05-23 15:50:25 +02:00
Linus Dierheimer caf976bec2 Fix building without chafa enabled 2022-05-23 15:36:19 +02:00
Linus Dierheimer b3d855355e Rewrote image dimension calculation 2022-05-23 15:32:10 +02:00
Linus Dierheimer 0a2eb49891 Merge pull request #164 from draumaz/master
Add Rocky Linux logo
2022-05-23 12:34:06 +02:00
draumaz ab2efa151a update readme 2022-05-23 03:29:04 -07:00
draumaz 1aee3f81c5 added Rocky Linux logo 2022-05-23 03:22:39 -07:00
Linus Dierheimer 4c7031cb12 Merge pull request #161 from Samisafool/patch-1
Typo
2022-05-16 11:51:08 +02:00
Samisafool 81c96d0f11 Typo 2022-05-16 09:54:48 +05:30
Linus Dierheimer 4d8680ec2d Merge pull request #160 from draumaz/master
Add Devuan logo
2022-05-15 23:46:56 +02:00
draumaz 039eb3a38a Fix alphabetical ordering 2022-05-15 13:48:10 -07:00
draumaz d07a653404 Update README.md 2022-05-15 13:45:31 -07:00
draumaz 76c0b7e457 Update README.md 2022-05-15 13:43:36 -07:00
draumaz 1c0e532b79 add Devuan 2022-05-15 06:22:28 -07:00
Linus Dierheimer c79a9f1bff Format uptime better 2022-05-14 14:13:10 +02:00
Linus Dierheimer 759069adfa Merge pull request #157 from Samisafool/patch-1
Fix bug_report.md
2022-05-14 14:03:04 +02:00
Samisafool 66ff6adfb0 Update bug_report.md 2022-05-13 14:06:05 +05:30
Samisafool 1dba19c49f Typo 2022-05-12 08:29:47 +05:30
Samisafool 2afd158d96 Fix bug_report.md 2022-05-12 08:28:24 +05:30
Linus Dierheimer 36c2ce6219 Look for newer versions of librpm 2022-05-05 15:48:01 +02:00
Linus Dierheimer 5f6432c150 RedstarOS logo 2022-05-04 18:11:32 +02:00
Linus Dierheimer e9f0eca3dd Add documentation about logo height option 2022-04-30 11:25:22 +02:00
Linus Dierheimer 998691847e logo-height option 2022-04-30 11:22:51 +02:00
Linus Dierheimer 64e5ef0df7 Fix output with no custom logo 2022-04-29 21:52:42 +02:00
Linus Dierheimer cc1e876faf Better automatic logo type detection 2022-04-29 21:44:32 +02:00
Linus Dierheimer 964a5aa8b4 Add chafa to feature list 2022-04-29 14:11:22 +02:00
Linus Dierheimer ad2601f097 Fix visual bug in README.md 2022-04-29 13:08:39 +02:00
Linus Dierheimer 7cae63ac05 Require chafa>=1.10 2022-04-29 13:07:20 +02:00
Linus Dierheimer 0d26cfb218 Dont try to build with ubuntu's outdated chafa enabled 2022-04-29 13:05:38 +02:00
Linus Dierheimer 3b6855b9da Build github packages with chafa support 2022-04-28 19:17:13 +02:00
Linus Dierheimer 51414c5511 Ascii image output using chafa 2022-04-28 19:15:46 +02:00
Linus Dierheimer 24f8ad7673 Release 1.3.4
* Bugfix: Using custom logos in terminals that don't support \033[14t or \033[18t once again works
* Feature: Ubuntu flavour detection
* Feature: Kubuntu logo
* Feature: Deepin logo
2022-04-27 08:03:15 +02:00
Linus Dierheimer e404dd62c0 Check for ubuntu flavours 2022-04-26 19:21:19 +02:00
Linus Dierheimer 21b315d548 Use a timeout when waiting for terminal responses 2022-04-26 17:17:16 +02:00
Linus Dierheimer 14fa052257 Use reasonable timeout for dbus 2022-04-25 18:42:05 +02:00
Linus Dierheimer 5861012d95 Deepin logo 2022-04-25 18:01:29 +02:00
Linus Dierheimer 4d9fbd93d2 Kubuntu logo 2022-04-25 17:51:51 +02:00
53 changed files with 2683 additions and 970 deletions
+10 -4
View File
@@ -7,6 +7,13 @@ assignees: ''
---
# General description of bug:
# Often helpful questions:
* Does the issue occur across multiple terminal emulators? [Y/N]
* Does the issue occur across multiple shells? (bash, zsh, fish, etc) [Y/N]
Output of `fastfetch --version`:
```
//paste here
@@ -27,9 +34,8 @@ Output of `fastfetch --list-features`:
//paste here
```
<!--
If you get the following error: `Error: couldn't find config: [...]`, copy the files in [presets](../../presets/) to `/usr/share/fastfetch/presets/` or `~/.local/share/fastfetch/presets/`.
If this isn't possible (or to much work) for you, post the output of `fastfetch --show-errors --recache --multithreading false --disable-linewrap false`.
If this isn't possible (or too much work) for you, post the output of `fastfetch --show-errors --recache --multithreading false --disable-linewrap false`.
-->
Often helpful questions:
* Does the issue occur across multiple terminal emulators?
* Does the issue occur across multiple shells? (bash, zsh, fish, etc)
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
uses: actions/checkout@v2
- 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 rpm librpm-dev libzstd-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
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v2
- 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 rpm librpm-dev libzstd-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
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
+146 -43
View File
@@ -1,20 +1,13 @@
cmake_minimum_required(VERSION 3.1.0) # Threads::Threads
cmake_minimum_required(VERSION 3.9.0) # CMAKE_INTERPROCEDURAL_OPTIMIZATION
project(fastfetch
VERSION 1.3.3
VERSION 1.5.3
LANGUAGES C
)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
# This is set to off by github actions for release builds
OPTION(SET_TWEAK "Add tweak to project version" ON)
# Also create test executables
OPTION(BUILD_TESTS "Build tests" OFF)
#####################
# Configure options #
#####################
OPTION(ENABLE_LIBPCI "Enable libpci" ON)
OPTION(ENABLE_VULKAN "Enable vulkan" ON)
@@ -27,19 +20,50 @@ OPTION(ENABLE_GIO "Enable gio-2.0" ON)
OPTION(ENABLE_DCONF "Enable dconf" ON)
OPTION(ENABLE_DBUS "Enable dbus-1" ON)
OPTION(ENABLE_XFCONF "Enable libxfconf-0" ON)
OPTION(ENABLE_SQLITE3 "Enable sqlite3" ON)
OPTION(ENABLE_RPM "Enable rpm" ON)
OPTION(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON)
OPTION(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON)
OPTION(ENABLE_ZLIB "Enable zlib" ON)
OPTION(ENABLE_CHAFA "Enable chafa" ON)
OPTION(ENABLE_EGL "Enable egl" ON)
OPTION(ENABLE_GLX "Enable glx" ON)
OPTION(ENABLE_OSMESA "Enable osmesa" ON)
OPTION(ENABLE_OPENCL "Enable opencl" ON)
OPTION(BUILD_TESTS "Build tests" OFF) # Also create test executables
OPTION(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds
#############################
# Compile time dependencies #
#############################
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
####################
# Compiler options #
####################
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wconversion")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-Wl,-O3")
# These variables are mainly here for android, which has a different root fs structure.
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_SUPPORTED)
if(IPO_SUPPORTED)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
#######################
# Target FS structure #
#######################
if(NOT TARGET_DIR_ROOT)
if(NOT ANDROID)
set(TARGET_DIR_ROOT "")
@@ -64,15 +88,10 @@ if(NOT TARGET_DIR_HOME)
endif()
endif()
function(fastfetch_load_text FILENAME OUTVAR)
file(READ "${FILENAME}" TEMP)
string(REPLACE "\n" "\\n" TEMP "${TEMP}")
string(REPLACE "\"" "\\\"" TEMP "${TEMP}")
string(REPLACE "$\\" "" TEMP "${TEMP}")
set("${OUTVAR}" "${TEMP}" PARENT_SCOPE)
endfunction(fastfetch_load_text)
#################
# Tweak version #
#################
# Track commits between version bumps for output in --version
if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
execute_process(
COMMAND git describe --tags
@@ -83,6 +102,18 @@ if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
string(REGEX MATCH "-[0-9]+" PROJECT_VERSION_TWEAK "${PROJECT_VERSION_TWEAK}")
endif()
#############
# Text data #
#############
function(fastfetch_load_text FILENAME OUTVAR)
file(READ "${FILENAME}" TEMP)
string(REPLACE "\n" "\\n" TEMP "${TEMP}")
string(REPLACE "\"" "\\\"" TEMP "${TEMP}")
string(REPLACE "$\\" "" TEMP "${TEMP}")
set("${OUTVAR}" "${TEMP}" PARENT_SCOPE)
endfunction(fastfetch_load_text)
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
fastfetch_load_text(src/data/config.txt DATATEXT_CONFIG)
fastfetch_load_text(src/data/modules.txt DATATEXT_MODULES)
@@ -91,9 +122,15 @@ fastfetch_load_text(src/data/help_color.txt DATATEXT_HELP_COLOR)
fastfetch_load_text(src/data/help_format.txt DATATEXT_HELP_FORMAT)
fastfetch_load_text(src/data/help_config.txt DATATEXT_HELP_CONFIG)
######################
# Configure config.h #
######################
configure_file(src/fastfetch_config.h.in fastfetch_config.h)
# Init CMake targets
#######################
# libfastfetch target #
#######################
add_library(libfastfetch STATIC
src/util/FFstrbuf.c
@@ -121,6 +158,7 @@ add_library(libfastfetch STATIC
src/detection/plasma.c
src/detection/gtk.c
src/detection/terminalShell.c
src/detection/vulkan.c
src/detection/media.c
src/detection/datetime.c
src/detection/displayserver/displayServer.c
@@ -156,6 +194,7 @@ add_library(libfastfetch STATIC
src/modules/disk.c
src/modules/battery.c
src/modules/locale.c
src/modules/vulkan.c
src/modules/localip.c
src/modules/publicip.c
src/modules/player.c
@@ -164,6 +203,8 @@ add_library(libfastfetch STATIC
src/modules/date.c
src/modules/time.c
src/modules/colors.c
src/modules/opengl.c
src/modules/opencl.c
)
if(ENABLE_LIBPCI)
@@ -265,12 +306,21 @@ if(ENABLE_XFCONF)
endif()
endif()
if(ENABLE_SQLITE3)
pkg_check_modules(SQLITE3 sqlite3)
if(SQLITE3_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_SQLITE3=1)
else()
message(WARNING "Package sqlite3 not found. Building without support.")
endif()
endif()
if(ENABLE_RPM)
pkg_check_modules(RPM rpm)
if(RPM_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_RPM=1)
else()
message(WARNING "Package librpm not found. Building without support.")
message(WARNING "Package rpm not found. Building without support.")
endif()
endif()
@@ -321,6 +371,55 @@ if(ENABLE_ZLIB)
endif()
endif()
if(ENABLE_CHAFA)
if(IMAGEMAGICK6_FOUND OR IMAGEMAGICK7_FOUND)
pkg_check_modules(CHAFA chafa>=1.10)
if(CHAFA_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CHAFA=1)
else()
message(WARNING "Package chafa>=1.10 not found. Building without support.")
endif()
else()
message(WARNING "Chafa not enabled, because neither ImageMagick6 nor ImageMagick7 were found. Building without support.")
endif()
endif()
if(ENABLE_EGL)
pkg_check_modules(EGL egl)
if(EGL_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EGL=1)
else()
message(WARNING "Package egl not found. Building without support.")
endif()
endif()
if(ENABLE_GLX)
pkg_check_modules(GLX glx)
if(GLX_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GLX=1)
else()
message(WARNING "Package glx not found. Building without support.")
endif()
endif()
if(ENABLE_OSMESA)
pkg_check_modules(OSMESA osmesa)
if(OSMESA_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_OSMESA=1)
else()
message(WARNING "Package osmesa not found. Building without support.")
endif()
endif()
if(ENABLE_OPENCL)
pkg_check_modules(OPENCL OpenCL)
if(OPENCL_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_OPENCL=1)
else()
message(WARNING "Package opencl not found. Building without support.")
endif()
endif()
target_include_directories(libfastfetch
PUBLIC ${PROJECT_BINARY_DIR}
PUBLIC ${PROJECT_SOURCE_DIR}/src
@@ -336,10 +435,17 @@ target_include_directories(libfastfetch
PRIVATE ${DCONF_INCLUDE_DIRS}
PRIVATE ${DBUS_INCLUDE_DIRS}
PRIVATE ${XFCONF_INCLUDE_DIRS}
PRIVATE ${SQLITE3_INCLUDE_DIRS}
PRIVATE ${RPM_INCLUDE_DIRS}
PRIVATE ${IMAGEMAGICK7_INCLUDE_DIRS}
PRIVATE ${IMAGEMAGICK6_INCLUDE_DIRS}
PRIVATE ${ZLIB_INCLUDE_DIRS}
PRIVATE ${CHAFA_INCLUDE_DIRS}
PRIVATE ${VULKAN_INCLUDE_DIRS}
PRIVATE ${EGL_INCLUDE_DIRS}
PRIVATE ${GLX_INCLUDE_DIRS}
PRIVATE ${OSMESA_INCLUDE_DIRS}
PRIVATE ${OPENCL_INCLUDE_DIRS}
)
target_link_libraries(libfastfetch
@@ -347,7 +453,13 @@ target_link_libraries(libfastfetch
PRIVATE Threads::Threads
)
set_target_properties(libfastfetch PROPERTIES OUTPUT_NAME "fastfetch")
set_target_properties(libfastfetch PROPERTIES
OUTPUT_NAME "fastfetch"
)
######################
# Executable targets #
######################
add_executable(fastfetch
src/fastfetch.c
@@ -363,7 +475,9 @@ target_link_libraries(flashfetch
PRIVATE libfastfetch
)
# Testing
###################
# Testing targets #
###################
if (BUILD_TESTS)
add_executable(fastfetch-test-performance
@@ -384,7 +498,9 @@ if (BUILD_TESTS)
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
endif()
# Installation
##################
# install target #
##################
include(GNUInstallDirs)
@@ -414,7 +530,9 @@ install(
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/licenses/${CMAKE_PROJECT_NAME}
)
# Packaging
##################
# package target #
##################
set(CPACK_GENERATOR "DEB;RPM;TGZ;ZIP")
@@ -429,21 +547,6 @@ set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/LinusDierheimer")
set(CPACK_DEBIAN_PACKAGE_SECTION, "utils")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "\
libpci3, \
libvulkan1, \
libwayland-client0, \
libxcb-randr0, \
xcb, \
libxrandr2, \
libx11-6, \
libdconf1, \
libglib2.0-0, \
libdbus-1-3, \
libxfconf-0-3, \
libmagickcore-6.q16hdri-6, \
zlib1g \
")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
-2
View File
@@ -11,11 +11,9 @@ Here i just add things that are easy to forget.
- `libffdetect`: contains all the detection stuff. To be used by anything that needs system information
- `libffprint`: contains the printing functions, logos, format etc
- `fastfetch` and `flashfetch`: Executables, that initialize the config of libffprint. Fist one at runtime, second one at compile time
- [ ] Support for printing images as ascii art logos (using imlib2 and libcaca probably)
- [ ] Better OS output for all possible combinations of /etc/os-release variables.
- [ ] Expose temperatures to CPU format string
- [ ] Expose temperatures to GPU format string
- [ ] Fallback GPU detection using GL (multi GPU suport somehow possible?)
- [ ] Find wayland compositor by looking at \${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY:-wayland-0}
- [ ] Make LocalIP module more configurable
- [ ] Automatic migrate old config files to newer versions
+33 -24
View File
@@ -19,32 +19,38 @@ There are some presets defined for fastfech in [`presets`](presets), you can can
Fastfetch dynamically loads needed libraries if they are available. Therefore its only hard dependencies are `libc` (any implementation of the c standard library), `libdl` and `libpthread`. They are all shipped with [`glibc`](https://www.gnu.org/software/libc/), which is already installed on most linux distributions, so you probably don't have to worry about it.
The following libraries are used if present at runtime:
* [`libpci`](https://github.com/pciutils/pciutils): GPU output.
* [`libvulkan`](https://www.vulkan.org/): Fallback for GPU output.
* [`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.
* [`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.
* [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol.
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song.
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
* [`librpm`](http://rpm.org/): Needed for rpm package count.
* [`libpci`](https://github.com/pciutils/pciutils): GPU output.
* [`libvulkan`](https://www.vulkan.org/): Vulkan module & fallback for GPU output.
* [`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.
* [`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.
* [`libchafa`](https://github.com/hpjansson/chafa): Image output as ascii art.
* [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol.
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song.
* [`libEGL`](https://www.khronos.org/registry/EGL/),
[`libGLX`](https://dri.freedesktop.org/wiki/GLX/),
[`libOSMesa`](https://docs.mesa3d.org/osmesa.html): At least one of them is needed by the OpenGL module for gl context creation.
* [`libOpenCL`](https://www.khronos.org/opencl/): OpenCL module
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
* [`libsqlite3`](https://www.sqlite.org/index.html): Needed for rpm package count.
* [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE.
## Support status
All categories not listed here should work without needing a specific implementation.
##### Available Modules
```
Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resolution, DE, WM, WMTheme, Theme, Icons, Font, Cursor, Terminal, Terminal Font, CPU, CPUUsage, GPU, Memory, Disk, Battery, Player, Song, LocalIP, PublicIP, DateTime, Date, Time, Locale, Colors, Break, Custom
Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resolution, DE, WM, WMTheme, Theme, Icons, Font, Cursor, Terminal, Terminal Font, CPU, CPUUsage, GPU, Memory, Disk, Battery, Player, Song, Vulkan, OpenGL, OpenCL, LocalIP, PublicIP, DateTime, Date, Time, Locale, Colors, Break, Custom
```
##### Logos
```
Android, Arch, Arco, Artix, CachyOS, CentOS, Debian, Endeavour, Fedora, Garuda, Gentoo, KDE Neon, Linux, Manjaro, Mint, NixOS, OpenSUSE, OpenSUSE Tumbleweed, OpenSUSE LEAP, Pop!_OS, RebornOS, Ubuntu, Void, Zorin
Android, Arch, Arco, Artix, Bedrock, CachyOS, CentOS, Debian, Devuan, Deepin, Endeavour, Fedora, Garuda, Gentoo, KDE Neon, Kubuntu, Linux, Manjaro, Mint, NixOS, OpenSUSE, OpenSUSE Tumbleweed, OpenSUSE LEAP, Pop!_OS, RebornOS, RedstarOS, Rocky, Ubuntu, Void, 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.
@@ -79,20 +85,23 @@ fastfetch uses [`cmake`](https://cmake.org/) and [`pkg-config`](https://www.free
mkdir -p build
cd build
cmake ..
cmake --build . -j$(nproc) --target fastfetch --target flashfetch
cmake --build . --target fastfetch --target flashfetch
```
If pkg-config fails to find the headers for a library listed in [dependencies](#dependencies), fastfetch will simply build without support for that specific feature. This means, it won't look for it at runtime and just act like it isn't available.
## Packaging
* [AUR](https://aur.archlinux.org/packages/fastfetch-git/): Packaged by me. Will install the fastfetch binary, bash completion and the presets. Git version
* [Manjaro Repositories](https://gitlab.manjaro.org/packages/community/fastfetch): Packaged by a manjaro maintainer. Usually a bit outdated.
* [Gentoo (Guru)](https://github.com/gentoo/guru/tree/master/app-misc/fastfetch): Packed by some other guy. May be out of date some times.
* DEB / RPM: Run `cmake -B build && cmake --build build --target package` to build the packages in build.
* Manually:
* Build: Follow the [build instructions](#building).
* Install: `sudo cmake --install build --prefix /usr/local`
### Repositories
[![Packaging status](https://repology.org/badge/vertical-allrepos/fastfetch.svg?header=)](https://repology.org/project/fastfetch/versions)
### Manual
Build: Follow the [build instructions](#building).
* Create DEB / RPM: Run `cmake --build . --target package`.
* Install directly: Run `sudo cmake --install . --prefix /usr/local`
## FAQ
+16 -1
View File
@@ -130,6 +130,8 @@ __fastfetch_completion()
"--localip-show-ipv4"
"--localip-show-ipv6"
"--localip-show-loop"
"--escape-bedrock"
"--pipe"
)
local FF_OPTIONS_STRING=(
@@ -152,6 +154,7 @@ __fastfetch_completion()
"-s"
"--structure"
"--set"
"--gl"
"--os-format"
"--os-key"
"--host-format"
@@ -216,6 +219,12 @@ __fastfetch_completion()
"--date-key"
"--time-format"
"--time-key"
"--vulkan-key"
"--vulkan-format"
"--opengl-key"
"--opengl-format"
"--opencl-key"
"--opencl-format"
)
local FF_OPTIONS_PATH=(
@@ -231,9 +240,15 @@ __fastfetch_completion()
"--lib-DConf"
"--lib-DBus"
"--lib-XFConf"
"--lib-RPM"
"--lib-sqlite3"
"--lib-rpm"
"--lib-imagemagick"
"--lib-z"
"--lib-chafa"
"--lib-egl"
"--lib-glx"
"--lib-osmesa"
"--lib-opencl"
"--battery-dir"
"--load-config"
)
+1 -1
View File
@@ -1 +1 @@
--structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Break:Colors
--structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:OpenGL:OpenCL:Break:Colors
+3
View File
@@ -26,3 +26,6 @@
--player-format "Name: {}"
--song-format "Song: {}; Artist: {}; Album: {}"
--datetime-format "year: {}; yearShort: {}; month: {}; monthPretty: {}; monthName: {}; monthNameShort: {}; weekNumber: {}; weekday: {}; weekdayShort: {}; dayInYear: {}; dayInMonth: {}; dayInWeek: {}; hour: {}; hourPretty: {}; hour12: {}; hour12Pretty: {}; minute: {}; minutePretty: {}; second: {}; secondPretty: {}"
--vulkan-format "driver: {}; Api Version: {}; Conformance Version: {}"
--opengl-format "version: {}; renderer: {}; vendor: {}"
--opencl-format "version: {}; device: {}; vendor: {}"
-3
View File
@@ -35,9 +35,6 @@ static void writeCacheFile(FFinstance* instance, const char* moduleName, const c
void ffCacheValidate(FFinstance* instance)
{
if(instance->config.recache)
return;
FFstrbuf content;
ffStrbufInit(&content);
readCacheFile(instance, "cacheversion", "ffv", &content);
+59 -21
View File
@@ -108,7 +108,8 @@ static void defaultConfig(FFinstance* instance)
instance->config.logoType = FF_LOGO_TYPE_AUTO;
for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i)
ffStrbufInit(&instance->config.logoColors[i]);
instance->config.logoWidth = 65;
instance->config.logoWidth = 0;
instance->config.logoHeight = 0; //preserve aspect ratio
instance->config.logoPaddingLeft = 0;
instance->config.logoPaddingRight = 4;
instance->config.logoPrintRemaining = true;
@@ -123,6 +124,9 @@ static void defaultConfig(FFinstance* instance)
instance->config.allowSlowOperations = false;
instance->config.disableLinewrap = true;
instance->config.hideCursor = true;
instance->config.escapeBedrock = true;
instance->config.glType = FF_GL_TYPE_AUTO;
instance->config.pipe = false;
ffStrbufInitA(&instance->config.osFormat, 0);
ffStrbufInitA(&instance->config.osKey, 0);
@@ -186,6 +190,12 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.dateFormat, 0);
ffStrbufInitA(&instance->config.timeKey, 0);
ffStrbufInitA(&instance->config.timeFormat, 0);
ffStrbufInitA(&instance->config.vulkanKey, 0);
ffStrbufInitA(&instance->config.vulkanFormat, 0);
ffStrbufInitA(&instance->config.openGLKey, 0);
ffStrbufInitA(&instance->config.openGLFormat, 0);
ffStrbufInitA(&instance->config.openCLKey, 0);
ffStrbufInitA(&instance->config.openCLFormat, 0);
ffStrbufInitA(&instance->config.libPCI, 0);
ffStrbufInitA(&instance->config.libVulkan, 0);
@@ -198,9 +208,15 @@ static void defaultConfig(FFinstance* instance)
ffStrbufInitA(&instance->config.libDConf, 0);
ffStrbufInitA(&instance->config.libDBus, 0);
ffStrbufInitA(&instance->config.libXFConf, 0);
ffStrbufInitA(&instance->config.libSQLite3, 0);
ffStrbufInitA(&instance->config.librpm, 0);
ffStrbufInitA(&instance->config.libImageMagick, 0);
ffStrbufInitA(&instance->config.libZ, 0);
ffStrbufInitA(&instance->config.libChafa, 0);
ffStrbufInitA(&instance->config.libEGL, 0);
ffStrbufInitA(&instance->config.libGLX, 0);
ffStrbufInitA(&instance->config.libOSMesa, 0);
ffStrbufInitA(&instance->config.libOpenCL, 0);
ffStrbufInitA(&instance->config.diskFolders, 0);
@@ -225,29 +241,29 @@ void ffInitInstance(FFinstance* instance)
defaultConfig(instance);
}
static void resetConsole(bool disableLinewrap, bool hideCursor)
{
if(disableLinewrap)
fputs("\033[?7h", stdout);
if(hideCursor)
fputs("\033[?25h", stdout);
}
static volatile bool ffDisableLinewrap = true;
static volatile bool ffHideCursor = true;
static void resetConsole()
{
if(ffDisableLinewrap)
fputs("\033[?7h", stdout);
if(ffHideCursor)
fputs("\033[?25h", stdout);
}
static void exitSignalHandler(int signal)
{
FF_UNUSED(signal);
resetConsole(ffDisableLinewrap, ffHideCursor);
resetConsole();
exit(0);
}
void ffStart(FFinstance* instance)
{
ffDisableLinewrap = instance->config.disableLinewrap;
ffHideCursor = instance->config.hideCursor;
ffDisableLinewrap = instance->config.disableLinewrap && !instance->config.pipe;
ffHideCursor = instance->config.hideCursor && !instance->config.pipe;
struct sigaction action = {};
action.sa_handler = exitSignalHandler;
@@ -257,24 +273,28 @@ void ffStart(FFinstance* instance)
sigaction(SIGQUIT, &action, NULL);
//We do the cache validation here, so we can skip it if --recache is given
ffCacheValidate(instance);
if(!instance->config.recache)
ffCacheValidate(instance);
//reset everything to default before we start printing
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
if(instance->config.hideCursor)
if(ffHideCursor)
fputs("\033[?25l", stdout);
if(instance->config.disableLinewrap)
if(ffDisableLinewrap)
fputs("\033[?7l", stdout);
ffPrintLogo(instance);
ffLogoPrint(instance);
}
void ffFinish(FFinstance* instance)
{
ffPrintRemainingLogo(instance);
resetConsole(instance->config.disableLinewrap, instance->config.hideCursor);
if(instance->config.logoPrintRemaining)
ffLogoPrintRemaining(instance);
resetConsole();
}
//Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
@@ -317,14 +337,32 @@ void ffListFeatures()
#ifdef FF_HAVE_IMAGEMAGICK6
"imagemagick6\n"
#endif
#ifdef FF_HAVE_CHAFA
"chafa\n"
#endif
#ifdef FF_HAVE_ZLIB
"zlib\n"
#endif
#ifdef FF_HAVE_XFCONF
"xfconf\n"
#endif
#ifdef FF_HAVE_SQLITE3
"sqlite3\n"
#endif
#ifdef FF_HAVE_RPM
"librpm\n"
"rpm\n"
#endif
#ifdef FF_HAVE_EGL
"egl\n"
#endif
#ifdef FF_HAVE_GLX
"glx\n"
#endif
#ifdef FF_HAVE_OSMESA
"osmesa\n"
#endif
#ifdef FF_HAVE_OPENCL
"opencl\n"
#endif
""
, stdout);
+26 -16
View File
@@ -1,11 +1,11 @@
#include "fastfetch.h"
#include <stdio.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <termios.h>
#include <poll.h>
bool ffWriteFDContent(int fd, const FFstrbuf* content)
{
@@ -61,7 +61,7 @@ void ffAppendFDContent(int fd, FFstrbuf* buffer)
(uint32_t) readed == free
) {
buffer->length += (uint32_t) readed;
ffStrbufEnsureCapacity(buffer, (buffer->allocated * 2) - 1); // -1 for null terminator
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
free = ffStrbufGetFree(buffer);
}
@@ -128,32 +128,42 @@ bool ffFileExists(const char* fileName, mode_t mode)
return stat(fileName, &fileStat) == 0 && ((fileStat.st_mode & S_IFMT) == mode);
}
void ffGetTerminalResponse(const char* request, char end, const char* format, ...)
void ffGetTerminalResponse(const char* request, const char* format, ...)
{
struct termios oldTerm, newTerm;
tcgetattr(STDIN_FILENO, &oldTerm);
if(tcgetattr(STDIN_FILENO, &oldTerm) == -1)
return;
newTerm = oldTerm;
newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newTerm);
if(tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) == -1)
return;
fputs(request, stdout);
fflush(stdout);
struct pollfd pfd;
pfd.fd = STDIN_FILENO;
pfd.events = POLLIN;
pfd.revents = 0;
//Give the terminal 35ms to respond
if(poll(&pfd, 1, 35) <= 0)
{
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm);
return;
}
char buffer[512];
int pos = 0;
while((size_t) pos < sizeof(buffer) - 1)
{
char c = (char) getc(stdin);
if(c == '\0')
break;
buffer[pos++] = c;
if(c == end)
break;
}
buffer[pos] = '\0';
ssize_t readed = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm);
if(readed <= 0)
return;
buffer[readed] = '\0';
va_list args;
va_start(args, format);
vsscanf(buffer, format, args);
+26
View File
@@ -39,6 +39,32 @@ void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* mino
ffStrbufAppend(buffer, patch);
}
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2)
{
if(version1->major != version2->major)
return version1->major > version2->major ? 1 : -1;
if(version1->minor != version2->minor)
return version1->minor > version2->minor ? 1 : -1;
if(version1->patch != version2->patch)
return version1->patch > version2->patch ? 1 : -1;
return 0;
}
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
{
if(version->major > 0 || version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, "%u", version->major);
if(version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->minor);
if(version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->patch);
}
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
{
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
+42
View File
@@ -1,5 +1,42 @@
#include "fastfetch.h"
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
{
ffLogoPrintLine(instance);
if(!instance->config.pipe)
{
fputs(FASTFETCH_TEXT_MODIFIER_RESET FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.mainColor);
}
if(customKeyFormat == NULL || customKeyFormat->length == 0)
{
fputs(moduleName, stdout);
if(moduleIndex > 0)
printf(" %hhu", moduleIndex);
}
else
{
FFstrbuf key;
ffStrbufInit(&key);
ffParseFormatString(&key, customKeyFormat, NULL, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT8, &moduleIndex}
});
ffStrbufWriteTo(&key, stdout);
ffStrbufDestroy(&key);
}
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
ffStrbufWriteTo(&instance->config.separator, stdout);
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numFormatArgs, const char* message, ...)
{
if(!instance->config.showErrors)
@@ -50,6 +87,11 @@ void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t m
void ffPrintColor(const FFstrbuf* colorValue)
{
//If the color is not set, this would reset in \033[m, which resets everything.
//So we only print it, if the main color is at least one char.
if(colorValue->length == 0)
return;
fputs("\033[", stdout);
ffStrbufWriteTo(colorValue, stdout);
fputc('m', stdout);
+21 -11
View File
@@ -90,24 +90,33 @@ bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer)
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
{
bool* searchedValues = malloc(sizeof(bool) * numQueries);
bool valueStorage[4];
bool* unsetValues;
if(numQueries > sizeof(valueStorage) / sizeof(valueStorage[0]))
unsetValues = malloc(sizeof(bool) * numQueries);
else
unsetValues = valueStorage;
bool allSet = true;
for(uint32_t i = 0; i < numQueries; i++)
{
if((searchedValues[i] = queries[i].buffer->length == 0))
if((unsetValues[i] = queries[i].buffer->length == 0))
allSet = false;
}
if(allSet)
{
free(searchedValues);
return true;
}
FILE* file = fopen(filename, "r");
if(file == NULL)
return false;
if(allSet)
{
fclose(file);
if(unsetValues != valueStorage)
free(unsetValues);
return true;
}
char* line = NULL;
size_t len = 0;
@@ -115,7 +124,7 @@ bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquer
{
for(uint32_t i = 0; i < numQueries; i++)
{
if(!searchedValues[i])
if(!unsetValues[i])
continue;
uint32_t currentLength = queries[i].buffer->length;
@@ -125,13 +134,14 @@ bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquer
}
}
free(searchedValues);
if(line != NULL)
free(line);
fclose(file);
if(unsetValues != valueStorage)
free(unsetValues);
return true;
}
+69
View File
@@ -1,6 +1,7 @@
#include "fastfetch.h"
#include <pthread.h>
#include <string.h>
#define FF_LIBRARY_DATA_LOAD_INIT(dataObject, userLibraryName, ...) \
static dataObject data; \
@@ -267,6 +268,74 @@ FFvariant ffSettingsGetXFConf(FFinstance* instance, const char* channelName, con
}
#endif //FF_HAVE_XFCONF
#ifdef FF_HAVE_SQLITE3
#include <sqlite3.h>
typedef struct SQLiteData
{
FF_LIBRARY_SYMBOL(sqlite3_open_v2)
FF_LIBRARY_SYMBOL(sqlite3_prepare_v2)
FF_LIBRARY_SYMBOL(sqlite3_step)
FF_LIBRARY_SYMBOL(sqlite3_data_count)
FF_LIBRARY_SYMBOL(sqlite3_column_int)
FF_LIBRARY_SYMBOL(sqlite3_finalize)
FF_LIBRARY_SYMBOL(sqlite3_close)
} SQLiteData;
static const SQLiteData* getSQLiteData(const FFinstance* instance)
{
FF_LIBRARY_DATA_LOAD_INIT(SQLiteData, instance->config.libSQLite3, "libsqlite3.so", 1);
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_open_v2)
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_prepare_v2)
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_step)
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_data_count)
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_column_int)
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_finalize)
FF_LIBRARY_DATA_LOAD_SYMBOL(sqlite3_close)
FF_LIBRARY_DATA_LOAD_RETURN
}
int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query)
{
const SQLiteData* data = getSQLiteData(instance);
if(data == NULL)
return 0;
sqlite3* db;
if(data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK)
return 0;
sqlite3_stmt* stmt;
if(data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK)
{
data->ffsqlite3_close(db);
return 0;
}
if(data->ffsqlite3_step(stmt) != SQLITE_ROW || data->ffsqlite3_data_count(stmt) < 1)
{
data->ffsqlite3_finalize(stmt);
data->ffsqlite3_close(db);
return 0;
}
int result = data->ffsqlite3_column_int(stmt, 0);
data->ffsqlite3_finalize(stmt);
data->ffsqlite3_close(db);
return result;
}
#else //FF_HAVE_SQLITE3
int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query)
{
FF_UNUSED(instance, dbPath, query)
return 0;
}
#endif //FF_HAVE_SQLITE3
#ifdef __ANDROID__
#include <sys/system_properties.h>
bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result) {
+32 -2
View File
@@ -61,16 +61,22 @@
# Logo type option:
# Sets the logo type to use.
# Must be auto, builtin, file, raw, sixel or kitty.
# Must be auto, builtin, file, raw, sixel, kitty or chafa.
# Default is auto.
#--logo-type auto
# Logo width option:
# Sets the width of the logos (in characters) if the logo is an image.
# Sets the width of the logo (in characters) if the logo is an image.
# Must be a positive integer.
# Default is 65.
#--logo-width 65
# Logo height option:
# Sets the height of the logo (in characters) if the logo is an image.
# Must be a positive integer.
# Default is 0 (keeps aspect ration).
#--logo-height 0
# Logo color options:
# Overwrite a color in the logo. Also works for user provided logos.
# In the user logo, they replace $[1-9]. Use $$ to print a single $ sign.
@@ -145,6 +151,18 @@
# Default is the first match starting with org.mpris.MediaPlayer2.
#--player-name spotify
# Escape bedrock option
# Sets if fastfetch should escape the bedrock jail, if it detectes that it is running in one
# Must be true or false.
# Default is true.
#--escape-bedrock true
# GL option
# Sets with opengl context creation library to use
# Must be either auto, egl, glx or osmesa
# Default is auto.
#--gl auto
# Key options:
# Sets the displayed key of a module
# Can be any string. Some of theme take an argument like a format string. See "fastfetch --help format" for help.
@@ -177,6 +195,9 @@
#--player-key Media Player
#--song-key Song
#--datetime-key Date Time
#--vulkan-key Vulkan
#--opengl-key OpenGL
#--opencl-key OpenCL
# Format options:
# Sets the format string for module values.
@@ -212,6 +233,9 @@
#--player-format
#--song-format
#--datetime-format
#--vulkan-format
#--opengl-format
#--opencl-format
# Library options:
# Sets an user specific path to a library to load.
@@ -227,6 +251,12 @@
#--lib-DConf /usr/lib/libdconf.so
#--lib-DBus /usr/lib/libdbus-1.so
#--lib-XFConf /usr/lib/libxfconf-0.so
#--lib-sqlite3 /usr/lib/libsqlite3.so
#--lib-rpm /usr/lib/librpm.so
#--lib-imagemagick /usr/lib/libMagickCore-7.Q16HDRI.so
#--lib-z /usr/lib/libz.so
#--lib-chafa /usr/lib/libchafa.so
#--lib-egl /usr/lib/libEGL.so
#--lib-glx /usr/lib/libGLX.so
#--lib-osmesa /usr/lib/libOSMesa.so
#--lib-opencl /usr/lib/libOpenCL.so
+19 -2
View File
@@ -18,11 +18,14 @@ General options:
--load-config <file>: load a config file or a preset (+)
--multithreading <?value>: use multiple threads to detect values
--allow-slow-operations <?value>: allow operations that are usually very slow for more detailed output
--escape-bedrock <?value>: on bedrock linux, sets if it should escape the bedrock jail or not
--pipe <?value>: disable logo and all escape sequences
Logo options:
-l,--logo <logo>: set the logo to use. The type is specified by --logo-type. If default: the name of a builtin logo or a path to a file
--logo-type <type>: set the type of the logo given. Must be auto, builtin, file, raw, sixel or kitty.
--logo-type <type>: set the type of the logo given. Must be auto, builtin, file, raw, sixel, kitty or chafa.
--logo-width <width>: set the width of the logo (in characters), if it is an image
--logo-height <height>: set the height of the logo (in characters), if it is an image
--logo-color-[1-9] <color>: overwrite a color in the logo
--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
@@ -30,6 +33,7 @@ Logo options:
--logo-print-remaining <?value>: weather to print the remaining logo, if it has more lines than modules to display
--sixel <file>: short for --logo-type sixel --logo <file>
--kitty <file>: short for --logo-type kitty --logo <file>
--chafa <file>: short for --logo-type chafa --logo <file>
--file <file>: short for --logo-type file --logo <file>
--raw <file>: short for --logo-type raw --logo <file>
@@ -74,6 +78,9 @@ Format options: Provide the format string for custom output. Use fastfetch --hel
--datetime-format <format>
--time-format <format>
--date-format <format>
--vulkan-format <format>
--opengl-format <format>
--opencl-format <format>
Key options: Provide a custom key for an output
--os-key <key>
@@ -107,6 +114,9 @@ Key options: Provide a custom key for an output
--datetime-key <key>
--time-key <key>
--date-key <key>
--vulkan-key <key>
--opengl-key <key>
--opencl-key <key>
Library options: Set the path of a library to load
--lib-PCI <path>
@@ -120,9 +130,15 @@ Library options: Set the path of a library to load
--lib-DConf <path>
--lib-DBus <path>
--lib-XFConf <path>
--lib-RPM <path>
--lib-sqlite3 <path>
--lib-rpm <path>
--lib-imagemagick <path>
--lib-z <path>
--lib-chafa <path>
--lib-egl <path>
--lib-glx <path>
--lib-osmesa <path>
--lib-opencl <path>
Module specific options:
--separator-string <str>: Set the string printed by the separator module
@@ -134,6 +150,7 @@ Module specific options:
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
--player-name: The name of the player to use
--gl <value>: Sets the opengl context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
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.
+3
View File
@@ -17,6 +17,8 @@ Locale
LocalIP
Memory
OS
OpenCL
OpenGL
Packages
Player
Processes
@@ -31,5 +33,6 @@ Theme
Time
Title
Uptime
Vulkan
WM
WMTheme
+10 -2
View File
@@ -98,7 +98,15 @@ static void getKDE(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);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/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);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/wayland-sessions/plasmawayland5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
applyBetterWM(result, getenv("KDEWM"));
}
@@ -289,13 +297,13 @@ static void getWMProtocolNameFromEnv(FFDisplayServerResult* result)
static void getFromProcDir(const FFinstance* instance, FFDisplayServerResult* result)
{
DIR* proc = opendir(FASTFETCH_TARGET_DIR_ROOT"/proc");
DIR* proc = opendir("/proc");
if(proc == NULL)
return;
FFstrbuf procPath;
ffStrbufInitA(&procPath, 64);
ffStrbufAppendS(&procPath, FASTFETCH_TARGET_DIR_ROOT"/proc/");
ffStrbufAppendS(&procPath, "/proc/");
uint32_t procPathLength = procPath.length;
+4 -4
View File
@@ -213,15 +213,15 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc)
return false;
bool res = xcbRandrHandleMode(data, crtcInfoReply->mode);
free(crtcInfoReply);
return res ? true : ffdsAppendResolution(
res = res ? true : ffdsAppendResolution(
data->result,
(uint32_t) crtcInfoReply->width,
(uint32_t) crtcInfoReply->height,
data->defaultRefreshRate
);
free(crtcInfoReply);
return res;
}
static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output)
+4 -4
View File
@@ -161,15 +161,15 @@ static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc)
return false;
bool res = xrandrHandleMode(data, crtcInfo->mode);
data->ffXRRFreeCrtcInfo(crtcInfo);
return res ? true : ffdsAppendResolution(
res = res ? true : ffdsAppendResolution(
data->result,
(uint32_t) crtcInfo->width,
(uint32_t) crtcInfo->height,
data->defaultRefreshRate
);
data->ffXRRFreeCrtcInfo(crtcInfo);
return res;
}
static bool xrandrHandleOutput(XrandrData* data, RROutput output)
+17 -53
View File
@@ -69,23 +69,14 @@ static void detectGTKFromDConf(FFinstance* instance, FFGTKResult* result)
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;
}
//Fallback + Gnome impl
if(themeName == NULL)
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Gnome") == 0)
{
themeName = ffSettingsGet(instance, "/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
if(iconsName == NULL)
iconsName = ffSettingsGet(instance, "/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
if(fontName == NULL)
fontName = ffSettingsGet(instance, "/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
if(cursorTheme == NULL)
cursorTheme = ffSettingsGet(instance, "/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
if(cursorSize <= 0)
cursorSize = ffSettingsGet(instance, "/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
}
pthread_mutex_unlock(&mutex);
applyGTKDConfSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize);
@@ -146,41 +137,8 @@ static void detectGTKFromConfigDir(FFstrbuf* configDir, const char* version, FFG
ffStrbufSubstrBefore(configDir, configDirLength);
}
static void detectGTK(FFinstance* instance, const char* version, const char* envVariable, FFGTKResult* result)
static void detectGTK(FFinstance* instance, const char* version, FFGTKResult* result)
{
FFstrbuf buffer;
ffStrbufInitA(&buffer, 128);
// From ENV: GTK*_RC_FILES
ffStrbufSetS(&buffer, getenv(envVariable));
uint32_t startIndex = 0;
while (startIndex < buffer.length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&buffer, startIndex, ':');
buffer.chars[colonIndex] = '\0';
detectGTKFromConfigFile(buffer.chars + startIndex, result);
if(allPropertiesSet(result))
{
ffStrbufDestroy(&buffer);
return;
}
startIndex = colonIndex + 1;
}
//From DConf / GSettings
detectGTKFromDConf(instance, result);
if(allPropertiesSet(result))
{
ffStrbufDestroy(&buffer);
return;
}
//From config dirs
//We need to do this because we use multiple threads on configDirs
FFstrbuf baseDirCopy;
ffStrbufInitA(&baseDirCopy, 64);
@@ -191,14 +149,20 @@ static void detectGTK(FFinstance* instance, const char* version, const char* env
ffStrbufSet(&baseDirCopy, baseDir);
detectGTKFromConfigDir(&baseDirCopy, version, result);
if(allPropertiesSet(result))
break;
{
ffStrbufDestroy(&baseDirCopy);
return;
}
}
ffStrbufDestroy(&baseDirCopy);
ffStrbufDestroy(&buffer);
//Mate, Cinnamon and Gnome use dconf to save theme config
//On other DEs, this will do nothing
detectGTKFromDConf(instance, result);
}
#define FF_CALCULATE_GTK_IMPL(version) \
#define FF_DETECT_GTK_IMPL(version) \
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; \
static FFGTKResult result; \
static bool init = false; \
@@ -213,23 +177,23 @@ static void detectGTK(FFinstance* instance, const char* version, const char* env
ffStrbufInit(&result.font); \
ffStrbufInit(&result.cursor); \
ffStrbufInit(&result.cursorSize); \
detectGTK(instance, #version, "GTK"#version"_RC_FILES", &result); \
detectGTK(instance, #version, &result); \
pthread_mutex_unlock(&mutex); \
return &result;
const FFGTKResult* ffDetectGTK2(FFinstance* instance)
{
FF_CALCULATE_GTK_IMPL(2)
FF_DETECT_GTK_IMPL(2)
}
const FFGTKResult* ffDetectGTK3(FFinstance* instance)
{
FF_CALCULATE_GTK_IMPL(3)
FF_DETECT_GTK_IMPL(3)
}
const FFGTKResult* ffDetectGTK4(FFinstance* instance)
{
FF_CALCULATE_GTK_IMPL(4)
FF_DETECT_GTK_IMPL(4)
}
#undef FF_CALCULATE_GTK_IMPL
+6 -2
View File
@@ -4,6 +4,7 @@
#include <pthread.h>
#define FF_DBUS_MPRIS_PREFIX "org.mpris.MediaPlayer2."
#define FF_DBUS_TIMEOUT_MILLISECONDS 35
#ifdef FF_HAVE_DBUS
#include <dbus/dbus.h>
@@ -68,8 +69,11 @@ static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data)
while(true)
{
if((foundAValue = getValue(&subIter, result, data)))
if(getValue(&subIter, result, data))
{
foundAValue = true;
ffStrbufAppendS(result, ", ");
}
FF_DBUS_ITER_CONTINUE(subIter);
}
@@ -83,7 +87,7 @@ static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data)
static DBusMessage* getReply(DBusMessage* request, DBusData* data)
{
DBusPendingCall* pendingCall = NULL;
dbus_bool_t succesfull = data->ffdbus_connection_send_with_reply(data->connection, request, &pendingCall, DBUS_TIMEOUT_USE_DEFAULT);
dbus_bool_t succesfull = data->ffdbus_connection_send_with_reply(data->connection, request, &pendingCall, FF_DBUS_TIMEOUT_MILLISECONDS);
data->ffdbus_message_unref(request);
if(!succesfull || pendingCall == NULL)
return NULL;
+81 -4
View File
@@ -1,15 +1,16 @@
#include "fastfetch.h"
#include <string.h>
#include <pthread.h>
#if !defined(__ANDROID__)
static void parseFile(const char* fileName, FFOSResult* result)
static bool parseFile(const char* fileName, FFOSResult* result)
{
if(result->name.length > 0 && result->prettyName.length > 0)
return;
if(result->id.length > 0 && result->name.length > 0 && result->prettyName.length > 0)
return true;
ffParsePropFileValues(fileName, 13, (FFpropquery[]) {
return ffParsePropFileValues(fileName, 13, (FFpropquery[]) {
{"NAME =", &result->name},
{"DISTRIB_DESCRIPTION =", &result->prettyName},
{"PRETTY_NAME =", &result->prettyName},
@@ -26,6 +27,67 @@ static void parseFile(const char* fileName, FFOSResult* result)
});
}
static void getUbuntuFlavour(FFOSResult* result)
{
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if(strstr(xdgConfigDirs, "kde") != NULL || strstr(xdgConfigDirs, "plasma") != NULL)
{
ffStrbufSetS(&result->name, "Kubuntu");
ffStrbufSetS(&result->prettyName, "Kubuntu");
ffStrbufSetS(&result->id, "kubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "xfce") != NULL || strstr(xdgConfigDirs, "xubuntu") != NULL)
{
ffStrbufSetS(&result->name, "Xubuntu");
ffStrbufSetS(&result->prettyName, "Xubuntu");
ffStrbufSetS(&result->id, "xubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "lxde") != NULL || strstr(xdgConfigDirs, "lubuntu") != NULL)
{
ffStrbufSetS(&result->name, "Lubuntu");
ffStrbufSetS(&result->prettyName, "Lubuntu");
ffStrbufSetS(&result->id, "lubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "budgie") != NULL)
{
ffStrbufSetS(&result->name, "Ubuntu Budgie");
ffStrbufSetS(&result->prettyName, "Ubuntu Budgie");
ffStrbufSetS(&result->id, "ubuntu-budgie");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "mate") != NULL)
{
ffStrbufSetS(&result->name, "Ubuntu MATE");
ffStrbufSetS(&result->prettyName, "Ubuntu MATE");
ffStrbufSetS(&result->id, "ubuntu-mate");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "studio") != NULL)
{
ffStrbufSetS(&result->name, "Ubuntu Studio");
ffStrbufSetS(&result->prettyName, "Ubuntu Studio");
ffStrbufSetS(&result->id, "ubuntu-studio");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
}
#endif
const FFOSResult* ffDetectOS(const FFinstance* instance)
@@ -62,12 +124,27 @@ const FFOSResult* ffDetectOS(const FFinstance* instance)
{
parseFile(instance->config.osFile.chars, &result);
}
else if(instance->config.escapeBedrock && parseFile(FASTFETCH_TARGET_DIR_ROOT"/bedrock/etc/bedrock-release", &result))
{
if(result.id.length == 0)
ffStrbufAppendS(&result.id, "bedrock");
if(result.name.length == 0)
ffStrbufAppendS(&result.name, "Bedrock");
if(result.prettyName.length == 0)
ffStrbufAppendS(&result.prettyName, "Bedrock Linux");
}
else
{
parseFile(FASTFETCH_TARGET_DIR_ROOT"/etc/os-release", &result);
parseFile(FASTFETCH_TARGET_DIR_USR"/lib/os-release", &result);
parseFile(FASTFETCH_TARGET_DIR_ROOT"/etc/lsb-release", &result);
}
if(ffStrbufIgnCaseCompS(&result.id, "ubuntu") == 0)
getUbuntuFlavour(&result);
#else
ffStrbufSetS(&result.name, "Android");
ffStrbufSetS(&result.id, "android");
+2 -2
View File
@@ -16,7 +16,7 @@ static void getProcessInformation(const char* pid, FFstrbuf* processName, FFstrb
{
FFstrbuf cmdlineFilePath;
ffStrbufInit(&cmdlineFilePath);
ffStrbufAppendS(&cmdlineFilePath, FASTFETCH_TARGET_DIR_ROOT"/proc/");
ffStrbufAppendS(&cmdlineFilePath, "/proc/");
ffStrbufAppendS(&cmdlineFilePath, pid);
ffStrbufAppendS(&cmdlineFilePath, "/cmdline");
@@ -36,7 +36,7 @@ static void getTerminalShell(FFTerminalShellResult* result, const char* pid)
{
FFstrbuf statFilePath;
ffStrbufInit(&statFilePath);
ffStrbufAppendS(&statFilePath, FASTFETCH_TARGET_DIR_ROOT"/proc/");
ffStrbufAppendS(&statFilePath, "/proc/");
ffStrbufAppendS(&statFilePath, pid);
ffStrbufAppendS(&statFilePath, "/stat");
+225
View File
@@ -0,0 +1,225 @@
#include "fastfetch.h"
#include <pthread.h>
#ifdef FF_HAVE_VULKAN
#include <vulkan/vulkan.h>
static inline void applyVulkanVersion(uint32_t vulkanVersion, FFVersion* ffVersion)
{
ffVersion->major = VK_VERSION_MAJOR(vulkanVersion);
ffVersion->minor = VK_VERSION_MINOR(vulkanVersion);
ffVersion->patch = VK_VERSION_PATCH(vulkanVersion);
}
static void applyDriverName(VkPhysicalDeviceDriverProperties* properties, FFstrbuf* result)
{
if(!ffStrSet(properties->driverName))
return;
ffStrbufAppendS(result, properties->driverName);
if(!ffStrSet(properties->driverInfo))
return;
ffStrbufAppendS(result, " [");
ffStrbufAppendS(result, properties->driverInfo);
ffStrbufAppendC(result, ']');
}
static void detectVulkan(const FFinstance* instance, FFVulkanResult* result)
{
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", 2)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetInstanceProcAddr,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkCreateInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkDestroyInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkEnumeratePhysicalDevices,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetPhysicalDeviceProperties,)
//Some drivers (nvdc) print messages to stdout
//and thats the best way i found to disable that
ffSuppressIO(true);
FFVersion instanceVersion = FF_VERSION_INIT;
//We need to get the function pointer this way, because it is only provided by vulkan 1.1 and higher.
//a dlsym would fail on 1.0 implementations
PFN_vkEnumerateInstanceVersion ffvkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) ffvkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
if(ffvkEnumerateInstanceVersion != NULL)
{
uint32_t version;
if(ffvkEnumerateInstanceVersion(&version) == VK_SUCCESS)
applyVulkanVersion(version, &instanceVersion);
}
const uint32_t projectVersion = VK_MAKE_VERSION(
FASTFETCH_PROJECT_VERSION_MAJOR,
FASTFETCH_PROJECT_VERSION_MINOR,
FASTFETCH_PROJECT_VERSION_PATCH
);
//We need to request 1.2 to get physicalDeviceDriverProperties
uint32_t requestedVkVersion = VK_API_VERSION_1_0;
if(instanceVersion.minor >= 2)
requestedVkVersion = VK_API_VERSION_1_2;
const VkApplicationInfo applicationInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = NULL,
.pApplicationName = FASTFETCH_PROJECT_NAME,
.applicationVersion = projectVersion,
.pEngineName = "vulkanPrintGPUs",
.engineVersion = projectVersion,
.apiVersion = requestedVkVersion
};
const VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = NULL,
.pApplicationInfo = &applicationInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = NULL,
.enabledExtensionCount = 0,
.ppEnabledExtensionNames = NULL,
.flags = 0
};
VkInstance vkInstance;
if(ffvkCreateInstance(&instanceCreateInfo, NULL, &vkInstance) != VK_SUCCESS)
{
dlclose(vulkan);
ffSuppressIO(false);
return;
}
//if instance creation succeeded, but vkEnumerateInstanceVersion didn't, this means we are running against a vulkan 1.0 implementation
//explicitly set this version, if no device is found, so we still have at least this info
if(instanceVersion.major == 0 && instanceVersion.minor == 0 && instanceVersion.patch == 0)
instanceVersion.major = 1;
uint32_t physicalDeviceCount;
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL) != VK_SUCCESS)
{
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
VkPhysicalDevice* physicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices) != VK_SUCCESS)
{
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2");
FFVersion maxDeviceApiVersion = FF_VERSION_INIT;
FFVersion maxDeviceConformanceVersion = FF_VERSION_INIT;
for(uint32_t i = 0; i < physicalDeviceCount; i++)
{
//Get device properties.
//On VK 1.2 and up, we use vkGetPhysicalDeviceProperties2, so we can put VkPhysicalDeviceDriverProperties in the pNext chain.
//This is required to get the driver name and conformance version.
VkPhysicalDeviceDriverProperties driverProperties;
driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
driverProperties.pNext = NULL;
driverProperties.driverName[0] = '\0';
driverProperties.conformanceVersion = (VkConformanceVersion) {0, 0, 0, 0};
VkPhysicalDeviceProperties2 physicalDeviceProperties;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProperties.pNext = &driverProperties;
if(ffvkGetPhysicalDeviceProperties2 != NULL)
ffvkGetPhysicalDeviceProperties2(physicalDevices[i], &physicalDeviceProperties);
else
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties);
//If the device api version is higher than the current highest device api version, overwrite it
//In this case, also use the current device driver name as the shown driver name
FFVersion deviceAPIVersion = FF_VERSION_INIT;
applyVulkanVersion(physicalDeviceProperties.properties.apiVersion, &deviceAPIVersion);
if(ffVersionCompare(&deviceAPIVersion, &maxDeviceApiVersion) > 0)
{
maxDeviceApiVersion = deviceAPIVersion;
applyDriverName(&driverProperties, &result->driver);
}
//If the device conformance version is higher than the current highest device conformance version, overwrite it
FFVersion deviceConformanceVersion = FF_VERSION_INIT;
deviceConformanceVersion.major = driverProperties.conformanceVersion.major;
deviceConformanceVersion.minor = driverProperties.conformanceVersion.minor;
deviceConformanceVersion.patch = driverProperties.conformanceVersion.patch;
if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0)
maxDeviceConformanceVersion = deviceConformanceVersion;
//Add the device to the list of devices shown by the GPU module
//We don't want softare rasterizers to show up as physical gpu
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
FFGPUResult* gpu = ffListAdd(&result->devices);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufAppendS(&gpu->name, physicalDeviceProperties.properties.deviceName);
}
//If the highest device version is lower than the instance version, use it as our vulkan version
//otherwise the instance version is the vulkan version
if(ffVersionCompare(&instanceVersion, &maxDeviceApiVersion) > 0)
ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion);
else
ffVersionToPretty(&instanceVersion, &result->apiVersion);
//Use the highest device conformace version as our conformance version
ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion);
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
}
#endif
const FFVulkanResult* ffDetectVulkan(const FFinstance* instance)
{
static FFVulkanResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.driver);
ffStrbufInit(&result.apiVersion);
ffStrbufInit(&result.conformanceVersion);
ffListInit(&result.devices, sizeof(FFGPUResult));
#ifdef FF_HAVE_VULKAN
detectVulkan(instance, &result);
#else
FF_UNUSED(instance);
#endif
pthread_mutex_unlock(&mutex);
return &result;
}
+105 -4
View File
@@ -93,7 +93,7 @@ static inline void printCommandHelp(const char* command)
}
else if(strcasecmp(command, "packages-format") == 0)
{
constructAndPrintCommandHelpFormat("packages", "{2} (pacman){?3}[{3}]{?}, {4} (dpkg), {5} (rpm), {6} (emerge), {7} (xps), {8}, (flatpak), {9} (snap)", 9,
constructAndPrintCommandHelpFormat("packages", "{2} (pacman){?3}[{3}]{?}, {4} (dpkg), {5} (rpm), {6} (emerge), {7} (xbps), {8} (nix-user), {9} (nix-default), {10} (flatpak), {11} (snap)", 11,
"Number of all packages",
"Number of pacman packages",
"Pacman branch on manjaro",
@@ -101,6 +101,8 @@ static inline void printCommandHelp(const char* command)
"Number of rpm packages",
"Number of emerge packages",
"Number of xbps packages",
"Number of nix-user packages",
"Number of nix-default packages",
"Number of flatpak packages",
"Number of snap packages"
);
@@ -343,6 +345,31 @@ static inline void printCommandHelp(const char* command)
"second with leading zero"
);
}
else if(strcasecmp(command, "vulkan-format") == 0)
{
constructAndPrintCommandHelpFormat("vulkan", "{} (driver), {} (api version)", 3,
"Driver name",
"API version",
"Conformance version"
);
}
else if(strcasecmp(command, "opengl-format") == 0)
{
constructAndPrintCommandHelpFormat("opengl", "{}", 3,
"version",
"renderer",
"vendor",
"shading language version"
);
}
else if(strcasecmp(command, "opencl-format") == 0)
{
constructAndPrintCommandHelpFormat("opencl", "{}", 3,
"version",
"device",
"vendor"
);
}
else
fprintf(stderr, "No specific help for command %s provided\n", command);
}
@@ -673,17 +700,17 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
}
else if(strcasecmp(key, "--list-logos") == 0)
{
ffListBuiltinLogos();
ffLogoBuiltinList();
exit(0);
}
else if(strcasecmp(key, "--list-logos-autocompletion") == 0)
{
ffListBuiltinLogosAutocompletion();
ffLogoBuiltinListAutocompletion();
exit(0);
}
else if(strcasecmp(key, "--print-logos") == 0)
{
ffPrintBuiltinLogos(instance);
ffLogoBuiltinPrint(instance);
exit(0);
}
@@ -708,13 +735,26 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
data->multithreading = optionParseBoolean(value);
else if(strcasecmp(key, "--allow-slow-operations") == 0)
instance->config.allowSlowOperations = optionParseBoolean(value);
else if(strcasecmp(key, "--escape-bedrock") == 0)
instance->config.escapeBedrock = optionParseBoolean(value);
else if(strcasecmp(key, "--pipe") == 0)
instance->config.pipe = optionParseBoolean(value);
////////////////
//Logo options//
////////////////
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
{
optionParseString(key, value, &instance->config.logoSource);
//this is usally wanted when using the none logo
if(strcasecmp(value, "none") == 0)
{
instance->config.logoPaddingRight = 0;
instance->config.logoPaddingLeft = 0;
}
}
else if(strcasecmp(key, "--logo-type") == 0)
{
if(value == NULL)
@@ -735,6 +775,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
else if(strcasecmp(value, "kitty") == 0)
instance->config.logoType = FF_LOGO_TYPE_KITTY;
else if(strcasecmp(value, "chafa") == 0)
instance->config.logoType = FF_LOGO_TYPE_CHAFA;
else
{
fprintf(stderr, "Error: unknown logo type: %s\n", value);
@@ -757,6 +799,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
}
else if(strcasecmp(key, "--logo-width") == 0)
instance->config.logoWidth = optionParseUInt32(key, value);
else if(strcasecmp(key, "--logo-height") == 0)
instance->config.logoHeight = optionParseUInt32(key, value);
else if(strcasecmp(key, "--logo-padding") == 0)
{
uint32_t padding = optionParseUInt32(key, value);
@@ -789,6 +833,11 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.logoSource);
instance->config.logoType = FF_LOGO_TYPE_RAW;
}
else if(strcasecmp(key, "--chafa") == 0)
{
optionParseString(key, value, &instance->config.logoSource);
instance->config.logoType = FF_LOGO_TYPE_CHAFA;
}
///////////////////
//Display options//
@@ -955,6 +1004,18 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.timeKey);
else if(strcasecmp(key, "--time-format") == 0)
optionParseString(key, value, &instance->config.timeFormat);
else if(strcasecmp(key, "--vulkan-key") == 0)
optionParseString(key, value, &instance->config.vulkanKey);
else if(strcasecmp(key, "--vulkan-format") == 0)
optionParseString(key, value, &instance->config.vulkanFormat);
else if(strcasecmp(key, "--opengl-key") == 0)
optionParseString(key, value, &instance->config.openGLKey);
else if(strcasecmp(key, "--opengl-format") == 0)
optionParseString(key, value, &instance->config.openGLFormat);
else if(strcasecmp(key, "--opencl-key") == 0)
optionParseString(key, value, &instance->config.openCLKey);
else if(strcasecmp(key, "--opencl-format") == 0)
optionParseString(key, value, &instance->config.openCLFormat);
///////////////////
//Library options//
@@ -982,12 +1043,24 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.libDBus);
else if(strcasecmp(key, "--lib-XFConf") == 0)
optionParseString(key, value, &instance->config.libXFConf);
else if(strcasecmp(key, "--lib-sqlite") == 0 || strcasecmp(key, "--lib-sqlite3") == 0)
optionParseString(key, value, &instance->config.libSQLite3);
else if(strcasecmp(key, "--lib-rpm") == 0)
optionParseString(key, value, &instance->config.librpm);
else if(strcasecmp(key, "--lib-imagemagick") == 0)
optionParseString(key, value, &instance->config.libImageMagick);
else if(strcasecmp(key, "--lib-z") == 0)
optionParseString(key, value, &instance->config.libZ);
else if(strcasecmp(key, "--lib-chafa") == 0)
optionParseString(key, value, &instance->config.libChafa);
else if(strcasecmp(key, "--lib-egl") == 0)
optionParseString(key, value, &instance->config.libEGL);
else if(strcasecmp(key, "--lib-glx") == 0)
optionParseString(key, value, &instance->config.libGLX);
else if(strcasecmp(key, "--lib-osmesa") == 0)
optionParseString(key, value, &instance->config.libOSMesa);
else if(strcasecmp(key, "--lib-opencl") == 0)
optionParseString(key, value, &instance->config.libOpenCL);
//////////////////
//Module options//
@@ -1011,6 +1084,28 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
optionParseString(key, value, &instance->config.playerName);
else if(strcasecmp(key, "--public-ip-timeout") == 0)
instance->config.publicIpTimeout = optionParseUInt32(key, value);
else if(strcasecmp(key, "--gl") == 0)
{
if(value == NULL)
{
fprintf(stderr, "Error: usage: %s <type>\n", key);
exit(491);
}
if(strcasecmp(value, "auto") == 0)
instance->config.glType = FF_GL_TYPE_AUTO;
else if(strcasecmp(value, "egl") == 0)
instance->config.glType = FF_GL_TYPE_EGL;
else if(strcasecmp(value, "glx") == 0)
instance->config.glType = FF_GL_TYPE_GLX;
else if(strcasecmp(value, "osmesa") == 0)
instance->config.glType = FF_GL_TYPE_OSMESA;
else
{
fprintf(stderr, "Error: unknown gl type: %s\n", value);
exit(492);
}
}
//////////////////
//Unknown option//
@@ -1152,6 +1247,12 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char
ffPrintTime(instance);
else if(strcasecmp(line, "colors") == 0)
ffPrintColors(instance);
else if(strcasecmp(line, "vulkan") == 0)
ffPrintVulkan(instance);
else if(strcasecmp(line, "opengl") == 0)
ffPrintOpenGL(instance);
else if(strcasecmp(line, "opencl") == 0)
ffPrintOpenCL(instance);
else
ffPrintError(instance, line, 0, NULL, NULL, 0, "<no implementation provided>");
}
+69 -11
View File
@@ -38,20 +38,30 @@ typedef enum FFLogoType
FF_LOGO_TYPE_FILE, //Raw text file, printed as is.
FF_LOGO_TYPE_RAW, //Raw text file, printed with color codes replacement.
FF_LOGO_TYPE_SIXEL, //Image file, printed as sixel codes.
FF_LOGO_TYPE_KITTY //Image file, printed as kitty graphics protocol
FF_LOGO_TYPE_KITTY, //Image file, printed as kitty graphics protocol
FF_LOGO_TYPE_CHAFA //Image file, printed as ascii art using libchafa
} FFLogoType;
typedef enum FFGLType
{
FF_GL_TYPE_AUTO,
FF_GL_TYPE_EGL,
FF_GL_TYPE_GLX,
FF_GL_TYPE_OSMESA
} FFGLType;
typedef struct FFconfig
{
FFstrbuf logoSource;
FFLogoType logoType;
FFstrbuf logoColors[FASTFETCH_LOGO_MAX_COLORS];
uint32_t logoWidth;
uint32_t logoHeight;
uint32_t logoPaddingLeft;
uint32_t logoPaddingRight;
bool logoPrintRemaining;
FFstrbuf mainColor; //If this is empty, ffPrintLogo will set it to the main color of the logo
FFstrbuf mainColor; //If this is empty, ffLogoPrint will set it to the main color of the logo
FFstrbuf separator;
bool showErrors;
@@ -60,6 +70,9 @@ typedef struct FFconfig
bool allowSlowOperations;
bool disableLinewrap;
bool hideCursor;
bool escapeBedrock;
FFGLType glType;
bool pipe; //disables logo and all escape sequences
FFstrbuf osFormat;
FFstrbuf osKey;
@@ -123,6 +136,12 @@ typedef struct FFconfig
FFstrbuf dateFormat;
FFstrbuf timeKey;
FFstrbuf timeFormat;
FFstrbuf vulkanKey;
FFstrbuf vulkanFormat;
FFstrbuf openGLKey;
FFstrbuf openGLFormat;
FFstrbuf openCLKey;
FFstrbuf openCLFormat;
FFstrbuf libPCI;
FFstrbuf libVulkan;
@@ -135,9 +154,15 @@ typedef struct FFconfig
FFstrbuf libDConf;
FFstrbuf libDBus;
FFstrbuf libXFConf;
FFstrbuf libSQLite3;
FFstrbuf librpm;
FFstrbuf libImageMagick;
FFstrbuf libZ;
FFstrbuf libChafa;
FFstrbuf libEGL;
FFstrbuf libGLX;
FFstrbuf libOSMesa;
FFstrbuf libOpenCL;
FFstrbuf diskFolders;
@@ -176,6 +201,14 @@ typedef struct FFinstance
FFstate state;
} FFinstance;
typedef struct FFVersion
{
uint32_t major;
uint32_t minor;
uint32_t patch;
} FFVersion;
#define FF_VERSION_INIT ((FFVersion) {0})
typedef struct FFTitleResult
{
FFstrbuf userName;
@@ -231,6 +264,21 @@ typedef struct FFTerminalShellResult
FFstrbuf userShellVersion;
} FFTerminalShellResult;
typedef struct FFGPUResult
{
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
} FFGPUResult;
typedef struct FFVulkanResult
{
FFstrbuf driver;
FFstrbuf apiVersion;
FFstrbuf conformanceVersion;
FFlist devices; //List of FFGPUResult
} FFVulkanResult;
typedef struct FFResolutionResult
{
uint32_t width;
@@ -405,9 +453,10 @@ bool ffWriteFileContent(const char* fileName, const FFstrbuf* buffer);
bool ffFileExists(const char* fileName, mode_t mode);
void ffSuppressIO(bool suppress); // Not thread safe!
void ffGetTerminalResponse(const char* request, char end, const char* format, ...);
void ffGetTerminalResponse(const char* request, const char* format, ...);
//common/printing.c
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat);
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numFormatArgs, const char* message, ...);
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintColor(const FFstrbuf* colorValue);
@@ -448,6 +497,9 @@ 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);
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
//common/processing.c
void ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]);
@@ -463,6 +515,8 @@ FFvariant ffSettingsGetGSettings(FFinstance* instance, const char* schemaName, c
FFvariant ffSettingsGet(FFinstance* instance, const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
FFvariant ffSettingsGetXFConf(FFinstance* instance, const char* channelName, const char* propertyName, FFvarianttype type);
int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query);
#ifdef __ANDROID__
bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result);
#endif
@@ -471,15 +525,13 @@ bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result);
// Logo functions //
////////////////////
void ffPrintLogo(FFinstance* instance);
void ffPrintRemainingLogo(FFinstance* instance);
void ffLogoPrint(FFinstance* instance);
void ffLogoPrintRemaining(FFinstance* instance);
void ffLogoPrintLine(FFinstance* instance);
void ffPrintLogoLine(FFinstance* instance);
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat);
void ffPrintBuiltinLogos(FFinstance* instance);
void ffListBuiltinLogos();
void ffListBuiltinLogosAutocompletion();
void ffLogoBuiltinPrint(FFinstance* instance);
void ffLogoBuiltinList();
void ffLogoBuiltinListAutocompletion();
/////////////////////////
// Detection functions //
@@ -511,6 +563,9 @@ const FFMediaResult* ffDetectMedia(FFinstance* instance);
//detection/dateTime.c
const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance);
//detection/vulkan.c
const FFVulkanResult* ffDetectVulkan(const FFinstance* instance);
//////////////////////
// Module functions //
//////////////////////
@@ -558,5 +613,8 @@ void ffPrintTime(FFinstance* instance);
void ffPrintLocalIp(FFinstance* instance);
void ffPrintPublicIp(FFinstance* instance);
void ffPrintColors(FFinstance* instance);
void ffPrintVulkan(FFinstance* instance);
void ffPrintOpenGL(FFinstance* instance);
void ffPrintOpenCL(FFinstance* instance);
#endif
+2
View File
@@ -4,6 +4,8 @@
#define FASTFETCH_PROJECT_NAME "@PROJECT_NAME@"
#define FASTFETCH_PROJECT_VERSION "@PROJECT_VERSION@"
#define FASTFETCH_PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define FASTFETCH_PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define FASTFETCH_PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define FASTFETCH_PROJECT_VERSION_TWEAK "@PROJECT_VERSION_TWEAK@"
#define FASTFETCH_TARGET_DIR_ROOT "@TARGET_DIR_ROOT@"
+2
View File
@@ -50,6 +50,8 @@ int main(int argc, char** argv)
//ffPrintDateTime(&instance);
//ffPrintDate(&instance);
//ffPrintTime(&instance);
//ffPrintVulkan(&instance);
//ffPrintOpenGL(&instance);
ffPrintBreak(&instance);
ffPrintColors(&instance);
+211 -203
View File
@@ -1,28 +1,15 @@
#include "logo.h"
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
typedef struct FFlogo
{
const char* data;
const char** names; //Null terminated
const char** builtinColors; //Null terminated
bool performColorReplacement;
} FFlogo;
#define FF_LOGO_INIT static FFlogo logo; static bool init = false; if(init) return &logo; init = true;
#define FF_LOGO_NAMES(...) static const char* names[] = (const char*[]) { __VA_ARGS__, NULL }; logo.names = names;
#define FF_LOGO_LINES(x) logo.data = x;
#define FF_LOGO_COLORS(...) static const char* colors[] = (const char*[]) { __VA_ARGS__, NULL }; logo.builtinColors = colors;
#define FF_LOGO_RETURN return &logo;
static const FFlogo* getLogoUnknown()
const FFlogo* ffLogoBuiltinGetUnknown()
{
FF_LOGO_INIT
FF_LOGO_NAMES("unkown", "question mark", "?")
FF_LOGO_NAMES("unknown", "question mark", "?")
FF_LOGO_LINES(
" ________\n"
" _jgN########Ngg_\n"
@@ -239,6 +226,36 @@ static const FFlogo* getLogoArcoLinux()
FF_LOGO_RETURN
}
static const FFlogo* getLogoBedrock()
{
FF_LOGO_INIT
FF_LOGO_NAMES("bedrock", "bedrocklinux", "bedrock-linux")
FF_LOGO_LINES(
"--------------------------------------\n"
"--------------------------------------\n"
"--------------------------------------\n"
"---$2\\\\\\\\\\\\\\\\\\\\\\\\$1-----------------------\n"
"----$2\\\\\\ \\\\\\$1----------------------\n"
"-----$2\\\\\\ \\\\\\$1---------------------\n"
"------$2\\\\\\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\$1------\n"
"-------$2\\\\\\ \\\\\\$1-----\n"
"--------$2\\\\\\ \\\\\\$1----\n"
"---------$2\\\\\\ ______ \\\\\\$1---\n"
"----------$2\\\\\\ ///$1---\n"
"-----------$2\\\\\\ ///$1----\n"
"------------$2\\\\\\ ///$1-----\n"
"-------------$2\\\\\\////////////////$1------\n"
"--------------------------------------\n"
"--------------------------------------\n"
"--------------------------------------"
)
FF_LOGO_COLORS(
"90", //grey
"37" //white
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoCachyOS()
{
FF_LOGO_INIT
@@ -408,6 +425,82 @@ static const FFlogo* getLogoDebianSmall()
FF_LOGO_RETURN
}
static const FFlogo* getLogoDevuan()
{
FF_LOGO_INIT
FF_LOGO_NAMES("devuan", "devuan-linux")
FF_LOGO_LINES(
" ..,,;;;::;,..\n"
" `':ddd;:,.\n"
" `'dPPd:,.\n"
" `:b$$b`.\n"
" 'P$$$d`\n"
" .$$$$$`\n"
" ;$$$$$P\n"
" .:P$$$$$$`\n"
" .,:b$$$$$$$;'\n"
" .,:dP$$$$$$$$b:'\n"
" .,:;db$$$$$$$$$$Pd'`\n"
" ,db$$$$$$$$$$$$$$b:'`\n"
":$$$$$$$$$$$$b:'`\n"
" `$$$$$bd:''`\n"
" `'''`\n"
)
FF_LOGO_COLORS(
"35" //magenta
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoDevuanSmall()
{
FF_LOGO_INIT
FF_LOGO_NAMES("devuan_small", "devuan-linux-small")
FF_LOGO_LINES(
" ..:::.\n"
" ..-==-\n"
" .+#:\n"
" =@@\n"
" :+%@#:\n"
".:=+#@@%*:\n"
"#@@@#=:\n"
)
FF_LOGO_COLORS(
"34" //blue
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoDeepin()
{
FF_LOGO_INIT
FF_LOGO_NAMES("deepin", "deepin-linux")
FF_LOGO_LINES(
"$1 ............\n"
" .';;;;;. .,;,.\n"
" .,;;;;;;;. ';;;;;;;.\n"
" .;::::::::' .,::;;,''''',.\n"
" ,'.:::::::: .;;'. ';\n"
" ;' 'cccccc, ,' :: '.. .:\n"
" ,, :ccccc. ;: .c, '' :. ,;\n"
".l. cllll' ., .lc :; .l' l.\n"
".c :lllc ;cl: .l' .ll. :'\n"
".l 'looc. . ,o: 'oo' c,\n"
".o. .:ool::coc' .ooo' o.\n"
" :: ..... .;dddo ;c\n"
" l:... .';lddddo. ,o\n"
" lxxxxxdoolllodxxxxxxxxxc :l\n"
" ,dxxxxxxxxxxxxxxxxxxl. 'o,\n"
" ,dkkkkkkkkkkkkko;. .;o;\n"
" .;okkkkkdl;. .,cl:.\n"
" .,:cccccccc:,."
)
FF_LOGO_COLORS(
"32" //green
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoEndeavour()
{
FF_LOGO_INIT
@@ -632,6 +725,39 @@ static const FFlogo* getLogoKDENeon()
FF_LOGO_RETURN
}
static const FFlogo* getLogoKubuntu()
{
FF_LOGO_INIT
FF_LOGO_NAMES("kubuntu", "kubuntu-linux", "kde-ubuntu", "ubuntu-kde", "ubuntu-plasma")
FF_LOGO_LINES(
"$1 `.:/ossyyyysso/:.\n"
" .:oyyyyyyyyyyyyyyyyyyo:`\n"
" -oyyyyyyyo$2dMMy$1yyyyyyysyyyyo-\n"
" -syyyyyyyyyy$2dMMy$1oyyyy$2dmMMy$1yyyys-\n"
" oyyys$2dMy$1syyyy$2dMMMMMMMMMMMMMy$1yyyyyyo\n"
" `oyyyy$2dMMMMy$1syysoooooo$2dMMMMy$1yyyyyyyyo`\n"
" oyyyyyy$2dMMMMy$1yyyyyyyyyyys$2dMMy$1sssssyyyo\n"
"-yyyyyyyy$2dMy$1syyyyyyyyyyyyyys$2dMMMMMy$1syyy-\n"
"oyyyysoo$2dMy$1yyyyyyyyyyyyyyyyyy$2dMMMMy$1syyyo\n"
"yyys$2dMMMMMy$1yyyyyyyyyyyyyyyyyysosyyyyyyyy\n"
"yyys$2dMMMMMy$1yyyyyyyyyyyyyyyyyyyyyyyyyyyyy\n"
"oyyyyysos$2dy$1yyyyyyyyyyyyyyyyyy$2dMMMMy$1syyyo\n"
"-yyyyyyyy$2dMy$1syyyyyyyyyyyyyys$2dMMMMMy$1syyy-\n"
" oyyyyyy$2dMMMy$1syyyyyyyyyyys$2dMMy$1oyyyoyyyo\n"
" `oyyyy$2dMMMy$1syyyoooooo$2dMMMMy$1oyyyyyyyyo\n"
" oyyysyyoyyyys$2dMMMMMMMMMMMy$1yyyyyyyo\n"
" -syyyyyyyyy$2dMMMy$1syyy$2dMMMy$1syyyys-\n"
" -oyyyyyyy$2dMMy$1yyyyyysosyyyyo-\n"
" ./oyyyyyyyyyyyyyyyyyyo/.\n"
" `.:/oosyyyysso/:.`"
)
FF_LOGO_COLORS(
"34", //blue
"37" //white
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoLinux()
{
FF_LOGO_INIT
@@ -1112,6 +1238,67 @@ static const FFlogo* getLogoRedHatEnterpriseLinux()
FF_LOGO_RETURN
}
static const FFlogo* getLogoRedstarOS()
{
FF_LOGO_INIT
FF_LOGO_NAMES("redstar", "redstar-os", "redstaros", "redstaros-linux", "redstar-os-linux")
FF_LOGO_LINES(
"$1 ..\n"
" .oK0l\n"
" :0KKKKd.\n"
" .xKO0KKKKd\n"
" ,Od' .d0000l\n"
" .c;. .'''... ..'.\n"
".,:cloddxxxkkkkOOOOkkkkkkkkxxxxxxxxxkkkx:\n"
";kOOOOOOOkxOkc'...',;;;;,,,'',;;:cllc:,.\n"
" .okkkkd,.lko .......',;:cllc:;,,'''''.\n"
" .cdo. :xd' cd:. ..';'',,,'',,;;;,'.\n"
" . .ddl.;doooc'..;oc;'..';::;,'.\n"
" coo;.oooolllllllcccc:'. .\n"
" .ool''lllllccccccc:::::;.\n"
" ;lll. .':cccc:::::::;;;;'\n"
" :lcc:'',..';::::;;;;;;;,,.\n"
" :cccc::::;...';;;;;,,,,,,.\n"
" ,::::::;;;,'. ..',,,,'''.\n"
" ........ ......"
)
FF_LOGO_COLORS(
"31" //red
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoRockyLinux()
{
FF_LOGO_INIT
FF_LOGO_NAMES("rocky", "rocky-linux", "rockylinux")
FF_LOGO_LINES(
" __wgliliiligw_,\n"
" _williiiiiiliilililw,\n"
" _%iiiiiilililiiiiiiiiiii_\n"
" .Qliiiililiiiiiiililililiilm.\n"
" _iiiiiliiiiiililiiiiiiiiiiliil,\n"
" .lililiiilililiiiilililililiiiii,\n"
"_liiiiiiliiiiiiiliiiiiF{iiiiiilili,\n"
"jliililiiilililiiili@` ~ililiiiiiL\n"
"iiiliiiiliiiiiiili>` ~liililii\n"
"liliiiliiilililii` -9liiiil\n"
"iiiiiliiliiiiii~ ''4lili\n"
"4ililiiiiilil~| -w, )4lf\n"
"-liiiiililiF' _liig, )'\n"
" )iiiliii@` _QIililig,\n"
" )iiii>` .Qliliiiililw\n"
" )<>~ .mliiiiiliiiiiil,\n"
" _gllilililiililii~\n"
" giliiiiiiiiiiiiT`\n"
" -^~$ililili@~~'"
)
FF_LOGO_COLORS(
"32" //green
)
FF_LOGO_RETURN
}
static const FFlogo* getLogoUbuntu()
{
FF_LOGO_INIT
@@ -1242,13 +1429,11 @@ static const FFlogo* getLogoZorin()
FF_LOGO_RETURN
}
typedef const FFlogo*(*GetLogoMethod)();
static GetLogoMethod* getLogos()
GetLogoMethod* ffLogoBuiltinGetAll()
{
static GetLogoMethod logoMethods[] = {
ffLogoBuiltinGetUnknown,
getLogoNone,
getLogoUnknown,
getLogoAndroid,
getLogoAndroidSmall,
getLogoArch,
@@ -1256,12 +1441,16 @@ static GetLogoMethod* getLogos()
getLogoArcoLinux,
getLogoArtix,
getLogoArtixSmall,
getLogoBedrock,
getLogoCachyOS,
getLogoCelOS,
getLogoCentOS,
getLogoCentOSSmall,
getLogoDebian,
getLogoDevuan,
getLogoDevuanSmall,
getLogoDebianSmall,
getLogoDeepin,
getLogoEndeavour,
getLogoFedora,
getLogoFedoraSmall,
@@ -1270,6 +1459,7 @@ static GetLogoMethod* getLogos()
getLogoGentoo,
getLogoGentooSmall,
getLogoKDENeon,
getLogoKubuntu,
getLogoLinux,
getLogoManjaro,
getLogoManjaroSmall,
@@ -1288,6 +1478,8 @@ static GetLogoMethod* getLogos()
getLogoReborn,
getLogoRebornSmall,
getLogoRedHatEnterpriseLinux,
getLogoRedstarOS,
getLogoRockyLinux,
getLogoUbuntu,
getLogoUbuntuSmall,
getLogoVoid,
@@ -1298,187 +1490,3 @@ static GetLogoMethod* getLogos()
return logoMethods;
}
static bool logoHasName(const FFlogo* logo, const char* name)
{
const char** logoName = logo->names;
while(*logoName != NULL)
{
if(strcasecmp(*logoName, name) == 0)
return true;
++logoName;
}
return false;
}
static const FFlogo* getBuiltinLogo(const char* name)
{
GetLogoMethod* methods = getLogos();
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
if(logoHasName(logo, name))
return logo;
++methods;
}
return NULL;
}
static const FFlogo* detectBuiltinLogoWithVersion(const FFstrbuf* versionString, const FFstrbuf* name)
{
if(versionString->length == 0)
return getBuiltinLogo(name->chars);
#define FF_PRINT_LOGO_VERSIONED_IF_EXISTS(newLogo, oldLogo, ver) \
if(logoHasName(newLogo, name->chars)) \
{ \
long version = strtol(versionString->chars, NULL, 10); \
return (version == 0 || version == LONG_MAX || version == LONG_MIN || version > ver) ? newLogo : oldLogo; \
}
FF_PRINT_LOGO_VERSIONED_IF_EXISTS(getLogoFedora(), getLogoFedoraOld(), 34)
FF_PRINT_LOGO_VERSIONED_IF_EXISTS(getLogoMint(), getLogoMintOld(), 19)
return getBuiltinLogo(name->chars);
}
static const FFlogo* detectBuiltinLogo(const FFinstance* instance)
{
static const FFlogo* logo;
static bool detected = false;
if(detected)
return logo;
detected = true;
const FFOSResult* os = ffDetectOS(instance);
logo = detectBuiltinLogoWithVersion(&os->version, &os->name);
if(logo != NULL)
return logo;
logo = detectBuiltinLogoWithVersion(&os->version, &os->id);
if(logo != NULL)
return logo;
logo = detectBuiltinLogoWithVersion(&os->version, &os->idLike);
if(logo != NULL)
return logo;
logo = detectBuiltinLogoWithVersion(&os->version, &os->systemName);
if(logo != NULL)
return logo;
return getLogoUnknown();
}
void ffLogoSetMainColor(FFinstance* instance)
{
const FFlogo* logo = NULL;
if(instance->config.logoSource.length > 0)
logo = getBuiltinLogo(instance->config.logoSource.chars);
if(logo == NULL)
logo = detectBuiltinLogo(instance);
ffStrbufAppendS(&instance->config.mainColor, logo->builtinColors[0]);
}
static void printLogoStruct(FFinstance* instance, const FFlogo* logo, bool doColorReplacement)
{
if(!doColorReplacement)
{
ffLogoPrint(instance, logo->data, false);
return;
}
const char** colors = logo->builtinColors;
for(int i = 0; *colors != NULL && i < FASTFETCH_LOGO_MAX_COLORS; i++, colors++)
{
if(instance->config.logoColors[i].length == 0)
ffStrbufAppendS(&instance->config.logoColors[i], *colors);
}
ffLogoPrint(instance, logo->data, true);
}
void ffLogoPrintUnknown(FFinstance* instance)
{
printLogoStruct(instance, getLogoUnknown(), false);
}
bool ffLogoPrintBuiltinIfExists(FFinstance* instance)
{
const FFlogo* logo = getBuiltinLogo(instance->config.logoSource.chars);
if(logo == NULL)
return false;
printLogoStruct(instance, logo, true);
return true;
}
void ffLogoPrintBuiltinDetected(FFinstance* instance)
{
printLogoStruct(instance, detectBuiltinLogo(instance), true);
}
void ffPrintBuiltinLogos(FFinstance* instance)
{
GetLogoMethod* methods = getLogos();
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
printf("\033[%sm%s:\033[0m\n", logo->builtinColors[0], logo->names[0]);
printLogoStruct(instance, logo, true);
ffPrintRemainingLogo(instance);
instance->state.logoHeight = 0;
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
ffStrbufClear(&instance->config.logoColors[i]);
puts("\n");
++methods;
}
}
void ffListBuiltinLogos()
{
GetLogoMethod* methods = getLogos();
uint32_t counter = 0;
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
const char** names = logo->names;
printf("%u)%s ", counter, counter < 10 ? " " : "");
++counter;
while(*names != NULL)
{
printf("\"%s\" ", *names);
++names;
}
putchar('\n');
++methods;
}
}
void ffListBuiltinLogosAutocompletion()
{
GetLogoMethod* methods = getLogos();
while(*methods != NULL)
{
printf("%s\n", (*methods)()->names[0]);
++methods;
}
}
+251 -84
View File
@@ -5,13 +5,16 @@
#define FF_KITTY_MAX_CHUNK_SIZE 4096
#define FF_CACHE_FILE_HEIGHT "height"
#define FF_CACHE_FILE_WIDTH "width"
#define FF_CACHE_FILE_SIXEL "sixel"
#define FF_CACHE_FILE_KITTY_COMPRESSED "kittyc"
#define FF_CACHE_FILE_KITTY_UNCOMPRESSED "kittyu"
#define FF_CACHE_FILE_CHAFA "chafa"
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#ifdef FF_HAVE_ZLIB
#include <zlib.h>
@@ -79,42 +82,54 @@ static inline bool checkAllocationResult(void* data, size_t length)
return true;
}
static void finishPrinting(FFinstance* instance, const FFLogoRequestData* requestData)
static inline uint32_t simpleCeil(double value)
{
instance->state.logoWidth = (uint32_t) (requestData->imagePixelWidth / requestData->characterPixelWidth) + instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
instance->state.logoHeight = (uint32_t) (requestData->imagePixelHeight / requestData->characterPixelHeight);
//Seems to be required on all consoles that support sixel. TBH i don't know why.
if(requestData->type == FF_LOGO_TYPE_SIXEL)
instance->state.logoHeight += 1;
fputs("\033[9999999D", stdout);
printf("\033[%uA", instance->state.logoHeight);
uint32_t result = (uint32_t) value;
return value == (double) result ? result : result + 1;
}
static void writeResult(FFinstance* instance, FFLogoRequestData* requestData, const FFstrbuf* result, const char* cacheFileName)
static void writeCacheStrbuf(FFLogoRequestData* requestData, const FFstrbuf* value, const char* cacheFileName)
{
uint32_t cacheDirLength = requestData->cacheDir.length;
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
ffWriteFileContent(requestData->cacheDir.chars, value);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
}
static void writeCacheUint32(FFLogoRequestData* requestData, uint32_t value, const char* cacheFileName)
{
FFstrbuf content;
content.chars = (char*) &value;
content.length = sizeof(value);
writeCacheStrbuf(requestData, &content, cacheFileName);
}
static void printImagePixels(FFinstance* instance, FFLogoRequestData* requestData, const FFstrbuf* result, const char* cacheFileName)
{
//Calculate character dimensions
instance->state.logoWidth = requestData->logoCharacterWidth + instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
instance->state.logoHeight = requestData->logoCharacterHeight;
if(requestData->type == FF_LOGO_TYPE_KITTY)
instance->state.logoHeight -= 1;
//Write cache files
writeCacheStrbuf(requestData, result, cacheFileName);
if(instance->config.logoWidth == 0)
writeCacheUint32(requestData, instance->state.logoWidth, FF_CACHE_FILE_WIDTH);
if(instance->config.logoHeight == 0)
writeCacheUint32(requestData, instance->state.logoHeight, FF_CACHE_FILE_HEIGHT);
//Write result to stdout
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
fflush(stdout);
ffWriteFDContent(STDOUT_FILENO, result);
//Write result to cache file
uint32_t cacheDirLength = requestData->cacheDir.length;
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
ffWriteFileContent(requestData->cacheDir.chars, result);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
//Write height cache file
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
FFstrbuf content;
content.chars = (char*) &requestData->imagePixelHeight;
content.length = sizeof(requestData->imagePixelHeight);
ffWriteFileContent(requestData->cacheDir.chars, &content);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
//Write escape codes to stdout
finishPrinting(instance, requestData);
//Go to upper left corner
fputs("\033[9999999D", stdout);
printf("\033[%uA", instance->state.logoHeight);
}
static bool printImageSixel(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
@@ -130,7 +145,7 @@ static bool printImageSixel(FFinstance* instance, FFLogoRequestData* requestData
result.chars = (char*) blob;
result.length = (uint32_t) length;
writeResult(instance, requestData, &result, FF_CACHE_FILE_SIXEL);
printImagePixels(instance, requestData, &result, FF_CACHE_FILE_SIXEL);
free(blob);
return true;
@@ -179,20 +194,79 @@ static bool printImageKitty(FFinstance* instance, FFLogoRequestData* requestData
const char* currentPos = chars;
size_t remainingLength = length;
ffStrbufAppendF(&result, "\033_Ga=T,f=32,s=%u,v=%u", requestData->imagePixelWidth, requestData->imagePixelHeight);
ffStrbufAppendF(&result, "\033_Ga=T,f=32,s=%u,v=%u", requestData->logoPixelWidth, requestData->logoPixelHeight);
if(isCompressed)
ffStrbufAppendS(&result, ",o=z");
appendKittyChunk(&result, &currentPos, &remainingLength, false);
while(remainingLength > 0)
appendKittyChunk(&result, &currentPos, &remainingLength, true);
writeResult(instance, requestData, &result, isCompressed ? FF_CACHE_FILE_KITTY_COMPRESSED : FF_CACHE_FILE_KITTY_UNCOMPRESSED);
printImagePixels(instance, requestData, &result, isCompressed ? FF_CACHE_FILE_KITTY_COMPRESSED : FF_CACHE_FILE_KITTY_UNCOMPRESSED);
ffStrbufDestroy(&result);
free(chars);
return true;
}
#ifdef FF_HAVE_CHAFA
#include <chafa/chafa.h>
static bool printImageChafa(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
{
FF_LIBRARY_LOAD(chafa, instance->config.libChafa, false, "libchafa.so", 1)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_new, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_add_by_tags, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_new, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_set_geometry, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_set_symbol_map, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_new, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_draw_all_pixels, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_print, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_unref, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_canvas_config_unref, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, chafa_symbol_map_unref, false)
FF_LIBRARY_LOAD_SYMBOL(chafa, g_string_free, false)
imageData->ffCopyMagickString(imageData->imageInfo->magick, "RGBA", 5);
size_t length;
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
if(!checkAllocationResult(blob, length))
return false;
ChafaSymbolMap* symbolMap = ffchafa_symbol_map_new();
ffchafa_symbol_map_add_by_tags(symbolMap, CHAFA_SYMBOL_TAG_ALL);
ChafaCanvasConfig* canvasConfig = ffchafa_canvas_config_new();
ffchafa_canvas_config_set_geometry(canvasConfig, (gint) requestData->logoCharacterWidth, (gint) requestData->logoCharacterHeight);
ffchafa_canvas_config_set_symbol_map(canvasConfig, symbolMap);
ChafaCanvas* canvas = ffchafa_canvas_new(canvasConfig);
ffchafa_canvas_draw_all_pixels(
canvas,
CHAFA_PIXEL_RGBA8_UNASSOCIATED,
blob,
(gint) imageData->image->columns,
(gint) imageData->image->rows,
(gint) imageData->image->columns * 4
);
GString* str = ffchafa_canvas_print(canvas, NULL);
FFstrbuf result;
result.allocated = (uint32_t) str->allocated_len;
result.length = (uint32_t) str->len;
result.chars = str->str;
ffLogoPrintChars(instance, result.chars, false);
writeCacheStrbuf(requestData, &result, FF_CACHE_FILE_CHAFA);
ffg_string_free(str, TRUE);
ffchafa_canvas_unref(canvas);
ffchafa_canvas_config_unref(canvasConfig);
ffchafa_symbol_map_unref(symbolMap);
return true;
}
#endif
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData)
{
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
@@ -222,31 +296,43 @@ FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData*
//+1, because we need to copy the null byte too
imageData.ffCopyMagickString(imageInfoIn->filename, instance->config.logoSource.chars, instance->config.logoSource.length + 1);
Image* originalImage = ffReadImage(imageInfoIn, imageData.exceptionInfo);
imageData.image = ffReadImage(imageInfoIn, imageData.exceptionInfo);
ffDestroyImageInfo(imageInfoIn);
if(originalImage == NULL)
{
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
//imagePixelWidth is set in ffLogoPrintImageIfExists
requestData->imagePixelHeight = (uint32_t) ((requestData->imagePixelWidth / (double) originalImage->columns) * (double) originalImage->rows);
if(requestData->imagePixelHeight < 1)
{
ffDestroyImage(originalImage);
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
imageData.image = (Image*) imData->resizeFunc(originalImage, requestData->imagePixelWidth, requestData->imagePixelHeight, imageData.exceptionInfo);
ffDestroyImage(originalImage);
if(imageData.image == NULL)
{
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
if(requestData->logoPixelWidth == 0 && requestData->logoPixelHeight == 0)
{
requestData->logoPixelWidth = (uint32_t) imageData.image->columns;
requestData->logoPixelHeight = (uint32_t) imageData.image->rows;
}
else if(requestData->logoPixelWidth == 0)
requestData->logoPixelWidth = (uint32_t) ((double) imageData.image->columns / (double) imageData.image->rows * requestData->logoPixelHeight);
else if(requestData->logoPixelHeight == 0)
requestData->logoPixelHeight = (uint32_t) ((double) imageData.image->rows / (double) imageData.image->columns * requestData->logoPixelWidth);
requestData->logoCharacterWidth = simpleCeil((double) requestData->logoPixelWidth / requestData->characterPixelWidth);
requestData->logoCharacterHeight = simpleCeil((double) requestData->logoPixelHeight / requestData->characterPixelHeight);
if(requestData->logoPixelWidth == 0 || requestData->logoPixelHeight == 0 || requestData->logoCharacterWidth == 0 || requestData->logoCharacterHeight == 0)
{
ffDestroyImage(imageData.image);
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
Image* resized = imData->resizeFunc(imageData.image, requestData->logoPixelWidth, requestData->logoPixelHeight, imageData.exceptionInfo);
ffDestroyImage(imageData.image);
if(resized == NULL)
{
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
imageData.image = resized;
imageData.imageInfo = ffAcquireImageInfo();
if(imageData.imageInfo == NULL)
{
@@ -255,10 +341,16 @@ FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData*
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
bool printSuccessful;
if(requestData->type == FF_LOGO_TYPE_KITTY)
bool printSuccessful = false;
if(requestData->type == FF_LOGO_TYPE_CHAFA)
{
#ifdef FF_HAVE_CHAFA
printSuccessful = printImageChafa(instance, requestData, &imageData);
#endif
}
else if(requestData->type == FF_LOGO_TYPE_KITTY)
printSuccessful = printImageKitty(instance, requestData, &imageData);
else
else if(requestData->type == FF_LOGO_TYPE_SIXEL)
printSuccessful = printImageSixel(instance, requestData, &imageData);
ffDestroyImageInfo(imageData.imageInfo);
@@ -277,32 +369,80 @@ static int getCacheFD(FFLogoRequestData* requestData, const char* fileName)
return fd;
}
static bool printCached(FFinstance* instance, FFLogoRequestData* requestData)
static void readCachedStrbuf(FFLogoRequestData* requestData, FFstrbuf* result, const char* cacheFileName)
{
uint32_t cacheDirLength = requestData->cacheDir.length;
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
ffAppendFileContent(requestData->cacheDir.chars, result);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
}
static uint32_t readCachedUint32(FFLogoRequestData* requestData, const char* cacheFileName)
{
FFstrbuf content;
ffStrbufInitA(&content, sizeof(requestData->imagePixelHeight) + 1); // +1 because strbuf is null terminated
memset(content.chars, 0, sizeof(requestData->imagePixelHeight));
ffStrbufInit(&content);
readCachedStrbuf(requestData, &content, cacheFileName);
ffAppendFileContent(requestData->cacheDir.chars, &content);
memcpy(&requestData->imagePixelHeight, content.chars, sizeof(requestData->imagePixelHeight));
uint32_t result = 0;
if(content.length != sizeof(result))
{
ffStrbufDestroy(&content);
return 0;
}
memcpy(&result, content.chars, sizeof(result));
ffStrbufDestroy(&content);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
if(requestData->imagePixelHeight < 1)
return result;
}
static bool printCachedChars(FFinstance* instance, FFLogoRequestData* requestData)
{
FFstrbuf content;
ffStrbufInitA(&content, 32768);
if(requestData->type == FF_LOGO_TYPE_CHAFA)
readCachedStrbuf(requestData, &content, FF_CACHE_FILE_CHAFA);
if(content.length == 0)
{
ffStrbufDestroy(&content);
return false;
}
int fd;
ffLogoPrintChars(instance, content.chars, false);
ffStrbufDestroy(&content);
return true;
}
static bool printCachedPixel(FFinstance* instance, FFLogoRequestData* requestData)
{
requestData->logoCharacterWidth = instance->config.logoWidth;
if(requestData->logoCharacterWidth == 0)
{
requestData->logoCharacterWidth = readCachedUint32(requestData, FF_CACHE_FILE_WIDTH);
if(requestData->logoCharacterWidth == 0)
return false;
}
requestData->logoCharacterHeight = instance->config.logoHeight;
if(requestData->logoCharacterHeight == 0)
{
requestData->logoCharacterHeight = readCachedUint32(requestData, FF_CACHE_FILE_HEIGHT);
if(requestData->logoCharacterHeight == 0)
return false;
}
int fd = -1;
if(requestData->type == FF_LOGO_TYPE_KITTY)
{
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_COMPRESSED);
if(fd == -1)
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_UNCOMPRESSED);
}
else
else if(requestData->type == FF_LOGO_TYPE_SIXEL)
fd = getCacheFD(requestData, FF_CACHE_FILE_SIXEL);
if(fd == -1)
@@ -314,48 +454,73 @@ static bool printCached(FFinstance* instance, FFLogoRequestData* requestData)
char buffer[32768];
ssize_t readBytes;
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
(void) write(STDOUT_FILENO, buffer, (size_t) readBytes);
FF_UNUSED(write(STDOUT_FILENO, buffer, (size_t) readBytes));
close(fd);
finishPrinting(instance, requestData);
instance->state.logoWidth = requestData->logoCharacterWidth + instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
instance->state.logoHeight = requestData->logoCharacterHeight;
//Go to upper left corner
fputs("\033[9999999D", stdout);
printf("\033[%uA", instance->state.logoHeight);
return true;
}
static bool getTermInfo(struct winsize* winsize)
static bool printCached(FFinstance* instance, FFLogoRequestData* requestData)
{
if(requestData->type == FF_LOGO_TYPE_CHAFA)
return printCachedChars(instance, requestData);
else
return printCachedPixel(instance, requestData);
}
static bool getCharacterPixelDimensions(FFLogoRequestData* requestData)
{
struct winsize winsize;
//Initialize every member to 0, because it isn't guaranteed that every terminal sets them all
memset(winsize, 0, sizeof(struct winsize));
memset(&winsize, 0, sizeof(struct winsize));
ioctl(STDOUT_FILENO, TIOCGWINSZ, winsize);
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
if(winsize->ws_row == 0 || winsize->ws_col == 0)
ffGetTerminalResponse("\033[18t", 't', "\033[8;%hu;%hut", &winsize->ws_row, &winsize->ws_col);
if(winsize.ws_row == 0 || winsize.ws_col == 0)
ffGetTerminalResponse("\033[18t", "\033[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
if(winsize->ws_ypixel == 0 || winsize->ws_xpixel == 0)
ffGetTerminalResponse("\033[14t", 't', "\033[4;%hu;%hut", &winsize->ws_ypixel, &winsize->ws_xpixel);
if(winsize.ws_row == 0 || winsize.ws_col == 0)
return false;
return
winsize->ws_row > 0 &&
winsize->ws_col > 0 &&
winsize->ws_ypixel > 0 &&
winsize->ws_xpixel > 0;
if(winsize.ws_ypixel == 0 || winsize.ws_xpixel == 0)
ffGetTerminalResponse("\033[14t", "\033[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);
requestData->characterPixelWidth = winsize.ws_xpixel / (double) winsize.ws_col;
requestData->characterPixelHeight = winsize.ws_ypixel / (double) winsize.ws_row;
return requestData->characterPixelWidth > 1.0 && requestData->characterPixelHeight > 1.0;
}
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
{
//Performance optimisation
#ifndef FF_HAVE_CHAFA
if(type == FF_LOGO_TYPE_CHAFA)
return false;
#endif
FFLogoRequestData requestData;
if(!getTermInfo(&requestData.winsize))
return false;
requestData.type = type;
requestData.characterPixelWidth = requestData.winsize.ws_xpixel / (double) requestData.winsize.ws_col;
requestData.characterPixelHeight = requestData.winsize.ws_ypixel / (double) requestData.winsize.ws_row;
requestData.imagePixelWidth = (uint32_t) (instance->config.logoWidth * requestData.characterPixelWidth);
if(requestData.imagePixelWidth < 1)
requestData.characterPixelWidth = 1;
requestData.characterPixelHeight = 1;
if(
(type != FF_LOGO_TYPE_CHAFA || instance->config.logoWidth == 0 || instance->config.logoHeight == 0) &&
!getCharacterPixelDimensions(&requestData)
)
return false;
requestData.logoPixelWidth = simpleCeil((double) instance->config.logoWidth * requestData.characterPixelWidth);
requestData.logoPixelHeight = simpleCeil((double) instance->config.logoHeight * requestData.characterPixelHeight);
ffStrbufInitA(&requestData.cacheDir, PATH_MAX * 2);
ffStrbufAppend(&requestData.cacheDir, &instance->state.cacheDir);
ffStrbufAppendS(&requestData.cacheDir, "images");
@@ -371,7 +536,9 @@ bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
if(!ffStrbufEndsWithC(&requestData.cacheDir, '/'))
ffStrbufAppendC(&requestData.cacheDir, '/');
ffStrbufAppendF(&requestData.cacheDir, "%u", requestData.imagePixelWidth);
ffStrbufAppendF(&requestData.cacheDir, "%u", requestData.logoPixelWidth);
ffStrbufAppendC(&requestData.cacheDir, '*');
ffStrbufAppendF(&requestData.cacheDir, "%u", requestData.logoPixelHeight);
ffStrbufAppendC(&requestData.cacheDir, '/');
if(!instance->config.recache && printCached(instance, &requestData))
+7 -7
View File
@@ -3,12 +3,10 @@
#ifndef FF_INCLUDED_LOGO_SIXEL_sixel
#define FF_INCLUDED_LOGO_SIXEL_sixel
#include "fastfetch.h"
#include "../logo.h"
#if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6)
#include <sys/ioctl.h>
#define MAGICKCORE_HDRI_ENABLE 1
#define MAGICKCORE_QUANTUM_DEPTH 16
@@ -24,11 +22,14 @@ typedef struct FFLogoRequestData
FFLogoType type;
FFstrbuf cacheDir;
struct winsize winsize;
double characterPixelWidth;
double characterPixelHeight;
uint32_t imagePixelWidth;
uint32_t imagePixelHeight;
uint32_t logoPixelWidth;
uint32_t logoPixelHeight;
uint32_t logoCharacterHeight;
uint32_t logoCharacterWidth;
} FFLogoRequestData;
typedef struct FFIMData
@@ -50,5 +51,4 @@ FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoRequestData* r
FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoRequestData* requestData);
#endif
#endif
+230 -73
View File
@@ -1,8 +1,9 @@
#include "logo.h"
#include <ctype.h>
#include <string.h>
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement)
void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplacement)
{
uint32_t currentlineLength = 0;
@@ -145,112 +146,268 @@ void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement
printf("\033[%uA", instance->state.logoHeight);
}
static void logoPrintFile(FFinstance* instance, bool doColorReplacement)
static void logoApplyMainColor(FFinstance* instance, const FFlogo* logo)
{
if(instance->config.mainColor.length == 0)
ffStrbufAppendS(&instance->config.mainColor, logo->builtinColors[0]);
}
static bool logoHasName(const FFlogo* logo, const char* name)
{
const char** logoName = logo->names;
while(*logoName != NULL)
{
if(strcasecmp(*logoName, name) == 0)
return true;
++logoName;
}
return false;
}
static const FFlogo* logoGetBuiltin(const char* name)
{
GetLogoMethod* methods = ffLogoBuiltinGetAll();
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
if(logoHasName(logo, name))
return logo;
++methods;
}
return NULL;
}
static const FFlogo* logoGetBuiltinDetected(FFinstance* instance)
{
const FFOSResult* os = ffDetectOS(instance);
const FFlogo* logo = logoGetBuiltin(os->id.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->name.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->prettyName.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->idLike.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->systemName.chars);
if(logo != NULL)
return logo;
return ffLogoBuiltinGetUnknown();
}
static inline void logoApplyMainColorDetected(FFinstance* instance)
{
logoApplyMainColor(instance, logoGetBuiltinDetected(instance));
}
static void logoPrintStruct(FFinstance* instance, const FFlogo* logo)
{
logoApplyMainColor(instance, logo);
const char** colors = logo->builtinColors;
for(int i = 0; *colors != NULL && i < FASTFETCH_LOGO_MAX_COLORS; i++, colors++)
{
if(instance->config.logoColors[i].length == 0)
ffStrbufAppendS(&instance->config.logoColors[i], *colors);
}
ffLogoPrintChars(instance, logo->data, true);
}
static bool logoPrintBuiltinIfExists(FFinstance* instance, const char* name)
{
const FFlogo* logo = logoGetBuiltin(name);
if(logo == NULL)
return false;
logoPrintStruct(instance, logo);
return true;
}
static inline void logoPrintDetected(FFinstance* instance)
{
logoPrintStruct(instance, logoGetBuiltinDetected(instance));
}
static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement)
{
FFstrbuf content;
ffStrbufInitA(&content, 2047);
if(ffAppendFileContent(instance->config.logoSource.chars, &content))
ffLogoPrint(instance, content.chars, doColorReplacement);
else
ffLogoPrintUnknown(instance);
}
static void logoPrintDetected(FFinstance* instance)
{
if(instance->config.logoSource.length > 0)
if(!ffAppendFileContent(instance->config.logoSource.chars, &content))
{
if(
!ffLogoPrintBuiltinIfExists(instance) &&
!ffLogoPrintImageIfExists(instance, FF_LOGO_TYPE_KITTY)
) logoPrintFile(instance, true);
return;
ffStrbufDestroy(&content);
return false;
}
ffLogoPrintBuiltinDetected(instance);
logoApplyMainColorDetected(instance);
ffLogoPrintChars(instance, content.chars, doColorReplacement);
ffStrbufDestroy(&content);
return true;
}
void ffPrintLogo(FFinstance* instance)
static bool logoPrintImageIfExists(FFinstance* instance, FFLogoType logoType)
{
if(instance->config.mainColor.length == 0)
ffLogoSetMainColor(instance);
if(!ffLogoPrintImageIfExists(instance, logoType))
return false;
if(( //Logo type needs set logo name, but nothing was given. Print question mark
instance->config.logoType == FF_LOGO_TYPE_BUILTIN ||
instance->config.logoType == FF_LOGO_TYPE_FILE ||
instance->config.logoType == FF_LOGO_TYPE_RAW ||
instance->config.logoType == FF_LOGO_TYPE_SIXEL
) && instance->config.logoSource.length == 0)
ffLogoPrintUnknown(instance);
else if(instance->config.logoType == FF_LOGO_TYPE_BUILTIN)
{
if(!ffLogoPrintBuiltinIfExists(instance))
ffLogoPrintUnknown(instance);
}
logoApplyMainColorDetected(instance);
return true;
}
static void logoPrintKnownType(FFinstance* instance)
{
bool successfull;
if(instance->config.logoType == FF_LOGO_TYPE_BUILTIN)
successfull = logoPrintBuiltinIfExists(instance, instance->config.logoSource.chars);
else if(instance->config.logoType == FF_LOGO_TYPE_FILE)
logoPrintFile(instance, true);
successfull = logoPrintFileIfExists(instance, true);
else if(instance->config.logoType == FF_LOGO_TYPE_RAW)
logoPrintFile(instance, false);
else if(instance->config.logoType == FF_LOGO_TYPE_SIXEL || instance->config.logoType == FF_LOGO_TYPE_KITTY)
{
if(!ffLogoPrintImageIfExists(instance, instance->config.logoType))
ffLogoPrintBuiltinDetected(instance);
}
else
successfull = logoPrintFileIfExists(instance, false);
else //image
successfull = logoPrintImageIfExists(instance, instance->config.logoType);
if(!successfull)
logoPrintDetected(instance);
}
static inline void printLogoWidth(const FFinstance* instance)
void ffLogoPrint(FFinstance* instance)
{
//In pipe mode, we don't have a logo or padding.
//We also don't need to set main color, because it won't be printed anyway.
//So we can return quickly here.
if(instance->config.pipe)
{
instance->state.logoHeight = 0;
instance->state.logoWidth = 0;
return;
}
//If the source is not set, we can directly print the detected logo.
if(instance->config.logoSource.length == 0)
{
logoPrintDetected(instance);
return;
}
//If the source and source type is set to something else than auto, always print with the set type.
if(instance->config.logoSource.length > 0 && instance->config.logoType != FF_LOGO_TYPE_AUTO)
{
logoPrintKnownType(instance);
return;
}
//If source matches the name of a builtin logo, print it and return.
if(logoPrintBuiltinIfExists(instance, instance->config.logoSource.chars))
return;
const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(instance);
//Terminal emulators that support kitty graphics protocol.
bool supportsKitty =
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wezterm") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0;
//Try to load the logo as an image. If it succeeds, print it and return.
if(logoPrintImageIfExists(instance, supportsKitty ? FF_LOGO_TYPE_KITTY : FF_LOGO_TYPE_CHAFA))
return;
//Try to load the logo as a file. If it succeeds, print it and return.
if(logoPrintFileIfExists(instance, true))
return;
logoPrintDetected(instance);
}
void ffLogoPrintLine(FFinstance* instance)
{
if(instance->state.logoWidth > 0)
printf("\033[%uC", instance->state.logoWidth);
++instance->state.keysHeight;
}
void ffPrintRemainingLogo(FFinstance* instance)
void ffLogoPrintRemaining(FFinstance* instance)
{
if(!instance->config.logoPrintRemaining)
return;
for(uint32_t i = instance->state.keysHeight; i <= instance->state.logoHeight; i++)
while(instance->state.keysHeight < instance->state.logoHeight)
{
printLogoWidth(instance);
ffLogoPrintLine(instance);
putchar('\n');
}
}
void ffPrintLogoLine(FFinstance* instance)
void ffLogoBuiltinPrint(FFinstance* instance)
{
printLogoWidth(instance);
++instance->state.keysHeight;
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
GetLogoMethod* methods = ffLogoBuiltinGetAll();
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
printf("\033[%sm%s:\033[0m\n", logo->builtinColors[0], logo->names[0]);
logoPrintStruct(instance, logo);
ffLogoPrintRemaining(instance);
//reset everything
instance->state.logoHeight = 0;
instance->state.keysHeight = 0;
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
ffStrbufClear(&instance->config.logoColors[i]);
puts("\n");
++methods;
}
}
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
void ffLogoBuiltinList()
{
ffPrintLogoLine(instance);
GetLogoMethod* methods = ffLogoBuiltinGetAll();
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.mainColor);
uint32_t counter = 0;
if(customKeyFormat == NULL || customKeyFormat->length == 0)
while(*methods != NULL)
{
fputs(moduleName, stdout);
const FFlogo* logo = (*methods)();
const char** names = logo->names;
if(moduleIndex > 0)
printf(" %hhu", moduleIndex);
}
else
{
FFstrbuf key;
ffStrbufInit(&key);
ffParseFormatString(&key, customKeyFormat, NULL, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT8, &moduleIndex}
});
ffStrbufWriteTo(&key, stdout);
ffStrbufDestroy(&key);
}
printf("%u)%s ", counter, counter < 10 ? " " : "");
++counter;
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
ffStrbufWriteTo(&instance->config.separator, stdout);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
while(*names != NULL)
{
printf("\"%s\" ", *names);
++names;
}
putchar('\n');
++methods;
}
}
void ffLogoBuiltinListAutocompletion()
{
GetLogoMethod* methods = ffLogoBuiltinGetAll();
while(*methods != NULL)
{
printf("%s\n", (*methods)()->names[0]);
++methods;
}
}
+13 -7
View File
@@ -5,17 +5,23 @@
#include "fastfetch.h"
typedef struct FFlogo
{
const char* data;
const char** names; //Null terminated
const char** builtinColors; //Null terminated
} FFlogo;
typedef const FFlogo*(*GetLogoMethod)();
//logo.c
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement);
void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplacement);
//builtin.c
void ffLogoSetMainColor(FFinstance* instance);
const FFlogo* ffLogoBuiltinGetUnknown();
GetLogoMethod* ffLogoBuiltinGetAll();
void ffLogoPrintUnknown(FFinstance* instance);
bool ffLogoPrintBuiltinIfExists(FFinstance* instance);
void ffLogoPrintBuiltinDetected(FFinstance* instance);
//sixel/image.c
//image/image.c
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type);
#endif
+1 -1
View File
@@ -2,6 +2,6 @@
void ffPrintBreak(FFinstance* instance)
{
ffPrintLogoLine(instance);
ffLogoPrintLine(instance);
putchar('\n');
}
+11 -2
View File
@@ -2,7 +2,16 @@
void ffPrintColors(FFinstance* instance)
{
ffPrintLogoLine(instance);
if(instance->config.pipe)
{
ffLogoPrintLine(instance);
puts("████████████████████████");
ffLogoPrintLine(instance);
puts("████████████████████████");
return;
}
ffLogoPrintLine(instance);
// 4%d: Set the background color
// 3%d: Set the foreground color
@@ -11,7 +20,7 @@ void ffPrintColors(FFinstance* instance)
puts(FASTFETCH_TEXT_MODIFIER_RESET);
ffPrintLogoLine(instance);
ffLogoPrintLine(instance);
// 1: Set everything to bolt. This causes normal colors on some systems to be bright.
// 4%d: Set the backgound to the not bright color
+2 -2
View File
@@ -39,10 +39,10 @@ void ffPrintCPU(FFinstance* instance)
if(ffPrintFromCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpuKey, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS))
return;
FILE* cpuinfo = fopen(FASTFETCH_TARGET_DIR_ROOT"/proc/cpuinfo", "r");
FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
if(cpuinfo == NULL)
{
ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpuKey, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, "fopen(\""FASTFETCH_TARGET_DIR_ROOT"/proc/cpuinfo\", \"r\") == NULL");
ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpuKey, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, "fopen(\"""/proc/cpuinfo\", \"r\") == NULL");
return;
}
+2 -2
View File
@@ -9,10 +9,10 @@
void ffPrintCPUUsage(FFinstance* instance)
{
long user, nice, system, idle, iowait, irq, softirq;
FILE* procStat = fopen(FASTFETCH_TARGET_DIR_ROOT"/proc/stat", "r");
FILE* procStat = fopen("/proc/stat", "r");
if(procStat == NULL)
{
ffPrintError(instance, FF_CPU_USAGE_MODULE_NAME, 0, &instance->config.cpuUsageKey, &instance->config.cpuUsageFormat, FF_CPU_USAGE_NUM_FORMAT_ARGS, "fopen(\""FASTFETCH_TARGET_DIR_ROOT"/proc/stat\", \"r\") == NULL");
ffPrintError(instance, FF_CPU_USAGE_MODULE_NAME, 0, &instance->config.cpuUsageKey, &instance->config.cpuUsageFormat, FF_CPU_USAGE_NUM_FORMAT_ARGS, "fopen(\"""/proc/stat\", \"r\") == NULL");
return;
}
if (fscanf(procStat, "cpu%ld%ld%ld%ld%ld%ld%ld", &user, &nice, &system, &idle, &iowait, &irq, &softirq) < 0) goto exit;
+119 -194
View File
@@ -5,181 +5,7 @@
#define FF_GPU_MODULE_NAME "GPU"
#define FF_GPU_NUM_FORMAT_ARGS 5
typedef struct GPUResult
{
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
} GPUResult;
#ifdef FF_HAVE_VULKAN
#include <vulkan/vulkan.h>
static void vulkanFillGPUs(FFinstance* instance, FFlist* results)
{
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", 2)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkCreateInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkDestroyInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkEnumeratePhysicalDevices,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetPhysicalDeviceProperties,)
//Some drivers (nvdc) print messages to stdout
//and thats the best way i found to disable that
ffSuppressIO(true);
const VkApplicationInfo applicationInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = NULL,
.pApplicationName = FASTFETCH_PROJECT_NAME,
.applicationVersion = VK_MAKE_VERSION(FASTFETCH_PROJECT_VERSION_MAJOR, 0, 0),
.pEngineName = "vulkanPrintGPUs",
.engineVersion = VK_MAKE_VERSION(FASTFETCH_PROJECT_VERSION_MAJOR, 0, 0),
.apiVersion = VK_API_VERSION_1_0,
};
const VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = NULL,
.pApplicationInfo = &applicationInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = NULL,
.enabledExtensionCount = 0,
.ppEnabledExtensionNames = NULL,
.flags = 0
};
VkInstance vkInstance;
if(ffvkCreateInstance(&instanceCreateInfo, NULL, &vkInstance) != VK_SUCCESS)
{
dlclose(vulkan);
ffSuppressIO(false);
return;
}
uint32_t physicalDeviceCount;
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL) != VK_SUCCESS)
{
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
VkPhysicalDevice* physicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices) != VK_SUCCESS)
{
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
for(uint32_t i = 0; i < physicalDeviceCount; i++)
{
VkPhysicalDeviceProperties physicalDeviceProperties;
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties);
//We don't want softare rasterizers
if(physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
GPUResult* result = ffListAdd(results);
ffStrbufInit(&result->vendor);
ffStrbufInit(&result->name);
ffStrbufInit(&result->driver);
ffStrbufAppendS(&result->name, physicalDeviceProperties.deviceName);
}
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
#endif
#ifdef FF_HAVE_LIBPCI
#include <pci/pci.h>
#include <unistd.h>
//see https://github.com/pciutils/pciutils/blob/5bdf63b6b1bc35b59c4b3f47f7ca83ca1868155b/ls-kernel.c#L220
static void pciGetDriver(struct pci_dev* dev, FFstrbuf* driver, char*(*ffpci_get_param)(struct pci_access*, char*))
{
if(dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
return;
const char* base = ffpci_get_param(dev->access, "sysfs.path");
if(!ffStrSet(base))
return;
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffStrbufAppendF(&path, "%s/devices/%04x:%02x:%02x.%d/driver", base, dev->domain, dev->bus, dev->dev, dev->func);
ffStrbufEnsureFree(driver, 1023);
ssize_t resultLength = readlink(path.chars, driver->chars, driver->allocated - 1); //-1 for null terminator
if(resultLength > 0)
{
driver->length = (uint32_t) resultLength;
driver->chars[resultLength] = '\0';
ffStrbufSubstrAfterLastC(driver, '/');
}
ffStrbufDestroy(&path);
}
static void pciFillGPUs(FFinstance* instance, FFlist* results)
{
FF_LIBRARY_LOAD(pci, instance->config.libPCI, , "libpci.so", 4)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_alloc,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_init,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_scan_bus,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_fill_info,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_lookup_name,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_get_param,)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_cleanup,)
struct pci_access *pacc = ffpci_alloc();
ffpci_init(pacc);
ffpci_scan_bus(pacc);
struct pci_dev* dev;
for (dev=pacc->devices; dev; dev=dev->next)
{
ffpci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS);
char class[1024];
ffpci_lookup_name(pacc, class, sizeof(class), PCI_LOOKUP_CLASS, dev->device_class);
if(
strcasecmp("VGA compatible controller", class) == 0 ||
strcasecmp("3D controller", class) == 0 ||
strcasecmp("Display controller", class) == 0
) {
GPUResult* result = ffListAdd(results);
ffStrbufInitA(&result->vendor, 256);
ffpci_lookup_name(pacc, result->vendor.chars, (int) result->vendor.allocated -1, PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->vendor);
ffStrbufInitA(&result->name, 256);
ffpci_lookup_name(pacc, result->name.chars, (int) result->name.allocated - 1, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->name);
ffStrbufInit(&result->driver);
if(instance->config.gpuFormat.length > 0) //We only need it for the format string, so don't detect it if it isn't needed
pciGetDriver(dev, &result->driver, ffpci_get_param);
};
}
ffpci_cleanup(pacc);
dlclose(pci);
}
#endif
static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, GPUResult* result)
static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache, FFGPUResult* result)
{
const char* vendorPretty;
if(ffStrbufIgnCaseCompS(&result->vendor, "Advanced Micro Devices, Inc. [AMD/ATI]") == 0)
@@ -222,32 +48,131 @@ static void printGPUResult(FFinstance* instance, uint8_t index, FFcache* cache,
ffStrbufDestroy(&namePretty);
}
static void printGPUList(FFinstance* instance, const FFlist* list)
{
FFcache cache;
ffCacheOpenWrite(instance, FF_GPU_MODULE_NAME, &cache);
for(uint8_t i = 0; i < (uint8_t) list->length; i++)
printGPUResult(instance, list->length == 1 ? 0 : (uint8_t) (i + 1), &cache, ffListGet(list, i));
ffCacheClose(&cache);
}
#ifdef FF_HAVE_LIBPCI
#include <pci/pci.h>
#include <unistd.h>
//see https://github.com/pciutils/pciutils/blob/5bdf63b6b1bc35b59c4b3f47f7ca83ca1868155b/ls-kernel.c#L220
static void pciGetDriver(struct pci_dev* dev, FFstrbuf* driver, char*(*ffpci_get_param)(struct pci_access*, char*))
{
if(dev->access->method != PCI_ACCESS_SYS_BUS_PCI)
return;
const char* base = ffpci_get_param(dev->access, "sysfs.path");
if(!ffStrSet(base))
return;
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffStrbufAppendF(&path, "%s/devices/%04x:%02x:%02x.%d/driver", base, dev->domain, dev->bus, dev->dev, dev->func);
ffStrbufEnsureFree(driver, 1023);
ssize_t resultLength = readlink(path.chars, driver->chars, driver->allocated - 1); //-1 for null terminator
if(resultLength > 0)
{
driver->length = (uint32_t) resultLength;
driver->chars[resultLength] = '\0';
ffStrbufSubstrAfterLastC(driver, '/');
}
ffStrbufDestroy(&path);
}
static bool pciPrintGPUs(FFinstance* instance)
{
FF_LIBRARY_LOAD(pci, instance->config.libPCI, false, "libpci.so", 4)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_alloc, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_init, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_scan_bus, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_fill_info, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_lookup_name, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_get_param, false)
FF_LIBRARY_LOAD_SYMBOL(pci, pci_cleanup, false)
FFlist results;
ffListInit(&results, sizeof(FFGPUResult));
struct pci_access *pacc = ffpci_alloc();
ffpci_init(pacc);
ffpci_scan_bus(pacc);
struct pci_dev* dev;
for (dev=pacc->devices; dev; dev=dev->next)
{
ffpci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS);
char class[1024];
ffpci_lookup_name(pacc, class, sizeof(class), PCI_LOOKUP_CLASS, dev->device_class);
if(
strcasecmp("VGA compatible controller", class) == 0 ||
strcasecmp("3D controller", class) == 0 ||
strcasecmp("Display controller", class) == 0
) {
FFGPUResult* result = ffListAdd(&results);
ffStrbufInitA(&result->vendor, 256);
ffpci_lookup_name(pacc, result->vendor.chars, (int) result->vendor.allocated -1, PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->vendor);
ffStrbufInitA(&result->name, 256);
ffpci_lookup_name(pacc, result->name.chars, (int) result->name.allocated - 1, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
ffStrbufRecalculateLength(&result->name);
ffStrbufInit(&result->driver);
if(instance->config.gpuFormat.length > 0) //We only need it for the format string, so don't detect it if it isn't needed
pciGetDriver(dev, &result->driver, ffpci_get_param);
};
}
ffpci_cleanup(pacc);
dlclose(pci);
if(results.length == 0)
{
ffListDestroy(&results);
return false;
}
printGPUList(instance, &results);
ffListDestroy(&results);
return true;
}
#endif
static bool vulkanPrintGPUs(FFinstance* instance)
{
const FFVulkanResult* result = ffDetectVulkan(instance);
if(result->devices.length == 0)
return false;
printGPUList(instance, &result->devices);
return true;
}
void ffPrintGPU(FFinstance* instance)
{
if(ffPrintFromCache(instance, FF_GPU_MODULE_NAME, &instance->config.gpuKey, &instance->config.gpuFormat, FF_GPU_NUM_FORMAT_ARGS))
return;
FFlist gpus;
ffListInitA(&gpus, sizeof(GPUResult), 4);
FFcache cache;
ffCacheOpenWrite(instance, FF_GPU_MODULE_NAME, &cache);
#ifdef FF_HAVE_LIBPCI
pciFillGPUs(instance, &gpus);
if(pciPrintGPUs(instance))
return;
#endif
#ifdef FF_HAVE_VULKAN
if(gpus.length == 0)
vulkanFillGPUs(instance, &gpus);
#endif
if(vulkanPrintGPUs(instance))
return;
for(uint8_t i = 0; i < (uint8_t) gpus.length; i++)
printGPUResult(instance, gpus.length == 1 ? 0 : (uint8_t) (i + 1), &cache, ffListGet(&gpus, i));
if(gpus.length == 0)
ffPrintError(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpuKey, &instance->config.gpuFormat, FF_GPU_NUM_FORMAT_ARGS, "No GPUs found.");
ffCacheClose(&cache);
ffListDestroy(&gpus);
ffPrintError(instance, FF_GPU_MODULE_NAME, 0, &instance->config.gpuKey, &instance->config.gpuFormat, FF_GPU_NUM_FORMAT_ARGS, "No GPUs found.");
}
+12 -2
View File
@@ -28,10 +28,20 @@ void ffPrintLocale(FFinstance* instance)
FFstrbuf locale;
ffStrbufInit(&locale);
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/locale.conf", "LANG =", &locale);
//Ubuntu (and deriviates) use a non standard locale file.
//Parse it first, because on distributions where it exists, it takes precedence.
//Otherwise use the standard /etc/locale.conf file.
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/default/locale", "LANG =", &locale);
if (locale.length == 0)
if(locale.length == 0)
{
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/locale.conf", "LANG =", &locale);
}
if(locale.length == 0)
{
getLocaleFromEnv(&locale);
}
if(locale.length == 0)
{
+3 -3
View File
@@ -6,9 +6,9 @@
// Impl inspired by: https://github.com/sam-barr/paleofetch/blob/b7c58a52c0de39b53c9b5f417889a5886d324bfa/paleofetch.c#L544
void ffPrintMemory(FFinstance* instance)
{
FILE* meminfo = fopen(FASTFETCH_TARGET_DIR_ROOT"/proc/meminfo", "r");
FILE* meminfo = fopen("/proc/meminfo", "r");
if(meminfo == NULL) {
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, "fopen(\""FASTFETCH_TARGET_DIR_ROOT"/proc/meminfo\", \"r\") == NULL");
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, "fopen(\"""/proc/meminfo\", \"r\") == NULL");
return;
}
@@ -42,7 +42,7 @@ void ffPrintMemory(FFinstance* instance)
if(used_mem == 0 && total_mem == 0 && percentage == 0)
{
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, FASTFETCH_TARGET_DIR_ROOT"/proc/meminfo could't be parsed");
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, "/proc/meminfo could't be parsed");
return;
}
+91
View File
@@ -0,0 +1,91 @@
#include "fastfetch.h"
#define FF_OPENCL_MODULE_NAME "OpenCL"
#define FF_OPENCL_NUM_FORMAT_ARGS 3
#ifdef FF_HAVE_OPENCL
#define CL_TARGET_OPENCL_VERSION 100
#include <CL/cl.h>
typedef struct OpenCLData
{
FF_LIBRARY_SYMBOL(clGetPlatformIDs);
FF_LIBRARY_SYMBOL(clGetDeviceIDs);
FF_LIBRARY_SYMBOL(clGetDeviceInfo);
} OpenCLData;
static const char* openCLHandelData(FFinstance* instance, OpenCLData* data)
{
cl_platform_id platformID;
cl_uint numPlatforms;
data->ffclGetPlatformIDs(1, &platformID, &numPlatforms);
if(numPlatforms == 0)
return "clGetPlatformIDs returned 0 platforms";
cl_device_id deviceID;
cl_uint numDevices;
data->ffclGetDeviceIDs(platformID, CL_DEVICE_TYPE_GPU, 1, &deviceID, &numDevices);
if(numDevices == 0)
data->ffclGetDeviceIDs(platformID, CL_DEVICE_TYPE_ALL, 1, &deviceID, &numDevices);
if(numDevices == 0)
return "clGetDeviceIDs returned 0 devices";
char version[64];
data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VERSION, sizeof(version), version, NULL);
if(!ffStrSet(version))
return "clGetDeviceInfo returned NULL or empty string";
char device[128];
data->ffclGetDeviceInfo(deviceID, CL_DEVICE_NAME, sizeof(device), device, NULL);
char vendor[32];
data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VENDOR, sizeof(vendor), vendor, NULL);
if(instance->config.openCLFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_OPENCL_MODULE_NAME, 0, &instance->config.openCLKey);
puts(version);
}
else
{
ffPrintFormatString(instance, FF_OPENCL_MODULE_NAME, 0, &instance->config.openCLKey, &instance->config.openCLFormat, NULL, FF_OPENCL_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRING, version},
{FF_FORMAT_ARG_TYPE_STRING, device},
{FF_FORMAT_ARG_TYPE_STRING, vendor}
});
}
return NULL;
}
static const char* printOpenCL(FFinstance* instance)
{
OpenCLData data;
FF_LIBRARY_LOAD(opencl, instance->config.libOpenCL, "dlopen libOpenCL.so failed", "libOpenCL.so", 1);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(opencl, data.ffclGetPlatformIDs, clGetPlatformIDs, "dlsym clGetPlatformIDs failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(opencl, data.ffclGetDeviceIDs, clGetDeviceIDs, "dlsym clGetDeviceIDs failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(opencl, data.ffclGetDeviceInfo, clGetDeviceInfo, "dlsym clGetDeviceInfo failed");
const char* error = openCLHandelData(instance, &data);
dlclose(opencl);
return error;
}
#endif
void ffPrintOpenCL(FFinstance* instance)
{
const char* error;
#ifdef FF_HAVE_OPENCL
error = printOpenCL(instance);
#else
error = "Fastfetch was build without OpenCL support";
#endif
if(error != NULL)
ffPrintError(instance, FF_OPENCL_MODULE_NAME, 0, &instance->config.openCLKey, &instance->config.openCLFormat, FF_OPENCL_NUM_FORMAT_ARGS, error);
}
+392
View File
@@ -0,0 +1,392 @@
#include "fastfetch.h"
#include <string.h>
#define FF_OPENGL_MODULE_NAME "OpenGL"
#define FF_OPENGL_NUM_FORMAT_ARGS 4
#if defined(FF_HAVE_EGL) || defined(FF_HAVE_GLX) || defined(FF_HAVE_OSMESA)
#define FF_HAVE_GL 1
#include <GL/gl.h>
#define FF_OPENGL_BUFFER_WIDTH 1
#define FF_OPENGL_BUFFER_HEIGHT 1
typedef struct GLData
{
FF_LIBRARY_SYMBOL(glGetString);
} GLData;
static const char* glHandlePrint(FFinstance* instance, const GLData* data)
{
const char* version = (const char*) data->ffglGetString(GL_VERSION);
if(!ffStrSet(version))
return "glGetString(GL_VERSION) returned NULL";
const char* renderer = (const char*) data->ffglGetString(GL_RENDERER);
const char* vendor = (const char*) data->ffglGetString(GL_VENDOR);
const char* slv = (const char*) data->ffglGetString(GL_SHADING_LANGUAGE_VERSION);
if(instance->config.openGLFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGLKey);
puts(version);
}
else
{
ffPrintFormatString(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGLKey, &instance->config.openGLFormat, NULL, FF_OPENGL_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRING, version},
{FF_FORMAT_ARG_TYPE_STRING, renderer},
{FF_FORMAT_ARG_TYPE_STRING, vendor},
{FF_FORMAT_ARG_TYPE_STRING, slv}
});
}
return NULL;
}
#ifdef FF_HAVE_EGL
#include <EGL/egl.h>
typedef struct EGLData
{
GLData glData;
FF_LIBRARY_SYMBOL(eglGetProcAddress);
FF_LIBRARY_SYMBOL(eglGetDisplay);
FF_LIBRARY_SYMBOL(eglInitialize);
FF_LIBRARY_SYMBOL(eglBindAPI);
FF_LIBRARY_SYMBOL(eglGetConfigs);
FF_LIBRARY_SYMBOL(eglCreatePbufferSurface);
FF_LIBRARY_SYMBOL(eglCreateContext);
FF_LIBRARY_SYMBOL(eglMakeCurrent);
FF_LIBRARY_SYMBOL(eglDestroyContext);
FF_LIBRARY_SYMBOL(eglDestroySurface);
FF_LIBRARY_SYMBOL(eglTerminate);
EGLDisplay display;
EGLConfig config;
EGLSurface surface;
EGLContext context;
} EGLData;
static const char* eglHandleContext(FFinstance* instance, EGLData* data)
{
if(data->ffeglMakeCurrent(data->display, data->surface, data->surface, data->context) != EGL_TRUE)
return "eglMakeCurrent returned EGL_FALSE";
return glHandlePrint(instance, &data->glData);
}
static const char* eglHandleSurface(FFinstance* instance, EGLData* data)
{
data->context = data->ffeglCreateContext(data->display, data->config, EGL_NO_CONTEXT, (EGLint[]){EGL_NONE});
if(data->context == EGL_NO_CONTEXT)
return "eglCreateContext returned EGL_NO_CONTEXT";
const char* error = eglHandleContext(instance, data);
data->ffeglDestroyContext(data->display, data->context);
return error;
}
static const char* eglHandleDisplay(FFinstance* instance, EGLData* data)
{
if(data->ffeglBindAPI(EGL_OPENGL_API) != EGL_TRUE)
return "eglBindAPI returned EGL_FALSE";
EGLint eglConfigCount;
data->ffeglGetConfigs(data->display, &data->config, 1, &eglConfigCount);
if(eglConfigCount == 0)
return "eglGetConfigs returned 0 configs";
data->surface = data->ffeglCreatePbufferSurface(data->display, data->config, (EGLint[]){
EGL_WIDTH, FF_OPENGL_BUFFER_WIDTH,
EGL_HEIGHT, FF_OPENGL_BUFFER_HEIGHT,
EGL_NONE
});
if(data->surface == EGL_NO_SURFACE)
return "eglCreatePbufferSurface returned EGL_NO_SURFACE";
const char* error = eglHandleSurface(instance, data);
data->ffeglDestroySurface(data->display, data->surface);
return error;
}
static const char* eglHandleData(FFinstance* instance, EGLData* data)
{
data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) data->ffeglGetProcAddress("glGetString");
if(!data->glData.ffglGetString)
return "eglGetProcAddress(glGetString) returned NULL";
data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY);
if(data->display == EGL_NO_DISPLAY)
return "eglGetDisplay returned EGL_NO_DISPLAY";
EGLint major, minor;
if(data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE)
return "eglInitialize returned EGL_FALSE";
const char* error = eglHandleDisplay(instance, data);
data->ffeglTerminate(data->display);
return error;
}
static const char* eglPrint(FFinstance* instance)
{
EGLData eglData;
FF_LIBRARY_LOAD(egl, instance->config.libEGL, "dlopen egl failed", "libEGL.so", 1);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglGetProcAddress, eglGetProcAddress, "dlsym eglGetProcAddress failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglGetDisplay, eglGetDisplay, "dlsym eglGetDisplay failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglInitialize, eglInitialize, "dlsym eglInitialize failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglBindAPI, eglBindAPI, "dlsym eglBindAPI failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglGetConfigs, eglGetConfigs, "dlsym eglGetConfigs failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglCreatePbufferSurface, eglCreatePbufferSurface, "dlsym eglCreatePbufferSurface failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglCreateContext, eglCreateContext, "dlsym eglCreateContext failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglMakeCurrent, eglMakeCurrent, "dlsym eglMakeCurrent failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglDestroyContext, eglDestroyContext, "dlsym eglDestroyContext failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglDestroySurface, eglDestroySurface, "dlsym eglDestroySurface failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(egl, eglData.ffeglTerminate, eglTerminate, "dlsym eglTerminate failed");
const char* error = eglHandleData(instance, &eglData);
dlclose(egl);
return error;
}
#endif //FF_HAVE_EGL
#ifdef FF_HAVE_GLX
#include <GL/glx.h>
typedef struct GLXData
{
GLData glData;
FF_LIBRARY_SYMBOL(glXGetProcAddress);
FF_LIBRARY_SYMBOL(XOpenDisplay);
FF_LIBRARY_SYMBOL(glXChooseVisual);
FF_LIBRARY_SYMBOL(XCreatePixmap);
FF_LIBRARY_SYMBOL(glXCreateGLXPixmap);
FF_LIBRARY_SYMBOL(glXCreateContext);
FF_LIBRARY_SYMBOL(glXMakeCurrent);
FF_LIBRARY_SYMBOL(glXDestroyContext);
FF_LIBRARY_SYMBOL(glXDestroyGLXPixmap);
FF_LIBRARY_SYMBOL(XFreePixmap);
FF_LIBRARY_SYMBOL(XCloseDisplay);
Display* display;
XVisualInfo* visualInfo;
Pixmap pixmap;
GLXPixmap glxPixmap;
GLXContext context;
} GLXData;
static const char* glxHandleContext(FFinstance* instance, GLXData* data)
{
if(data->ffglXMakeCurrent(data->display, data->glxPixmap, data->context) != True)
return "glXMakeCurrent returned False";
return glHandlePrint(instance, &data->glData);
}
static const char* glxHandleGLXPixmap(FFinstance* instance, GLXData* data)
{
data->context = data->ffglXCreateContext(data->display, data->visualInfo, NULL, True);
if(data->context == NULL)
return "glXCreateContext returned NULL";
const char* error = glxHandleContext(instance, data);
data->ffglXDestroyContext(data->display, data->context);
return error;
}
static const char* glxHandlePixmap(FFinstance* instance, GLXData* data)
{
data->glxPixmap = data->ffglXCreateGLXPixmap(data->display, data->visualInfo, data->pixmap);
if(data->glxPixmap == None)
return "glXCreateGLXPixmap returned None";
const char* error = glxHandleGLXPixmap(instance, data);
data->ffglXDestroyGLXPixmap(data->display, data->glxPixmap);
return error;
}
static const char* glxHandleVisualInfo(FFinstance* instance, GLXData* data)
{
data->pixmap = data->ffXCreatePixmap(data->display, DefaultRootWindow(data->display), FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, (unsigned int) data->visualInfo->depth);
if(data->pixmap == None)
return "XCreatePixmap returned None";
const char* error = glxHandlePixmap(instance, data);
data->ffXFreePixmap(data->display, data->pixmap);
return error;
}
static const char* glxHandleDisplay(FFinstance* instance, GLXData* data)
{
data->visualInfo = data->ffglXChooseVisual(data->display, DefaultScreen(data->display), (int[]){None});
if(data->visualInfo == NULL)
return "glXChooseVisual returned NULL";
return glxHandleVisualInfo(instance, data);
}
static const char* glxHandleData(FFinstance* instance, GLXData* data)
{
data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) data->ffglXGetProcAddress((const GLubyte*) "glGetString");
if(data->glData.ffglGetString == NULL)
return "glXGetProcAddress(glGetString) returned NULL";
data->display = data->ffXOpenDisplay(NULL);
if(data->display == NULL)
return "XOpenDisplay returned NULL";
const char* error = glxHandleDisplay(instance, data);
data->ffXCloseDisplay(data->display);
return error;
}
static const char* glxPrint(FFinstance* instance)
{
GLXData data;
FF_LIBRARY_LOAD(glx, instance->config.libGLX, "dlopen glx failed", "libGLX.so", 1);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXGetProcAddress, glXGetProcAddress, "dlsym glXGetProcAddress failed");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXOpenDisplay, XOpenDisplay, "dlsym XOpenDisplay returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXChooseVisual, glXChooseVisual, "dlsym glXChooseVisual returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXCreatePixmap, XCreatePixmap, "dlsym XCreatePixmap returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXCreateGLXPixmap, glXCreateGLXPixmap, "dlsym glXCreateGLXPixmap returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXCreateContext, glXCreateContext, "dlsym glXCreateContext returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXMakeCurrent, glXMakeCurrent, "dlsym glXMakeCurrent returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXDestroyContext, glXDestroyContext, "dlsym glXDestroyContext returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffglXDestroyGLXPixmap, glXDestroyGLXPixmap, "dlsym glXDestroyGLXPixmap returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXFreePixmap, XFreePixmap, "dlsym XFreePixmap returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(glx, data.ffXCloseDisplay, XCloseDisplay, "dlsym XCloseDisplay returned NULL");
const char* error = glxHandleData(instance, &data);
dlclose(glx);
return error;
}
#endif //FF_HAVE_GLX
#ifdef FF_HAVE_OSMESA
#include <GL/osmesa.h>
typedef struct OSMesaData
{
GLData glData;
FF_LIBRARY_SYMBOL(OSMesaGetProcAddress);
FF_LIBRARY_SYMBOL(OSMesaCreateContext);
FF_LIBRARY_SYMBOL(OSMesaMakeCurrent);
FF_LIBRARY_SYMBOL(OSMesaDestroyContext);
OSMesaContext context;
} OSMesaData;
static const char* osMesaHandleContext(FFinstance* instance, OSMesaData* data)
{
unsigned char buffer[FF_OPENGL_BUFFER_WIDTH * FF_OPENGL_BUFFER_HEIGHT * sizeof(uint32_t)]; // 4 bytes per pixel (RGBA)
if(data->ffOSMesaMakeCurrent(data->context, buffer, GL_UNSIGNED_BYTE, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT) != GL_TRUE)
return "OSMesaMakeCurrent returned GL_FALSE";
return glHandlePrint(instance, &data->glData);
}
static const char* osMesaHandleData(FFinstance* instance, OSMesaData* data)
{
//The case to void* is required here, because OSMESAproc can't be cast to (__typeof__(data->glData.ffglGetString)) without a warning, even though it is the actual type.
data->glData.ffglGetString = (__typeof__(data->glData.ffglGetString)) (void*) data->ffOSMesaGetProcAddress("glGetString");
if(data->glData.ffglGetString == NULL)
return "OSMesaGetProcAddress(glGetString) returned NULL";
data->context = data->ffOSMesaCreateContext(OSMESA_RGBA, NULL);
if(data->context == NULL)
return "OSMesaCreateContext returned NULL";
const char* error = osMesaHandleContext(instance, data);
data->ffOSMesaDestroyContext(data->context);
return error;
}
static const char* osMesaPrint(FFinstance* instance)
{
OSMesaData data;
FF_LIBRARY_LOAD(osmesa, instance->config.libOSMesa, "dlopen osmesa failed", "libOSMesa.so", 8);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(osmesa, data.ffOSMesaGetProcAddress, OSMesaGetProcAddress, "dlsym OSMesaGetProcAddress returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(osmesa, data.ffOSMesaCreateContext, OSMesaCreateContext, "dlsym OSMesaCreateContext returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(osmesa, data.ffOSMesaMakeCurrent, OSMesaMakeCurrent, "dlsym OSMesaMakeCurrent returned NULL");
FF_LIBRARY_LOAD_SYMBOL_ADRESS(osmesa, data.ffOSMesaDestroyContext, OSMesaDestroyContext, "dlsym OSMesaDestroyContext returned NULL");
const char* error = osMesaHandleData(instance, &data);
dlclose(osmesa);
return error;
}
#endif //FF_HAVE_OSMESA
static const char* glPrint(FFinstance* instance)
{
if(instance->config.glType == FF_GL_TYPE_GLX)
{
#ifdef FF_HAVE_GLX
return glxPrint(instance);
#else
return "fastfetch was compiled without glx support";
#endif
}
if(instance->config.glType == FF_GL_TYPE_EGL)
{
#ifdef FF_HAVE_EGL
return eglPrint(instance);
#else
return "fastfetch was compiled without egl support";
#endif
}
if(instance->config.glType == FF_GL_TYPE_OSMESA)
{
#ifdef FF_HAVE_OSMESA
return osMesaPrint(instance);
#else
return "fastfetch was compiled without osmesa support";
#endif
}
const char* error = ""; // not NULL dummy value
#ifdef FF_HAVE_EGL
error = eglPrint(instance);
#endif
#ifdef FF_HAVE_GLX
if(error != NULL)
error = glxPrint(instance);
#endif
//We don't use osmesa in auto mode here, because it is a software implementation,
//that doesn't reflect the opengl supported by the hardware
return error;
}
#endif // FF_HAVE_GL
void ffPrintOpenGL(FFinstance* instance)
{
const char* error;
#ifndef FF_HAVE_GL
error = "Fastfetch was built without gl support.";
#else
error = glPrint(instance);
#endif
if(error != NULL)
ffPrintError(instance, FF_OPENGL_MODULE_NAME, 0, &instance->config.openGLKey, &instance->config.openGLFormat, FF_OPENGL_NUM_FORMAT_ARGS, error);
}
+22 -17
View File
@@ -5,9 +5,6 @@
void ffPrintOS(FFinstance* instance)
{
if(ffPrintFromCache(instance, FF_OS_MODULE_NAME, &instance->config.osKey, &instance->config.osFormat, FF_OS_NUM_FORMAT_ARGS))
return;
const FFOSResult* result = ffDetectOS(instance);
if(result->name.length == 0 && result->prettyName.length == 0)
@@ -69,20 +66,28 @@ void ffPrintOS(FFinstance* instance)
ffStrbufAppendC(&os, ']');
}
ffPrintAndWriteToCache(instance, FF_OS_MODULE_NAME, &instance->config.osKey, &os, &instance->config.osFormat, FF_OS_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &result->systemName},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->id},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->idLike},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->variant},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->variantID},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->version},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->versionID},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->codename},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->buildID},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->architecture}
});
if(instance->config.osFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_OS_MODULE_NAME, 0, &instance->config.osKey);
ffStrbufPutTo(&os, stdout);
}
else
{
ffPrintFormatString(instance, FF_OS_MODULE_NAME, 0, &instance->config.osKey, &instance->config.osFormat, NULL, FF_OS_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &result->systemName},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->id},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->idLike},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->variant},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->variantID},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->version},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->versionID},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->codename},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->buildID},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->architecture}
});
}
ffStrbufDestroy(&os);
}
+185 -112
View File
@@ -4,45 +4,21 @@
#include <dirent.h>
#define FF_PACKAGES_MODULE_NAME "Packages"
#define FF_PACKAGES_NUM_FORMAT_ARGS 9
#define FF_PACKAGES_NUM_FORMAT_ARGS 11
#ifdef FF_HAVE_RPM
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>
#include <rpm/rpmlog.h>
static uint32_t getRpmPackageCount(FFinstance* instance)
typedef struct PackageCounts
{
FF_LIBRARY_LOAD(rpm, instance->config.librpm, 0, "librpm.so", 5)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmReadConfigFiles, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsCreate, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsInitIterator, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbGetIteratorCount, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbFreeIterator, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsFree, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmlogSetMask, 0)
uint32_t pacman;
uint32_t dpkg;
uint32_t rpm;
uint32_t emerge;
uint32_t xbps;
uint32_t nixDefault;
uint32_t flatpak;
uint32_t snap;
// Don't print any error messages
ffrpmlogSetMask(RPMLOG_MASK(RPMLOG_EMERG));
uint32_t count = 0;
rpmts ts = NULL;
rpmdbMatchIterator mi = NULL;
if (ffrpmReadConfigFiles(NULL, NULL)) goto exit;
if (!(ts = ffrpmtsCreate())) goto exit;
if (!(mi = ffrpmtsInitIterator(ts, RPMDBI_LABEL, NULL, 0))) goto exit;
count = (uint32_t) ffrpmdbGetIteratorCount(mi);
exit:
if (mi) ffrpmdbFreeIterator(mi);
if (ts) ffrpmtsFree(ts);
dlclose(rpm);
return count;
}
#endif
FFstrbuf pacmanBranch;
} PackageCounts;
static uint32_t getNumElements(const char* dirname, unsigned char type)
{
@@ -126,25 +102,19 @@ static uint32_t countFilesRecursive(FFstrbuf* baseDirPath, const char* filename)
return sum;
}
static uint32_t countFilesIn(const char* dirname, const char* filename)
static uint32_t getNixPackages(char* path)
{
FFstrbuf baseDirPath;
ffStrbufInitA(&baseDirPath, 128);
ffStrbufAppendS(&baseDirPath, dirname);
uint32_t result = countFilesRecursive(&baseDirPath, filename);
ffStrbufDestroy(&baseDirPath);
return result;
}
//Nix detection is kinda slow, so we only do it if the dir exists
if(!ffFileExists(path, S_IFDIR))
return 0;
static uint32_t getNixPackages(const FFstrbuf* path)
{
FFstrbuf output;
ffStrbufInitA(&output, 128);
ffProcessAppendStdOut(&output, (char* const[]) {
"nix-store",
"-qR",
path->chars,
path,
NULL
});
@@ -157,89 +127,190 @@ static uint32_t getNixPackages(const FFstrbuf* path)
return result;
}
static uint32_t getNixPackagesDefault()
#ifdef FF_HAVE_RPM
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
#include <rpm/rpmdb.h>
#include <rpm/rpmlog.h>
static uint32_t getRpmFromLibrpm(const FFinstance* instance)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffStrbufAppendS(&path, FASTFETCH_TARGET_DIR_ROOT"/nix/var/nix/profiles/default");
uint32_t result = getNixPackages(&path);
ffStrbufDestroy(&path);
return result;
FF_LIBRARY_LOAD(rpm, instance->config.librpm, 0, "librpm.so", 12)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmReadConfigFiles, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsCreate, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsInitIterator, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbGetIteratorCount, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmdbFreeIterator, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsFree, 0)
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmlogSetMask, 0)
// Don't print any error messages
ffrpmlogSetMask(RPMLOG_MASK(RPMLOG_EMERG));
if(ffrpmReadConfigFiles(NULL, NULL) != 0)
{
dlclose(rpm);
return 0;
}
rpmts ts = ffrpmtsCreate();
if(ts == NULL)
{
dlclose(rpm);
return 0;
}
rpmdbMatchIterator mi = ffrpmtsInitIterator(ts, RPMDBI_LABEL, NULL, 0);
if(mi == NULL)
{
ffrpmtsFree(ts);
dlclose(rpm);
return 0;
}
int count = ffrpmdbGetIteratorCount(mi);
ffrpmdbFreeIterator(mi);
ffrpmtsFree(ts);
dlclose(rpm);
return count > 0 ? (uint32_t) count : 0;
}
#endif
static void getPackageCounts(const FFinstance* instance, FFstrbuf* baseDir, PackageCounts* packageCounts)
{
uint32_t baseDirLength = baseDir->length;
//pacman
ffStrbufAppendS(baseDir, "/var/lib/pacman/local");
packageCounts->pacman += getNumElements(baseDir->chars, DT_DIR);
ffStrbufSubstrBefore(baseDir, baseDirLength);
//dpkg
ffStrbufAppendS(baseDir, "/var/lib/dpkg/status");
packageCounts->dpkg += getNumStrings(baseDir->chars, "Status: ");
ffStrbufSubstrBefore(baseDir, baseDirLength);
//rpm
ffStrbufAppendS(baseDir, "/var/lib/rpm/rmpdb.sqlite");
packageCounts->rpm += (uint32_t) ffSettingsGetSQLite3Int(instance, baseDir->chars, "SELECT count(blob) FROM Packages");
ffStrbufSubstrBefore(baseDir, baseDirLength);
//emerge
ffStrbufAppendS(baseDir, "/var/db/pkg");
packageCounts->emerge += countFilesRecursive(baseDir, "SIZE");
ffStrbufSubstrBefore(baseDir, baseDirLength);
//xps
ffStrbufAppendS(baseDir, "/var/db/xbps");
packageCounts->xbps += getNumElements(baseDir->chars, DT_REG);
ffStrbufSubstrBefore(baseDir, baseDirLength);
//flatpak
ffStrbufAppendS(baseDir, "/var/lib/flatpak/app");
packageCounts->flatpak += getNumElements(baseDir->chars, DT_DIR);
ffStrbufSubstrBefore(baseDir, baseDirLength);
//nix default
ffStrbufAppendS(baseDir, "/var/nix/profiles/default");
packageCounts->nixDefault += getNixPackages(baseDir->chars);
ffStrbufSubstrBefore(baseDir, baseDirLength);
//snap
ffStrbufAppendS(baseDir, "/snap");
uint32_t snap = getNumElements(baseDir->chars, DT_DIR);
if(snap > 0)
packageCounts->snap += (snap - 1); //Accounting for the /snap/bin folder
ffStrbufSubstrBefore(baseDir, baseDirLength);
//pacman branch
ffStrbufAppendS(baseDir, "/etc/pacman-mirrors.conf");
if(ffParsePropFile(baseDir->chars, "Branch =", &packageCounts->pacmanBranch) && packageCounts->pacmanBranch.length == 0)
ffStrbufAppendS(&packageCounts->pacmanBranch, "stable");
ffStrbufSubstrBefore(baseDir, baseDirLength);
}
static uint32_t getNixPackagesUser(const FFinstance* instance)
static void getPackageCountsBedrock(const FFinstance* instance, FFstrbuf* baseDir, PackageCounts* packageCounts)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffStrbufAppendS(&path, instance->state.passwd->pw_dir);
ffStrbufAppendS(&path, "/.nix-profile");
uint32_t result = getNixPackages(&path);
ffStrbufDestroy(&path);
return result;
ffStrbufAppendS(baseDir, "/bedrock/strata");
DIR* dir = opendir(baseDir->chars);
if(dir == NULL)
return;
ffStrbufAppendC(baseDir, '/');
uint32_t baseDirLength = baseDir->length;
struct dirent* entry;
while((entry = readdir(dir)) != NULL)
{
if(entry->d_type != DT_DIR)
continue;
ffStrbufAppendS(baseDir, entry->d_name);
getPackageCounts(instance, baseDir, packageCounts);
ffStrbufSubstrBefore(baseDir, baseDirLength);
}
closedir(dir);
}
void ffPrintPackages(FFinstance* instance)
{
uint32_t pacman = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/lib/pacman/local", DT_DIR);
uint32_t dpkg = getNumStrings(FASTFETCH_TARGET_DIR_ROOT"/var/lib/dpkg/status", "Status: ");
PackageCounts counts = {0};
ffStrbufInit(&counts.pacmanBranch);
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 512);
ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT);
if(ffStrbufIgnCaseCompS(&ffDetectOS(instance)->id, "bedrock") == 0)
getPackageCountsBedrock(instance, &baseDir, &counts);
else
getPackageCounts(instance, &baseDir, &counts);
// If SQL failed, we can still try with librpm.
// This is needed on openSUSE, which seems to use a proprietary database file
// This method doesn't work on bedrock, so we do it here.
#ifdef FF_HAVE_RPM
uint32_t rpm = getRpmPackageCount(instance);
#else
uint32_t rpm = 0;
if(counts.rpm == 0)
counts.rpm = getRpmFromLibrpm(instance);
#endif
uint32_t emerge = countFilesIn(FASTFETCH_TARGET_DIR_ROOT"/var/db/pkg", "SIZE");
uint32_t xbps = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/db/xbps", DT_REG);
//nix user
ffStrbufSetS(&baseDir, instance->state.passwd->pw_dir);
ffStrbufAppendS(&baseDir, "/.nix-profile");
uint32_t nixUser = getNixPackages(baseDir.chars);
uint32_t nixUser = 0;
uint32_t nixDefault = 0;
//Nix detection is kinda slow, so we only do it if the nix dir exists
if(ffFileExists(FASTFETCH_TARGET_DIR_ROOT"/nix", S_IFDIR))
{
nixUser = getNixPackagesUser(instance);
nixDefault = getNixPackagesDefault();
}
uint32_t flatpak = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/lib/flatpak/app", DT_DIR);
uint32_t snap = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/snap", DT_DIR);
//Accounting for the /snap/bin folder
if(snap > 0)
--snap;
uint32_t all = pacman + dpkg + rpm + emerge + xbps + nixUser + nixDefault + flatpak + snap;
ffStrbufDestroy(&baseDir);
uint32_t all = counts.dpkg + counts.emerge + counts.flatpak + counts.nixDefault + nixUser + counts.pacman + counts.rpm + counts.snap + counts.xbps;
if(all == 0)
{
ffPrintError(instance, FF_PACKAGES_MODULE_NAME, 0, &instance->config.packagesKey, &instance->config.packagesFormat, FF_PACKAGES_NUM_FORMAT_ARGS, "No packages from known package managers found");
return;
}
FFstrbuf manjaroBranch;
ffStrbufInit(&manjaroBranch);
if(ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/pacman-mirrors.conf", "Branch =", &manjaroBranch) && manjaroBranch.length == 0)
ffStrbufSetS(&manjaroBranch, "stable");
if(instance->config.packagesFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_PACKAGES_MODULE_NAME, 0, &instance->config.packagesKey);
#define FF_PRINT_PACKAGE(name) \
if(name > 0) \
if(counts.name > 0) \
{ \
printf("%u ("#name")", name); \
if((all = all - name) > 0) \
printf("%u ("#name")", counts.name); \
if((all = all - counts.name) > 0) \
printf(", "); \
};
if(pacman > 0)
if(counts.pacman > 0)
{
printf("%u (pacman)", pacman);
if(manjaroBranch.length > 0)
printf("[%s]", manjaroBranch.chars);
if((all = all - pacman) > 0)
printf("%u (pacman)", counts.pacman);
if(counts.pacmanBranch.length > 0)
printf("[%s]", counts.pacmanBranch.chars);
if((all = all - counts.pacman) > 0)
printf(", ");
};
@@ -254,10 +325,10 @@ void ffPrintPackages(FFinstance* instance)
printf(", ");
}
if(nixDefault > 0)
if(counts.nixDefault > 0)
{
printf("%u (nix-default)", nixDefault);
if((all = all - nixDefault) > 0)
printf("%u (nix-default)", counts.nixDefault);
if((all = all - counts.nixDefault) > 0)
printf(", ");
}
@@ -275,16 +346,18 @@ void ffPrintPackages(FFinstance* instance)
{
ffPrintFormatString(instance, FF_PACKAGES_MODULE_NAME, 0, &instance->config.packagesKey, &instance->config.packagesFormat, NULL, FF_PACKAGES_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT, &all},
{FF_FORMAT_ARG_TYPE_UINT, &pacman},
{FF_FORMAT_ARG_TYPE_STRBUF, &manjaroBranch},
{FF_FORMAT_ARG_TYPE_UINT, &dpkg},
{FF_FORMAT_ARG_TYPE_UINT, &rpm},
{FF_FORMAT_ARG_TYPE_UINT, &emerge},
{FF_FORMAT_ARG_TYPE_UINT, &xbps},
{FF_FORMAT_ARG_TYPE_UINT, &flatpak},
{FF_FORMAT_ARG_TYPE_UINT, &snap}
{FF_FORMAT_ARG_TYPE_UINT, &counts.pacman},
{FF_FORMAT_ARG_TYPE_STRBUF, &counts.pacmanBranch},
{FF_FORMAT_ARG_TYPE_UINT, &counts.dpkg},
{FF_FORMAT_ARG_TYPE_UINT, &counts.rpm},
{FF_FORMAT_ARG_TYPE_UINT, &counts.emerge},
{FF_FORMAT_ARG_TYPE_UINT, &counts.xbps},
{FF_FORMAT_ARG_TYPE_UINT, &nixUser},
{FF_FORMAT_ARG_TYPE_UINT, &counts.nixDefault},
{FF_FORMAT_ARG_TYPE_UINT, &counts.flatpak},
{FF_FORMAT_ARG_TYPE_UINT, &counts.snap}
});
}
ffStrbufDestroy(&manjaroBranch);
ffStrbufDestroy(&counts.pacmanBranch);
}
+1 -1
View File
@@ -5,7 +5,7 @@ void ffPrintSeparator(FFinstance* instance)
const FFTitleResult* result = ffDetectTitle(instance);
uint32_t titleLength = result->userName.length + 1 + result->hostname.length;
ffPrintLogoLine(instance);
ffLogoPrintLine(instance);
if(instance->config.separatorString.length == 0)
{
+10 -4
View File
@@ -30,17 +30,23 @@ const FFTitleResult* ffDetectTitle(FFinstance* instance)
static inline void printTitlePart(FFinstance* instance, const FFstrbuf* content)
{
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.mainColor);
if(!instance->config.pipe)
{
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.mainColor);
}
ffStrbufWriteTo(content, stdout);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
void ffPrintTitle(FFinstance* instance)
{
const FFTitleResult* result = ffDetectTitle(instance);
ffPrintLogoLine(instance);
ffLogoPrintLine(instance);
printTitlePart(instance, &result->userName);
putchar('@');
+34 -8
View File
@@ -17,17 +17,43 @@ void ffPrintUptime(FFinstance* instance)
if(days == 0 && hours == 0 && minutes == 0)
{
printf("%u seconds\n", seconds);
return;
}
else
if(days > 0)
{
if(days > 0)
printf("%u day%s%s, ", days, days <= 1 ? "" : "s", days < 100 ? "" : "(!)");
if(hours > 0)
printf("%u hour%s, ", hours, hours <= 1 ? "" : "s");
if(minutes > 0)
printf("%u min%s", minutes, minutes <= 1 ? "" : "s");
putchar('\n');
printf("%u day", days);
if(days > 1)
putchar('s');
if(days >= 100)
fputs("(!)", stdout);
if(hours > 0 || minutes > 0)
fputs(", ", stdout);
}
if(hours > 0)
{
printf("%u hour", hours);
if(hours > 1)
putchar('s');
if(minutes > 0)
fputs(", ", stdout);
}
if(minutes > 0)
{
printf("%u min", minutes);
if(minutes > 1)
putchar('s');
}
putchar('\n');
}
else
{
+41
View File
@@ -0,0 +1,41 @@
#include "fastfetch.h"
#define FF_VULKAN_MODULE_NAME "Vulkan"
#define FF_VULKAN_NUM_FORMAT_ARGS 3
void ffPrintVulkan(FFinstance* instance)
{
const FFVulkanResult* vulkan = ffDetectVulkan(instance);
if(vulkan->apiVersion.length == 0 && vulkan->driver.length == 0)
{
ffPrintError(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkanKey, &instance->config.vulkanFormat, FF_VULKAN_NUM_FORMAT_ARGS, "Failed to detect vulkan");
return;
}
if(instance->config.vulkanFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkanKey);
if(vulkan->driver.length > 0)
{
printf("%s (driver)", vulkan->driver.chars);
if(vulkan->apiVersion.length > 0)
fputs(", ", stdout);
}
if(vulkan->apiVersion.length > 0)
printf("%s (api version)", vulkan->apiVersion.chars);
putchar('\n');
}
else
{
ffPrintFormatString(instance, FF_VULKAN_MODULE_NAME, 0, &instance->config.vulkanKey, &instance->config.vulkanFormat, NULL, FF_VULKAN_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &vulkan->driver},
{FF_FORMAT_ARG_TYPE_STRBUF, &vulkan->apiVersion},
{FF_FORMAT_ARG_TYPE_STRBUF, &vulkan->conformanceVersion}
});
}
}
+10 -29
View File
@@ -29,31 +29,12 @@ void ffStrbufInitCopy(FFstrbuf* strbuf, const FFstrbuf* src)
ffStrbufAppend(strbuf, src);
}
static void setCapacity(FFstrbuf* strbuf, uint32_t capacity)
uint32_t ffStrbufGetFree(const FFstrbuf* strbuf)
{
if(strbuf->allocated == 0)
{
strbuf->chars = malloc(sizeof(*strbuf->chars) * capacity);
strbuf->chars[0] = '\0';
}
else
strbuf->chars = realloc(strbuf->chars, sizeof(*strbuf->chars) * capacity);
return 0;
strbuf->allocated = capacity;
}
void ffStrbufEnsureCapacity(FFstrbuf* strbuf, uint32_t capacity)
{
if(strbuf->allocated > capacity || capacity == 0)
return;
if(capacity == UINT32_MAX)
{
fputs("Warning: ffStrbufEnsureCapacity called with UINT32_MAX. Highest allowed value is UINT32_MAX - 1. Exiting.\n", stderr);
exit(812);
}
setCapacity(strbuf, capacity + 1); // + 1 for the null byte
return strbuf->allocated - strbuf->length - 1; // - 1 for the null byte
}
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
@@ -68,15 +49,15 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
while((strbuf->length + free + 1) > allocate) // + 1 for the null byte
allocate *= 2;
setCapacity(strbuf, allocate);
}
uint32_t ffStrbufGetFree(const FFstrbuf* strbuf)
{
if(strbuf->allocated == 0)
return 0;
{
strbuf->chars = malloc(sizeof(*strbuf->chars) * allocate);
strbuf->chars[0] = '\0';
}
else
strbuf->chars = realloc(strbuf->chars, sizeof(*strbuf->chars) * allocate);
return strbuf->allocated - strbuf->length - 1; // - 1 for the null byte
strbuf->allocated = allocate;
}
void ffStrbufClear(FFstrbuf* strbuf)
-1
View File
@@ -23,7 +23,6 @@ void ffStrbufInit(FFstrbuf* strbuf);
void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate);
void ffStrbufInitCopy(FFstrbuf* strbuf, const FFstrbuf* src);
void ffStrbufEnsureCapacity(FFstrbuf* strbuf, uint32_t capacity);
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free);
uint32_t ffStrbufGetFree(const FFstrbuf* strbuf);