Compare commits

..

82 Commits

Author SHA1 Message Date
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
Linus Dierheimer 1d99bd2e08 Fix prebuild deb package for real this time 2022-04-23 11:28:46 +02:00
Linus Dierheimer 52eed51eb6 Fix prebuild deb package 2022-04-23 11:24:24 +02:00
Linus Dierheimer e5237c14cb Fix build without any image magick enabled 2022-04-22 21:29:14 +02:00
Linus Dierheimer 47d8ddad35 Release 1.3.0: Image support 2022-04-22 15:51:54 +02:00
Linus Dierheimer 37ab01d5ee Refactored some variable namings to reflect image support 2022-04-22 15:49:50 +02:00
Linus Dierheimer 80f7a982e0 Even faster image caching 2022-04-22 13:20:40 +02:00
Linus Dierheimer cff3aed49c RHEL logo 2022-04-21 18:07:39 +02:00
Linus Dierheimer 572d4ec8e9 NixOS support 2022-04-21 17:59:26 +02:00
Linus Dierheimer 5bceb29c79 Image caching 2022-04-21 15:50:45 +02:00
Linus Dierheimer 8b153833b1 Fallback to escape sequences if ioctl failed 2022-04-19 11:48:08 +02:00
Linus Dierheimer adc92b5548 Update packages.c 2022-04-19 00:32:28 +02:00
Linus Dierheimer 03e949ed30 Update DEVELOPMENT.md 2022-04-15 00:56:02 +02:00
Linus Dierheimer 6accb587af zlib support 2022-04-14 15:11:14 +02:00
Linus Dierheimer 373e041e5e Always dlclose when possible 2022-04-14 11:43:06 +02:00
Linus Dierheimer 31bdd25a26 Kitty graphics protocol support 2022-04-14 11:36:57 +02:00
Linus Dierheimer 703ec597fa Improved ImageMagick detection 2022-04-13 23:13:25 +02:00
Linus Dierheimer 3b1314102f Kitty graphics initial support 2022-04-13 23:04:42 +02:00
Linus Dierheimer d349b7f7fb Merge pull request #145 from Henryws/patch-1
fix(README): fix typo
2022-04-13 11:27:59 +02:00
The TwilightBlood dabdb104e2 fix(README): fix typo 2022-04-12 18:34:40 -05:00
Linus Dierheimer 8d5ce7bcdb Fix build when ImageMagick 6 enabled 2022-04-11 22:54:07 +02:00
Linus Dierheimer 751568e9f3 Faster fallback in sixel code 2022-04-11 22:51:51 +02:00
Linus Dierheimer 430fe9fe9a Avoid unnecessary cache validation 2022-04-11 18:54:56 +02:00
Linus Dierheimer 8831c07d2b Look for multiple versions of a library 2022-04-11 17:41:21 +02:00
Linus Dierheimer e009bb1516 Try with include math.h for ubuntu build 2022-04-11 16:39:56 +02:00
Linus Dierheimer 82e2790e1b Define isnan for imagemagick 6 2022-04-11 16:32:47 +02:00
Linus Dierheimer 64182539aa Support ImageMagick 6 too (this one is for you, Ubuntu) 2022-04-11 16:19:02 +02:00
Linus Dierheimer c67fd169f8 Refactor sixel code a bit 2022-04-10 22:08:41 +02:00
Linus Dierheimer f58d0df336 Default to termux directories on android 2022-04-10 15:26:18 +02:00
Linus Dierheimer bd0c593871 Simplify packaging for termux 2022-04-10 15:07:52 +02:00
Linus Dierheimer a032d37ad4 Refactored method naming / ordering 2022-04-08 15:50:49 +02:00
Linus Dierheimer a4861606b7 Small Sixel improvements 2022-04-06 14:54:39 +02:00
Linus Dierheimer 88fe34102e Only support ImageMagick 7 for now 2022-04-06 14:21:52 +02:00
Linus Dierheimer 5346104ffa Initial sixel support 2022-04-06 14:02:05 +02:00
Linus Dierheimer 12371cdc84 Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2022-04-02 14:44:44 +02:00
Linus Dierheimer 3248afe91c Prepare flashfetch for images in terminal too 2022-04-02 14:44:26 +02:00
Linus Dierheimer 1731ab2c5f Prepare for images in the terminal #2 2022-04-02 14:42:18 +02:00
Linus Dierheimer fcc8927917 Prepare for images in the terminal 2022-04-02 14:35:43 +02:00
Linus Dierheimer ccf4e2d2b5 OpenSUSE logos 2022-03-28 12:36:08 +02:00
Linus Dierheimer f2998a329d Add license info to rpm package 2022-03-25 12:24:56 +01:00
Linus Dierheimer 30365e8997 Release prebuild binaries as tar.gz and zip 2022-03-25 12:16:06 +01:00
58 changed files with 4554 additions and 2710 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 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
- 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 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
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
+202 -85
View File
@@ -1,10 +1,15 @@
cmake_minimum_required(VERSION 3.1.0) # Threads::Threads
project(fastfetch
VERSION 1.2.1
VERSION 1.4.2
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)
@@ -22,7 +27,52 @@ 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)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
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.
if(NOT TARGET_DIR_ROOT)
if(NOT ANDROID)
set(TARGET_DIR_ROOT "")
else()
set(TARGET_DIR_ROOT "/data/data/com.termux/files/usr")
endif()
endif()
if(NOT TARGET_DIR_USR)
if(NOT ANDROID)
set(TARGET_DIR_USR "${TARGET_DIR_ROOT}/usr")
else()
set(TARGET_DIR_USR "${TARGET_DIR_ROOT}")
endif()
endif()
if(NOT TARGET_DIR_HOME)
if(NOT ANDROID)
set(TARGET_DIR_HOME "${TARGET_DIR_ROOT}/home")
else()
set(TARGET_DIR_HOME "/data/data/com.termux/files/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)
# Track commits between version bumps for output in --version
if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
@@ -35,21 +85,6 @@ if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
string(REGEX MATCH "-[0-9]+" PROJECT_VERSION_TWEAK "${PROJECT_VERSION_TWEAK}")
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wconversion")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-Wl,-O3")
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)
@@ -60,11 +95,6 @@ fastfetch_load_text(src/data/help_config.txt DATATEXT_HELP_CONFIG)
configure_file(src/fastfetch_config.h.in fastfetch_config.h)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
# Init CMake targets
add_library(libfastfetch STATIC
@@ -74,13 +104,21 @@ add_library(libfastfetch STATIC
src/common/init.c
src/common/threading.c
src/common/io.c
src/common/printing.c
src/common/caching.c
src/common/properties.c
src/common/font.c
src/common/processing.c
src/common/logo.c
src/common/format.c
src/common/parsing.c
src/common/settings.c
src/common/library.c
src/common/networking.c
src/logo/logo.c
src/logo/builtin.c
src/logo/image/image.c
src/logo/image/im7.c
src/logo/image/im6.c
src/detection/os.c
src/detection/plasma.c
src/detection/gtk.c
@@ -131,112 +169,177 @@ add_library(libfastfetch STATIC
)
if(ENABLE_LIBPCI)
pkg_check_modules (LIBPCI libpci)
pkg_check_modules(LIBPCI libpci)
if(LIBPCI_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBPCI=1)
else(LIBPCI_FOUND)
else()
message(WARNING "Package libpci not found. Building without support.")
endif(LIBPCI_FOUND)
endif(ENABLE_LIBPCI)
endif()
endif()
if(ENABLE_VULKAN)
pkg_check_modules (VULKAN vulkan)
pkg_check_modules(VULKAN vulkan)
if(VULKAN_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_VULKAN=1)
else(VULKAN_FOUND)
else()
message(WARNING "Package vulkan not found. Building without support.")
endif(VULKAN_FOUND)
endif(ENABLE_VULKAN)
endif()
endif()
if(ENABLE_WAYLAND)
pkg_check_modules (WAYLAND wayland-client)
if(WAYLAND_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WAYLAND=1)
else(WAYLAND_FOUND)
else()
message(WARNING "Package wayland-client not found. Building without support.")
endif(WAYLAND_FOUND)
endif(ENABLE_WAYLAND)
endif()
endif()
if(ENABLE_XCB_RANDR)
pkg_check_modules (XCB_RANDR xcb-randr)
pkg_check_modules(XCB_RANDR xcb-randr)
if(XCB_RANDR_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XCB_RANDR=1)
else(XCB_RANDR_FOUND)
else()
message(WARNING "Package xcb-randr not found. Building without support.")
endif(XCB_RANDR_FOUND)
endif(ENABLE_XCB_RANDR)
endif()
endif()
if(ENABLE_XCB)
pkg_check_modules (XCB xcb)
if(XCB_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XCB=1)
else(XCB_FOUND)
else()
message(WARNING "Package xcb not found. Building without support.")
endif(XCB_FOUND)
endif(ENABLE_XCB)
endif()
endif()
if(ENABLE_XRANDR)
pkg_check_modules (XRANDR xrandr)
pkg_check_modules(XRANDR xrandr)
if(XRANDR_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XRANDR=1)
else(XRANDR_FOUND)
else()
message(WARNING "Package xrandr not found. Building without support.")
endif(XRANDR_FOUND)
endif(ENABLE_XRANDR)
endif()
endif()
if(ENABLE_X11)
pkg_check_modules (X11 x11)
pkg_check_modules(X11 x11)
if(X11_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_X11=1)
else(X11_FOUND)
else()
message(WARNING "Package x11 not found. Building without support.")
endif(X11_FOUND)
endif(ENABLE_X11)
endif()
endif()
if(ENABLE_GIO)
pkg_check_modules (GIO gio-2.0)
pkg_check_modules(GIO gio-2.0)
if(GIO_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GIO=1)
else(GIO_FOUND)
else()
message(WARNING "Package gio-2.0 not found. Building without support.")
endif(GIO_FOUND)
endif(ENABLE_GIO)
endif()
endif()
if(ENABLE_DCONF)
pkg_check_modules (DCONF dconf)
pkg_check_modules(DCONF dconf)
if(DCONF_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_DCONF=1)
else(DCONF_FOUND)
else()
message(WARNING "Package dconf not found. Building without support.")
endif(DCONF_FOUND)
endif(ENABLE_DCONF)
endif()
endif()
if(ENABLE_DBUS)
pkg_check_modules (DBUS dbus-1)
pkg_check_modules(DBUS dbus-1)
if(DBUS_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_DBUS=1)
else(DBUS_FOUND)
else()
message(WARNING "Package dbus-1 not found. Building without support.")
endif(DBUS_FOUND)
endif(ENABLE_DBUS)
endif()
endif()
if(ENABLE_XFCONF)
pkg_check_modules (XFCONF libxfconf-0)
pkg_check_modules(XFCONF libxfconf-0)
if(XFCONF_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XFCONF=1)
else(XFCONF_FOUND)
else()
message(WARNING "Package libxfconf-0 not found. Building without support.")
endif(XFCONF_FOUND)
endif(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)
pkg_check_modules(RPM rpm)
if(RPM_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_RPM=1)
else(RPM_FOUND)
message(WARNING "Package librpm not found. Building without support.")
endif(RPM_FOUND)
endif(ENABLE_RPM)
else()
message(WARNING "Package rpm not found. Building without support.")
endif()
endif()
if(ENABLE_IMAGEMAGICK7)
pkg_check_modules(IMAGEMAGICK7 MagickCore-7.Q16HDRI)
if(NOT IMAGEMAGICK7_FOUND)
pkg_check_modules(IMAGEMAGICK7 /usr/lib/imagemagick7/pkgconfig/MagickCore-7.Q16HDRI.pc)
endif()
if(NOT IMAGEMAGICK7_FOUND)
pkg_check_modules(IMAGEMAGICK7 MagickCore-7.Q16)
endif()
if(NOT IMAGEMAGICK7_FOUND)
pkg_check_modules(IMAGEMAGICK7 /usr/lib/imagemagick7/pkgconfig/MagickCore-7.Q16.pc)
endif()
if(IMAGEMAGICK7_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_IMAGEMAGICK7=1)
else()
message(WARNING "Package MagickCore-7.Q16HDRI or MagickCore-7.Q16 not found. Building without support.")
endif()
endif()
if(ENABLE_IMAGEMAGICK6)
pkg_check_modules(IMAGEMAGICK6 MagickCore-6.Q16HDRI)
if(NOT IMAGEMAGICK6_FOUND)
pkg_check_modules(IMAGEMAGICK6 /usr/lib/imagemagick6/pkgconfig/MagickCore-6.Q16HDRI.pc)
endif()
if(NOT IMAGEMAGICK6_FOUND)
pkg_check_modules(IMAGEMAGICK6 MagickCore-6.Q16)
endif()
if(NOT IMAGEMAGICK6_FOUND)
pkg_check_modules(IMAGEMAGICK6 /usr/lib/imagemagick6/pkgconfig/MagickCore-6.Q16.pc)
endif()
if(IMAGEMAGICK6_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_IMAGEMAGICK6=1)
else()
message(WARNING "Package MagickCore-6.Q16HDRI or MagickCore-6.Q16 not found. Building without support.")
endif()
endif()
if(ENABLE_ZLIB)
pkg_check_modules(ZLIB zlib)
if(ZLIB_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_ZLIB=1)
else()
message(WARNING "Package zlib not found. Building without support")
endif()
endif()
if(ENABLE_CHAFA)
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()
endif()
target_include_directories(libfastfetch
PUBLIC ${PROJECT_BINARY_DIR}
@@ -253,7 +356,12 @@ 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}
)
target_link_libraries(libfastfetch
@@ -307,6 +415,11 @@ install(
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(
TARGETS flashfetch
DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(
FILES completions/bash
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions
@@ -325,31 +438,35 @@ install(
# Packaging
set(CPACK_GENERATOR "DEB;RPM;TZST")
set(CPACK_GENERATOR "DEB;RPM;TGZ;ZIP")
set(CPACK_PACKAGE_CONTACT "Linus Dierheimer <Linus@Dierheimer.de>")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Neofetch clone written in C")
set(CPACK_PACKAGE_DESCRIPTION "
fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way.
It is written in c to achieve much better performance.
set(CPACK_PACKAGE_DESCRIPTION "\
fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way. \
It is written in c to achieve much better performance.\
")
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
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")
include(CPack)
-3
View File
@@ -11,8 +11,6 @@ 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)
- [ ] Support for printing images in terminals that support it
- [ ] Better OS output for all possible combinations of /etc/os-release variables.
- [ ] Expose temperatures to CPU format string
- [ ] Expose temperatures to GPU format string
@@ -25,7 +23,6 @@ Here i just add things that are easy to forget.
- [ ] Make CPU usage detection much faster and more accurate
- [ ] Detect CPU usage in a common detection methode and expose it both to the cpuUsage module and the cpu format string
- [ ] Per session caching
- [ ] RPM packaging
### General
- More presets
+9 -4
View File
@@ -9,7 +9,7 @@ The output on my personal machine with default configurations looks like this:
With customization and speed being two competing goals, this project actually builds two executables.
The main one being `fastfetch`, which can be very greatly configured via flags. These flags can be made persistent in `~/.config/fastfetch/config.conf`. To view the available options run `fastfetch --help`.
The second executable being buildt is called `flashfetch`, which is configured at compile time to eliminate any possible overhead. Configuration of it can be very easily done in [`src/flashfetch.c`](src/flashfetch.c).
The second executable being built is called `flashfetch`, which is configured at compile time to eliminate any possible overhead. Configuration of it can be very easily done in [`src/flashfetch.c`](src/flashfetch.c).
At the moment the performance difference is measurable, but too small to be human recognizable. But the leap will get bigger with more and more options coming, and on slow machines this might actually make a difference.
There are some presets defined for fastfech in [`presets`](presets), you can can load them with `--load-config`. They may also serve as a good example for format arguments.
@@ -28,9 +28,13 @@ The following libraries are used if present at runtime:
* [`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.
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
* [`librpm`](http://rpm.org/): Needed for rpm package count.
* [`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.
@@ -42,16 +46,17 @@ Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resoluti
##### Logos
```
Android, Arch, Arco, Artix, CachyOS, CentOS, Debian, Endeavour, Fedora, Garuda, Gentoo, KDE Neon, Linux, Manjaro, Mint, Pop!_OS, RebornOS, Ubuntu, Void, Zorin
Android, Arch, Arco, Artix, 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.
* Unknown/unsupported logos will be replaced with a generic linux logo when running fastfetch.
* Get a list of all available logos with `fastfetch --print-logos`.
* Printing images as logo is supported using Sixel or Kitty graphics protocol.
##### Package managers
```
Pacman, dpkg, rpm, emerge, xbps, Flatpak, Snap
Pacman, dpkg, rpm, emerge, xbps, nix, Flatpak, Snap
```
##### WM themes
+20 -7
View File
@@ -122,8 +122,7 @@ __fastfetch_completion()
"--recache"
"--nocache"
"--show-errors"
"--color-logo"
"--print-remaining-logo"
"--logo-print-remaining"
"--multithreading"
"--allow-slow-operations"
"--disable-linewrap"
@@ -134,13 +133,23 @@ __fastfetch_completion()
)
local FF_OPTIONS_STRING=(
"--logo-type"
"--logo-padding"
"--logo-padding-left"
"--logo-padding-right"
"--logo-color-1"
"--logo-color-2"
"--logo-color-3"
"--logo-color-4"
"--logo-color-5"
"--logo-color-6"
"--logo-color-7"
"--logo-color-8"
"--logo-color-9"
"-c"
"--color"
"--spacing"
"-s"
"--separator"
"-x"
"--offsetx"
"-s"
"--structure"
"--set"
"--os-format"
@@ -222,7 +231,11 @@ __fastfetch_completion()
"--lib-DConf"
"--lib-DBus"
"--lib-XFConf"
"--lib-RPM"
"--lib-sqlite3"
"--lib-rpm"
"--lib-imagemagick"
"--lib-z"
"--lib-chafa"
"--battery-dir"
"--load-config"
)
+203
View File
@@ -0,0 +1,203 @@
#include "fastfetch.h"
#define FF_CACHE_VALUE_EXTENSION "ffcv"
#define FF_CACHE_SPLIT_EXTENSION "ffcs"
static void getCacheFilePath(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
{
ffStrbufAppend(buffer, &instance->state.cacheDir);
ffStrbufAppendS(buffer, moduleName);
if(extension != NULL)
{
ffStrbufAppendC(buffer, '.');
ffStrbufAppendS(buffer, extension);
}
}
static void readCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
getCacheFilePath(instance, moduleName, extension, &path);
ffAppendFileContent(path.chars, buffer);
ffStrbufDestroy(&path);
}
static void writeCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* content)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
getCacheFilePath(instance, moduleName, extension, &path);
ffWriteFileContent(path.chars, content);
ffStrbufDestroy(&path);
}
void ffCacheValidate(FFinstance* instance)
{
if(instance->config.recache)
return;
FFstrbuf content;
ffStrbufInit(&content);
readCacheFile(instance, "cacheversion", "ffv", &content);
bool isSameVersion = ffStrbufCompS(&content, FASTFETCH_PROJECT_VERSION) == 0;
ffStrbufDestroy(&content);
if(isSameVersion)
return;
instance->config.recache = true;
FFstrbuf version;
ffStrbufInitA(&version, sizeof(FASTFETCH_PROJECT_VERSION));
ffStrbufAppendS(&version, FASTFETCH_PROJECT_VERSION);
writeCacheFile(instance, "cacheversion", "ffv", &version);
ffStrbufDestroy(&version);
}
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache)
{
FFstrbuf cacheFileValue;
ffStrbufInitA(&cacheFileValue, 64);
getCacheFilePath(instance, moduleName, FF_CACHE_VALUE_EXTENSION, &cacheFileValue);
cache->value = fopen(cacheFileValue.chars, "w");
ffStrbufDestroy(&cacheFileValue);
FFstrbuf cacheFileSplit;
ffStrbufInitA(&cacheFileSplit, 64);
getCacheFilePath(instance, moduleName, FF_CACHE_SPLIT_EXTENSION, &cacheFileSplit);
cache->split = fopen(cacheFileSplit.chars, "w");
ffStrbufDestroy(&cacheFileSplit);
}
void ffCacheClose(FFcache* cache)
{
if(cache->value != NULL)
fclose(cache->value);
if(cache->split != NULL)
fclose(cache->split);
}
static bool printCachedValue(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat)
{
FFstrbuf content;
ffStrbufInitA(&content, 512);
readCacheFile(instance, moduleName, FF_CACHE_VALUE_EXTENSION, &content);
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
if(content.length == 0)
return false;
uint8_t moduleCounter = 1;
uint32_t startIndex = 0;
while(startIndex < content.length)
{
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
puts(content.chars + startIndex);
startIndex = nullByteIndex + 1;
++moduleCounter;
}
ffStrbufDestroy(&content);
return moduleCounter > 1;
}
static bool printCachedFormat(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
{
FFstrbuf content;
ffStrbufInitA(&content, 512);
readCacheFile(instance, moduleName, FF_CACHE_SPLIT_EXTENSION, &content);
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
if(content.length == 0)
return false;
uint8_t moduleCounter = 1;
FFformatarg* arguments = calloc(numArgs, sizeof(FFformatarg));
uint32_t argumentCounter = 0;
uint32_t startIndex = 0;
while(startIndex < content.length)
{
arguments[argumentCounter].type = FF_FORMAT_ARG_TYPE_STRING;
arguments[argumentCounter].value = &content.chars[startIndex];
++argumentCounter;
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
if(argumentCounter == numArgs)
{
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
++moduleCounter;
argumentCounter = 0;
}
startIndex = nullByteIndex + 1;
}
free(arguments);
ffStrbufDestroy(&content);
return moduleCounter > 1;
}
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
{
if(instance->config.recache)
return false;
if(formatString == NULL || formatString->length == 0)
return printCachedValue(instance, moduleName, customKeyFormat);
else
return printCachedFormat(instance, moduleName, customKeyFormat, formatString, numArgs);
}
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
{
if(formatString == NULL || formatString->length == 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
ffStrbufPutTo(value, stdout);
}
else
{
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
}
if(cache->value != NULL)
{
ffStrbufWriteTo(value, cache->value);
fputc('\0', cache->value);
}
if(cache->split == NULL)
return;
for(uint32_t i = 0; i < numArgs; i++)
{
FFstrbuf buffer;
ffStrbufInitA(&buffer, 64);
ffFormatAppendFormatArg(&buffer, &arguments[i]);
ffStrbufWriteTo(&buffer, cache->split);
ffStrbufDestroy(&buffer);
fputc('\0', cache->split);
}
}
void ffPrintAndWriteToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
{
FFcache cache;
ffCacheOpenWrite(instance, moduleName, &cache);
ffPrintAndAppendToCache(instance, moduleName, 0, customKeyFormat, &cache, value, formatString, numArgs, arguments);
ffCacheClose(&cache);
}
+207
View File
@@ -0,0 +1,207 @@
#include "fastfetch.h"
#include <string.h>
static void fontInit(FFfont* font)
{
ffStrbufInit(&font->pretty);
ffStrbufInit(&font->name);
ffStrbufInitA(&font->size, 4);
ffListInitA(&font->styles, sizeof(FFstrbuf), 4);
}
static void fontInitPretty(FFfont* font)
{
ffStrbufAppend(&font->pretty, &font->name);
if(font->size.length == 0 && font->styles.length == 0)
return;
else if(font->pretty.length == 0)
ffStrbufAppendS(&font->pretty, "default");
ffStrbufAppendS(&font->pretty, " (");
if(font->size.length > 0)
{
ffStrbufAppend(&font->pretty, &font->size);
ffStrbufAppendS(&font->pretty, "pt");
if(font->styles.length > 0)
ffStrbufAppendS(&font->pretty, ", ");
}
for(uint32_t i = 0; i < font->styles.length; i++)
{
ffStrbufAppend(&font->pretty, ffListGet(&font->styles, i));
if(i < font->styles.length - 1)
ffStrbufAppendS(&font->pretty, ", ");
}
ffStrbufAppendC(&font->pretty, ')');
}
void ffFontInitQt(FFfont* font, const char* data)
{
fontInit(font);
//See https://doc.qt.io/qt-5/qfont.html#toString
//Family
while(*data != ',' && *data != '\0')
{
ffStrbufAppendC(&font->name, *data);
++data;
}
if(*data != '\0')
++data;
ffStrbufTrim(&font->name, ' ');
//Size
while(*data != ',' && *data != '\0')
{
ffStrbufAppendC(&font->size, *data);
++data;
}
if(*data != '\0')
++data;
ffStrbufTrim(&font->size, ' ');
#define FF_FONT_QT_SKIP_VALUE \
while(*data != ',' && *data != '\0') \
++data; \
if(*data != '\0') \
++data;
FF_FONT_QT_SKIP_VALUE //Pixel size
FF_FONT_QT_SKIP_VALUE //Style hint
FF_FONT_QT_SKIP_VALUE //Font weight
FF_FONT_QT_SKIP_VALUE //Font style
FF_FONT_QT_SKIP_VALUE //Underline
FF_FONT_QT_SKIP_VALUE //Strike out
FF_FONT_QT_SKIP_VALUE //Fixed pitch
FF_FONT_QT_SKIP_VALUE //Always 0
#undef FF_FONT_QT_SKIP_VALUE
while(*data != '\0')
{
while(*data == ' ')
++data;
if(*data == '\0')
break;
FFstrbuf* style = ffListAdd(&font->styles);
ffStrbufInit(style);
while(*data != ' ' && *data != '\0')
{
ffStrbufAppendC(style, *data);
++data;
}
}
fontInitPretty(font);
}
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
{
while(**data == ' ' || **data == '\t' || **data == ',')
++(*data);
const char* wordStart = *data;
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
++(*data);
uint32_t wordLength = (uint32_t) (*data - wordStart);
if(wordLength == 0)
return;
if(**data == '\0' || **data == '`' || **data == '\\')
{
ffStrbufAppendNS(&font->size, wordLength, wordStart);
if(ffStrbufEndsWithS(&font->size, "px"))
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
double dummy;
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
return;
ffStrbufClear(&font->size);
}
if(
strncasecmp(wordStart, "Ultra", 5) == 0 ||
strncasecmp(wordStart, "Extra", 5) == 0 ||
strncasecmp(wordStart, "Semi", 4) == 0 ||
strncasecmp(wordStart, "Demi", 4) == 0 ||
strncasecmp(wordStart, "Normal", wordLength) == 0 ||
strncasecmp(wordStart, "Roman", wordLength) == 0 ||
strncasecmp(wordStart, "Oblique", wordLength) == 0 ||
strncasecmp(wordStart, "Italic", wordLength) == 0 ||
strncasecmp(wordStart, "Thin", wordLength) == 0 ||
strncasecmp(wordStart, "Light", wordLength) == 0 ||
strncasecmp(wordStart, "Bold", wordLength) == 0 ||
strncasecmp(wordStart, "Black", wordLength) == 0 ||
strncasecmp(wordStart, "Condensed", wordLength) == 0 ||
strncasecmp(wordStart, "Expanded", wordLength) == 0
) {
if(alternativeBuffer == NULL)
{
alternativeBuffer = ffListAdd(&font->styles);
ffStrbufInit(alternativeBuffer);
}
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
if(
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
strncasecmp(wordStart, "Extra ", 6) == 0 ||
strncasecmp(wordStart, "Semi ", 5) == 0 ||
strncasecmp(wordStart, "Demi ", 5) == 0
) {
fontPangoParseWord(data, font, alternativeBuffer);
}
return;
}
if(alternativeBuffer != NULL)
{
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
return;
}
if(font->name.length > 0)
ffStrbufAppendC(&font->name, ' ');
ffStrbufAppendNS(&font->name, wordLength, wordStart);
}
void ffFontInitPango(FFfont* font, const char* data)
{
fontInit(font);
while(*data != '\0' && *data != '`' && *data != '\\')
fontPangoParseWord(&data, font, NULL);
fontInitPretty(font);
}
void ffFontInitCopy(FFfont* font, const char* name)
{
fontInit(font);
ffStrbufAppendS(&font->name, name);
fontInitPretty(font);
}
void ffFontDestroy(FFfont* font)
{
ffStrbufDestroy(&font->pretty);
ffStrbufDestroy(&font->name);
ffStrbufDestroy(&font->size);
for(uint32_t i = 0; i < font->styles.length; i++)
ffStrbufDestroy(ffListGet(&font->styles, i));
ffListDestroy(&font->styles);
}
+2 -3
View File
@@ -173,7 +173,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFst
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
{
ffStrbufAppendS(buffer, "\033[0m");
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
--numOpenColors;
}
@@ -284,6 +284,5 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFst
ffStrbufTrimRight(buffer, ' ');
if(numOpenColors > 0)
ffStrbufAppendS(buffer, "\033[0m");
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
+44 -16
View File
@@ -58,12 +58,12 @@ static void initConfigDirs(FFstate* state)
FFstrbuf* systemConfigHome = ffListAdd(&state->configDirs);
ffStrbufInitA(systemConfigHome, 64);
ffStrbufAppendS(systemConfigHome, "/etc/xdg");
ffStrbufAppendS(systemConfigHome, FASTFETCH_TARGET_DIR_ROOT"/etc/xdg");
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfigHome)
FFstrbuf* systemConfig = ffListAdd(&state->configDirs);
ffStrbufInitA(systemConfig, 64);
ffStrbufAppendS(systemConfig, "/etc");
ffStrbufAppendS(systemConfig, FASTFETCH_TARGET_DIR_ROOT"/etc");
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfig)
#undef FF_ENSURE_ONLY_ONCE_IN_LIST
@@ -92,6 +92,8 @@ static void initCacheDir(FFstate* state)
static void initState(FFstate* state)
{
state->logoWidth = 0;
state->logoHeight = 0;
state->keysHeight = 0;
state->passwd = getpwuid(getuid());
uname(&state->utsname);
sysinfo(&state->sysinfo);
@@ -102,25 +104,26 @@ static void initState(FFstate* state)
static void defaultConfig(FFinstance* instance)
{
ffStrbufInit(&instance->config.color);
ffStrbufInit(&instance->config.logoSource);
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 = 0;
instance->config.logoHeight = 0; //preserve aspect ratio
instance->config.logoPaddingLeft = 0;
instance->config.logoPaddingRight = 4;
instance->config.logoPrintRemaining = true;
ffStrbufInit(&instance->config.mainColor);
ffStrbufInit(&instance->config.separator);
ffStrbufAppendS(&instance->config.separator, ": ");
instance->config.logoKeySpacing = 4;
instance->config.offsetx = 0;
instance->config.colorLogo = true;
instance->config.showErrors = false;
instance->config.recache = false;
instance->config.cacheSave = true;
instance->config.printRemainingLogo = true;
instance->config.allowSlowOperations = false;
instance->config.disableLinewrap = true;
instance->config.hideCursor = true;
instance->config.userLogoIsRaw = false;
for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i)
ffStrbufInit(&instance->config.logoColors[i]);
ffStrbufInitA(&instance->config.osFormat, 0);
ffStrbufInitA(&instance->config.osKey, 0);
@@ -196,7 +199,11 @@ 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.diskFolders, 0);
@@ -219,7 +226,6 @@ void ffInitInstance(FFinstance* instance)
{
initState(&instance->state);
defaultConfig(instance);
ffCacheValidate(instance);
}
static void resetConsole(bool disableLinewrap, bool hideCursor)
@@ -253,21 +259,28 @@ void ffStart(FFinstance* instance)
sigaction(SIGTERM, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
//We do the cache validation here, so we can skip it if --recache is given
ffCacheValidate(instance);
//reset everything to default before we start printing
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
if(instance->config.hideCursor)
fputs("\033[?25l", stdout);
if(instance->config.disableLinewrap)
fputs("\033[?7l", stdout);
ffPrintLogo(instance);
}
void ffFinish(FFinstance* instance)
{
if(instance->config.printRemainingLogo)
ffPrintRemainingLogo(instance);
ffPrintRemainingLogo(instance);
resetConsole(instance->config.disableLinewrap, instance->config.hideCursor);
}
//Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
void ffListFeatures()
{
fputs(
@@ -301,11 +314,26 @@ void ffListFeatures()
#ifdef FF_HAVE_DBUS
"dbus\n"
#endif
#ifdef FF_HAVE_IMAGEMAGICK7
"imagemagick7\n"
#endif
#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
""
, stdout);
+77 -411
View File
@@ -1,421 +1,52 @@
#include "fastfetch.h"
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define FF_IO_CACHE_VALUE_EXTENSION "ffcv"
#define FF_IO_CACHE_SPLIT_EXTENSION "ffcs"
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
{
ffPrintLogoLine(instance);
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.color);
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);
}
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
ffStrbufWriteTo(&instance->config.separator, 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)
return;
va_list arguments;
va_start(arguments, message);
if(formatString == NULL || formatString->length == 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
vprintf(message, arguments);
puts(FASTFETCH_TEXT_MODIFIER_RESET);
}
else
{
FF_STRBUF_CREATE(error);
ffStrbufAppendVF(&error, message, arguments);
// calloc sets all to 0 and FF_FORMAT_ARG_TYPE_NULL also has value 0 so we don't need to explictly set it
FFformatarg* nullArgs = calloc(numFormatArgs, sizeof(FFformatarg));
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, &error, numFormatArgs, nullArgs);
free(nullArgs);
ffStrbufDestroy(&error);
}
va_end(arguments);
}
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)
{
FFstrbuf buffer;
ffStrbufInitA(&buffer, 256);
ffParseFormatString(&buffer, formatString, error, numArgs, arguments);
if(buffer.length > 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
ffStrbufPutTo(&buffer, stdout);
}
ffStrbufDestroy(&buffer);
}
void ffGetCacheFilePath(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
{
ffStrbufAppend(buffer, &instance->state.cacheDir);
ffStrbufAppendS(buffer, moduleName);
if(extension != NULL)
{
ffStrbufAppendC(buffer, '.');
ffStrbufAppendS(buffer, extension);
}
}
void ffReadCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffGetCacheFilePath(instance, moduleName, extension, &path);
ffAppendFileContent(path.chars, buffer);
ffStrbufDestroy(&path);
}
void ffWriteCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* content)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffGetCacheFilePath(instance, moduleName, extension, &path);
ffWriteFileContent(path.chars, content);
ffStrbufDestroy(&path);
}
static bool printCachedValue(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat)
{
FFstrbuf content;
ffStrbufInitA(&content, 512);
ffReadCacheFile(instance, moduleName, FF_IO_CACHE_VALUE_EXTENSION, &content);
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
if(content.length == 0)
return false;
uint8_t moduleCounter = 1;
uint32_t startIndex = 0;
while(startIndex < content.length)
{
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
puts(content.chars + startIndex);
startIndex = nullByteIndex + 1;
++moduleCounter;
}
ffStrbufDestroy(&content);
return moduleCounter > 1;
}
static bool printCachedFormat(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
{
FFstrbuf content;
ffStrbufInitA(&content, 512);
ffReadCacheFile(instance, moduleName, FF_IO_CACHE_SPLIT_EXTENSION, &content);
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
if(content.length == 0)
return false;
uint8_t moduleCounter = 1;
FFformatarg* arguments = calloc(numArgs, sizeof(FFformatarg));
uint32_t argumentCounter = 0;
uint32_t startIndex = 0;
while(startIndex < content.length)
{
arguments[argumentCounter].type = FF_FORMAT_ARG_TYPE_STRING;
arguments[argumentCounter].value = &content.chars[startIndex];
++argumentCounter;
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
if(argumentCounter == numArgs)
{
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
++moduleCounter;
argumentCounter = 0;
}
startIndex = nullByteIndex + 1;
}
free(arguments);
ffStrbufDestroy(&content);
return moduleCounter > 1;
}
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
{
if(instance->config.recache)
return false;
if(formatString == NULL || formatString->length == 0)
return printCachedValue(instance, moduleName, customKeyFormat);
else
return printCachedFormat(instance, moduleName, customKeyFormat, formatString, numArgs);
}
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
{
if(formatString == NULL || formatString->length == 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
ffStrbufPutTo(value, stdout);
}
else
{
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
}
if(cache->value != NULL)
{
ffStrbufWriteTo(value, cache->value);
fputc('\0', cache->value);
}
if(cache->split == NULL)
return;
for(uint32_t i = 0; i < numArgs; i++)
{
FFstrbuf buffer;
ffStrbufInitA(&buffer, 64);
ffFormatAppendFormatArg(&buffer, &arguments[i]);
ffStrbufWriteTo(&buffer, cache->split);
ffStrbufDestroy(&buffer);
fputc('\0', cache->split);
}
}
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
{
FFcache cache;
ffCacheOpenWrite(instance, moduleName, &cache);
ffPrintAndAppendToCache(instance, moduleName, 0, customKeyFormat, &cache, value, formatString, numArgs, arguments);
ffCacheClose(&cache);
}
void ffCacheValidate(FFinstance* instance)
{
FFstrbuf path;
ffStrbufInitA(&path, 64);
ffGetCacheFilePath(instance, "cacheversion", "ffv", &path);
FFstrbuf content;
ffStrbufInit(&content);
ffAppendFileContent(path.chars, &content);
bool isSameVersion = ffStrbufCompS(&content, FASTFETCH_PROJECT_VERSION) == 0;
ffStrbufDestroy(&content);
if(isSameVersion)
{
ffStrbufDestroy(&path);
return;
}
instance->config.recache = true;
FFstrbuf version;
ffStrbufInit(&version);
ffStrbufAppendS(&version, FASTFETCH_PROJECT_VERSION);
ffWriteFileContent(path.chars, &version);
ffStrbufDestroy(&version);
ffStrbufDestroy(&path);
}
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache)
{
FFstrbuf cacheFileValue;
ffStrbufInitA(&cacheFileValue, 64);
ffGetCacheFilePath(instance, moduleName, FF_IO_CACHE_VALUE_EXTENSION, &cacheFileValue);
cache->value = fopen(cacheFileValue.chars, "w");
ffStrbufDestroy(&cacheFileValue);
FFstrbuf cacheFileSplit;
ffStrbufInitA(&cacheFileSplit, 64);
ffGetCacheFilePath(instance, moduleName, FF_IO_CACHE_SPLIT_EXTENSION, &cacheFileSplit);
cache->split = fopen(cacheFileSplit.chars, "w");
ffStrbufDestroy(&cacheFileSplit);
}
void ffCacheClose(FFcache* cache)
{
if(cache->value != NULL)
fclose(cache->value);
if(cache->split != NULL)
fclose(cache->split);
}
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
{
bool* searchedValues = malloc(sizeof(bool) * numQueries);
bool allSet = true;
for(uint32_t i = 0; i < numQueries; i++)
{
if((searchedValues[i] = queries[i].buffer->length == 0))
allSet = false;
}
if(allSet)
{
free(searchedValues);
return true;
}
FILE* file = fopen(filename, "r");
if(file == NULL)
return false;
char* line = NULL;
size_t len = 0;
while (getline(&line, &len, file) != -1)
{
for(uint32_t i = 0; i < numQueries; i++)
{
if(!searchedValues[i])
continue;
uint32_t currentLength = queries[i].buffer->length;
queries[i].buffer->length = 0;
if(!ffGetPropValue(line, queries[i].start, queries[i].buffer))
queries[i].buffer->length = currentLength;
}
}
free(searchedValues);
if(line != NULL)
free(line);
fclose(file);
return true;
}
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
}
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
FFstrbuf absolutePath;
ffStrbufInitA(&absolutePath, 64);
ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir);
ffStrbufAppendC(&absolutePath, '/');
ffStrbufAppendS(&absolutePath, relativeFile);
bool result = ffParsePropFileValues(absolutePath.chars, numQueries, queries);
ffStrbufDestroy(&absolutePath);
return result;
}
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileHomeValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
bool foundAFile = false;
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
{
FFstrbuf* baseDir = (FFstrbuf*) ffListGet(&instance->state.configDirs, i);
uint32_t baseDirLength = baseDir->length;
if(*relativeFile != '/')
ffStrbufAppendC(baseDir, '/');
ffStrbufAppendS(baseDir, relativeFile);
if(ffParsePropFileValues(baseDir->chars, numQueries, queries))
foundAFile = true;
ffStrbufSubstrBefore(baseDir, baseDirLength);
bool allSet = true;
for(uint32_t k = 0; k < numQueries; k++)
{
if(queries[k].buffer->length == 0)
{
allSet = false;
break;
}
}
if(allSet)
break;
}
return foundAFile;
}
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
#include <stdarg.h>
#include <termios.h>
#include <poll.h>
bool ffWriteFDContent(int fd, const FFstrbuf* content)
{
return write(fd, content->chars, content->length) != -1;
}
void ffWriteFileContent(const char* fileName, const FFstrbuf* content)
static void createSubfolders(const char* fileName)
{
int fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(fd == -1)
return;
FFstrbuf path;
ffStrbufInit(&path);
ffWriteFDContent(fd, content);
while(*fileName != '\0')
{
ffStrbufAppendC(&path, *fileName);
if(*fileName == '/')
mkdir(path.chars, S_IRWXU | S_IRGRP | S_IROTH);
++fileName;
}
ffStrbufDestroy(&path);
}
bool ffWriteFileContent(const char* fileName, const FFstrbuf* content)
{
int openFlagsModes = O_WRONLY | O_CREAT | O_TRUNC;
int openFlagsRights = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int fd = open(fileName, openFlagsModes, openFlagsRights);
if(fd == -1)
{
createSubfolders(fileName);
fd = open(fileName, openFlagsModes, openFlagsRights);
if(fd == -1)
return false;
}
bool ret = ffWriteFDContent(fd, content);
close(fd);
return ret;
}
void ffAppendFDContent(int fd, FFstrbuf* buffer)
@@ -491,15 +122,50 @@ void ffSuppressIO(bool suppress)
dup2(suppress ? nullFile : origErr, STDERR_FILENO);
}
void ffPrintColor(const FFstrbuf* colorValue)
{
fputs("\033[", stdout);
ffStrbufWriteTo(colorValue, stdout);
fputc('m', stdout);
}
bool ffFileExists(const char* fileName, mode_t mode)
{
struct stat fileStat;
return stat(fileName, &fileStat) == 0 && ((fileStat.st_mode & S_IFMT) == mode);
}
void ffGetTerminalResponse(const char* request, const char* format, ...)
{
struct termios oldTerm, newTerm;
if(tcgetattr(STDIN_FILENO, &oldTerm) == -1)
return;
newTerm = oldTerm;
newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO);
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];
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);
va_end(args);
}
+34 -4
View File
@@ -2,6 +2,33 @@
#include <stdarg.h>
static void* libraryLoad(const char* path, int maxVersion)
{
void* result = dlopen(path, RTLD_LAZY);
if(result != NULL)
return result;
FFstrbuf pathbuf;
ffStrbufInitA(&pathbuf, 64);
ffStrbufAppendS(&pathbuf, path);
ffStrbufAppendC(&pathbuf, '.');
for(int i = maxVersion; i >= 0; --i)
{
uint32_t originalLength = pathbuf.length;
ffStrbufAppendF(&pathbuf, "%i", i);
result = dlopen(pathbuf.chars, RTLD_LAZY);
if(result != NULL)
break;
ffStrbufSubstrBefore(&pathbuf, originalLength);
}
ffStrbufDestroy(&pathbuf);
return result;
}
void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...)
{
if(userProvidedName->length > 0)
@@ -11,12 +38,15 @@ void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...)
va_start(defaultNames, userProvidedName);
void* result = NULL;
const char* name = va_arg(defaultNames, const char*);
while(result == NULL && name != NULL)
while(result == NULL)
{
result = dlopen(name, RTLD_LAZY);
name = va_arg(defaultNames, const char*);
const char* path = va_arg(defaultNames, const char*);
if(path == NULL)
break;
int maxVersion = va_arg(defaultNames, int);
result = libraryLoad(path, maxVersion);
}
va_end(defaultNames);
-1399
View File
File diff suppressed because it is too large Load Diff
+39 -328
View File
@@ -1,8 +1,45 @@
#include "fastfetch.h"
#include <string.h>
bool ffStrSet(const char* str)
{
if(str == NULL)
return false;
void ffGetGtkPretty(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
while(*str != '\0')
{
if(*str != ' ' && *str != '\t' && *str != '\n' && *str != '\r')
return true;
}
return false;
}
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch)
{
if(major->length > 0)
ffStrbufAppend(buffer, major);
else if(minor->length > 0 || patch->length > 0)
ffStrbufAppendC(buffer, '1');
if(minor->length == 0 && patch->length == 0)
return;
ffStrbufAppendC(buffer, '.');
if(minor->length > 0)
ffStrbufAppend(buffer, minor);
else if(patch->length > 0)
ffStrbufAppendC(buffer, '0');
if(patch->length == 0)
return;
ffStrbufAppendC(buffer, '.');
ffStrbufAppend(buffer, patch);
}
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
{
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
{
@@ -81,329 +118,3 @@ void ffGetGtkPretty(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3
ffStrbufAppendS(buffer, " [GTK4]");
}
}
static void fontInit(FFfont* font)
{
ffStrbufInit(&font->pretty);
ffStrbufInit(&font->name);
ffStrbufInitA(&font->size, 4);
ffListInitA(&font->styles, sizeof(FFstrbuf), 4);
}
static void fontInitPretty(FFfont* font)
{
ffStrbufAppend(&font->pretty, &font->name);
if(font->size.length == 0 && font->styles.length == 0)
return;
else if(font->pretty.length == 0)
ffStrbufAppendS(&font->pretty, "default");
ffStrbufAppendS(&font->pretty, " (");
if(font->size.length > 0)
{
ffStrbufAppend(&font->pretty, &font->size);
ffStrbufAppendS(&font->pretty, "pt");
if(font->styles.length > 0)
ffStrbufAppendS(&font->pretty, ", ");
}
for(uint32_t i = 0; i < font->styles.length; i++)
{
ffStrbufAppend(&font->pretty, ffListGet(&font->styles, i));
if(i < font->styles.length - 1)
ffStrbufAppendS(&font->pretty, ", ");
}
ffStrbufAppendC(&font->pretty, ')');
}
void ffFontInitQt(FFfont* font, const char* data)
{
fontInit(font);
//See https://doc.qt.io/qt-5/qfont.html#toString
//Family
while(*data != ',' && *data != '\0')
{
ffStrbufAppendC(&font->name, *data);
++data;
}
if(*data != '\0')
++data;
ffStrbufTrim(&font->name, ' ');
//Size
while(*data != ',' && *data != '\0')
{
ffStrbufAppendC(&font->size, *data);
++data;
}
if(*data != '\0')
++data;
ffStrbufTrim(&font->size, ' ');
#define FF_FONT_QT_SKIP_VALUE \
while(*data != ',' && *data != '\0') \
++data; \
if(*data != '\0') \
++data;
FF_FONT_QT_SKIP_VALUE //Pixel size
FF_FONT_QT_SKIP_VALUE //Style hint
FF_FONT_QT_SKIP_VALUE //Font weight
FF_FONT_QT_SKIP_VALUE //Font style
FF_FONT_QT_SKIP_VALUE //Underline
FF_FONT_QT_SKIP_VALUE //Strike out
FF_FONT_QT_SKIP_VALUE //Fixed pitch
FF_FONT_QT_SKIP_VALUE //Always 0
#undef FF_FONT_QT_SKIP_VALUE
while(*data != '\0')
{
while(*data == ' ')
++data;
if(*data == '\0')
break;
FFstrbuf* style = ffListAdd(&font->styles);
ffStrbufInit(style);
while(*data != ' ' && *data != '\0')
{
ffStrbufAppendC(style, *data);
++data;
}
}
fontInitPretty(font);
}
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
{
while(**data == ' ' || **data == '\t' || **data == ',')
++(*data);
const char* wordStart = *data;
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
++(*data);
uint32_t wordLength = (uint32_t) (*data - wordStart);
if(wordLength == 0)
return;
if(**data == '\0' || **data == '`' || **data == '\\')
{
ffStrbufAppendNS(&font->size, wordLength, wordStart);
if(ffStrbufEndsWithS(&font->size, "px"))
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
double dummy;
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
return;
ffStrbufClear(&font->size);
}
if(
strncasecmp(wordStart, "Ultra", 5) == 0 ||
strncasecmp(wordStart, "Extra", 5) == 0 ||
strncasecmp(wordStart, "Semi", 4) == 0 ||
strncasecmp(wordStart, "Demi", 4) == 0 ||
strncasecmp(wordStart, "Normal", wordLength) == 0 ||
strncasecmp(wordStart, "Roman", wordLength) == 0 ||
strncasecmp(wordStart, "Oblique", wordLength) == 0 ||
strncasecmp(wordStart, "Italic", wordLength) == 0 ||
strncasecmp(wordStart, "Thin", wordLength) == 0 ||
strncasecmp(wordStart, "Light", wordLength) == 0 ||
strncasecmp(wordStart, "Bold", wordLength) == 0 ||
strncasecmp(wordStart, "Black", wordLength) == 0 ||
strncasecmp(wordStart, "Condensed", wordLength) == 0 ||
strncasecmp(wordStart, "Expanded", wordLength) == 0
) {
if(alternativeBuffer == NULL)
{
alternativeBuffer = ffListAdd(&font->styles);
ffStrbufInit(alternativeBuffer);
}
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
if(
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
strncasecmp(wordStart, "Extra ", 6) == 0 ||
strncasecmp(wordStart, "Semi ", 5) == 0 ||
strncasecmp(wordStart, "Demi ", 5) == 0
) {
fontPangoParseWord(data, font, alternativeBuffer);
}
return;
}
if(alternativeBuffer != NULL)
{
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
return;
}
if(font->name.length > 0)
ffStrbufAppendC(&font->name, ' ');
ffStrbufAppendNS(&font->name, wordLength, wordStart);
}
void ffFontInitPango(FFfont* font, const char* data)
{
fontInit(font);
while(*data != '\0' && *data != '`' && *data != '\\')
fontPangoParseWord(&data, font, NULL);
fontInitPretty(font);
}
void ffFontInitCopy(FFfont* font, const char* name)
{
fontInit(font);
ffStrbufAppendS(&font->name, name);
fontInitPretty(font);
}
void ffFontDestroy(FFfont* font)
{
ffStrbufDestroy(&font->pretty);
ffStrbufDestroy(&font->name);
ffStrbufDestroy(&font->size);
for(uint32_t i = 0; i < font->styles.length; i++)
ffStrbufDestroy(ffListGet(&font->styles, i));
ffListDestroy(&font->styles);
}
static bool getPropValueLine(const char** line, const char* start, FFstrbuf* buffer)
{
if(**line == '\0')
return false;
//Skip any amount of whitespace at the begin of line
while(**line == ' ' || **line == '\t')
++(*line);
while(*start != '\0')
{
// Any amount of whitespace in the format string matches any amount of whitespace in the line, even none
if(*start == ' ' || *start == '\t')
{
while(*start == ' ' || *start == '\t')
++start;
while(**line == ' ' || **line == '\t')
++(*line);
continue;
}
//Line doesn't match start, skip it
if(**line != *start || **line == '\0')
return false;
//Line and start match, continue testing
++(*line);
++start;
}
char valueEnd = '\n';
//Allow faster parsing of XML
if(*(*line - 1) == '>')
valueEnd = '<';
//Skip any amount of whitespace at the begin of the value
while(**line == ' ' || **line == '\t')
++(*line);
//Allow faster parsing of quotet values
if(**line == '"' || **line == '\'')
{
valueEnd = **line;
++(*line);
}
//Copy the value to the buffer
while(**line != valueEnd && **line != '\n' && **line != '\0')
{
ffStrbufAppendC(buffer, **line);
++(*line);
}
ffStrbufTrimRight(buffer, ' ');
return true;
}
bool ffGetPropValue(const char* line, const char* start, FFstrbuf* buffer)
{
return getPropValueLine(&line, start, buffer);
}
bool ffGetPropValueFromLines(const char* lines, const char* start, FFstrbuf* buffer)
{
while(!getPropValueLine(&lines, start, buffer))
{
while(*lines != '\0' && *lines != '\n')
++lines;
if(*lines == '\0')
return false;
//Skip '\n'
++lines;
}
return true;
}
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch)
{
if(major->length > 0)
ffStrbufAppend(buffer, major);
else if(minor->length > 0 || patch->length > 0)
ffStrbufAppendC(buffer, '1');
if(minor->length == 0 && patch->length == 0)
return;
ffStrbufAppendC(buffer, '.');
if(minor->length > 0)
ffStrbufAppend(buffer, minor);
else if(patch->length > 0)
ffStrbufAppendC(buffer, '0');
if(patch->length == 0)
return;
ffStrbufAppendC(buffer, '.');
ffStrbufAppend(buffer, patch);
}
bool ffStrSet(const char* str)
{
if(str == NULL)
return false;
while(*str != '\0')
{
if(*str != ' ' && *str != '\t' && *str != '\n' && *str != '\r')
return true;
}
return false;
}
+62
View File
@@ -0,0 +1,62 @@
#include "fastfetch.h"
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)
return;
va_list arguments;
va_start(arguments, message);
if(formatString == NULL || formatString->length == 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
vprintf(message, arguments);
puts(FASTFETCH_TEXT_MODIFIER_RESET);
}
else
{
FF_STRBUF_CREATE(error);
ffStrbufAppendVF(&error, message, arguments);
// calloc sets all to 0 and FF_FORMAT_ARG_TYPE_NULL also has value 0 so we don't need to explictly set it
FFformatarg* nullArgs = calloc(numFormatArgs, sizeof(FFformatarg));
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, &error, numFormatArgs, nullArgs);
free(nullArgs);
ffStrbufDestroy(&error);
}
va_end(arguments);
}
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)
{
FFstrbuf buffer;
ffStrbufInitA(&buffer, 256);
ffParseFormatString(&buffer, formatString, error, numArgs, arguments);
if(buffer.length > 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
ffStrbufPutTo(&buffer, stdout);
}
ffStrbufDestroy(&buffer);
}
void ffPrintColor(const FFstrbuf* colorValue)
{
fputs("\033[", stdout);
ffStrbufWriteTo(colorValue, stdout);
fputc('m', stdout);
}
void ffPrintCharTimes(char c, uint32_t times)
{
for(uint32_t i = 0; i < times; i++)
putchar(c);
}
+202
View File
@@ -0,0 +1,202 @@
#include "fastfetch.h"
static bool parsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer)
{
if(**line == '\0')
return false;
//Skip any amount of whitespace at the begin of line
while(**line == ' ' || **line == '\t')
++(*line);
while(*start != '\0')
{
// Any amount of whitespace in the format string matches any amount of whitespace in the line, even none
if(*start == ' ' || *start == '\t')
{
while(*start == ' ' || *start == '\t')
++start;
while(**line == ' ' || **line == '\t')
++(*line);
continue;
}
//Line doesn't match start, skip it
if(**line != *start || **line == '\0')
return false;
//Line and start match, continue testing
++(*line);
++start;
}
char valueEnd = '\n';
//Allow faster parsing of XML
if(*(*line - 1) == '>')
valueEnd = '<';
//Skip any amount of whitespace at the begin of the value
while(**line == ' ' || **line == '\t')
++(*line);
//Allow faster parsing of quotet values
if(**line == '"' || **line == '\'')
{
valueEnd = **line;
++(*line);
}
//Copy the value to the buffer
while(**line != valueEnd && **line != '\n' && **line != '\0')
{
ffStrbufAppendC(buffer, **line);
++(*line);
}
ffStrbufTrimRight(buffer, ' ');
return true;
}
bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer)
{
return parsePropLinePointer(&line, start, buffer);
}
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer)
{
while(!parsePropLinePointer(&lines, start, buffer))
{
while(*lines != '\0' && *lines != '\n')
++lines;
if(*lines == '\0')
return false;
//Skip '\n'
++lines;
}
return true;
}
// The following functions return true if the file was found, independently if start was found
// Buffers which already contain content are not overwritten
// The last occurence of start in the first file will be the one used
// The *Values methods always return true, if all properties were already found before, without testing if the file exists
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
{
bool* searchedValues = malloc(sizeof(bool) * numQueries);
bool allSet = true;
for(uint32_t i = 0; i < numQueries; i++)
{
if((searchedValues[i] = queries[i].buffer->length == 0))
allSet = false;
}
if(allSet)
{
free(searchedValues);
return true;
}
FILE* file = fopen(filename, "r");
if(file == NULL)
return false;
char* line = NULL;
size_t len = 0;
while (getline(&line, &len, file) != -1)
{
for(uint32_t i = 0; i < numQueries; i++)
{
if(!searchedValues[i])
continue;
uint32_t currentLength = queries[i].buffer->length;
queries[i].buffer->length = 0;
if(!ffParsePropLine(line, queries[i].start, queries[i].buffer))
queries[i].buffer->length = currentLength;
}
}
free(searchedValues);
if(line != NULL)
free(line);
fclose(file);
return true;
}
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
}
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
FFstrbuf absolutePath;
ffStrbufInitA(&absolutePath, 64);
ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir);
ffStrbufAppendC(&absolutePath, '/');
ffStrbufAppendS(&absolutePath, relativeFile);
bool result = ffParsePropFileValues(absolutePath.chars, numQueries, queries);
ffStrbufDestroy(&absolutePath);
return result;
}
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileHomeValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
{
bool foundAFile = false;
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
{
FFstrbuf* baseDir = (FFstrbuf*) ffListGet(&instance->state.configDirs, i);
uint32_t baseDirLength = baseDir->length;
if(*relativeFile != '/')
ffStrbufAppendC(baseDir, '/');
ffStrbufAppendS(baseDir, relativeFile);
if(ffParsePropFileValues(baseDir->chars, numQueries, queries))
foundAFile = true;
ffStrbufSubstrBefore(baseDir, baseDirLength);
bool allSet = true;
for(uint32_t k = 0; k < numQueries; k++)
{
if(queries[k].buffer->length == 0)
{
allSet = false;
break;
}
}
if(allSet)
break;
}
return foundAFile;
}
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
+72 -3
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; \
@@ -80,7 +81,7 @@ typedef struct GSettingsData
static const GSettingsData* getGSettingsData(FFinstance* instance)
{
FF_LIBRARY_DATA_LOAD_INIT(GSettingsData, instance->config.libGIO, "libgio-2.0.so", "libgio-2.0.so.0");
FF_LIBRARY_DATA_LOAD_INIT(GSettingsData, instance->config.libGIO, "libgio-2.0.so", 1);
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_schema_source_lookup)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_schema_has_key)
@@ -152,7 +153,7 @@ typedef struct DConfData
static const DConfData* getDConfData(FFinstance* instance)
{
FF_LIBRARY_DATA_LOAD_INIT(DConfData, instance->config.libDConf, "libdconf.so", "libdconf.so.1");
FF_LIBRARY_DATA_LOAD_INIT(DConfData, instance->config.libDConf, "libdconf.so", 2);
FF_LIBRARY_DATA_LOAD_SYMBOL(dconf_client_read_full)
FF_LIBRARY_DATA_LOAD_SYMBOL(dconf_client_new)
@@ -222,7 +223,7 @@ typedef struct XFConfData
static const XFConfData* getXFConfData(FFinstance* instance)
{
FF_LIBRARY_DATA_LOAD_INIT(XFConfData, instance->config.libXFConf, "libxfconf-0.so", "libxfconf-0.so.3");
FF_LIBRARY_DATA_LOAD_INIT(XFConfData, instance->config.libXFConf, "libxfconf-0.so", 4);
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_get)
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_has_property)
@@ -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) {
+79 -63
View File
@@ -27,38 +27,17 @@
# Get the default structure with "fastfetch --print-structure".
#--structure $"FASTFETCH_DATATEXT_STRUCTURE$"
# Logo option:
# Sets the logo to use.
# List available logos with "fastfetch --list-logos".
# Print available logos with "fastfetch --print-logos".
# Must be the name of an available logo or a path to a text file containing a custom logo.
# Default is the current distribution.
#--logo arch
# Multithreading option:
# Sets if fastfetch should use multiple threads to detect the values.
# Must be true or false.
# Default is true.
#--multithreading true
# Color option:
# Sets the color of the keys.
# Must be linux console color codes or the name of a color.
# Default is the primary color of the logo.
# Use "fastfetch --help color" to learn more and see examples.
#--color magenta
# Spacing option:
# Sets the amount of whitespace between the logo and keys.
# Must be an positive integer.
# Default is 4.
#--spacing 4
# Separator option:
# Sets the string placed between a key and its value.
# Can be any string.
# Default is ": ".
#--separator ": "
# Offset option:
# Sets the amount of whitespace before the logo. Can be negative to cut the logo.
# Must be an integer.
# Default is 0.
#--offsetx 0
# Slow operations option:
# Sets if fastfetch is allowed to use known slow operations to detect more / better values.
# Must be true or false.
# Default is false.
#--allow-slow-operations false
# Linewrap option:
# Sets if fastfetch should disable linewrap during the run.
@@ -72,35 +51,31 @@
# Default is true.
#--hide-cursor true
# Remaing logo option:
# Sets if the remaining logo should be printed, if it is higher than the information printed.
# Must be true or false.
# Default is true.
#--print-remaining-logo true
# Logo option:
# Sets the logo to use.
# List available logos with "fastfetch --list-logos".
# Print available logos with "fastfetch --print-logos".
# Must be the name of an available logo or a path to a text file containing a custom logo.
# Default is the current distribution.
#--logo arch
# Multithreading option:
# Sets if fastfetch should use multiple threads to detect the values.
# Must be true or false.
# Default is true.
#--multithreading true
# Logo type option:
# Sets the logo type to use.
# Must be auto, builtin, file, raw, sixel, kitty or chafa.
# Default is auto.
#--logo-type auto
# Slow operations option:
# Sets if fastfetch is allowed to use known slow operations to detect more / better values.
# Must be true or false.
# Default is false.
#--allow-slow-operations false
# Logo width option:
# 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
# Color logo option:
# Sets if the logo should be colored.
# Must be true or false.
# Default is true.
#--color-logo true
# Separator string option:
# Sets the string printed by the "separator" module (usually between title and rest of output)
# Must be any string. It is repated / cut to fit perfectly.
# Default is "-"
#--separator-string -
# 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.
@@ -109,16 +84,53 @@
# Default is the one specified by the logo.
# Use "fastfetch --help color" to learn more and see examples.
# Valid index range is [1-9].
#--color-1 red
#--color-2 32
#--logo-color-1 red
#--logo-color-2 32
# [...]
#--color-9 yellow
#--logo-color-9 yellow
# User logo raw option:
# Sets if color replacements should be performed on the user provided logo.
# Logo padding option:
# Adds a padding to the left and the right side of the logo.
# Must be a positive integer.
# Default is 0.
#--logo-padding 0
# Logo padding left option:
# Adds a padding to the left side of the logo.
# Must be a positive integer.
# Default is 0.
#--logo-padding-left 0
# Logo padding right option:
# Adds a padding to the right side of the logo.
# Must be a positive integer.
# Default is 0.
#--logo-padding-right 0
# Logo print remaining option:
# Sets if the remaining logo should be printed, it is has more lines than modules to show.
# Must be true or false.
# Default is true.
#--color-raw true
#--logo-print-remaining true
# Color option:
# Sets the color of the keys.
# Must be linux console color codes or the name of a color.
# Default is the primary color of the logo.
# Use "fastfetch --help color" to learn more and see examples.
#--color magenta
# Separator option:
# Sets the string placed between a key and its value.
# Can be any string.
# Default is ": ".
#--separator ": "
# Separator string option:
# Sets the string printed by the "separator" module (usually between title and rest of output)
# Must be any string. It is repated / cut to fit perfectly.
# Default is "-"
#--separator-string -
# Public IP timeout option:
# Sets the time to wait for the public ip server to respond.
@@ -221,4 +233,8 @@
#--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
+43 -30
View File
@@ -1,39 +1,48 @@
Usage: fastfetch <options>
Informative options:
-h, --help: shows this message and exits
-h <command>, --help <command>: shows help for a specific command and exits
-v --version: prints the version of fastfetch and exits
--list-logos: list available logos and exits
--list-modules: lists available modules and exits
--list-presets: list presets fastfetch knows about and exits. They can be loaded with --load-config. (+)
--list-features: list the supported features fastfetch was compiled with and exits. Mainly for development.
--print-logos: show available logos and exits
--print-config: prints the default config and exits
--print-structure: prints the default stucture and exits
-h,--help: shows this message and exits
-h,--help <command>: shows help for a specific command and exits
-v,--version: prints the version of fastfetch and exits
--list-logos: list available logos and exits
--list-modules: lists available modules and exits
--list-presets: list presets fastfetch knows about and exits. They can be loaded with --load-config. (+)
--list-features: list the supported features fastfetch was compiled with and exits. Mainly for development.
--print-logos: show available logos and exits
--print-config: prints the default config and exits
--print-structure: prints the default stucture and exits
General options:
--structure <structure>: sets the structure of the fetch. Must be a colon separated list of keys. Use "fastfetch --list-modules" to see the ones available.
--set <key=value>: hard set the value of a key
-c <color>, --color <color>: sets the color of the keys. Must be a linux console color code or the name of a color (+)
--color-[1-9] <color>: overwrites a color of the logo. Must be a linux console color code or the name of a color
--spacing <width>: sets the distance between logo and text
-s <str>, --separator <str>: sets the separator between key and value. Default is a colon with a space
-x <offset>, --offsetx <offset>: sets the x offset. Can be negative to cut the logo, but no more than logo width.
--show-errors <?value>: print occuring errors
-r <?value> --recache <?value>: generate new cached values
--nocache <?value>: don't use cached values, but also don't overwrite existing ones
--print-remaining-logo <?value>: print the remaining logo, if it is higher than the number of lines shown
--multithreading <?value>: use multiple threads to detect values
--load-config <file>: load a config file (+)
--allow-slow-operations <?value>: Allow operations that are usually very slow for more detailed output
--disable-linewrap <?value>: Disable linewrap during the run
--hide-cursor <?value>: Hide the cursor during the run
--logo-raw <?value>: Print a custom logo as is, without any color replacements
-r,--recache <?value>: generate new cached values
--nocache <?value>: don't use cached values, but also don't overwrite existing ones
--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
Logo options:
-l <name>, --logo <name>: sets the shown logo. Also changes the main color accordingly. This will also load file contents as logo if the given argument is a valid path.
--color-logo <?value>: if set to false, the logo will be black / white
-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, 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
--logo-padding-right <padding>: set the padding on the right of the logo
--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>
Display options:
-s,--structure <structure>: sets the structure of the fetch. Must be a colon separated list of keys. Use "fastfetch --list-modules" to see the ones available.
-c,--color <color>: sets the color of the keys. Must be a linux console color code or the name of a color (+)
--separator <str>: sets the separator between key and value. Default is a colon with a space
--set <key=value>: hard set the value of a key
--show-errors <?value>: print occuring errors
--disable-linewrap <?value>: weather to disable linewrap during the run
--hide-cursor <?value>: weather to hide the cursor during the run
Format options: Provide the format string for custom output. Use fastfetch --help *-format for specific help.
--os-format <format>
@@ -113,7 +122,11 @@ 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>
Module specific options:
--separator-string <str>: Set the string printed by the separator module
+1 -1
View File
@@ -78,7 +78,7 @@ void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* resul
if(getenv("XDG_RUNTIME_DIR") == NULL)
return;
FF_LIBRARY_LOAD(wayland, instance->config.libWayland, , "libwayland-client.so", "libwayland-client.so.0")
FF_LIBRARY_LOAD(wayland, instance->config.libWayland, , "libwayland-client.so", 1)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect,)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_dispatch,)
+9 -9
View File
@@ -98,7 +98,7 @@ static void getKDE(FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "plasmashell");
ffStrbufSetS(&result->dePrettyName, "KDE Plasma");
ffParsePropFile("/usr/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
applyBetterWM(result, getenv("KDEWM"));
}
@@ -106,14 +106,14 @@ static void getGnome(FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "gnome-shell");
ffStrbufSetS(&result->dePrettyName, "GNOME");
ffParsePropFile("/usr/share/gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
}
static void getCinnamon(FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "cinnamon");
ffStrbufSetS(&result->dePrettyName, "Cinnamon");
ffParsePropFile("/usr/share/applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
}
static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
@@ -130,7 +130,7 @@ static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
FFstrbuf micro;
ffStrbufInit(&micro);
ffParsePropFileValues("/usr/share/mate-about/mate-version.xml", 3, (FFpropquery[]) {
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR"/share/mate-about/mate-version.xml", 3, (FFpropquery[]) {
{"<platform>", &major},
{"<minor>", &minor},
{"<micro>", &micro}
@@ -159,7 +159,7 @@ static void getXFCE4(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "xfce4-session");
ffStrbufSetS(&result->dePrettyName, "Xfce4");
ffParsePropFile("/usr/share/gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
@@ -180,12 +180,12 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "lxqt-session");
ffStrbufSetS(&result->dePrettyName, "LXQt");
ffParsePropFile("/usr/lib/pkgconfig/lxqt.pc", "Version:", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/lib/pkgconfig/lxqt.pc", "Version:", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile("/usr/share/cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile("/usr/share/cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
@@ -197,7 +197,7 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
});
result->deVersion.length = 0; //don't set '\0' byte
ffGetPropValueFromLines(result->deVersion.chars , "liblxqt", &result->deVersion);
ffParsePropLines(result->deVersion.chars , "liblxqt", &result->deVersion);
}
FFstrbuf wmProcessNameBuffer;
+6 -6
View File
@@ -89,7 +89,7 @@ static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connect
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xcb, instance->config.libXcb, , "libxcb.so", "libxcb.so.1")
FF_LIBRARY_LOAD(xcb, instance->config.libXcb, , "libxcb.so", 2)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_connect,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_get_setup,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_setup_roots_iterator,)
@@ -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)
@@ -324,7 +324,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xcbRandr, instance->config.libXcbRandr, , "libxcb-randr.so", "libxcb-randr.so.0")
FF_LIBRARY_LOAD(xcbRandr, instance->config.libXcbRandr, , "libxcb-randr.so", 1)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_connect,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_get_setup,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_setup_roots_iterator,)
+6 -6
View File
@@ -53,7 +53,7 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(x11, instance->config.libX11, , "libX11.so", "libX11.so.6", "libX11-xcb.so", "libX11-xcb.so.1")
FF_LIBRARY_LOAD(x11, instance->config.libX11, , "libX11.so", 7, "libX11-xcb.so", 2)
FF_LIBRARY_LOAD_SYMBOL(x11, XOpenDisplay,)
FF_LIBRARY_LOAD_SYMBOL(x11, XCloseDisplay,)
@@ -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)
@@ -257,7 +257,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xrandr, instance->config.libXrandr, , "libXrandr.so", "libXrandr.so.2")
FF_LIBRARY_LOAD(xrandr, instance->config.libXrandr, , "libXrandr.so", 3)
FF_LIBRARY_LOAD_SYMBOL(xrandr, XOpenDisplay,)
FF_LIBRARY_LOAD_SYMBOL(xrandr, XCloseDisplay,)
+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
+7 -3
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;
@@ -285,7 +289,7 @@ static void getMedia(FFinstance* instance, FFMediaResult* result)
{
DBusData data;
FF_LIBRARY_LOAD(dbus, instance->config.libDBus, , "libdbus-1.so", "libdbus-1.so.3");
FF_LIBRARY_LOAD(dbus, instance->config.libDBus, , "libdbus-1.so", 4);
FF_LIBRARY_LOAD_SYMBOL(dbus, dbus_bus_get,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_new_method_call, dbus_message_new_method_call,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_init, dbus_message_iter_init,)
+70 -4
View File
@@ -1,5 +1,6 @@
#include "fastfetch.h"
#include <string.h>
#include <pthread.h>
#if !defined(__ANDROID__)
@@ -26,9 +27,70 @@ 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(FFinstance* instance)
const FFOSResult* ffDetectOS(const FFinstance* instance)
{
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static FFOSResult result;
@@ -64,10 +126,14 @@ const FFOSResult* ffDetectOS(FFinstance* instance)
}
else
{
parseFile("/etc/os-release", &result);
parseFile("/usr/lib/os-release", &result);
parseFile("/etc/lsb-release", &result);
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");
+5 -5
View File
@@ -42,20 +42,20 @@ static bool detectFromConfigFile(const FFstrbuf* filename, FFPlasmaResult* resul
}
if(category == PLASMA_CATEGORY_KDE && result->widgetStyle.length == 0)
ffGetPropValue(line, "widgetStyle =", &result->widgetStyle);
ffParsePropLine(line, "widgetStyle =", &result->widgetStyle);
else if(category == PLASMA_CATEGORY_ICONS && result->icons.length == 0)
ffGetPropValue(line, "Theme =", &result->icons);
ffParsePropLine(line, "Theme =", &result->icons);
else if(category == PLASMA_CATEGORY_GENERAL)
{
if(result->colorScheme.length == 0)
ffGetPropValue(line, "ColorScheme =", &result->colorScheme);
ffParsePropLine(line, "ColorScheme =", &result->colorScheme);
if(result->font.length == 0)
ffGetPropValue(line, "font =", &result->font);
ffParsePropLine(line, "font =", &result->font);
//Before plasma 5.23, "Font" was the key instead of "font". Since a lot of distros ship older versions, we test for both.
if(result->font.length == 0)
ffGetPropValue(line, "Font =", &result->font);
ffParsePropLine(line, "Font =", &result->font);
}
}
+185 -117
View File
@@ -12,8 +12,6 @@ typedef struct FFdata
{
FFvaluestore valuestore;
FFstrbuf structure;
FFstrbuf logoName;
FFstrbuf logoColors[FASTFETCH_LOGO_MAX_COLORS];
bool multithreading;
} FFdata;
@@ -395,7 +393,7 @@ static inline void listAvailablePresets(FFinstance* instance)
ffStrbufAppendS(&folder, "/.local/share/fastfetch/presets/");
listAvailablePresetsFromFolder(&folder, 0, NULL);
ffStrbufSetS(&folder, "/usr/share/fastfetch/presets/");
ffStrbufSetS(&folder, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
listAvailablePresetsFromFolder(&folder, 0, NULL);
ffStrbufDestroy(&folder);
@@ -490,7 +488,7 @@ static void optionParseConfigFile(FFinstance* instance, FFdata* data, const char
return;
}
ffStrbufSetS(&filename, "/usr/share/fastfetch/presets/");
ffStrbufSetS(&filename, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
ffStrbufAppendS(&filename, value);
file = fopen(filename.chars, "r");
@@ -608,8 +606,31 @@ static void optionParseColor(const char* key, const char* value, FFstrbuf* buffe
}
}
static uint32_t optionParseUInt32(const char* key, const char* value)
{
if(value == NULL)
{
fprintf(stderr, "Error: usage: %s <num>\n", key);
exit(480);
}
char* end;
uint32_t num = (uint32_t) strtoul(value, &end, 10);
if(*end != '\0')
{
fprintf(stderr, "Error: usage: %s <num>\n", key);
exit(479);
}
return num;
}
static void parseOption(FFinstance* instance, FFdata* data, const char* key, const char* value)
{
///////////////////////
//Informative options//
///////////////////////
if(strcasecmp(key, "-h") == 0 || strcasecmp(key, "--help") == 0)
{
printCommandHelp(value);
@@ -625,21 +646,6 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
puts(FASTFETCH_PROJECT_VERSION);
exit(0);
}
else if(strcasecmp(key, "--list-logos") == 0)
{
ffListLogos();
exit(0);
}
else if(strcasecmp(key, "--list-logos-autocompletion") == 0)
{
ffListLogosForAutocompletion();
exit(0);
}
else if(strcasecmp(key, "--print-logos") == 0)
{
ffPrintLogos(instance);
exit(0);
}
else if(strcasecmp(key, "--print-config") == 0)
{
fputs(FASTFETCH_DATATEXT_CONFIG, stdout);
@@ -665,32 +671,150 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
ffListFeatures();
exit(0);
}
else if(strcasecmp(key, "--spacing") == 0)
else if(strcasecmp(key, "--list-logos") == 0)
{
ffListBuiltinLogos();
exit(0);
}
else if(strcasecmp(key, "--list-logos-autocompletion") == 0)
{
ffListBuiltinLogosAutocompletion();
exit(0);
}
else if(strcasecmp(key, "--print-logos") == 0)
{
ffPrintBuiltinLogos(instance);
exit(0);
}
///////////////////
//General options//
///////////////////
else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0)
{
//Set cacheSave as well, because the user expects the values to be cached when expliciting using --recache
instance->config.recache = optionParseBoolean(value);
instance->config.cacheSave = instance->config.recache;
}
else if(strcasecmp(key, "--nocache") == 0)
{
instance->config.recache = optionParseBoolean(value);
instance->config.cacheSave = false;
}
else if(strcasecmp(key, "--load-config") == 0)
optionParseConfigFile(instance, data, key, value);
else if(strcasecmp(key, "--multithreading") == 0)
data->multithreading = optionParseBoolean(value);
else if(strcasecmp(key, "--allow-slow-operations") == 0)
instance->config.allowSlowOperations = optionParseBoolean(value);
////////////////
//Logo options//
////////////////
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
optionParseString(key, value, &instance->config.logoSource);
else if(strcasecmp(key, "--logo-type") == 0)
{
if(value == NULL)
{
fprintf(stderr, "Error: usage: %s <width>\n", key);
exit(404);
fprintf(stderr, "Error: usage: %s <type>\n", key);
exit(476);
}
if(sscanf(value, "%hu", &instance->config.logoKeySpacing) != 1)
if(strcasecmp(value, "auto") == 0)
instance->config.logoType = FF_LOGO_TYPE_AUTO;
else if(strcasecmp(value, "builtin") == 0)
instance->config.logoType = FF_LOGO_TYPE_BUILTIN;
else if(strcasecmp(value, "file") == 0)
instance->config.logoType = FF_LOGO_TYPE_FILE;
else if(strcasecmp(value, "raw") == 0)
instance->config.logoType = FF_LOGO_TYPE_RAW;
else if(strcasecmp(value, "sixel") == 0)
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: couldn't parse %s to uint16_t\n", value);
exit(405);
fprintf(stderr, "Error: unknown logo type: %s\n", value);
exit(478);
}
}
else if(strcasecmp(key, "-x") == 0 || strcasecmp(key, "--offsetx") == 0)
else if(strncasecmp(key, "--logo-color-", 13) == 0 && key[13] != '\0' && key[14] == '\0') // matches "--logo-color-*"
{
if(value == NULL)
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
int index = (int)key[13] - 49;
//Match only --logo-color-[1-9]
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
{
fprintf(stderr, "Error: usage: %s <offset>\n", key);
exit(408);
}
if(sscanf(value, "%hi", &instance->config.offsetx) != 1)
{
fprintf(stderr, "Error: couldn't parse %s to int16_t\n", value);
exit(409);
fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[13]);
exit(472);
}
optionParseColor(key, value, &instance->config.logoColors[index]);
}
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);
instance->config.logoPaddingLeft = padding;
instance->config.logoPaddingRight = padding;
}
else if(strcasecmp(key, "--logo-padding-left") == 0)
instance->config.logoPaddingLeft = optionParseUInt32(key, value);
else if(strcasecmp(key, "--logo-padding-right") == 0)
instance->config.logoPaddingRight = optionParseUInt32(key, value);
else if(strcasecmp(key, "--logo-print-remaining") == 0)
instance->config.logoPrintRemaining = optionParseBoolean(value);
else if(strcasecmp(key, "--sixel") == 0)
{
optionParseString(key, value, &instance->config.logoSource);
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
}
else if(strcasecmp(key, "--kitty") == 0)
{
optionParseString(key, value, &instance->config.logoSource);
instance->config.logoType = FF_LOGO_TYPE_KITTY;
}
else if(strcasecmp(key, "--file") == 0)
{
optionCheckString(key, value, &instance->config.logoSource);
instance->config.logoType = FF_LOGO_TYPE_FILE;
}
else if(strcasecmp(key, "--raw") == 0)
{
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//
///////////////////
else if(strcasecmp(key, "--show-errors") == 0)
instance->config.showErrors = optionParseBoolean(value);
else if(strcasecmp(key, "--disable-linewrap") == 0)
instance->config.disableLinewrap = optionParseBoolean(value);
else if(strcasecmp(key, "--hide-cursor") == 0)
instance->config.hideCursor = optionParseBoolean(value);
else if(strcasecmp(key, "-s") == 0 || strcasecmp(key, "--structure") == 0)
optionParseString(key, value, &data->structure);
else if(strcasecmp(key, "--separator") == 0)
optionParseString(key, value, &instance->config.separator);
else if(strcasecmp(key, "-c") == 0 || strcasecmp(key, "--color") == 0)
optionParseColor(key, value, &instance->config.mainColor);
else if(strcasecmp(key, "--set") == 0)
{
if(value == NULL)
@@ -711,43 +835,11 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
ffValuestoreSet(&data->valuestore, value, separator + 1);
}
else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0)
{
//Set cacheSave as well, beacuse the user expects the values to be cached when expliciting using --recache
instance->config.recache = optionParseBoolean(value);
instance->config.cacheSave = instance->config.recache;
}
else if(strcasecmp(key, "--nocache") == 0)
{
instance->config.recache = optionParseBoolean(value);
instance->config.cacheSave = false;
}
else if(strcasecmp(key, "--load-config") == 0)
optionParseConfigFile(instance, data, key, value);
else if(strcasecmp(key, "--show-errors") == 0)
instance->config.showErrors = optionParseBoolean(value);
else if(strcasecmp(key, "--color-logo") == 0)
instance->config.colorLogo = optionParseBoolean(value);
else if(strcasecmp(key, "--print-remaining-logo") == 0)
instance->config.printRemainingLogo = optionParseBoolean(value);
else if(strcasecmp(key, "--multithreading") == 0)
data->multithreading = optionParseBoolean(value);
else if(strcasecmp(key, "--allow-slow-operations") == 0)
instance->config.allowSlowOperations = optionParseBoolean(value);
else if(strcasecmp(key, "--disable-linewrap") == 0)
instance->config.disableLinewrap = optionParseBoolean(value);
else if(strcasecmp(key, "--hide-cursor") == 0)
instance->config.hideCursor = optionParseBoolean(value);
else if(strcasecmp(key, "--logo-raw") == 0)
instance->config.userLogoIsRaw = optionParseBoolean(value);
else if(strcasecmp(key, "--structure") == 0)
optionParseString(key, value, &data->structure);
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
optionParseString(key, value, &data->logoName);
else if(strcasecmp(key, "-s") == 0 || strcasecmp(key, "--separator") == 0)
optionParseString(key, value, &instance->config.separator);
else if(strcasecmp(key, "-c") == 0 || strcasecmp(key, "--color") == 0)
optionParseColor(key, value, &instance->config.color);
////////////////////////
//Format + Key options//
////////////////////////
else if(strcasecmp(key, "--os-format") == 0)
optionParseString(key, value, &instance->config.osFormat);
else if(strcasecmp(key, "--os-key") == 0)
@@ -872,6 +964,11 @@ 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);
///////////////////
//Library options//
///////////////////
else if(strcasecmp(key, "--lib-PCI") == 0)
optionParseString(key, value, &instance->config.libPCI);
else if(strcasecmp(key, "--lib-vulkan") == 0)
@@ -894,8 +991,21 @@ 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);
//////////////////
//Module options//
//////////////////
else if(strcasecmp(key, "--disk-folders") == 0)
optionParseString(key, value, &instance->config.diskFolders);
else if(strcasecmp(key, "--battery-dir") == 0)
@@ -913,33 +1023,12 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
else if(strcasecmp(key, "--player-name") == 0)
optionParseString(key, value, &instance->config.playerName);
else if(strcasecmp(key, "--public-ip-timeout") == 0)
{
if(value == NULL)
{
fprintf(stderr, "Error: usage: %s <value>\n", key);
exit(465);
}
instance->config.publicIpTimeout = optionParseUInt32(key, value);
if(sscanf(value, "%u", &instance->config.publicIpTimeout) != 1)
{
fprintf(stderr, "Error: couldn't parse %s to uint32_t\n", value);
exit(466);
}
}
else if(strncasecmp(key, "--color-", 7) == 0 && key[8] != '\0' && key[9] == '\0') // matches "--color-*"
{
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
int index = (int)key[8] - 49;
//////////////////
//Unknown option//
//////////////////
//Match only --color-[1-9]
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
{
fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[8]);
exit(472);
}
optionParseColor(key, value, &data->logoColors[index]);
}
else
{
fprintf(stderr, "Error: unknown option: %s\n", key);
@@ -1089,32 +1178,11 @@ int main(int argc, const char** argv)
FFdata data;
ffValuestoreInit(&data.valuestore);
ffStrbufInitA(&data.structure, 256);
ffStrbufInitA(&data.logoName, 0);
data.multithreading = true;
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
ffStrbufInitA(&data.logoColors[i], 0);
parseDefaultConfigFile(&instance, &data);
parseArguments(&instance, &data, argc, argv);
//Load custom logo if it exists
if(data.logoName.length > 0)
ffLoadLogoSet(&instance, data.logoName.chars);
else
ffLoadLogo(&instance);
//If we haven't set key color, use primary color of logo
if(instance.config.color.length == 0)
ffStrbufSet(&instance.config.color, &instance.config.logoColors[0]);
//Overwrite logo colors with custom colors
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
{
if(data.logoColors[i].length > 0)
ffStrbufSet(&instance.config.logoColors[i], &data.logoColors[i]);
}
//Start detection threads
if(data.multithreading)
ffStartDetectionThreads(&instance);
+86 -71
View File
@@ -31,32 +31,37 @@ static inline void ffUnused(int dummy, ...) { (void) dummy; }
#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9)
typedef struct FFlogo
typedef enum FFLogoType
{
const char** names; //Null terminated
char* lines;
bool isFromUser;
const char** builtinColors; // [0] is used as key color, if not user specified
} FFlogo;
FF_LOGO_TYPE_AUTO, //If something is given, first try builtin, then file. Otherwise detect logo
FF_LOGO_TYPE_BUILTIN, //Builtin ascii art.
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_CHAFA //Image file, printed as ascii art using libchafa
} FFLogoType;
typedef struct FFconfig
{
const FFlogo* logo;
FFstrbuf logoSource;
FFLogoType logoType;
FFstrbuf logoColors[FASTFETCH_LOGO_MAX_COLORS];
uint32_t logoWidth;
uint32_t logoHeight;
uint32_t logoPaddingLeft;
uint32_t logoPaddingRight;
bool logoPrintRemaining;
uint16_t logoKeySpacing;
FFstrbuf mainColor; //If this is empty, ffPrintLogo will set it to the main color of the logo
FFstrbuf separator;
int16_t offsetx;
FFstrbuf color;
bool colorLogo;
bool showErrors;
bool recache;
bool cacheSave;
bool printRemainingLogo;
bool allowSlowOperations;
bool disableLinewrap;
bool hideCursor;
bool userLogoIsRaw;
FFstrbuf osFormat;
FFstrbuf osKey;
@@ -132,7 +137,11 @@ typedef struct FFconfig
FFstrbuf libDConf;
FFstrbuf libDBus;
FFstrbuf libXFConf;
FFstrbuf libSQLite3;
FFstrbuf librpm;
FFstrbuf libImageMagick;
FFstrbuf libZ;
FFstrbuf libChafa;
FFstrbuf diskFolders;
@@ -154,7 +163,8 @@ typedef struct FFconfig
typedef struct FFstate
{
uint32_t logoWidth;
char* logoLinesIndex;
uint32_t logoHeight;
uint32_t keysHeight;
struct passwd* passwd;
struct utsname utsname;
@@ -375,9 +385,9 @@ typedef enum FFInitState
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADRESS(library, ff ## symbolName, symbolName, returnValue);
/*************************/
/* Common util functions */
/*************************/
//////////////////////
// Common functions //
//////////////////////
//common/init.c
void ffInitInstance(FFinstance* instance);
@@ -390,37 +400,36 @@ void ffListFeatures();
void ffStartDetectionThreads(FFinstance* instance);
//common/io.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 ffGetCacheFilePath(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer);
void ffReadCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer);
void ffWriteCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* content);
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs);
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
void ffCacheValidate(FFinstance* instance);
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache);
void ffCacheClose(FFcache* cache);
void ffAppendFDContent(int fd, FFstrbuf* buffer);
bool ffAppendFileContent(const char* fileName, FFstrbuf* buffer); //returns true if open() succeeds. This is used to differentiate between <file not found> and <empty file>
bool ffGetFileContent(const char* fileName, FFstrbuf* buffer);
bool ffWriteFDContent(int fd, const FFstrbuf* content);
void ffWriteFileContent(const char* fileName, const FFstrbuf* buffer);
bool ffWriteFileContent(const char* fileName, const FFstrbuf* buffer);
bool ffFileExists(const char* fileName, mode_t mode);
void ffSuppressIO(bool suppress); // Not thread safe!
// Not thread safe!
void ffSuppressIO(bool suppress);
void ffGetTerminalResponse(const char* request, const char* format, ...);
//common/printing.c
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);
void ffPrintCharTimes(char c, uint32_t times);
// They return true if the file was found, independently if start was found
// Buffers which already contain content are not overwritten
// The last occurence of start in the first file will be the one used
// The *Values methods always return true, if all properties were already found before, without testing if the file exists
//common/caching.c
void ffCacheValidate(FFinstance* instance);
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache);
void ffCacheClose(FFcache* cache);
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs);
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintAndWriteToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
//common/properties.c
bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer);
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer);
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer);
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
@@ -428,6 +437,21 @@ bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, c
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer);
//common/font.c
void ffFontInitQt(FFfont* font, const char* data);
void ffFontInitPango(FFfont* font, const char* data);
void ffFontInitCopy(FFfont* font, const char* name);
void ffFontDestroy(FFfont* font);
//common/format.c
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
//common/parsing.c
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);
//common/processing.c
void ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]);
@@ -437,47 +461,38 @@ void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...);
//common/networking.c
void ffNetworkingGetHttp(const char* host, const char* path, uint32_t timeout, FFstrbuf* buffer);
//common/logo.c
void ffLoadLogoSet(FFinstance* instance, const char* logo);
void ffLoadLogo(FFinstance* instance);
void ffPrintLogoLine(FFinstance* instance);
void ffPrintRemainingLogo(FFinstance* instance);
void ffPrintLogos(FFinstance* instance);
void ffListLogos();
void ffListLogosForAutocompletion();
//common/format.c
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
//common/parsing.c
void ffGetGtkPretty(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
void ffFontInitQt(FFfont* font, const char* data);
void ffFontInitPango(FFfont* font, const char* data);
void ffFontInitCopy(FFfont* font, const char* name);
void ffFontDestroy(FFfont* font);
bool ffGetPropValue(const char* line, const char* start, FFstrbuf* buffer);
bool ffGetPropValueFromLines(const char* lines, const char* start, FFstrbuf* buffer);
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
bool ffStrSet(const char* str);
//common/settings.c
FFvariant ffSettingsGetDConf(FFinstance* instance, const char* key, FFvarianttype type);
FFvariant ffSettingsGetGSettings(FFinstance* instance, const char* schemaName, const char* path, const char* key, FFvarianttype type);
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
////////////////////
// Logo functions //
////////////////////
void ffPrintLogo(FFinstance* instance);
void ffPrintRemainingLogo(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();
/////////////////////////
// Detection functions //
/////////////////////////
//detection/os.c
const FFOSResult* ffDetectOS(FFinstance* instance);
const FFOSResult* ffDetectOS(const FFinstance* instance);
//detection/plasma.c
const FFPlasmaResult* ffDetectPlasma(FFinstance* instance);
@@ -502,9 +517,9 @@ const FFMediaResult* ffDetectMedia(FFinstance* instance);
//detection/dateTime.c
const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance);
/********************/
/* Module functions */
/********************/
//////////////////////
// Module functions //
//////////////////////
//Common
const FFTitleResult* ffDetectTitle(FFinstance* instance);
+4
View File
@@ -6,6 +6,10 @@
#define FASTFETCH_PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define FASTFETCH_PROJECT_VERSION_TWEAK "@PROJECT_VERSION_TWEAK@"
#define FASTFETCH_TARGET_DIR_ROOT "@TARGET_DIR_ROOT@"
#define FASTFETCH_TARGET_DIR_USR "@TARGET_DIR_USR@"
#define FASTFETCH_TARGET_DIR_HOME "@TARGET_DIR_HOME@"
#define FASTFETCH_DATATEXT_STRUCTURE "@DATATEXT_STRUCTURE@"
#define FASTFETCH_DATATEXT_CONFIG "@DATATEXT_CONFIG@" //Requires FASTFETCH_PROJECT_VERSION and FASTFETCH_DATATEXT_STRUCTURE to be set
#define FASTFETCH_DATATEXT_MODULES "@DATATEXT_MODULES@"
-3
View File
@@ -10,9 +10,6 @@ int main(int argc, char** argv)
//Modify instance.config here
ffLoadLogo(&instance); //ffLoadLogoSet(&instance, "my custom logo");
ffStrbufSet(&instance.config.color, &instance.config.logoColors[0]); //Use the primary color of the logo as key color
//Multithreading --> better performance
ffStartDetectionThreads(&instance);
+1660
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
#ifdef FF_HAVE_IMAGEMAGICK6
#include "image.h"
#include <magick/MagickCore.h>
static FF_LIBRARY_SYMBOL(ResizeImage);
static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo)
{
return ffResizeImage(image, width, height, UndefinedFilter, 1.0, exceptionInfo);
}
FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoRequestData* requestData)
{
FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-6.Q16HDRI.so", 8, "libMagickCore-6.Q16.so", 8)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR);
FFIMData imData;
imData.resizeFunc = logoResize;
imData.library = imageMagick;
FFLogoImageResult result = ffLogoPrintImageImpl(instance, requestData, &imData);
dlclose(imageMagick);
return result;
}
#endif
+29
View File
@@ -0,0 +1,29 @@
#ifdef FF_HAVE_IMAGEMAGICK7
#include "image.h"
#include <MagickCore/MagickCore.h>
static FF_LIBRARY_SYMBOL(ResizeImage);
static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo)
{
return ffResizeImage(image, width, height, UndefinedFilter, exceptionInfo);
}
FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoRequestData* requestData)
{
FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-7.Q16HDRI.so", 11, "libMagickCore-7.Q16.so", 11)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR);
FFIMData imData;
imData.resizeFunc = logoResize;
imData.library = imageMagick;
FFLogoImageResult result = ffLogoPrintImageImpl(instance, requestData, &imData);
dlclose(imageMagick);
return result;
}
#endif
+571
View File
@@ -0,0 +1,571 @@
#include "image.h"
#if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6)
#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>
static bool compressBlob(const FFinstance* instance, void** blob, size_t* length)
{
FF_LIBRARY_LOAD(zlib, instance->config.libZ, false, "libz.so", 2)
FF_LIBRARY_LOAD_SYMBOL(zlib, compressBound, false)
FF_LIBRARY_LOAD_SYMBOL(zlib, compress2, false)
uLong compressedLength = ffcompressBound(*length);
void* compressed = malloc(compressedLength);
if(compressed == NULL)
{
dlclose(zlib);
return false;
}
int compressResult = ffcompress2(compressed, &compressedLength, *blob, *length, Z_BEST_COMPRESSION);
dlclose(zlib);
if(compressResult != Z_OK)
{
free(compressed);
return false;
}
free(*blob);
*length = (size_t) compressedLength;
*blob = compressed;
return true;
}
#endif // FF_HAVE_ZLIB
//We use only the defines from here, that are exactly the same in both versions
#ifdef FF_HAVE_IMAGEMAGICK7
#include <MagickCore/MagickCore.h>
#else
#include <magick/MagickCore.h>
#endif
typedef struct ImageData
{
FF_LIBRARY_SYMBOL(CopyMagickString)
FF_LIBRARY_SYMBOL(ImageToBlob)
FF_LIBRARY_SYMBOL(Base64Encode)
ImageInfo* imageInfo;
Image* image;
ExceptionInfo* exceptionInfo;
} ImageData;
static inline bool checkAllocationResult(void* data, size_t length)
{
if(data == NULL)
return false;
if(length == 0)
{
free(data);
return false;
}
return true;
}
static inline uint32_t simpleCeil(double value)
{
uint32_t result = (uint32_t) value;
return value == (double) result ? result : result + 1;
}
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);
//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)
{
imageData->ffCopyMagickString(imageData->imageInfo->magick, "SIXEL", 6);
size_t length;
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
if(!checkAllocationResult(blob, length))
return false;
FFstrbuf result;
result.chars = (char*) blob;
result.length = (uint32_t) length;
printImagePixels(instance, requestData, &result, FF_CACHE_FILE_SIXEL);
free(blob);
return true;
}
static void appendKittyChunk(FFstrbuf* result, const char** blob, size_t* length, bool printEscapeCode)
{
uint32_t chunkSize = *length > FF_KITTY_MAX_CHUNK_SIZE ? FF_KITTY_MAX_CHUNK_SIZE : (uint32_t) *length;
if(printEscapeCode)
ffStrbufAppendS(result, "\033_G");
else
ffStrbufAppendC(result, ',');
ffStrbufAppendS(result, chunkSize != *length ? "m=1" : "m=0");
ffStrbufAppendC(result, ';');
ffStrbufAppendNS(result, chunkSize, *blob);
ffStrbufAppendS(result, "\033\\");
*length -= chunkSize;
*blob += chunkSize;
}
static bool printImageKitty(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
{
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;
#ifdef FF_HAVE_ZLIB
bool isCompressed = compressBlob(instance, &blob, &length);
#else
bool isCompressed = false;
#endif
char* chars = imageData->ffBase64Encode(blob, length, &length);
free(blob);
if(!checkAllocationResult(chars, length))
return false;
FFstrbuf result;
ffStrbufInitA(&result, (uint32_t) (length + 1024));
const char* currentPos = chars;
size_t remainingLength = length;
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);
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;
ffLogoPrint(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)
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL(imData->library, ReadImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
ImageData imageData;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffCopyMagickString, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffImageToBlob, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffBase64Encode, Base64Encode, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
imageData.exceptionInfo = ffAcquireExceptionInfo();
if(imageData.exceptionInfo == NULL)
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
ImageInfo* imageInfoIn = ffAcquireImageInfo();
if(imageInfoIn == NULL)
{
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
//+1, because we need to copy the null byte too
imageData.ffCopyMagickString(imageInfoIn->filename, instance->config.logoSource.chars, instance->config.logoSource.length + 1);
imageData.image = ffReadImage(imageInfoIn, imageData.exceptionInfo);
ffDestroyImageInfo(imageInfoIn);
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)
{
ffDestroyImage(imageData.image);
ffDestroyExceptionInfo(imageData.exceptionInfo);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
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 if(requestData->type == FF_LOGO_TYPE_SIXEL)
printSuccessful = printImageSixel(instance, requestData, &imageData);
ffDestroyImageInfo(imageData.imageInfo);
ffDestroyImage(imageData.image);
ffDestroyExceptionInfo(imageData.exceptionInfo);
return printSuccessful ? FF_LOGO_IMAGE_RESULT_SUCCESS : FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
static int getCacheFD(FFLogoRequestData* requestData, const char* fileName)
{
uint32_t cacheDirLength = requestData->cacheDir.length;
ffStrbufAppendS(&requestData->cacheDir, fileName);
int fd = open(requestData->cacheDir.chars, O_RDONLY);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
return fd;
}
static void readCachedStrbuf(FFLogoRequestData* requestData, FFstrbuf* result, const char* cacheFileName)
{
uint32_t cacheDirLength = requestData->cacheDir.length;
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
ffAppendFileContent(requestData->cacheDir.chars, result);
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
}
static uint32_t readCachedUint32(FFLogoRequestData* requestData, const char* cacheFileName)
{
FFstrbuf content;
ffStrbufInit(&content);
readCachedStrbuf(requestData, &content, cacheFileName);
uint32_t result = 0;
if(content.length != sizeof(result))
{
ffStrbufDestroy(&content);
return 0;
}
memcpy(&result, content.chars, sizeof(result));
ffStrbufDestroy(&content);
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;
}
ffLogoPrint(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 if(requestData->type == FF_LOGO_TYPE_SIXEL)
fd = getCacheFD(requestData, FF_CACHE_FILE_SIXEL);
if(fd == -1)
return false;
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
fflush(stdout);
char buffer[32768];
ssize_t readBytes;
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
FF_UNUSED(write(STDOUT_FILENO, buffer, (size_t) readBytes));
close(fd);
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 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));
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
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_row == 0 || winsize.ws_col == 0)
return false;
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;
}
FFLogoImageResult ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
{
//Performance optimisation
#ifndef FF_HAVE_CHAFA
if(type == FF_LOGO_TYPE_CHAFA)
return FF_LOGO_IMAGE_RESULT_INIT_ERROR;
#endif
FFLogoRequestData requestData;
requestData.type = type;
requestData.characterPixelWidth = 1;
requestData.characterPixelHeight = 1;
if(
(type != FF_LOGO_TYPE_CHAFA || instance->config.logoWidth == 0 || instance->config.logoHeight == 0) &&
!getCharacterPixelDimensions(&requestData)
)
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
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");
ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX);
if(realpath(instance->config.logoSource.chars, requestData.cacheDir.chars + requestData.cacheDir.length) == NULL)
{
//We can safely return here, because if realpath failed, we surely won't be able to read the file
ffStrbufDestroy(&requestData.cacheDir);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
ffStrbufRecalculateLength(&requestData.cacheDir);
if(!ffStrbufEndsWithC(&requestData.cacheDir, '/'))
ffStrbufAppendC(&requestData.cacheDir, '/');
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))
{
ffStrbufDestroy(&requestData.cacheDir);
return FF_LOGO_IMAGE_RESULT_SUCCESS;
}
FFLogoImageResult result = FF_LOGO_IMAGE_RESULT_INIT_ERROR;
#ifdef FF_HAVE_IMAGEMAGICK7
result = ffLogoPrintImageIM7(instance, &requestData);
#endif
#ifdef FF_HAVE_IMAGEMAGICK6
if(result == FF_LOGO_IMAGE_RESULT_INIT_ERROR)
result = ffLogoPrintImageIM6(instance, &requestData);
#endif
ffStrbufDestroy(&requestData.cacheDir);
return result;
}
#else //FF_HAVE_IMAGEMAGICK{6, 7}
FFLogoImageResult ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
{
FF_UNUSED(instance, type);
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
}
#endif //FF_HAVE_IMAGEMAGICK{6, 7}
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#ifndef FF_INCLUDED_LOGO_SIXEL_sixel
#define FF_INCLUDED_LOGO_SIXEL_sixel
#include "../logo.h"
#if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6)
#define MAGICKCORE_HDRI_ENABLE 1
#define MAGICKCORE_QUANTUM_DEPTH 16
typedef struct FFLogoRequestData
{
FFLogoType type;
FFstrbuf cacheDir;
double characterPixelWidth;
double characterPixelHeight;
uint32_t logoPixelWidth;
uint32_t logoPixelHeight;
uint32_t logoCharacterHeight;
uint32_t logoCharacterWidth;
} FFLogoRequestData;
typedef struct FFIMData
{
void* library;
void*(*resizeFunc)(const void* image, size_t width, size_t height, void* exceptionInfo);
} FFIMData;
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData);
#endif
#ifdef FF_HAVE_IMAGEMAGICK7
FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoRequestData* requestData);
#endif
#ifdef FF_HAVE_IMAGEMAGICK6
#include <math.h>
FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoRequestData* requestData);
#endif
#endif
+281
View File
@@ -0,0 +1,281 @@
#include "logo.h"
#include <ctype.h>
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement)
{
uint32_t currentlineLength = 0;
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
//Use logoColor[0] as the default color
if(doColorReplacement)
ffPrintColor(&instance->config.logoColors[0]);
while(*data != '\0')
{
//We are at the end of a line. Print paddings and update max line length
if(*data == '\n' || (*data == '\r' && *(data + 1) == '\n'))
{
ffPrintCharTimes(' ', instance->config.logoPaddingRight);
//We have \r\n, skip the \r
if(*data == '\r')
++data;
putchar('\n');
++data;
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
if(currentlineLength > instance->state.logoWidth)
instance->state.logoWidth = currentlineLength;
currentlineLength = 0;
++instance->state.logoHeight;
continue;
}
//Always print tabs as 4 spaces, to have consistent spacing
if(*data == '\t')
{
ffPrintCharTimes(' ', 4);
++data;
continue;
}
//We have an escape sequence direclty as bytes. We print it, but don't increase the line length
if(*data == '\033' && *(data + 1) == '[')
{
const char* start = data;
fputs("\033[", stdout);
data += 2;
while(isdigit(*data) || *data == ';')
putchar(*data++); // number
//We have a valid control sequence, print it and continue with next char
if(isascii(*data))
{
putchar(*data++); // single letter, end of control sequence
continue;
}
//Invalid control sequence, try to get most accurate length
currentlineLength += (uint32_t) (data - start - 1); //-1 for \033 which for sure doesn't take any space
//Don't continue here, print the char after the letters with the unicode printing
}
//We have a fastfetch color placeholder. Replace it with the esacape sequence, don't increase the line length
if(doColorReplacement && *data == '$')
{
++data;
//If we have $$, or $\0, print it as single $
if(*data == '$' || *data == '\0')
{
putchar('$');
++currentlineLength;
++data;
continue;
}
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
int index = ((int) *data) - 49;
//If the index is valid, print the color. Otherwise continue as normal
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
{
putchar('$');
++currentlineLength;
//Don't continue here, we want to print the current char as unicode
}
else
{
ffPrintColor(&instance->config.logoColors[index]);
++data;
continue;
}
}
//Do the printing, respecting unicode
++currentlineLength;
int codepoint = (unsigned char) *data;
uint8_t bytes;
if(codepoint <= 127)
bytes = 1;
else if((codepoint & 0xE0) == 0xC0)
bytes = 2;
else if((codepoint & 0xF0) == 0xE0)
bytes = 3;
else if((codepoint & 0xF8) == 0xF0)
bytes = 4;
else
bytes = 1; //Invalid utf8, print it as is, byte by byte
for(uint8_t i = 0; i < bytes; ++i)
{
if(*data == '\0')
break;
putchar(*data++);
}
}
ffPrintCharTimes(' ', instance->config.logoPaddingRight);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
//Happens if the last line is the longest
if(currentlineLength > instance->state.logoWidth)
instance->state.logoWidth = currentlineLength;
instance->state.logoWidth += instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
//Go to the leftmost position
fputs("\033[9999999D", stdout);
//If the logo height is > 1, go up the height
if(instance->state.logoHeight > 0)
printf("\033[%uA", instance->state.logoHeight);
}
static void logoPrintFile(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 no logo source is given, detect the logo from OS and print the right builtin one
if(instance->config.logoSource.length == 0)
{
ffLogoPrintBuiltinDetected(instance);
return;
}
//If a logo source is given, first look if it is the name of a builtin logo
if(ffLogoPrintBuiltinIfExists(instance))
return;
const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(instance);
FFLogoImageResult imageResult = FF_LOGO_IMAGE_RESULT_INIT_ERROR;
//Terminals that are known to support kitty graphics protocol
//Try to load the logo as image.
if(
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wezterm") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0
) {
imageResult = ffLogoPrintImageIfExists(instance, FF_LOGO_TYPE_KITTY);
if(imageResult == FF_LOGO_IMAGE_RESULT_SUCCESS)
return;
}
//If the logo can be loaded as an image, convert it to ascii art.
//This happens in all terminals, that don't support kitty graphics protocol
if(
imageResult != FF_LOGO_IMAGE_RESULT_RUN_ERROR &&
ffLogoPrintImageIfExists(instance, FF_LOGO_TYPE_CHAFA) == FF_LOGO_IMAGE_RESULT_SUCCESS
) return;
//Print the content of the file as logo
logoPrintFile(instance, true);
}
void ffPrintLogo(FFinstance* instance)
{
if(instance->config.mainColor.length == 0)
ffLogoSetMainColor(instance);
if( //Logo type needs set logo name, but nothing was given. Print question mark
instance->config.logoType != FF_LOGO_TYPE_AUTO &&
instance->config.logoSource.length == 0
)
ffLogoPrintUnknown(instance);
else if(instance->config.logoType == FF_LOGO_TYPE_BUILTIN)
{
if(!ffLogoPrintBuiltinIfExists(instance))
ffLogoPrintUnknown(instance);
}
else if(instance->config.logoType == FF_LOGO_TYPE_FILE)
logoPrintFile(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 || instance->config.logoType == FF_LOGO_TYPE_CHAFA)
{
if(ffLogoPrintImageIfExists(instance, instance->config.logoType) != FF_LOGO_IMAGE_RESULT_SUCCESS)
ffLogoPrintBuiltinDetected(instance);
}
else
logoPrintDetected(instance);
}
static inline void printLogoWidth(const FFinstance* instance)
{
if(instance->state.logoWidth > 0)
printf("\033[%uC", instance->state.logoWidth);
}
void ffPrintRemainingLogo(FFinstance* instance)
{
if(!instance->config.logoPrintRemaining)
return;
for(uint32_t i = instance->state.keysHeight; i <= instance->state.logoHeight; i++)
{
printLogoWidth(instance);
putchar('\n');
}
}
void ffPrintLogoLine(FFinstance* instance)
{
printLogoWidth(instance);
++instance->state.keysHeight;
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
{
ffPrintLogoLine(instance);
fputs(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);
}
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
ffStrbufWriteTo(&instance->config.separator, stdout);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#ifndef FASTFETCH_INCLUDED_LOGO_logo
#define FASTFETCH_INCLUDED_LOGO_logo
#include "fastfetch.h"
//logo.c
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement);
//builtin.c
void ffLogoSetMainColor(FFinstance* instance);
void ffLogoPrintUnknown(FFinstance* instance);
bool ffLogoPrintBuiltinIfExists(FFinstance* instance);
void ffLogoPrintBuiltinDetected(FFinstance* instance);
typedef enum FFLogoImageResult
{
FF_LOGO_IMAGE_RESULT_SUCCESS, //Logo printed
FF_LOGO_IMAGE_RESULT_INIT_ERROR, //Failed to load library, try again with next IM version
FF_LOGO_IMAGE_RESULT_RUN_ERROR //Failed to load / convert image, cancle whole sixel code
} FFLogoImageResult;
//image/image.c
FFLogoImageResult ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type);
#endif
+7 -7
View File
@@ -42,7 +42,7 @@ void ffPrintCPU(FFinstance* instance)
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(\"/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;
}
@@ -68,11 +68,11 @@ void ffPrintCPU(FFinstance* instance)
break;
(void)(
ffGetPropValue(line, "model name :", &name) ||
ffGetPropValue(line, "vendor_id :", &vendor) ||
ffGetPropValue(line, "cpu cores :", &physicalCoresString) ||
ffGetPropValue(line, "cpu MHz :", &procGhzString) ||
(name.length == 0 && ffGetPropValue(line, "Hardware :", &name)) //For Android devices
ffParsePropLine(line, "model name :", &name) ||
ffParsePropLine(line, "vendor_id :", &vendor) ||
ffParsePropLine(line, "cpu cores :", &physicalCoresString) ||
ffParsePropLine(line, "cpu MHz :", &procGhzString) ||
(name.length == 0 && ffParsePropLine(line, "Hardware :", &name)) //For Android devices
);
}
@@ -164,7 +164,7 @@ void ffPrintCPU(FFinstance* instance)
if(ghz > 0)
ffStrbufAppendF(&cpu, " @ %.9gGHz", ghz);
ffPrintAndSaveToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpuKey, &cpu, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){
ffPrintAndWriteToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpuKey, &cpu, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &name},
{FF_FORMAT_ARG_TYPE_STRBUF, &namePretty},
{FF_FORMAT_ARG_TYPE_STRBUF, &vendor},
+1 -1
View File
@@ -12,7 +12,7 @@ void ffPrintCPUUsage(FFinstance* instance)
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(\"/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;
+1 -1
View File
@@ -147,7 +147,7 @@ static bool printCursorFromXDG(FFinstance* instance, bool user)
if(user)
ffParsePropFileHome(instance, ".icons/default/index.theme", "Inherits =", &theme);
else
ffParsePropFile("/usr/share/icons/default/index.theme", "Inherits =", &theme);
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/icons/default/index.theme", "Inherits =", &theme);
if(theme.length == 0)
{
+3 -4
View File
@@ -79,18 +79,17 @@ void ffPrintDisk(FFinstance* instance)
{
if(instance->config.diskFolders.length == 0)
{
struct statvfs fsRoot;
int rootRet = statvfs("/", &fsRoot);
struct statvfs fsHome;
int homeRet = statvfs("/home", &fsHome);
int homeRet = statvfs(FASTFETCH_TARGET_DIR_HOME, &fsHome);
if(rootRet != 0 && homeRet != 0)
{
FF_STRBUF_CREATE(key);
getKey(instance, &key, "", false);
ffPrintError(instance, key.chars, 0, NULL, &instance->config.diskFormat, FF_DISK_NUM_FORMAT_ARGS, "statvfs failed for both / and /home");
ffPrintError(instance, key.chars, 0, NULL, &instance->config.diskFormat, FF_DISK_NUM_FORMAT_ARGS, "statvfs failed for both / and " FASTFETCH_TARGET_DIR_HOME);
ffStrbufDestroy(&key);
return;
}
@@ -99,7 +98,7 @@ void ffPrintDisk(FFinstance* instance)
printStatvfsCreateKey(instance, "/", &fsRoot);
if(homeRet == 0 && (rootRet != 0 || fsRoot.f_fsid != fsHome.f_fsid))
printStatvfsCreateKey(instance, "/home", &fsHome);
printStatvfsCreateKey(instance, FASTFETCH_TARGET_DIR_HOME, &fsHome);
}
else
{
+1 -1
View File
@@ -43,7 +43,7 @@ void ffPrintFont(FFinstance* instance)
FFstrbuf gtk;
ffStrbufInitA(&gtk, 64);
ffGetGtkPretty(&gtk, &gtk2.pretty, &gtk3.pretty, &gtk4.pretty);
ffParseGTK(&gtk, &gtk2.pretty, &gtk3.pretty, &gtk4.pretty);
if(instance->config.fontFormat.length == 0)
{
+2 -2
View File
@@ -17,7 +17,7 @@ typedef struct GPUResult
static void vulkanFillGPUs(FFinstance* instance, FFlist* results)
{
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", "libvulkan.so.1")
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,)
@@ -133,7 +133,7 @@ static void pciGetDriver(struct pci_dev* dev, FFstrbuf* driver, char*(*ffpci_get
static void pciFillGPUs(FFinstance* instance, FFlist* results)
{
FF_LIBRARY_LOAD(pci, instance->config.libPCI, , "libpci.so", "libpci.so.3")
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,)
+1 -1
View File
@@ -119,7 +119,7 @@ void ffPrintHost(FFinstance* instance)
ffStrbufAppend(&host, &version);
}
ffPrintAndSaveToCache(instance, FF_HOST_MODULE_NAME, &instance->config.hostKey, &host, &instance->config.hostFormat, FF_HOST_NUM_FORMAT_ARGS, (FFformatarg[]) {
ffPrintAndWriteToCache(instance, FF_HOST_MODULE_NAME, &instance->config.hostKey, &host, &instance->config.hostFormat, FF_HOST_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &family},
{FF_FORMAT_ARG_TYPE_STRBUF, &name},
{FF_FORMAT_ARG_TYPE_STRBUF, &version}
+1 -1
View File
@@ -30,7 +30,7 @@ void ffPrintIcons(FFinstance* instance)
}
FF_STRBUF_CREATE(gtkPretty);
ffGetGtkPretty(&gtkPretty, gtk2, gtk3, gtk4);
ffParseGTK(&gtkPretty, gtk2, gtk3, gtk4);
if(instance->config.iconsFormat.length == 0)
{
+2 -2
View File
@@ -28,7 +28,7 @@ void ffPrintLocale(FFinstance* instance)
FFstrbuf locale;
ffStrbufInit(&locale);
ffParsePropFile("/etc/locale.conf", "LANG =", &locale);
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/locale.conf", "LANG =", &locale);
if (locale.length == 0)
getLocaleFromEnv(&locale);
@@ -39,7 +39,7 @@ void ffPrintLocale(FFinstance* instance)
return;
}
ffPrintAndSaveToCache(instance, FF_LOCALE_MODULE_NAME, &instance->config.localeKey, &locale, &instance->config.localeFormat, FF_LOCALE_NUM_FORMAT_ARGS, (FFformatarg[]){
ffPrintAndWriteToCache(instance, FF_LOCALE_MODULE_NAME, &instance->config.localeKey, &locale, &instance->config.localeFormat, FF_LOCALE_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &locale}
});
+1 -1
View File
@@ -8,7 +8,7 @@ void ffPrintMemory(FFinstance* instance)
{
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(\"/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;
}
+1 -1
View File
@@ -69,7 +69,7 @@ void ffPrintOS(FFinstance* instance)
ffStrbufAppendC(&os, ']');
}
ffPrintAndSaveToCache(instance, FF_OS_MODULE_NAME, &instance->config.osKey, &os, &instance->config.osFormat, FF_OS_NUM_FORMAT_ARGS, (FFformatarg[]){
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},
+124 -31
View File
@@ -12,9 +12,9 @@
#include <rpm/rpmdb.h>
#include <rpm/rpmlog.h>
static uint32_t getRpmPackageCount(FFinstance* instance)
static uint32_t getRpmFromLibrpm(const FFinstance* instance)
{
FF_LIBRARY_LOAD(rpm, instance->config.librpm, 0, "librpm.so", "librpm.so.4")
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)
@@ -26,20 +26,34 @@ static uint32_t getRpmPackageCount(FFinstance* instance)
// 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) != 0)
{
dlclose(rpm);
return 0;
}
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);
rpmts ts = ffrpmtsCreate();
if(ts == NULL)
{
dlclose(rpm);
return 0;
}
exit:
if (mi) ffrpmdbFreeIterator(mi);
if (ts) ffrpmtsFree(ts);
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;
return count > 0 ? (uint32_t) count : 0;
}
#endif
@@ -136,31 +150,96 @@ static uint32_t countFilesIn(const char* dirname, const char* filename)
return result;
}
static uint32_t getNixPackages(const FFstrbuf* path)
{
FFstrbuf output;
ffStrbufInitA(&output, 128);
ffProcessAppendStdOut(&output, (char* const[]) {
"nix-store",
"-qR",
path->chars,
NULL
});
//Each package is a new line in the output. If at least one line is found, add 1 for the last line.
uint32_t result = ffStrbufCountC(&output, '\n');
if(result > 0)
result++;
ffStrbufDestroy(&output);
return result;
}
static uint32_t getNixPackagesDefault()
{
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;
}
static uint32_t getNixPackagesUser(const FFinstance* instance)
{
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;
}
static uint32_t getRpmPackageCount(const FFinstance* instance)
{
// We do our own sql querys instead of using (lib)rpm, because:
// - simply faster
// - we don't need to regulary increase librpm version, which increases rapidly without providing a major version symlink
uint32_t rpm = (uint32_t) ffSettingsGetSQLite3Int(instance, FASTFETCH_TARGET_DIR_ROOT"/var/lib/rpm/rpmdb.sqlite", "SELECT count(blob) FROM Packages");
if(rpm != 0)
return rpm;
rpm = (uint32_t) ffSettingsGetSQLite3Int(instance, FASTFETCH_TARGET_DIR_ROOT"/var/cache/dnf/packages.db", "SELECT count(pkg) FROM installed");
if(rpm != 0)
return rpm;
// If SQL failed, we can still try with rpm.
// This is needed on openSUSE, which seems to use a proprietary database file
#ifdef FF_HAVE_RPM
return getRpmFromLibrpm(instance);
#endif
return 0;
}
void ffPrintPackages(FFinstance* instance)
{
uint32_t pacman = getNumElements("/var/lib/pacman/local", DT_DIR);
uint32_t dpkg = getNumStrings("/var/lib/dpkg/status", "Status: ");
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: ");
uint32_t rpm = getRpmPackageCount(instance);
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);
#if __ANDROID__
dpkg += getNumStrings("/data/data/com.termux/files/usr/var/lib/dpkg/status", "Status: ");
#endif
uint32_t nixUser = 0;
uint32_t nixDefault = 0;
#ifdef FF_HAVE_RPM
uint32_t rpm = getRpmPackageCount(instance);
#else
uint32_t rpm = 0;
#endif
//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 emerge = countFilesIn("/var/db/pkg", "SIZE");
uint32_t xbps = getNumElements("/var/db/xbps", DT_REG);
uint32_t flatpak = getNumElements("/var/lib/flatpak/app", DT_DIR);
uint32_t snap = getNumElements("/snap", DT_DIR);
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 + flatpak + snap;
uint32_t all = pacman + dpkg + rpm + emerge + xbps + nixUser + nixDefault + flatpak + snap;
if(all == 0)
{
@@ -170,12 +249,12 @@ void ffPrintPackages(FFinstance* instance)
FFstrbuf manjaroBranch;
ffStrbufInit(&manjaroBranch);
if(ffParsePropFile("/etc/pacman-mirrors.conf", "Branch =", &manjaroBranch) && manjaroBranch.length == 0)
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.batteryKey);
ffPrintLogoAndKey(instance, FF_PACKAGES_MODULE_NAME, 0, &instance->config.packagesKey);
#define FF_PRINT_PACKAGE(name) \
if(name > 0) \
@@ -197,7 +276,21 @@ void ffPrintPackages(FFinstance* instance)
FF_PRINT_PACKAGE(dpkg)
FF_PRINT_PACKAGE(rpm)
FF_PRINT_PACKAGE(emerge)
FF_PRINT_PACKAGE(xbps)
if(nixUser > 0)
{
printf("%u (nix-user)", nixUser);
if((all = all - nixUser) > 0)
printf(", ");
}
if(nixDefault > 0)
{
printf("%u (nix-default)", nixDefault);
if((all = all - nixDefault) > 0)
printf(", ");
}
FF_PRINT_PACKAGE(flatpak)
FF_PRINT_PACKAGE(snap)
+1 -1
View File
@@ -184,7 +184,7 @@ static void printTTY(FFinstance* instance)
FFstrbuf fontName;
ffStrbufInit(&fontName);
ffParsePropFile("/etc/vconsole.conf", "Font =", &fontName);
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/vconsole.conf", "Font =", &fontName);
if(fontName.length == 0)
{
+1 -1
View File
@@ -38,7 +38,7 @@ void ffPrintTheme(FFinstance* instance)
ffStrbufTrim(&plasmaColorPretty, ' ');
FF_STRBUF_CREATE(gtkPretty);
ffGetGtkPretty(&gtkPretty, gtk2, gtk3, gtk4);
ffParseGTK(&gtkPretty, gtk2, gtk3, gtk4);
if(instance->config.themeFormat.length == 0)
{
+1 -1
View File
@@ -31,7 +31,7 @@ const FFTitleResult* ffDetectTitle(FFinstance* instance)
static inline void printTitlePart(FFinstance* instance, const FFstrbuf* content)
{
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.color);
ffPrintColor(&instance->config.mainColor);
ffStrbufWriteTo(content, stdout);
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
+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
{
+11
View File
@@ -495,6 +495,17 @@ bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end)
return true;
}
uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c)
{
uint32_t result = 0;
for(uint32_t i = 0; i < strbuf->length; i++)
{
if(strbuf->chars[i] == c)
result++;
}
return result;
}
static bool testEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end, uint32_t* endLength)
{
*endLength = (uint32_t) strlen(end);
+2
View File
@@ -87,6 +87,8 @@ bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start);
bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c);
bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end);
uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end);
void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file);
+10 -6
View File
@@ -25,12 +25,6 @@ int main(int argc, char** argv)
ffInitInstance(&instance);
)
FASTFETCH_TEST_PERFORMANCE(
puts("Configuration");
ffLoadLogo(&instance);
)
ffStrbufSet(&instance.config.color, &instance.config.logoColors[0]);
instance.config.showErrors = true;
instance.config.recache = argc == 1;
instance.config.cacheSave = false;
@@ -41,6 +35,11 @@ int main(int argc, char** argv)
ffStartDetectionThreads(&instance);
)
FASTFETCH_TEST_PERFORMANCE(
puts("Starting");
ffStart(&instance);
)
FASTFETCH_TEST_PERFORMANCE(ffPrintTitle(&instance))
FASTFETCH_TEST_PERFORMANCE(ffPrintSeparator(&instance))
FASTFETCH_TEST_PERFORMANCE(ffPrintOS(&instance))
@@ -74,5 +73,10 @@ int main(int argc, char** argv)
FASTFETCH_TEST_PERFORMANCE(ffPrintBreak(&instance))
FASTFETCH_TEST_PERFORMANCE(ffPrintColors(&instance))
FASTFETCH_TEST_PERFORMANCE(
puts("Finishing");
ffFinish(&instance);
)
return 0;
}