Compare commits

..

941 Commits

Author SHA1 Message Date
Linus Dierheimer 8404ae8e70 Merge pull request #212 from ceamac/bugs/install-presets
Fix installation of presets/ directory
2022-08-12 21:50:49 +02:00
Viorel d75f72c8fe Fix installation of presets/ directory 2022-08-12 22:35:31 +03:00
Linus Dierheimer 9fa00081e3 Release 1.6.2 2022-08-12 16:01:52 +02:00
Linus Dierheimer fca37b59c8 Print xbps package count once again
#209
2022-08-12 09:40:02 +02:00
Linus Dierheimer 2fe7476c67 Better xbps package count
#209
2022-08-07 19:42:16 +02:00
Linus Dierheimer 03cbd64d8a Merge pull request #208 from hervyqa/langitketujuh
Add LangitKetujuh Linux logo
2022-08-03 13:03:06 +02:00
Hervy Qurrotul Ainur Rozi f65aeed96f Add LangitKetujuh Linux logo 2022-08-03 16:46:14 +07:00
Linus Dierheimer b63f419cde Merge pull request #207 from draumaz/master
Add KISS Linux logo
2022-08-02 15:14:41 +02:00
draumaz 99aa2f7b45 swap order 2022-08-02 12:29:44 +00:00
draumaz b251c32c12 fix colors, update README 2022-08-02 12:24:15 +00:00
draumaz 034e23d7e3 Merge branch 'LinusDierheimer:master' into master 2022-08-02 05:13:30 -07:00
Linus Dierheimer bba912d42e Add missing include 2022-08-02 10:24:54 +02:00
draumaz 597652c35a one more backslash 2022-08-02 05:56:20 +00:00
draumaz 7f67846ad9 add KISS Linux logo 2022-08-02 05:51:15 +00:00
Linus Dierheimer bc2e292e22 Update issue templates 2022-07-31 17:44:07 +02:00
Linus Dierheimer 75dc228120 Update issue templates 2022-07-31 17:39:54 +02:00
Linus Dierheimer bc783f6efd Update issue templates 2022-07-31 17:33:03 +02:00
Linus Dierheimer 85e1d2b40c Add logo request template 2022-07-31 17:31:30 +02:00
Linus Dierheimer 3338189354 Rosa Linux logo 2022-07-31 17:22:03 +02:00
Linus Dierheimer d4c836fd25 Handle empty xdg env vars better 2022-07-30 23:30:46 +02:00
Linus Dierheimer 6787f1eba8 Merge branches 'master' and 'master' of github.com:LinusDierheimer/fastfetch 2022-07-27 21:56:42 +02:00
Linus Dierheimer eedc277bcf Respect target dir config during installation 2022-07-27 21:56:28 +02:00
Linus Dierheimer d4b32eaaec Merge pull request #205 from licy183/fix-android-header
Fix build error on Android
2022-07-27 19:31:29 +02:00
Linus Dierheimer 910f63f0ad Update changelog 2022-07-27 19:31:14 +02:00
Linus Dierheimer 9a0aa2ac72 Fix compilation issues
1) when building for android
2) when building without wayland
2022-07-27 19:28:55 +02:00
Chongyun Lee dce81055fe Release 1.6.1 2022-07-28 01:28:17 +08:00
Chongyun Lee 66a4fc1600 Fix build error on Android
host.c has an #elif, but actually #else is needed.
2022-07-27 22:50:11 +08:00
Linus Dierheimer 159a114bb7 Release 1.6.0
tag correctly
2022-07-26 22:38:40 +02:00
Linus Dierheimer ac08b46e71 Release 1.6.0
this time with correct packaging the second
2022-07-26 22:27:13 +02:00
Linus Dierheimer ceb92dafd7 Release 1.6.0
this time with correct packaging
2022-07-26 22:13:09 +02:00
Linus Dierheimer 31eeb6dd08 Release 1.6.0 2022-07-26 20:35:15 +02:00
Linus Dierheimer c021689a2b Better nix package sorting
#195
2022-07-26 19:15:00 +02:00
Linus Dierheimer 2ac2762c9f Print nix-default packages
#195
2022-07-26 19:03:15 +02:00
Linus Dierheimer 27dd097671 Improved Nix package detection
#195
2022-07-26 18:36:10 +02:00
Linus Dierheimer c7bf471e29 Refactor: move vulkan detection to own header 2022-07-26 18:18:14 +02:00
Linus Dierheimer 298bc10e5f Refactor: move media detection to own header 2022-07-26 18:15:45 +02:00
Linus Dierheimer 676485ef74 Refactor: move temps detection to own header 2022-07-26 18:13:12 +02:00
Linus Dierheimer fb6da20b0c Refactor: move date/time detection to own header 2022-07-26 18:09:25 +02:00
Linus Dierheimer 0c81d3e894 Refactor: move terminal/shell detection to own header 2022-07-26 18:06:30 +02:00
Linus Dierheimer 5c1aa20042 Refactor: move wm/de detection to own header 2022-07-26 17:56:42 +02:00
Linus Dierheimer 46a27c4e39 Refactor: move gtk detection to own header 2022-07-26 17:47:08 +02:00
Linus Dierheimer 128302596e Refactor: move qt detection to own header 2022-07-26 17:42:28 +02:00
Linus Dierheimer 7a15dee2be Refactor: move os detection to own header 2022-07-26 17:33:51 +02:00
Linus Dierheimer 000bd37f1d Refactor: move title detection to own header 2022-07-26 17:29:09 +02:00
Linus Dierheimer 707e0f930d Refactor: don't include FFvaluestore global 2022-07-25 19:54:33 +02:00
Linus Dierheimer 7676a313c5 Refactor: move threading functions to init 2022-07-25 15:01:11 +02:00
Linus Dierheimer 6e0d76a2fb Refactor: move networking functions to own header 2022-07-25 14:48:59 +02:00
Linus Dierheimer 4c7b7e4a4d Refactor: move processing functions to own header 2022-07-25 14:45:41 +02:00
Linus Dierheimer 4d34091573 Refactor: move format functions to own header 2022-07-25 14:26:08 +02:00
Linus Dierheimer c971e28aca Refactor: move setting functions to own header 2022-07-25 14:20:07 +02:00
Linus Dierheimer c41a29a5c1 Refactor: move parsing functions to own header 2022-07-25 13:59:19 +02:00
Linus Dierheimer 5c73125693 Refactor: move font functions to own header 2022-07-25 13:44:55 +02:00
Linus Dierheimer cea48474a1 Refactor: move caching functions to own header 2022-07-25 13:36:58 +02:00
Linus Dierheimer 536f914f3e Refactor: move printing functions to own header 2022-07-25 13:15:01 +02:00
Linus Dierheimer 778856dd57 Refactor: move property functions to own header 2022-07-25 12:24:23 +02:00
Linus Dierheimer 4a43144991 Refactor: move io functions to own header 2022-07-25 11:48:48 +02:00
Linus Dierheimer ac96cfc748 Refactor: move FFInitState to settings.c 2022-07-25 11:24:50 +02:00
Linus Dierheimer f18ffe3239 Refactor: move library functions and macros to own header 2022-07-25 11:20:38 +02:00
Linus Dierheimer 986bbeebb3 Don't segfault if invalid structure is given
#204
2022-07-25 11:00:41 +02:00
Linus Dierheimer b9d360af97 --title-fqdn option
#203
2022-07-22 19:36:00 +02:00
Linus Dierheimer ec1981c545 Use [QT] instead of [Plasma]
#198 #199
2022-07-22 17:18:36 +02:00
Linus Dierheimer f7e7d8e9f2 Update README.md 2022-07-22 13:42:26 +02:00
Linus Dierheimer ad9fc5845a GTK: Fix detection on XFCE DE
#198 #199
2022-07-22 12:23:35 +02:00
Linus Dierheimer a6b169f3e2 Disk: Print one decimal point if < 100GiB
#202
2022-07-22 11:47:20 +02:00
Linus Dierheimer 8aff9939bc GTK: prefer dconf over config files on certain DEs
#198 #199
2022-07-22 11:24:29 +02:00
Linus Dierheimer 0b8f51188b gh actions: configure correct path for packaging
the follow up
2022-07-21 22:58:38 +02:00
Linus Dierheimer 3c99a82619 gh actions: configure correct path for packaging 2022-07-21 22:55:47 +02:00
Linus Dierheimer d5f3ff1cfe Update README.md 2022-07-21 20:20:40 +02:00
Linus Dierheimer 011c033091 Update README.md 2022-07-21 20:18:34 +02:00
Linus Dierheimer 63bf22fb00 Load system config
#196
2022-07-21 14:37:13 +02:00
Linus Dierheimer f74973db65 Special NixOS OS output
#194
2022-07-21 11:33:19 +02:00
Linus Dierheimer 85656fd515 Fix Mutter detection
#200
2022-07-20 21:32:17 +02:00
Linus Dierheimer 23bf7a407b Fix alacritty term font size
#197
2022-07-20 20:56:02 +02:00
Linus Dierheimer e570cacbc9 Fix typos
#201
2022-07-20 20:44:16 +02:00
Linus Dierheimer a96f79795b Merge pull request #193 from Izorkin/update-nixos-logo
Update old nixos logo
2022-07-19 12:09:25 +02:00
Izorkin 2d51d935c8 update old nixos logo 2022-07-19 12:57:15 +03:00
Linus Dierheimer 9d395f7235 don't print GPU in WSL 2022-07-17 16:11:08 +02:00
Linus Dierheimer 5f16394916 Add alacritty to readme 2022-07-12 16:49:39 +02:00
Linus Dierheimer 6581c9d378 Merge pull request #191 from x-zvf/alacritty-term-support
[enhancement] Add best effort terminal font detection for alacritty.
2022-07-12 16:46:22 +02:00
Péter Bohner (xzvf) 67ac7eef59 buxfix: missing fontSize/fontName would overwrite the other 2022-07-12 16:43:21 +02:00
Péter Bohner (xzvf) b95e83e9e5 Use ffStrbufAppend instead of ffStrbugInitCopy 2022-07-12 16:41:20 +02:00
Péter Bohner (xzvf) e9d9b942fa Cleanup diff 2022-07-12 16:34:35 +02:00
Péter Bohner (xzvf) c95ad74ea2 Refactor to use ffFontInitCopy and detect font size
printAlacritty now usese ffFontInitCopy instead of ffFontInitPango
and also detects font size.
2022-07-12 16:31:19 +02:00
Péter Bohner (xzvf) 85b0be5213 Add best effort terminal font detection for alacritty.
Alacritty's config files are technically YML files, so
simply looking for a prop value "family:" may break some of the time,
but is in fact better than what neofetch does and much easier
to implement then writing a YML parser :)
2022-07-12 14:38:06 +02:00
Linus Dierheimer da671d6cfe Start cleaning up of config struct 2022-07-10 18:28:17 +02:00
Linus Dierheimer 18af9ab902 Wayland: don't destroy proxies our self 2022-07-08 11:48:43 +02:00
Linus Dierheimer 558fbc20e2 Don't detect guake-wrapped as terminal 2022-07-08 11:24:11 +02:00
Linus Dierheimer d9bbbd4fa8 Merge pull request #189 from x-zvf/alacritty-term-support
Fix memory leak in ffParsePropFileValues
2022-07-08 10:46:11 +02:00
Péter Bohner (xzvf) 292a809703 ffParsePropValues: Hoisted fopen call to simplify error handling 2022-07-08 09:09:59 +02:00
Péter Bohner (xzvf) fa13826043 Revert "Coalesce cleanup in ffParsePropFileValues"
This reverts commit 7bc85b2397.
2022-07-08 09:05:00 +02:00
Péter Bohner (xzvf) 7bc85b2397 Coalesce cleanup in ffParsePropFileValues 2022-07-07 15:19:56 +02:00
Péter Bohner (xzvf) 1863d8377a Fix memory leak in ffParseProfFileValues, if more than 4 queries are passed (unsetValues is on the heap) and the file
is not found.
2022-07-07 14:35:59 +02:00
xzvf f9e17f44b1 Merge branch 'LinusDierheimer:master' into master 2022-07-04 20:10:01 +02:00
Linus Dierheimer 02cc214dfc Release 1.5.6
Bugfix: Don't segfault when connecting to some wayland compositors
See https://github.com/LinusDierheimer/fastfetch/issues/188
2022-07-03 16:16:39 +02:00
Linus Dierheimer 609fa14f4f Wayland: use a single, common stub listener 2022-07-03 16:10:17 +02:00
Linus Dierheimer 7d6f92a446 Wayland: only use required stub listeners 2022-06-30 12:22:46 +02:00
Linus Dierheimer bc76ebfb3f Wayland: add stub listeners 2022-06-30 12:16:38 +02:00
Linus Dierheimer c2da7b19f9 Song: Don't show album by default 2022-06-29 12:47:57 +02:00
Linus Dierheimer 41b024d3b1 Refactor wayland code the third 2022-06-29 11:08:42 +02:00
Linus Dierheimer 9b62d17d8d Refactor wayland code the second 2022-06-28 21:41:13 +02:00
Linus Dierheimer 1861d55f7d Refactor wayland code 2022-06-28 11:57:08 +02:00
Linus Dierheimer 3b2a6e4a6e Don't load sqlite3 id db path doesn't exist 2022-06-27 15:38:34 +02:00
Linus Dierheimer 8ab7a8ba37 Release 1.5.5
Feature: Detect wayland WM much faster
Bugfix: Wayland backend for resolution working once again
Bugfix: Plasma values are no longer victims to race conditions
2022-06-26 13:41:55 +02:00
Linus Dierheimer 22a3ab4a81 Detect wayland WM _much_ faster 2022-06-26 13:35:16 +02:00
Linus Dierheimer 44d6780545 Merge pull request #185 from artixnous/master
Fix misaligned Artix logo
2022-06-25 17:41:16 +02:00
nous 5820c9bbff Update builtin.c 2022-06-25 13:26:07 +03:00
Linus Dierheimer 3ba486a5b8 Wayland: switch to wl_proxy_marshal_constructor_versioned 2022-06-23 15:59:59 +02:00
Linus Dierheimer 2d2ba4c5b3 Wayland: switch to wl_proxy_marshal_flags 2022-06-23 15:51:29 +02:00
Linus Dierheimer 94ad782caa No unneeded casts 2022-06-23 10:44:53 +02:00
Linus Dierheimer b079e86c5e update bug_report.yml 2022-06-23 10:36:53 +02:00
Linus Dierheimer 91ba03d988 Add warning about public IP to bug_report.yml 2022-06-23 10:35:46 +02:00
Linus Dierheimer c440fdfca8 Uses instance->state.configDirs consistenlty (in particular thread save) troughout the project 2022-06-22 20:14:10 +02:00
Linus Dierheimer af0c72aa61 Methods for caching generic data 2022-06-20 16:35:15 +02:00
Linus Dierheimer 8fa09ca093 Refactored read methods 2022-06-20 16:27:33 +02:00
Linus Dierheimer 6e731c80d0 Refactored write methods 2022-06-19 18:22:00 +02:00
Linus Dierheimer 45eae78980 Better ordering in initCacheDir 2022-06-19 18:21:41 +02:00
Linus Dierheimer fb35a6e889 Release 1.5.4
Feature: Better WSL / WSLg support
Feature: --<module>-error arguments
Bugfix: Show GiB instad of GB
Feature: Export much more information to host format string
Feature: Expose CPU temp to cpu format string
Feature: Expose GPU temp to gpi format string
Bugfix: Print last line of logo, if it is higher than the infos
Logo: Alpine Linux
Refactor: Cleaned up header includes
Refactor: Build libfastfetch as OBJECT lib, as the linked binary is never needed
Feature: Detect termux as terminal
2022-06-18 23:39:48 +02:00
Linus Dierheimer 26d17250b6 Detect WSLg 2022-06-18 14:55:56 +02:00
Linus Dierheimer 9176797327 Detect Windows Terminal better 2022-06-18 14:51:10 +02:00
Linus Dierheimer 9d3f762c20 Better fallback for wayland detection 2022-06-18 15:27:46 +02:00
Linus Dierheimer fe71291769 Clean up includes 2022-06-18 14:25:31 +02:00
Linus Dierheimer f35dc9f46a Detect termux 2022-06-18 00:45:28 +02:00
Linus Dierheimer a6209187ae Fix build on Android part 4 2022-06-18 00:41:43 +02:00
Linus Dierheimer af2f97e0c9 Fix build on Android part 3 2022-06-18 00:22:07 +02:00
Linus Dierheimer 0691112e5e Fix build on Android part 2 2022-06-18 00:20:22 +02:00
Linus Dierheimer e61b31acab Fix build on Android 2022-06-18 00:15:23 +02:00
Linus Dierheimer 5d853f3b17 GPU temp detection 2022-06-17 23:38:33 +02:00
Linus Dierheimer 20e2f1e19d Detect CPU temp only if a custom format string is given 2022-06-17 20:41:11 +02:00
Linus Dierheimer ad28b3aac5 rename date-time to datetime 2022-06-17 20:40:51 +02:00
Linus Dierheimer eb0bbd0796 Detect WSL as host name 2022-06-17 20:01:02 +02:00
Linus Dierheimer da77a7936f Detect WSL as host 2022-06-17 19:59:01 +02:00
Linus Dierheimer eac875b8b1 Update bash completion to include --<module>-error options 2022-06-17 18:28:37 +02:00
Linus Dierheimer 97d2096df8 Delete performance test
I never really used it, and it didn't even build any more
2022-06-17 18:19:53 +02:00
Linus Dierheimer 6e3e717224 --<module>-error options 2022-06-17 18:15:36 +02:00
Linus Dierheimer aae182c889 Merge pull request #180 from draumaz/master
Add Alpine Linux logos
2022-06-17 10:44:54 +02:00
draumaz 5c7b9d223a Merge pull request #1 from draumaz/workbench
Merge Alpine Linux logos
2022-06-17 04:12:50 +00:00
draumaz c80f8cf422 further fixes 2022-06-16 21:11:14 -07:00
draumaz b150e8d106 whoops 2022-06-16 21:10:23 -07:00
draumaz bb897f03f0 add small logo 2022-06-16 21:08:39 -07:00
draumaz 517d80eadc update getAll function 2022-06-16 21:03:39 -07:00
draumaz 36964d6b1d Initial Alpine addition 2022-06-16 21:02:20 -07:00
Linus Dierheimer 5e96ba8384 Fix cpu temp detection the second 2022-06-16 14:55:02 +02:00
Linus Dierheimer 481affa50a Fix cpu temp detection 2022-06-16 14:39:01 +02:00
Linus Dierheimer a33e296656 Merge pull request #178 from Samisafool/patch-1
fix spelling of temperature
2022-06-16 14:17:07 +02:00
Samisafool 85a36ae7ef fix spelling of temperature 2022-06-16 17:10:59 +05:30
Linus Dierheimer 1eff343733 Finish exposing temperatur to cpu format 2022-06-16 13:36:00 +02:00
Linus Dierheimer acdbf6933c Merge pull request #177 from x-zvf/feature-cpu-temp
Add CPU package temperature to CPU module.
2022-06-16 13:21:34 +02:00
xzvf ea53833466 Remove unnecessary checks for content->length 2022-06-16 13:18:38 +02:00
xzvf c491c11988 update DEVELOPMENT.md 2022-06-16 13:15:48 +02:00
xzvf dcaeab7e96 Rewrite to use ffDetectTemps. 2022-06-16 13:14:03 +02:00
xzvf bccd1cf960 Merge pull request #1 from LinusDierheimer/master
build temps file
2022-06-16 13:14:03 +02:00
xzvf 5b030de20a Quality of life improvement: make run.sh not run ff, if the build fails 2022-06-16 13:14:03 +02:00
xzvf fa9b38eb2d Merge pull request #1 from LinusDierheimer/master
build temps file
2022-06-16 12:54:28 +02:00
Linus Dierheimer 716522e29a build temps file 2022-06-15 23:15:49 +02:00
Linus Dierheimer 921e4a6c8d Merge pull request #176 from x-zvf/fix-run-sh-script
Quality of life improvement: make run.sh not run ff, if the build fails
2022-06-15 16:43:59 +02:00
xzvf 7d43118abb Quality of life improvement: make run.sh not run ff, if the build fails 2022-06-15 16:28:07 +02:00
xzvf d8bb36f119 Add CPU package temperature to CPU module.
This is done by looking for a specified thermal zone in
/sys/class/thermal/thermal_zone*/ .
Unfortunately there is no better way to find the
temperature, then to check all registered zones.
This still needs to be extended to support other hardware,
right now only x86 CPUs and Raspberry pi are tested.
Maybe the FF_CPU_THERMAL_ZONES array could be user configurable,
but I could not figure out how to add an array as a config parameter.
2022-06-15 16:21:50 +02:00
Linus Dierheimer ae8b5bde65 Fix printing of remaining logo 2022-06-15 11:07:22 +02:00
Linus Dierheimer 3d8a071781 Update verbose 2022-06-14 20:07:42 +02:00
Linus Dierheimer 4cf912e535 Disk: Change GB to GiB 2022-06-14 17:17:22 +02:00
Linus Dierheimer e1b5445783 Export much more values to host format string 2022-06-14 17:10:46 +02:00
Linus Dierheimer a04daf1fff Clean up git ignore 2022-06-13 21:28:49 +02:00
Linus Dierheimer df0a4c0d46 Remove unneeded property set from CMakeLists.txt 2022-06-11 14:17:10 +02:00
Linus Dierheimer d70e160d72 Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2022-06-10 23:02:11 +02:00
Linus Dierheimer 8c52cd0d91 Change libfastfetch target to be OBJECT library 2022-06-10 23:01:56 +02:00
Linus Dierheimer 4622d7a300 Change libfatsfetch target to be OBJECT library 2022-06-10 22:58:35 +02:00
Linus Dierheimer 09f7180dd5 Merge pull request #169 from ADawesomeguy/patch-1
fix: correct "hout" to "hour"
2022-06-10 22:37:07 +02:00
Abheek Dhawan 6ae8b46f68 fix: correct "hout" to "hour" 2022-06-10 15:12:39 -05:00
Linus Dierheimer 2d0ffb55b7 Release 1.5.3
Enable LTO by default
Fix compile bug when LTO enabled
2022-06-08 17:18:02 +02:00
Linus Dierheimer 22a8cfdcfe Remove obsolete strbuf function 2022-06-08 17:14:11 +02:00
Linus Dierheimer 63041aa24b Enable link time optimization 2022-06-08 16:25:14 +02:00
Linus Dierheimer 242df5f2f0 Explicitly set c standard to 11 2022-06-08 15:52:55 +02:00
Linus Dierheimer ec1bbd118f Update README.md 2022-06-08 12:11:00 +02:00
Linus Dierheimer fe624123dc Merge pull request #168 from Yureien/master
Fix build if ImageMagick is not installed
2022-06-08 12:08:10 +02:00
Linus Dierheimer 8577be3d6d Update packaging section in README 2022-06-08 12:07:06 +02:00
Soham Sen d185dc74b8 Bumped version to 1.5.2 2022-06-08 15:32:52 +05:30
Soham Sen 54c09cab18 Fix build if ImageMagick is not installed 2022-06-08 15:22:34 +05:30
Linus Dierheimer dbe24c7508 Fix --print-logos 2022-06-08 11:28:26 +02:00
Linus Dierheimer d23d4ef5a0 Relase 1.5.0
Module: Vulkan
Module: OpenGL
Module: OpenCL
Feature: Detect Bedrock linux
Feature: Detect packages on Bedrock linux
Feature: --pipe option
Logo: Bedrock linux
Bugfix: Locale detection on Ubuntu and deriviates
Bugfix: bolt keys and title, if main color is not set
2022-06-08 11:17:08 +02:00
Linus Dierheimer daac1b783c Refactored logo choosing logic 2022-06-08 10:59:33 +02:00
Linus Dierheimer 2e98dd7710 Move ffPrintLogoAndKey to printing.c 2022-06-06 14:30:06 +02:00
Linus Dierheimer 9d6d2ca5a4 Add osmesa to help texts 2022-06-06 14:24:14 +02:00
Linus Dierheimer e4a1a836fe Fix keys not being bolt if main color is not set 2022-06-06 14:20:05 +02:00
Linus Dierheimer 1e3cabff2d --pipe option 2022-06-06 14:02:21 +02:00
Linus Dierheimer 008cf3b83d OpenCL module 2022-06-05 00:18:40 +02:00
Linus Dierheimer 3daede53eb Don't cache OS 2022-06-04 22:43:57 +02:00
Linus Dierheimer 36d9b5a9bd Finish OpenGL module 2022-06-04 19:30:26 +02:00
Linus Dierheimer 1826e23c29 OpenGL module 2022-06-04 15:21:34 +02:00
Linus Dierheimer 43b3998b9d Fix bedrock linux detection 2022-06-03 01:48:50 +02:00
Linus Dierheimer c55cc9c732 ffParsePropFileValues: only allocate storage on the heap if numQuerys > 4 2022-06-03 00:24:53 +02:00
Linus Dierheimer 0244e5ebd7 removed unused code 2022-06-02 23:24:50 +02:00
Linus Dierheimer ea6805de82 Escape bedrock option 2022-06-02 23:06:49 +02:00
Linus Dierheimer 9aba57cdea Bedrock package support 2022-06-02 22:58:19 +02:00
Linus Dierheimer 0dffd8debf Vulkan module 2022-06-01 00:04:58 +02:00
Linus Dierheimer 032ba375b6 Enable chafa only if ImageMagick is found 2022-05-29 16:23:56 +02:00
Linus Dierheimer 743bc07bad Correctly detect locale on ubuntu systems 2022-05-29 16:17:36 +02:00
Linus Dierheimer 044e5496fd Fix bedrock logo 2022-05-25 14:28:08 +02:00
Linus Dierheimer 102b2d33c7 Bedrock linux detection 2022-05-25 14:06:59 +02:00
Linus Dierheimer afc144fa01 Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2022-05-25 14:00:36 +02:00
Linus Dierheimer ededa4d6dd Bedrock linux logo 2022-05-25 14:00:18 +02:00
Linus Dierheimer af4596b666 Bedrock linux 2022-05-25 13:59:40 +02:00
Linus Dierheimer 8c910089cc Detect KDE plasma version more reliable 2022-05-24 13:58:38 +02:00
Linus Dierheimer e79af7ba79 Relase 1.4.2
Bugfix: RPM package count on SUSE platforms
Bugfix: Prepend /var with TARGET_DIR_ROOT
2022-05-24 13:41:23 +02:00
Linus Dierheimer 960364bd47 Use librpm as rpm fallback 2022-05-24 13:36:33 +02:00
Linus Dierheimer ea44231c78 Don't prepend proc with TARGET_DIR_ROOT
Should make future packaging for termux simpler
2022-05-23 20:01:18 +02:00
Linus Dierheimer 60af0b9e39 Release 1.4.0
Feature: Display images converted to ascii art as logo, using chafa
Feature: Stretch images by using the --logo-height option
Logo: RedstarOS
Logo: Devuan
Logo: Rocky
Bugfix: Better calculation of image dimensions
Bugfix: Better rpm package detection
Bugfix: Format uptime right, when hours > 0 and minutes = 0
Bugfix: Only detect themes for installed gtk versions
2022-05-23 19:39:49 +02:00
Linus Dierheimer e4ecb9d069 Use sqlite to get rpm package count 2022-05-23 19:30:02 +02:00
Linus Dierheimer 3c648d84db Better GTK detection 2022-05-23 16:19:58 +02:00
Linus Dierheimer 45db4a5c3d Fix possible use after free 2022-05-23 15:50:25 +02:00
Linus Dierheimer caf976bec2 Fix building without chafa enabled 2022-05-23 15:36:19 +02:00
Linus Dierheimer b3d855355e Rewrote image dimension calculation 2022-05-23 15:32:10 +02:00
Linus Dierheimer 0a2eb49891 Merge pull request #164 from draumaz/master
Add Rocky Linux logo
2022-05-23 12:34:06 +02:00
draumaz ab2efa151a update readme 2022-05-23 03:29:04 -07:00
draumaz 1aee3f81c5 added Rocky Linux logo 2022-05-23 03:22:39 -07:00
Linus Dierheimer 4c7031cb12 Merge pull request #161 from Samisafool/patch-1
Typo
2022-05-16 11:51:08 +02:00
Samisafool 81c96d0f11 Typo 2022-05-16 09:54:48 +05:30
Linus Dierheimer 4d8680ec2d Merge pull request #160 from draumaz/master
Add Devuan logo
2022-05-15 23:46:56 +02:00
draumaz 039eb3a38a Fix alphabetical ordering 2022-05-15 13:48:10 -07:00
draumaz d07a653404 Update README.md 2022-05-15 13:45:31 -07:00
draumaz 76c0b7e457 Update README.md 2022-05-15 13:43:36 -07:00
draumaz 1c0e532b79 add Devuan 2022-05-15 06:22:28 -07:00
Linus Dierheimer c79a9f1bff Format uptime better 2022-05-14 14:13:10 +02:00
Linus Dierheimer 759069adfa Merge pull request #157 from Samisafool/patch-1
Fix bug_report.md
2022-05-14 14:03:04 +02:00
Samisafool 66ff6adfb0 Update bug_report.md 2022-05-13 14:06:05 +05:30
Samisafool 1dba19c49f Typo 2022-05-12 08:29:47 +05:30
Samisafool 2afd158d96 Fix bug_report.md 2022-05-12 08:28:24 +05:30
Linus Dierheimer 36c2ce6219 Look for newer versions of librpm 2022-05-05 15:48:01 +02:00
Linus Dierheimer 5f6432c150 RedstarOS logo 2022-05-04 18:11:32 +02:00
Linus Dierheimer e9f0eca3dd Add documentation about logo height option 2022-04-30 11:25:22 +02:00
Linus Dierheimer 998691847e logo-height option 2022-04-30 11:22:51 +02:00
Linus Dierheimer 64e5ef0df7 Fix output with no custom logo 2022-04-29 21:52:42 +02:00
Linus Dierheimer cc1e876faf Better automatic logo type detection 2022-04-29 21:44:32 +02:00
Linus Dierheimer 964a5aa8b4 Add chafa to feature list 2022-04-29 14:11:22 +02:00
Linus Dierheimer ad2601f097 Fix visual bug in README.md 2022-04-29 13:08:39 +02:00
Linus Dierheimer 7cae63ac05 Require chafa>=1.10 2022-04-29 13:07:20 +02:00
Linus Dierheimer 0d26cfb218 Dont try to build with ubuntu's outdated chafa enabled 2022-04-29 13:05:38 +02:00
Linus Dierheimer 3b6855b9da Build github packages with chafa support 2022-04-28 19:17:13 +02:00
Linus Dierheimer 51414c5511 Ascii image output using chafa 2022-04-28 19:15:46 +02:00
Linus Dierheimer 24f8ad7673 Release 1.3.4
* Bugfix: Using custom logos in terminals that don't support \033[14t or \033[18t once again works
* Feature: Ubuntu flavour detection
* Feature: Kubuntu logo
* Feature: Deepin logo
2022-04-27 08:03:15 +02:00
Linus Dierheimer e404dd62c0 Check for ubuntu flavours 2022-04-26 19:21:19 +02:00
Linus Dierheimer 21b315d548 Use a timeout when waiting for terminal responses 2022-04-26 17:17:16 +02:00
Linus Dierheimer 14fa052257 Use reasonable timeout for dbus 2022-04-25 18:42:05 +02:00
Linus Dierheimer 5861012d95 Deepin logo 2022-04-25 18:01:29 +02:00
Linus Dierheimer 4d9fbd93d2 Kubuntu logo 2022-04-25 17:51:51 +02:00
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
Linus Dierheimer 5b66938bf4 Release with rpm package too 2022-03-25 12:09:48 +01:00
Linus Dierheimer 80c5600a7b Use cmake to build packages 2022-03-25 11:57:58 +01:00
Linus Dierheimer 65ce2eafed Hopefully finally fix github actions 2022-03-24 22:26:44 +01:00
Linus Dierheimer d840c7a12d Use workflow instead of action 2022-03-24 22:15:46 +01:00
Linus Dierheimer 634e27bc42 Try to give github actions the right permissions 2022-03-24 22:02:39 +01:00
Linus Dierheimer cc18315e84 Fix check action 2022-03-24 21:59:15 +01:00
Linus Dierheimer 83e2787b24 Use reusable action for check 2022-03-24 21:57:53 +01:00
Linus Dierheimer ef5a9384da Try to fix github actions again 2022-03-24 21:49:39 +01:00
Linus Dierheimer 2d7e6c37ff Try to fix github actions 2022-03-24 21:43:27 +01:00
Linus Dierheimer 92e8f23261 Refactored github actions again 2022-03-24 21:38:56 +01:00
Linus Dierheimer e09f1d3647 Refactored github actions 2022-03-24 21:32:45 +01:00
Linus Dierheimer 6f01e33955 Clear URL from unsucessfull media detection too 2022-03-24 19:06:20 +01:00
Linus Dierheimer 4b813cdf59 Automatic track commits between versions 2022-03-24 18:56:44 +01:00
Linus Dierheimer 942c583c89 Media: Don't show website urls 2022-03-23 21:41:52 +01:00
Linus Dierheimer 24a48c1fc0 Dont show lyric information in song title 2022-03-23 16:07:47 +01:00
Linus Dierheimer e2e95732e8 Don't remove dirty / clean from song title 2022-03-23 15:58:30 +01:00
Linus Dierheimer d647f9e3f2 Pretty song output, if the media is a browser playing a video 2022-03-23 15:43:30 +01:00
Linus Dierheimer 4895c68ca9 Capitalize the first letter of media player if appropiate 2022-03-23 11:54:05 +01:00
Linus Dierheimer f0b9800974 Fix fastfetch recaching every time if an old cache exists 2022-03-23 11:38:42 +01:00
Linus Dierheimer be84549f4c Refactored media detection 2022-03-23 11:15:50 +01:00
Linus Dierheimer 0916258c87 Greatly improved detection of media player name 2022-03-22 18:59:04 +01:00
Linus Dierheimer ad006b466c Version output include extra info 2022-03-20 17:12:52 +01:00
Linus Dierheimer efdf38a9ea Version 1.0.0 ! 2022-03-20 16:47:05 +01:00
Linus Dierheimer 10a202fe80 First Release? v14 2022-03-20 16:44:08 +01:00
Linus Dierheimer 6e8aca0945 First Release? v13 2022-03-20 16:37:27 +01:00
Linus Dierheimer 4cd08b82d4 First Release? v12 2022-03-20 16:32:15 +01:00
Linus Dierheimer a2ebecdf6d First Release? v11 2022-03-20 16:28:57 +01:00
Linus Dierheimer aa352a4427 First Release? v10 2022-03-20 16:23:25 +01:00
Linus Dierheimer 10c97aea4b First Release? v9 2022-03-20 16:22:27 +01:00
Linus Dierheimer e08cb24cb5 First Release? v8 2022-03-20 16:08:20 +01:00
Linus Dierheimer bfbaecb533 First Release? v7 2022-03-20 16:01:31 +01:00
Linus Dierheimer d915f415b1 First Release? v6 2022-03-20 15:57:59 +01:00
Linus Dierheimer 1887e21ddc First Release? v5 2022-03-20 15:53:08 +01:00
Linus Dierheimer 0b6c974126 First Release? v4 2022-03-20 15:45:22 +01:00
Linus Dierheimer fdd8919e1c First Release? v3 2022-03-20 15:43:21 +01:00
Linus Dierheimer 0c936cab27 First Release? v2 2022-03-20 15:42:37 +01:00
Linus Dierheimer d17aae5d65 First Release? 2022-03-20 15:40:23 +01:00
Linus Dierheimer 77e05b0c95 prepare for releases 2022-03-20 13:16:04 +01:00
Linus Dierheimer 0f6e266fc3 Removed unneeded else 2022-03-17 16:52:19 +01:00
Linus Dierheimer de779cf1ea Create FUNDING.yml 2022-03-17 16:35:34 +01:00
Linus Dierheimer ecbb854e54 KDE Neon logo 2022-03-15 18:49:44 +01:00
Linus Dierheimer da26a3497e Update README.md 2022-03-15 11:13:15 +01:00
Linus Dierheimer a6770581d3 Easter egg for uptime >= 100 days
Similiar to htop
2022-03-14 18:02:03 +01:00
Linus Dierheimer 07a685bb9a 16 Colors in TTY 2022-03-14 17:31:16 +01:00
Linus Dierheimer 00fdb8a0c4 Generic Linux logo 2022-03-09 17:39:36 +01:00
shivanandvp 4e68c09f27 Adding RebornOS to the supported logos (#140)
* feat: Add logos for RebornOS

* feat: Decrease the size of the RebornOS logo and prepare a better small RebornOS logo

* fix: Align text for both the regular and small RebornOS logos
2022-03-08 18:39:23 +01:00
Linus Dierheimer b5a36b0825 Update README.md 2022-03-08 12:13:01 +01:00
Linus Dierheimer 231016264b Update CMakeLists.txt 2022-03-08 12:03:21 +01:00
Linus Dierheimer 0451852e34 Install License with cmake too 2022-03-08 11:59:06 +01:00
Linus Dierheimer b9dfe1f858 Fix compilation warnings 2022-03-08 11:07:31 +01:00
Linus Dierheimer 51bbff4741 Zorin Logo 2022-03-08 10:47:04 +01:00
Linus Dierheimer 7c9b5c2c61 Update datetime.c 2022-02-25 15:06:24 +01:00
Linus Dierheimer fd450bcccc Date Time support 2022-02-25 13:30:37 +01:00
Linus Dierheimer 0cb6e40bac Fix neofetch preset 2022-02-21 14:44:46 +01:00
Linus Dierheimer 9c20c50c3d Merge pull request #136 from CyberTailor/master
CMake improvements
2022-02-21 14:40:41 +01:00
Anna “CyberTailor” aa9dd9c155 CMakeLists.txt: make tests optional
Run test-strbuf using ctest.
2022-02-21 12:30:06 +05:00
Anna “CyberTailor” 415c097489 CMakeLists.txt: use git only when in repository
Allow building fastfetch from tarballs with -DPROJECT_VERSION and
-DPROJECT_VERSION_MAJOR options.
2022-02-21 12:30:06 +05:00
Anna “CyberTailor” 109026211c CMakeLists: add installation target 2022-02-21 12:30:05 +05:00
Linus Dierheimer ed63ef1a28 Support detecting artist if a browser is current media player 2022-02-14 13:04:57 +01:00
Linus Dierheimer f54ac1c4e6 Update tests 2022-02-14 12:04:54 +01:00
Linus Dierheimer 313084f91c Update presets 2022-02-14 11:44:10 +01:00
Linus Dierheimer 59bd9927a4 Fix concating of song artists 2022-02-14 11:08:04 +01:00
Linus Dierheimer e2be34e23d Update DEVELOPMENT.md 2022-02-14 01:12:26 +01:00
Linus Dierheimer 3ca3687993 Update README.md 2022-02-14 00:48:35 +01:00
Linus Dierheimer c066446685 Update GitHub Actions again 2022-02-14 00:43:56 +01:00
Linus Dierheimer ecb38e8d20 Update GitHub Actions 2022-02-14 00:41:11 +01:00
Linus Dierheimer c800077b73 Fix GitHub actions once again 2022-02-14 00:35:54 +01:00
Linus Dierheimer fcea3649e2 Fix GitHub actions again 2022-02-14 00:29:54 +01:00
Linus Dierheimer eaaa2705d3 Fix GitHub actions 2022-02-14 00:25:51 +01:00
Linus Dierheimer a32b1c5887 Update github actions to support song and media player update 2022-02-14 00:18:22 +01:00
Linus Dierheimer cfb5d204a1 Media player and song detection! 2022-02-13 23:51:13 +01:00
Linus Dierheimer d6ae32374e Update DEVELOPMENT.md 2022-02-13 13:26:00 +01:00
Linus Dierheimer 451848f6fd Small improvements to code quality 2022-02-12 22:30:57 +01:00
Linus Dierheimer a7728f61fb Battery: show full status 2022-02-12 18:20:00 +01:00
Linus Dierheimer fb3028cafa Update DEVELOPMENT.md 2022-02-12 12:45:00 +01:00
Linus Dierheimer ea5b663b16 Rename class to deviceClass, so cpp linters don't see a problem 2022-02-12 12:38:14 +01:00
Linus Dierheimer 9659f8c7b1 Add AUR packaging as submodul 2022-02-12 12:31:42 +01:00
Linus Dierheimer 3f64ef0876 Show emerge packages earlier in list 2022-02-12 12:13:02 +01:00
Linus Dierheimer 8c6cb9405d Use FFstrbuf in emerge package counting 2022-02-12 12:06:16 +01:00
Viorel 8a754f5b89 Add packages support for Gentoo Linux (#131)
Count packages installed by Gentoo emerge
2022-02-12 11:16:14 +01:00
Linus Dierheimer 5f965ac787 Fixed two compiler warnings 2022-02-09 15:22:57 +01:00
Linus Dierheimer bc8887fb42 Improved compile time by compiling common sources as a static lib 2022-02-09 15:20:07 +01:00
Linus Dierheimer 2ff3595251 Update DEVELOPMENT.md 2022-02-09 11:14:20 +01:00
Linus Dierheimer 47a58ad7b5 Update build-deb-package.yml 2022-02-08 19:30:55 +01:00
Linus Dierheimer ec523e0274 Update DEVELOPMENT.md 2022-02-08 19:28:05 +01:00
xzvf 87e410e0fc Add a Github Action to build and package fastfetch for Debian. (#127)
* Create a build.yml file

* add debian packaging

untested

* Copy & Paste is hard

* Fix typo, libRpm -> librpm

* Change working-dir

* Try again. Maybe now it will find the deb package

* Add more dependencies

* This should be it, hopefully

* Fix installed packages

* Change the name of the auto-created releases

* Document GH action

* Remove unnecessary packages. 

Apparently brute-forcing dependencies until the build is successful is not a good strategy.

* Move building the packaging into a seperate github action.

* Remove packaging from test Action
2022-02-08 19:15:28 +01:00
Linus Dierheimer cc43ed2351 Merge pull request #130 from ceamac/features/cmake/options
Make dependencies check optional
2022-02-08 11:51:08 +01:00
Viorel a28c4600f4 Make dependencies check optional 2022-02-08 07:10:46 +02:00
Linus Dierheimer 7ad73d3ba1 Fix arco linux logo 2022-01-29 10:32:23 +01:00
Linus Dierheimer f72ec8a99f Updated screenshot 2022-01-23 13:54:56 +01:00
Linus Dierheimer 6107241f4a Update README.md 2022-01-23 12:08:58 +01:00
Linus Dierheimer 68e8ddce6f Update README.md 2022-01-23 12:07:49 +01:00
Linus Dierheimer 1a57d82675 Update README.md 2022-01-23 12:07:04 +01:00
Linus Dierheimer c662416b33 Update README.md 2022-01-23 12:02:26 +01:00
Linus Dierheimer 79331d7fe5 Update README.md 2022-01-23 12:00:28 +01:00
Linus Dierheimer e887b56209 Fix performance test 2022-01-22 23:03:09 +01:00
Linus Dierheimer 23b71cc907 Fixed some rare compilation warnings from old compilers 2022-01-22 23:01:09 +01:00
Linus Dierheimer 4e45a2e3ba Fix building with librpm support enabled 2022-01-22 22:54:20 +01:00
Linus Dierheimer 14115eb089 Merge pull request #123 from x-zvf/master
Add packaging for Debian based distributions.
2022-01-22 13:11:41 +01:00
xzvf 8f466735a8 Add .deb file and deb-package build directory to .gitignore 2022-01-22 12:40:58 +01:00
xzvf 7a7eac9edd Copy presets to /usr/share/fastfetch/presets 2022-01-22 12:40:10 +01:00
xzvf 65dc9bb166 Remove flashfetch target, and fix 2 shellcheck warnings 2022-01-22 12:35:21 +01:00
xzvf (Péter Bohner) 57ef794864 Add packaging for Debian based distributions.
This commit adds a script (`create-deb-pkg.sh`), which creates a deb package containing the fastfetch and flashfetch executables as well as the bash-completion file. The script must be executed in an environment, where `dpkg-deb` is present (a debian based environment).
Because Deb versioning is not compatible with fastfetch version strings, it is adapted to the format: `0:1$FF_VERSION-0`.
2022-01-22 11:56:11 +01:00
Linus Dierheimer cd4739e4f7 Merge pull request #122 from TahaAbbasi-Hashemi/master
Artix_small logo had an extra space in line4
2022-01-20 15:25:02 +01:00
Taha Abbasi-Hashemi 3a667add01 Artix_small logo had an extra space in line4 2022-01-20 09:10:01 -05:00
Linus Dierheimer 6906094b8b Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2022-01-20 12:19:18 +01:00
Linus Dierheimer b8a239e379 Add endeavour logo 2022-01-20 12:18:56 +01:00
Linus Dierheimer e30a64e97e Update README.md 2022-01-20 01:22:13 +01:00
Linus Dierheimer f2663a65cc More flexible OS file detection 2022-01-18 18:56:37 +01:00
Linus Dierheimer a0f5432903 Temp detection 2022-01-16 16:33:15 +01:00
Linus Dierheimer 20427a534e Respect WAYLAND_SOCKET on builds without wayland-client support 2022-01-14 13:31:39 +01:00
Linus Dierheimer 9789d1f5f1 Fallback OS detection using lsb 2022-01-14 13:21:49 +01:00
Linus Dierheimer bf2152bac8 Disable public ip timeout by default 2022-01-12 19:16:49 +01:00
Linus Dierheimer accaaa7de5 Expose GPU driver to gpu format string 2022-01-12 18:57:35 +01:00
Linus Dierheimer 322e5c5a48 FFstrbuf: don't do unneeded destroy work 2022-01-12 02:05:12 +01:00
Linus Dierheimer 6d7ad48edf Clear destroyed FFstrbuf 2022-01-12 01:59:57 +01:00
Linus Dierheimer 6a62f909d4 Destroyed FFstrbufs can now be reused 2022-01-12 01:57:49 +01:00
Linus Dierheimer 3653836490 Merge pull request #119 from CachyOS/master
Add CachyOS logo support
2022-01-12 01:52:15 +01:00
Linus Dierheimer f21013f646 Use same variable name in definition and declaration 2022-01-12 01:33:03 +01:00
Linus Dierheimer 8639e59019 Silence a false positive compiler warning 2022-01-12 01:21:36 +01:00
Linus Dierheimer 33127388f0 refactored FFstrbuf 2022-01-12 01:02:14 +01:00
Vladislav Nepogodin f54101e9f5 🔥 add cachyos 2022-01-12 01:17:23 +04:00
Vladislav Nepogodin d79b7a8944 🔥 add cachyos 2022-01-12 01:11:58 +04:00
Vladislav Nepogodin 2c7314dd8e 🔥 add cachyos logo 2022-01-12 01:10:04 +04:00
Linus Dierheimer 729d9d5c47 Add help for IP format 2022-01-11 12:36:32 +01:00
Linus Dierheimer 1c72219a88 Fix ordering of macros in settings.c 2022-01-10 20:45:58 +01:00
Linus Dierheimer 816d86aee8 Public IP module 2022-01-10 20:20:18 +01:00
Linus Dierheimer d6a80d7c85 Android support part 7 2022-01-10 15:31:36 +01:00
Linus Dierheimer ef034b7adb Android support part 6 2022-01-10 15:26:25 +01:00
Linus Dierheimer 4bbb13b44d Android support part 5 2022-01-10 15:24:10 +01:00
Linus Dierheimer 4aff8a353b Android support part 4 2022-01-10 15:22:25 +01:00
Linus Dierheimer 190974e079 Android support part 3 2022-01-10 15:20:51 +01:00
Linus Dierheimer e95e1e3530 Android support part 2 2022-01-10 14:41:34 +01:00
Linus Dierheimer 1d6119f858 Update DEVELOPMENT.md 2022-01-09 19:49:19 +01:00
Linus Dierheimer bf60429e36 Android support part 1 2022-01-09 16:51:57 +01:00
Linus Dierheimer 31d0729cdd Small syntactic changes 2022-01-08 21:58:37 +01:00
Linus Dierheimer 0879746e0f Unified method for testing if c strings contain a value 2022-01-07 18:00:38 +01:00
Linus Dierheimer 3f30fa8d4a Improved WM / DE detection logic 2022-01-07 17:37:57 +01:00
Linus Dierheimer 53f31f2401 Look for different versions of the same library 2022-01-05 16:14:27 +01:00
Linus Dierheimer 59e61f53e1 XCB: set wm protocol if connection succeded 2022-01-05 15:02:54 +01:00
Linus Dierheimer 7a3bf2f77d Rewrote X11 code 2022-01-05 14:40:57 +01:00
Linus Dierheimer bd3a5fde07 Finish rewriting of WM/DE detection 2022-01-02 19:02:21 +01:00
Linus Dierheimer ecb1853d56 Using EWMH to detect WM in X11 sessions 2022-01-02 18:42:58 +01:00
Linus Dierheimer bcf543e129 Unified WM / DE / Resolution detection 2022-01-02 16:55:26 +01:00
Linus Dierheimer 06fa8e7478 Use ffStrbufEndsWithC instead of custom impl 2022-01-01 17:28:41 +01:00
Linus Dierheimer f73137aef8 Better filtering of batteries 2021-12-31 14:12:44 +01:00
Linus Dierheimer d4f753a9f8 Moved detection files to their own folder 2021-12-20 16:34:46 +01:00
Linus Dierheimer 65bac0efc9 Color name mapping 2021-12-20 12:12:55 +01:00
Linus Dierheimer a15b3661c3 Flashfetch: don't print cpu usage and local ip by default 2021-12-19 22:52:16 +01:00
Linus Dierheimer a011b55692 Custom logo colors support 2021-12-19 22:39:22 +01:00
Linus Dierheimer 87eb2659de Create codeql-analysis.yml 2021-12-15 22:18:35 +01:00
Linus Dierheimer 1a7f04fe0c Suppress the output of drivers more efficently 2021-12-15 19:12:07 +01:00
Linus Dierheimer 7638d0b8b6 Disable stdout during vulkan operations 2021-12-15 15:42:33 +01:00
Linus Dierheimer b89e41c1d7 Updated GitHub bug report template 2021-12-13 18:19:12 +01:00
Linus Dierheimer 809f9310a5 Updated DEVELOPMENT.md 2021-12-10 15:58:34 +01:00
Linus Dierheimer 9b7f236397 Update DEVELOPMENT.md 2021-12-09 13:27:36 +01:00
Linus Dierheimer 8f865cf823 Update DEVELOPMENT.md 2021-12-09 12:04:04 +01:00
Linus Dierheimer dedbd5b529 Update DEVELOPMENT.md 2021-12-07 17:46:44 +01:00
Linus Dierheimer 5f178880c7 updated DEVELOPMENT:md 2021-12-07 17:42:57 +01:00
Linus Dierheimer 74b809f68a removed obsolete function 2021-12-07 17:21:25 +01:00
Linus Dierheimer f0732d0056 small cleanup 2021-12-07 17:20:11 +01:00
Linus Dierheimer e6851eeabc Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2021-12-06 20:04:03 +01:00
Linus Dierheimer 9e2d6be31f Removed zsh completion stub 2021-12-06 20:03:53 +01:00
Linus Dierheimer 7f846dadaf Fix --logo option when using not existent file 2021-12-06 20:03:17 +01:00
Linus Dierheimer 79bec5c220 Merge pull request #112 from CarterLi/master
CPU Usage: add new module
2021-11-24 12:17:05 +01:00
Carter Li 8653a881fd CPU Usage: add new module 2021-11-24 19:14:27 +08:00
Linus Dierheimer aaa6f32f15 updated .editorconfig 2021-11-19 12:42:03 +01:00
Linus Dierheimer bbbf00e834 Separator string option 2021-11-18 18:25:24 +01:00
Linus Dierheimer 7bab4ef298 Fix disk space output 2021-11-17 23:22:42 +01:00
Linus Dierheimer 9db9a2c195 Added -Wconversion to compiler options 2021-11-17 18:38:57 +01:00
Linus Dierheimer cb16cd583b Orderd arco linux logo method alphabetically 2021-11-17 12:09:55 +01:00
Linus Dierheimer 2abaf64c12 fix a compiler warning in ffStrbufEnsureCapacity 2021-11-17 12:07:08 +01:00
Linus Dierheimer 4e818c981a Found a better way to fix the warning from pevious commit 2021-11-17 12:00:06 +01:00
Linus Dierheimer 6c4961aaff Fix a wrong compiler warning in io.c 2021-11-17 11:57:50 +01:00
Linus Dierheimer 7db781c508 Fix possible seg fault in ffStrbufAppendVF 2021-11-17 11:41:17 +01:00
Linus Dierheimer 7ced537e59 FFstrbuf is now always null terminated 2021-11-17 10:59:31 +01:00
Linus Dierheimer f0e623c3de Remove unnecesarry strbuf allocation 2021-11-16 13:05:02 +01:00
Linus Dierheimer 40d535ffba Allow 0 length FFstrbuf 2021-11-16 12:54:49 +01:00
Linus Dierheimer 18bfc6bd11 Merge pull request #110 from Rayrsn/master
Add Arco Linux logo support
2021-11-16 10:48:03 +01:00
Rayr 6823b65615 Added Arco Linux logo 2021-11-16 00:19:50 +03:30
Rayr ad347a6083 Update README.md 2021-11-16 00:19:37 +03:30
Rayr fff69ac7e2 Update README.md 2021-11-16 00:18:53 +03:30
Rayr d41d31a6a7 Added Arco Linux logo 2021-11-16 00:18:20 +03:30
Linus Dierheimer 9e6b0b03ea Tell vulkan the right project version 2021-11-13 18:43:33 +01:00
Linus Dierheimer dff3ca58ae GPU: vulkan fallback 2021-11-13 18:25:35 +01:00
Linus Dierheimer fc77e40ea9 Added dwm to list of known window managers 2021-11-13 16:57:59 +01:00
Linus Dierheimer 869aa67d1f Fix font detection on plasma 5.23+ 2021-11-13 16:46:32 +01:00
Linus Dierheimer fd447ab439 Common macros for loading shared libs 2021-11-13 14:10:30 +01:00
Linus Dierheimer 6cdf32dabc Small variants of logos 2021-11-12 01:39:21 +01:00
Linus Dierheimer 1c8eca1010 Logo printing: keep state and config separate 2021-11-11 19:10:52 +01:00
Linus Dierheimer 42b8182428 Added linux mint old logo 2021-11-10 14:03:11 +01:00
Linus Dierheimer e54398f7b3 Fix autocompletion of logos 2021-11-09 16:53:08 +01:00
Linus Dierheimer 27334f77cc Remove outdated section from DEVELOPMENT.md 2021-11-09 15:20:54 +01:00
Linus Dierheimer 6b0343a46c Merge branch 'master' of remote 2021-11-09 15:18:02 +01:00
Linus Dierheimer 214540e7ef Logo revolution 2021-11-09 15:14:25 +01:00
Linus Dierheimer 0c7a415f9b librpm: don't print error messages 2021-11-08 11:50:50 +01:00
Linus Dierheimer 0048c1ca98 Merge pull request #106 from CarterLi/master
Add CentOS logo support
2021-11-08 11:08:06 +01:00
Carter Li df2ad48d13 Logo: add CentOS logo 2021-11-08 17:37:17 +08:00
Carter Li a81f897258 CMakeList: don't require C++ compilers 2021-11-08 10:28:48 +08:00
Linus Dierheimer e9db9ac87a Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2021-11-07 21:36:08 +01:00
Linus Dierheimer a198322d58 logo part 1 2021-11-07 21:35:59 +01:00
Linus Dierheimer 6e6086a8b4 Merge pull request #105 from CarterLi/master
Packages: use the official librpm instead of libsqlite3
2021-11-07 21:23:32 +01:00
李通洲 b3b31d693e Settings: simplify macros and code cleanup 2021-11-06 22:50:52 +08:00
李通洲 f6700f5272 Packages: use the official RPM public API
instead of diving into its implementation detail to count installed rpm packages, which support CentOS
2021-11-06 22:47:51 +08:00
Linus Dierheimer 58ec50fa7f Merge pull request #103 from Linus789/preset-neofetch-fix
Make the preset neofetch more like neofetch
2021-11-03 18:23:05 +01:00
Linus789 15328345da Make the preset neofetch more like neofetch
- os-format: Print architecture without square brackets
- resolution-format: Do not print the refresh rate
- de-format: Use pretty name and print version
- theme-format: Print color scheme without brackets
- memory-format: Use MiB instead of Mib
2021-11-03 17:46:29 +01:00
Linus Dierheimer 0f16bf2698 Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2021-11-01 19:39:05 +01:00
Linus Dierheimer 46ecdd42b6 Development notice 2021-11-01 19:37:45 +01:00
Linus Dierheimer 7663637ea9 Development notice 2021-11-01 19:33:12 +01:00
Linus Dierheimer bf1fbd572a Fix display of long terminal names 2021-11-01 14:47:36 +01:00
Linus Dierheimer e3f0319575 Merge pull request #102 from NBonaparte/master
fix: check if `processName` is NULL/empty to prevent segfaults
2021-11-01 12:32:33 +01:00
NBonaparte f333ede1f7 fix: check if processName is NULL/empty to prevent segfaults 2021-10-31 22:13:29 -07:00
Linus Dierheimer c0584cf465 More options documented in config file 2021-10-31 12:12:51 +01:00
Linus Dierheimer 00c05f14c7 Update bug_report.md 2021-10-25 13:34:43 +02:00
Linus Dierheimer c008f66a76 Fix bug in terminal format 2021-10-25 13:31:25 +02:00
Linus Dierheimer 57377019e6 Verbose and devinfo presets 2021-10-25 13:29:39 +02:00
Linus Dierheimer 2f555df690 Update issue templates 2021-10-24 21:25:10 +02:00
Linus Dierheimer eb6b8778b3 Update issue templates 2021-10-24 21:20:58 +02:00
Linus Dierheimer 09285338c5 Fix possible unassigned variable in memory code 2021-10-24 15:11:17 +02:00
Linus Dierheimer 20dd2fa28f New fedora logo 2021-10-24 14:47:28 +02:00
Linus Dierheimer 7a21f44a3a Exit signal handler 2021-10-23 15:48:24 +02:00
Linus Dierheimer 1df591b46f More informations in default config file 2021-10-23 14:59:11 +02:00
Linus Dierheimer b3ef53ddc9 Store big strings in separate files 2021-10-22 21:53:29 +02:00
Linus Dierheimer e18199e8ec Fix odering of XDG_CONFIG_DIRS 2021-10-22 18:42:14 +02:00
Linus Dierheimer 3923f11a45 Merge pull request #100 from CarterLi/master
Fix double free memory error
2021-10-20 18:48:07 +02:00
李通洲 c223ace5eb Fix double free memory error 2021-10-21 00:41:35 +08:00
Linus Dierheimer 9b399da872 Merge pull request #99 from CarterLi/master
Add Android basic support
2021-10-20 16:31:11 +02:00
李通洲 1a5b1428dc Add Android basic support 2021-10-20 22:27:29 +08:00
Linus Dierheimer 5589293d76 Merge pull request #98 from CarterLi/cmake
CMakeList: cleanup
2021-10-20 15:19:35 +02:00
李通洲 714181175d CMakeList: cleanup
Default CMAKE_BUILD_TYPE to Release, which implies -O3 -DNDEBUG
Don't force building with -O3, which makes debugging more friendly.
Remove option BUILD_DEBUG, which is covered by -DCMAKE_BUILD_TYPE=DEBUG / RelWithDebInfo
2021-10-20 08:13:49 +00:00
Linus Dierheimer fd257ddde9 better FF_UNUSED 2021-10-19 19:34:55 +02:00
Linus Dierheimer 349e5b24fa better support for building without features 2021-10-19 18:44:59 +02:00
Linus Dierheimer 73436824f9 Merge pull request #96 from CarterLi/build
Make it possible to build without optional dependencies
2021-10-19 17:07:25 +02:00
李通洲 e5322cf165 Make it possible to build without optional dependencies 2021-10-19 22:50:17 +08:00
Linus Dierheimer 564ddfc1b6 Merge pull request #95 from CarterLi/master
Add a new module that shows the number of current running processes
2021-10-19 15:07:12 +02:00
李通洲 181dfb5cfc Processes: add new module 2021-10-19 02:25:34 +00:00
Linus Dierheimer 072a4bc412 Merge pull request #94 from yuannan/master
Multithreading make
2021-10-18 16:47:38 +02:00
yuannan 914cd9219d tests multithreading 2021-10-18 02:40:33 +01:00
yuannan dbc4a815c5 updated building instructions 2021-10-18 02:23:02 +01:00
yuannan 5d97436c7d multithreading make 2021-10-18 02:18:42 +01:00
Linus Dierheimer 5f0c5a0351 Merge pull request #91 from CarterLi/master
Fix detecting Windows Terminal on WSL2
2021-10-17 15:17:32 +02:00
李通洲 7dc70b9730 Fix detecting Windows Terminal on WSL2 and SSH env 2021-10-17 21:12:19 +08:00
Linus Dierheimer d288a698b0 Merge pull request #92 from CarterLi/localip
Add new module that shows local IP addresses which are useful with frontend development
2021-10-17 15:09:26 +02:00
李通洲 38e2f8cf3e LocalIp: add new module 2021-10-17 21:05:04 +08:00
Linus Dierheimer 0b3f96610b Merge pull request #93 from CarterLi/wsl2
Better support devices running without desktop environment ( and WSL2 ), fix #83
2021-10-17 14:33:24 +02:00
李通洲 3a649493ea Don't print error: XDG_RUNTIME_DIR not set in the environment. when $XDG_RUNTIME_DIR is not set
According to [the manpage](https://manpages.debian.org/experimental/libwayland-doc/wl_display_connect.3.en.html), $XDG_RUNTIME_DIR must be set before calling `wl_display_connect(NULL)`.
Otherwise `wl_display_connect` will always fail, and print the error message
2021-10-17 18:37:51 +08:00
李通洲 8d7d33882f Always assume TTY when both $XDG_SESSION_TYPE and $WAYLAND_DISPLAY are not set
$TERM can be set to value other than `linux` ( eg xterm, xterm-256color ), just assume TTY when no desktop env is found, which effectively bypasses `getWMDE`
Fix #83
2021-10-17 18:34:11 +08:00
Linus Dierheimer f265307dc4 Prefer process name in terminal output 2021-09-19 14:58:46 +02:00
Linus Dierheimer e02d81d866 Merge pull request #81 from halfhiddencode/patch-1
Update logo.c
2021-07-31 09:52:39 +02:00
halfhiddencode a2742ce60b Update logo.c
correction in garuda logo
2021-07-18 08:16:23 +00:00
Linus Dierheimer 588a68ac4c Better OS output 2021-07-12 19:01:31 +02:00
Linus Dierheimer 0f916bb492 Better ffParseSemver 2021-07-08 20:02:53 +02:00
Linus Dierheimer 9faf664320 Merge pull request #77 from BL4CKH47H4CK3R/patch-1
Beautify Arch Logo
2021-07-06 22:10:02 +02:00
BL4CKH47H4CK3R 7fa971bc86 Beautify Arch Logo 2021-07-06 19:49:27 +00:00
Linus Dierheimer b733bb628d Update README.md 2021-07-06 21:25:12 +02:00
Linus Dierheimer d7356a8323 Cleand up resolution code 2021-07-06 21:15:08 +02:00
Linus Dierheimer 26f4fac62b feature request #75: CelOS logo 2021-07-06 20:36:30 +02:00
Linus Dierheimer 273d4205b5 Xrandr: support for multiple output monitors 2021-07-05 20:59:58 +02:00
Linus Dierheimer 1717b51807 fix compiler warning about unused result of fscanf 2021-07-02 23:07:25 +02:00
Linus Dierheimer 7b5af1b133 Rewrote x11 resolution detection 2021-07-02 22:43:58 +02:00
Linus Dierheimer 45e5546c92 Don't show certain informations in TTY 2021-06-27 21:53:50 +02:00
Linus Dierheimer 8f1b067953 fix resolution in x11 / TTY 2021-06-27 21:43:09 +02:00
Linus Dierheimer ad220546ba small cleanup in cursor code 2021-06-27 21:18:43 +02:00
Linus Dierheimer 78af5cb8a8 better resolution detection 2021-06-27 21:09:18 +02:00
Linus Dierheimer dc2f45626f Merge pull request #72 from DarNCelsius/master
Clean up cursor.c
2021-06-26 19:13:39 +02:00
DarN 4d408f55fa Optimisation 2021-06-26 19:00:15 +02:00
Linus Dierheimer 3f936e084d Merge pull request #71 from DarNCelsius/master
LXQT cursor support
2021-06-26 18:35:02 +02:00
DarN 764d2b7fc9 Refactored config file cursor functions 2021-06-26 18:14:09 +02:00
DarN 11c07d6738 LXQT cursor support 2021-06-26 17:31:50 +02:00
Linus Dierheimer 262a3eb59f remove trailing - in cursor output 2021-06-26 17:08:15 +02:00
Linus Dierheimer 0d09b89016 Merge pull request #70 from DarNCelsius/master
Sanitize custom Plasma theme name
2021-06-26 16:54:49 +02:00
DarN d2156dfc1d Remove fluff 2021-06-26 16:53:43 +02:00
Linus Dierheimer 2c599b5924 prettier cursor output 2021-06-26 16:48:15 +02:00
DarN 3d3216ba91 Added flexible remove logic 2021-06-26 16:47:47 +02:00
DarN d7a8623f90 Merge branch 'LinusDierheimer:master' into master 2021-06-26 16:07:32 +02:00
Linus Dierheimer 582d5b6473 better naming of strbuf methods 2021-06-26 15:34:01 +02:00
Linus Dierheimer 19b71d9ce0 change cursor size from pt to px 2021-06-26 11:43:36 +02:00
Linus Dierheimer a88cb07dad better cursor support 2021-06-26 11:39:42 +02:00
DarN 4c02b8319b Comment edit 2021-06-26 08:40:23 +02:00
DarN ea8c68bab4 Sanitize custom Plasma theme name 2021-06-26 08:14:11 +02:00
Linus Dierheimer d4d9bc90e6 fix cursor detection in xfce 2021-06-20 22:26:06 +02:00
Linus Dierheimer c0cb55ca9a fix ffParsePropFileConfigValues 2021-06-20 22:17:18 +02:00
Linus Dierheimer 8cb3ff7c2b Cursor support 2021-06-20 21:04:55 +02:00
Linus Dierheimer ef31e08d2d Allow same GTK values in same file to overwrite each other 2021-06-17 13:59:18 +02:00
Linus Dierheimer f148dbacfb Disable linewrap and hide cursor by default 2021-06-17 13:49:25 +02:00
Linus Dierheimer 450ac7f2cd simplified host code 2021-06-16 12:20:56 +02:00
Linus Dierheimer 98f420ad3d handle cpu frequencies right 2021-06-16 11:47:32 +02:00
Linus Dierheimer 27915127a8 improved cpu detection 2021-06-16 11:28:33 +02:00
Linus Dierheimer ea2f6470d8 improved host detection 2021-06-16 10:50:16 +02:00
Linus Dierheimer 9ade52ddc0 Added "Default string" to not allowed host values 2021-06-15 18:12:33 +02:00
Linus Dierheimer 409b1f29a6 renamed calculation threads to detection threads 2021-06-15 13:12:29 +02:00
Linus Dierheimer f8c215775a better zsh and fish version detection 2021-06-15 12:35:44 +02:00
Linus Dierheimer 0bf486fa67 seperator is now always the width of the title 2021-06-15 11:04:44 +02:00
Linus Dierheimer 4fecc76083 specific fish version code 2021-06-15 09:51:55 +02:00
Linus Dierheimer 2bae720e00 removed unnecessary code 2021-06-15 09:27:53 +02:00
Linus Dierheimer bfd76ae455 merge 2021-06-15 09:24:14 +02:00
Linus Dierheimer cab5069be2 fix terminal / shell detection 2021-06-15 09:23:37 +02:00
Linus Dierheimer 5aa5ab2c16 fix terminal / exe detection 2021-06-15 09:21:38 +02:00
Linus Dierheimer 5515eea42d merging 2021-06-14 23:22:44 +02:00
Linus Dierheimer eab26149e7 rewrote shell / terminal detection 2021-06-14 23:22:14 +02:00
Linus Dierheimer d77fc9a9c3 Merge pull request #65 from wizard-28/Code-Quality
Improved code quality
2021-06-14 11:44:28 +02:00
Sourajyoti Basak 0108a3ade0 Revert headers 2021-06-14 14:57:45 +05:30
Sourajyoti Basak e79209c7bf Change shebang 2021-06-14 14:22:51 +05:30
Sourajyoti Basak 399eee1963 Change shebang 2021-06-14 14:22:28 +05:30
Sourajyoti Basak 4f2b3d740e Update run.sh 2021-06-14 12:19:21 +05:30
Sourajyoti Basak bc65c9f9c3 Add shebang 2021-06-14 12:18:39 +05:30
Sourajyoti Basak 756593e160 Fix heading increment 2021-06-14 12:12:17 +05:30
Sourajyoti Basak ed3e5b544f Fix heading punctuation 2021-06-14 12:09:18 +05:30
Sourajyoti Basak 7b58c97ff3 Fix list item idents 2021-06-14 12:07:08 +05:30
Linus Dierheimer ab2cb9e0e4 fix gentoo logo name 2021-06-13 14:28:09 +02:00
Linus Dierheimer 889c8570f2 Merge branch 'master' of github.com:LinusDierheimer/fastfetch 2021-06-13 14:24:12 +02:00
Linus Dierheimer 3ce12dfc47 rewrote logo code 2021-06-13 14:23:35 +02:00
Linus Dierheimer 020fdccaaf Merge pull request #63 from wizard-28/grammer
Improve grammer of the configuration file
2021-06-13 14:15:56 +02:00
Sourajyoti Basak f82a4a6d7d Improve grammer of the configuration file 2021-06-13 17:44:34 +05:30
Linus Dierheimer 32f520bf3b Merge pull request #62 from wizard-28/master
Optimize the images using ImgBot
2021-06-12 18:22:21 +02:00
Sourajyoti Basak fc3cfff1d4 Optimize images
[ImgBot] Optimize images
2021-06-12 20:55:30 +05:30
ImgBotApp 36df822ce6 [ImgBot] Optimize images
*Total -- 119.87kb -> 102.20kb (14.74%)

/screenshots/ffmanjaro.png -- 47.30kb -> 38.92kb (17.71%)
/screenshots/example.png -- 72.56kb -> 63.27kb (12.8%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2021-06-12 15:07:10 +00:00
Linus Dierheimer 4d565cb7ee Fix snap package count 2021-06-10 22:04:25 +02:00
Linus Dierheimer 580ad45459 Fedora support 2021-06-08 20:01:29 +02:00
Linus Dierheimer 9535aa885c battery don't show full status 2021-05-30 21:37:27 +02:00
Linus Dierheimer 6a65803929 prettier battery output 2021-05-30 21:35:04 +02:00
Linus Dierheimer 602c3767e5 Rewrote WM / DE detection 2021-05-30 20:28:15 +02:00
Linus Dierheimer 0b93feaa94 removed debug puts 2021-05-28 14:14:57 +02:00
Linus Dierheimer 49e7612795 fix logo display 2021-05-28 14:10:53 +02:00
Linus Dierheimer 0e8b1fff8e Merge pull request #57 from alborrajo/master
Custom logos read from files
2021-05-28 13:48:03 +02:00
alborrajo e4516dc548 Clean up buffer after loading logo from file 2021-05-28 13:46:33 +02:00
alborrajo 936c478a9a Moved --logo-file bash completions to path options 2021-05-28 13:46:22 +02:00
alborrajo de72ea6ee6 Separate --logo-file option 2021-05-27 17:13:26 +02:00
alborrajo 53389850c2 Faster removal of \n when loading a custom logo 2021-05-27 16:40:51 +02:00
alborrajo a10aa36b72 Revert "Custom logos explanation in readme"
This reverts commit ec82b80f5a.
2021-05-27 15:57:17 +02:00
alborrajo f20ec0ef9f Color support on custom logos 2021-05-27 15:56:11 +02:00
alborrajo b9c6830a14 Merge branch 'master' of https://github.com/LinusDierheimer/fastfetch 2021-05-27 15:48:15 +02:00
Linus Dierheimer 94e4443464 fix --color option 2021-05-27 14:56:31 +02:00
alborrajo ec82b80f5a Custom logos explanation in readme 2021-05-26 19:20:11 +02:00
alborrajo e630167585 Read custom logos from text files
If the --logo option is specified with a path to a file, use the
contents of the file as the logo
2021-05-26 19:01:31 +02:00
Linus Dierheimer 137b3f7010 mutter wm theme fix 2021-05-24 10:46:55 +02:00
Linus Dierheimer 571913ed44 better mutter theme 2021-05-23 21:50:01 +02:00
Linus Dierheimer 76f9da4b78 added missing const 2021-05-23 21:03:11 +02:00
Linus Dierheimer 72fbcf94ff better Mutter detection 2021-05-23 20:35:24 +02:00
Linus Dierheimer 9f7f57dfd8 Better handling of Mutter in not GNOME systems 2021-05-23 19:56:49 +02:00
Linus Dierheimer bd3c236480 a bit better parsing of fonts 2021-05-23 19:40:34 +02:00
Linus Dierheimer 14932466f7 refactored usage of GSettings 2021-05-20 20:06:08 +02:00
Linus Dierheimer dbfa9dcc1f Merge pull request #54 from DarNCelsius/patch-1
Update README.md
2021-05-20 16:06:46 +02:00
DarN cd56317186 Update README.md 2021-05-19 20:08:29 +02:00
DarN 6b40174656 Update README.md
Added Gnome Terminal to Terminal Fonts section
2021-05-19 19:43:16 +02:00
Linus Dierheimer f1c3b5275f Merge pull request #51 from DarNCelsius/master
Refactored terminal font functions
2021-05-18 15:38:34 +02:00
DarN 5dc5ac6d29 Merge branch 'master' of https://github.com/DarNCelsius/fastfetch 2021-05-17 23:04:48 +02:00
DarN 5b69bd77a6 Terminal font refactor 2021-05-17 23:02:27 +02:00
Linus Dierheimer f19a1f40be Merge pull request #50 from DarNCelsius/master
Added terminal font support for Gnome Terminal
2021-05-17 21:28:17 +02:00
DarN 15ed8504bf Syntax change 2021-05-17 14:32:51 +02:00
DarN 4191bd8865 Merge branch 'master' of https://github.com/DarNCelsius/fastfetch 2021-05-17 14:24:15 +02:00
DarN 00c426c98a Added terminal font support for Gnome Terminal 2021-05-17 14:21:55 +02:00
Linus Dierheimer 2bb4407030 Merge pull request #49 from DarNCelsius/master
Enhanced LXQt DE Support
2021-05-17 11:16:11 +02:00
DarN 67edfd7f59 Added more file checks 2021-05-17 11:10:56 +02:00
DarN a1985bd7e8 Update README.md
Added LXQt version
2021-05-17 07:52:16 +02:00
DarN bfc9384ce3 Added Manjaro screenshot 2021-05-17 07:13:09 +02:00
DarN 82674a7d14 Rewrote with fast and slow modes 2021-05-17 06:34:48 +02:00
DarN 0531afadb7 Merge branch 'LinusDierheimer:master' into master 2021-05-17 06:15:10 +02:00
Linus Dierheimer 142d9c30e0 faster ffGetPropValue 2021-05-16 21:02:06 +02:00
Linus Dierheimer c8a9f06b52 added multiline and xml support to ffGetPropValue 2021-05-16 18:41:00 +02:00
Linus Dierheimer 5f71ef71da small syntactic changes 2021-05-16 15:10:15 +02:00
DarN dbde798a56 Added LXQt DE Version info 2021-05-16 14:00:04 +02:00
Linus Dierheimer 8af1cde10b Merge pull request #48 from DarNCelsius/master
Changed ffStrbufRemoveStringsA() iterator logic
2021-05-16 11:24:03 +02:00
DarN 852d6dcdcb Changed ffStrbufRemoveStringsA iterator logic 2021-05-16 07:36:14 +02:00
Linus Dierheimer c49fed470a Merge pull request #45 from DarNCelsius/patch-1
Change order of WMs in README.md
2021-05-15 18:20:48 +02:00
DarN f7e0e70b2f Tweaks
It's an OCD thing. 😀
2021-05-15 18:18:58 +02:00
Linus Dierheimer 44339971bd pass manjaro pacman branch to format string 2021-05-15 18:17:34 +02:00
Linus Dierheimer d12edd02bf Merge pull request #44 from DarNCelsius/master
Added branch detection for Manjaro
2021-05-15 18:12:55 +02:00
DarN 0dbcce84f8 Implemented changes 2021-05-15 18:12:10 +02:00
DarN 0e2deb3534 Rewrote with suggestions 2021-05-15 17:21:02 +02:00
Linus Dierheimer bbb46e7c66 better ffGetPropValue 2021-05-15 14:58:43 +02:00
DarN 25d23b020e Merge branch 'LinusDierheimer:master' into master 2021-05-15 14:52:28 +02:00
Linus Dierheimer 2ee2c68db5 ffGetPropValue trim result 2021-05-15 14:42:14 +02:00
DarN e400ee4490 Tweak 2021-05-15 13:44:16 +02:00
DarN bbd41e6c7a Merge branch 'LinusDierheimer:master' into master 2021-05-15 13:22:34 +02:00
DarN f24f6756b1 Added branch detection for Manjaro 2021-05-15 13:21:59 +02:00
Linus Dierheimer cedde7eced Merge pull request #43 from DarNCelsius/master
Renamed all instances of 'seperator'
2021-05-15 12:44:31 +02:00
DarN ca08e07c37 Renamed all instances of 'seperator' 2021-05-15 12:36:25 +02:00
Linus Dierheimer a72e3fed29 Merge pull request #42 from DarNCelsius/Grammar-fastfetch.c
Typos and grammar
2021-05-15 11:38:19 +02:00
DarN d815f624db Typos and grammar
I only did comments and help text - You might wanna change the "--seperate" option.
```
sep·a·rate
    a. To set, force, or keep apart: The referee separated the two boxers.
    b. To put space between; space apart or scatter: small farms that were separated one from another by miles of open land.
    c. To form a border or barrier between (two areas or groups): A hedge separates the two yards.
    d. To place in different groups; sort: separate mail by postal zones.
```
2021-05-15 08:39:20 +02:00
Linus Dierheimer 635f31eae1 better Host output 2021-05-14 16:03:19 +02:00
Linus Dierheimer 8128db974b updated README.md 2021-05-14 12:58:27 +02:00
Linus Dierheimer a841489280 updated README.md 2021-05-14 12:53:53 +02:00
Linus Dierheimer 0e94658683 updated README.md 2021-05-14 12:47:12 +02:00
Linus Dierheimer 225bcbe89a Mate support 2021-05-14 12:43:54 +02:00
Linus Dierheimer ae01d28094 btw preset 2021-05-14 10:44:41 +02:00
Linus Dierheimer d14a398f17 updated readme 2021-05-13 21:27:24 +02:00
Linus Dierheimer 1e82780de7 updated screenshot 2021-05-13 21:24:03 +02:00
Linus Dierheimer 35681ec09f flashfetch logo detection at compile time 2021-05-13 17:39:08 +02:00
Linus Dierheimer 0940064759 Merge pull request #40 from DarNCelsius/patch-3
Fixed dconf library load snafu
2021-05-13 14:09:05 +02:00
DarN 959750de3d Fixed dconf library load snafu
Typo :)
2021-05-13 13:53:29 +02:00
Linus Dierheimer 9e597aa253 fix ffGetPropValue 2021-05-13 12:48:00 +02:00
Linus Dierheimer 4d7a06ac97 ffGetPropValue 2021-05-13 12:27:44 +02:00
Linus Dierheimer f8868ae3c4 ffPrintError don't print regexes 2021-05-12 20:17:16 +02:00
Linus Dierheimer 7afc27e52f small syntactic changes 2021-05-12 20:13:56 +02:00
Linus Dierheimer 1ece13c36f Merge pull request #36 from DarNCelsius/master
Added system font recognition for xfce-terminal
2021-05-12 19:54:56 +02:00
DarN c549c7c868 Rewrote function with XFConf 2021-05-11 22:28:10 +02:00
DarN cac0c27807 Merge branch 'LinusDierheimer:master' into master 2021-05-11 20:18:05 +02:00
Linus Dierheimer 039b69f4a7 better ffSettings* functions 2021-05-11 20:06:17 +02:00
Linus Dierheimer 97ab892051 renamed printWMThemeFromConfig to keep consistency 2021-05-09 22:09:01 +02:00
Linus Dierheimer 6cfe826cd7 replaced wrong format string 2021-05-09 22:04:18 +02:00
Linus Dierheimer e89b326d57 basic XFCE support 2021-05-09 21:41:17 +02:00
DarN ef3f4d9fa8 Tweaks
Hopefully an improvement
2021-05-09 20:39:00 +02:00
DarN 89187e9758 Removed auto include 2021-05-09 14:07:20 +02:00
DarN cf4b3c54cf Added check for manual edits 2021-05-09 14:05:57 +02:00
DarN 719a5c999d Added system font recognition for xfce-terminal 2021-05-09 13:40:17 +02:00
Linus Dierheimer 7432fc7a19 fixed WM::getFromProcDir 2021-05-09 12:56:07 +02:00
Linus Dierheimer ed2b72e0cf fixed unnecessary format string evaluation in ffPrintError 2021-05-09 12:39:44 +02:00
Linus Dierheimer b5454c28bf unified some terminal font methods 2021-05-09 12:30:10 +02:00
Linus Dierheimer fc314e6ded Merge pull request #35 from DarNCelsius/master
Added Terminal Font for lxterminal
2021-05-09 12:24:34 +02:00
DarN 479188ec3e Added lxterminal 2021-05-09 09:04:31 +02:00
DarN 70c1b477d0 Added Terminal Font for lxterminal 2021-05-09 09:02:56 +02:00
DarN 0e236c7d6a Cleanup/Note on future changes 2021-05-09 08:03:09 +02:00
Linus Dierheimer cdf82e91b2 Merge pull request #33 from DarNCelsius/patch-2
Update README.md
2021-05-08 22:04:05 +02:00
DarN 476988f695 Update README.md
Tilix, grammar
2021-05-08 22:02:50 +02:00
Linus Dierheimer 123d19bb69 Merge pull request #32 from DarNCelsius/patch-1
Added Terminal Font for Tilix
2021-05-08 21:31:37 +02:00
DarN 099ddeea01 Tweaks
Are we there yet? :D
2021-05-08 21:26:01 +02:00
DarN eac718085e Implemented suggestions
Much better.
2021-05-08 21:17:04 +02:00
Linus Dierheimer 30953a31dc small changes to memory managment 2021-05-08 21:13:58 +02:00
DarN 4f83dc8396 Added Terminal Font for Tilix
This adds Terminal Font recognition for Tilix's default profile. I can't find a way to detect which profile is the active one.
2021-05-08 20:31:18 +02:00
Linus Dierheimer dfeb5c49e1 updated FFvariant 2021-05-08 18:58:40 +02:00
Linus Dierheimer b054fec8d8 updated README 2021-05-08 18:35:51 +02:00
Linus Dierheimer c8cd51da84 variant for dconf 2021-05-08 17:56:56 +02:00
Linus Dierheimer a6cd29057b Merge pull request #31 from DarNCelsius/patch-4
Grammar
2021-05-08 17:21:13 +02:00
Linus Dierheimer 62f1c5d059 dont show gpu index on single gpu systems 2021-05-08 17:18:59 +02:00
DarN e249c1590a Grammar
I couldn't help myself. 😁
2021-05-08 17:13:26 +02:00
Linus Dierheimer e4a61c3572 updated initCacheDir 2021-05-08 16:56:37 +02:00
Linus Dierheimer c749763f05 updated ffAppendFDContent 2021-05-08 16:24:57 +02:00
Linus Dierheimer bd316496a2 better handling of cache directory 2021-05-08 12:14:55 +02:00
Linus Dierheimer 79810542af Merge pull request #29 from DarNCelsius/patch-2
Added .cache folder
2021-05-08 11:48:33 +02:00
DarN f09aae6541 Added .cache folder 2021-05-08 11:37:50 +02:00
Linus Dierheimer 7609a24778 Cinnamon support 2021-05-08 11:20:17 +02:00
Linus Dierheimer eea74b085b prettier GPU output 2021-05-07 17:10:22 +02:00
Linus Dierheimer 4e49416394 fixed DE output when SESSION_DESKTOP == WM 2021-05-07 16:16:23 +02:00
Linus Dierheimer a389b89ff0 supprt for custom / multiple config dirs 2021-05-07 14:55:43 +02:00
Linus Dierheimer ebc42b8f8b default KWin theme 2021-05-07 11:02:09 +02:00
Linus Dierheimer ec941bcb33 improoved GTK detection 2021-05-07 10:34:30 +02:00
Linus Dierheimer 91b7967677 fixed battery status 2021-05-05 21:29:09 +02:00
Linus Dierheimer cb61fde75d fixed X- truncating on DE output number 2 2021-05-05 21:26:42 +02:00
Linus Dierheimer 20322c4fe4 fixed X- truncating on DE output 2021-05-05 21:18:29 +02:00
Linus Dierheimer a7784f5a88 better os output 2021-05-05 21:12:42 +02:00
Linus Dierheimer 89aa4470aa support for gsettings bool value 2021-05-05 20:20:41 +02:00
Linus Dierheimer 14d3e3b1b3 dont show unknown battery status 2021-05-05 19:52:50 +02:00
Linus Dierheimer bc870197d7 remove X- from DE names 2021-05-05 19:49:40 +02:00
Linus Dierheimer 9c26f9d988 fix help gpu-format 2021-05-05 19:31:58 +02:00
Linus Dierheimer 7da0c76703 fixed ffSettingsGetDConf 2021-05-04 21:25:50 +02:00
Linus Dierheimer 7ec32bf5d3 ffSettingsGet* 2021-05-04 19:48:23 +02:00
Linus Dierheimer bd2e1da3b4 small fixes 2021-05-02 21:45:47 +02:00
Linus Dierheimer 88d2530460 better transforming from gsettings to dconf 2021-05-02 21:30:05 +02:00
Linus Dierheimer 286095a09a transform GSettings path to dconf key style 2021-05-02 21:12:03 +02:00
Linus Dierheimer f47a44f47a added ffGSettingsGetValuePath 2021-05-02 21:06:01 +02:00
Linus Dierheimer 35504b33b1 ffGSettingsGetValue 2021-05-02 18:52:42 +02:00
Linus Dierheimer 56c0e9d068 Merge pull request #26 from DarNCelsius/patch-1
Removed leftover puts()
2021-05-02 08:36:28 +02:00
DarN 46306d913f Removed leftover puts() 2021-05-02 05:26:46 +02:00
Linus Dierheimer 6917164271 updated ffDConfGetValue 2021-05-01 21:55:15 +02:00
Linus Dierheimer 39f0f9c483 updated README 2021-05-01 21:31:03 +02:00
Linus Dierheimer fb17273ec4 close stderr of child process 2021-05-01 21:27:46 +02:00
Linus Dierheimer 85c7f4c772 basic gnome support 2021-05-01 21:22:07 +02:00
Linus Dierheimer 6e8e2e6c47 fixed dconf bug #2 2021-05-01 17:25:22 +02:00
Linus Dierheimer 97ae9e9d28 fixed dconf bug 2021-05-01 17:19:17 +02:00
Linus Dierheimer 94caa86998 TTY improvements 2021-05-01 16:54:59 +02:00
Linus Dierheimer e66e78fcc5 removed wrong paths used for testing 2021-05-01 16:06:12 +02:00
Linus Dierheimer 6eddc6105f ffDconfGetValue 2021-05-01 16:01:59 +02:00
Linus Dierheimer 671842d316 merge branch 2021-05-01 13:04:15 +02:00
Linus Dierheimer f3c8ecacbb greatly improved WM / DE detection 2021-05-01 13:03:30 +02:00
Linus Dierheimer 2618465121 Merge pull request #24 from DarNCelsius/patch-1
Update README.md
2021-04-29 15:47:19 +02:00
DarN 7f4dba8856 Update README.md
Typos, grammar and double Muffin
2021-04-29 15:34:55 +02:00
Linus Dierheimer e3f3699b26 improved WM detection 2021-04-28 21:48:23 +02:00
Linus Dierheimer c3f7ed5247 merged changes 2021-04-28 19:54:03 +02:00
Linus Dierheimer 01ada03c5c renamed calculate to detect 2021-04-28 19:53:30 +02:00
Linus Dierheimer 5c93d70341 Merge pull request #23 from DarNCelsius/patch-3
Updated help documentation
2021-04-28 19:52:01 +02:00
Linus Dierheimer bbeddbe403 Merge pull request #22 from DarNCelsius/patch-2
Added Package Manager support for Void Linux
2021-04-28 19:51:49 +02:00
DarN 644843a70d Implemented corrections 2021-04-28 19:50:04 +02:00
DarN d403c035d0 Updated help documentation
Quick grammar corrections as a bonus ;)
2021-04-28 19:45:43 +02:00
DarN dd31e05fde Update packages.c 2021-04-28 16:05:06 +02:00
DarN 99849ccd77 Debloat
...
2021-04-28 07:10:55 +02:00
DarN 4674d6c2fc Removed useless enum 2021-04-28 06:59:44 +02:00
DarN f938847459 Added missing else
No need to compare twice if the first one checks out...
2021-04-28 06:46:20 +02:00
DarN f4d2b35260 Added Package Manager support for Void Linux
This adds support for xbps.
2021-04-27 21:52:55 +02:00
Linus Dierheimer b83499d1ec updated readme 2021-04-26 21:56:21 +02:00
Linus Dierheimer 2449681f30 Merge pull request #21 from DarNCelsius/patch-1
Added additional WM Theme support
2021-04-26 21:50:13 +02:00
DarN dd709461a5 Small correction
Something is adding this include automatically...
2021-04-26 21:49:12 +02:00
DarN dbc576862e Made corrections
Something like this?
2021-04-26 21:46:57 +02:00
DarN a4d4b66679 Implemented suggested changes 2021-04-26 20:47:32 +02:00
DarN 6bcf3bab7c Cleaned up whitespace 2021-04-26 17:39:05 +02:00
DarN 41dc49f170 Update wmtheme.c 2021-04-26 17:27:12 +02:00
Linus Dierheimer 2a29d3ed17 better handling of WM / DE 2021-04-25 21:32:35 +02:00
DarN 6c612cbd9a Added additional WM Theme support
Supports LXQt, LXDE and Openbox
2021-04-25 21:18:56 +02:00
Linus Dierheimer e9cf1c0252 fixed a bug in ffStrbufTrimRight 2021-04-25 19:12:05 +02:00
Linus Dierheimer 7da4e5b69a ffStrbufTrimLeft now sets a null byte at the end 2021-04-25 19:03:59 +02:00
Linus Dierheimer ffd5b45b2c added support status to README.md 2021-04-25 16:16:40 +02:00
Linus Dierheimer 843a9811d0 paleofetch preset 2021-04-25 15:22:35 +02:00
Linus Dierheimer 6b066911dd garuda logo support 2021-04-25 15:07:31 +02:00
Linus Dierheimer f4a691ebd6 neofetch preset 2021-04-25 14:21:28 +02:00
Linus Dierheimer ec76f1c2d9 updated readme 2021-04-25 12:31:39 +02:00
Linus Dierheimer dffbd4f0f0 fixed a compiler warning 2021-04-25 11:56:01 +02:00
Linus Dierheimer f7b6fb2d4f presets 2021-04-25 11:48:25 +02:00
Linus Dierheimer 1b1d28f0ab color in format strings 2021-04-25 09:13:18 +02:00
Linus Dierheimer d469120e9b format string more like template language 2021-04-24 21:42:48 +02:00
Linus Dierheimer 36a4d095ed better handling of custom disk folders string 2021-04-24 16:29:05 +02:00
Linus Dierheimer ad122e9569 better handling of custom battery dir 2021-04-24 14:37:40 +02:00
Linus Dierheimer fc1c17932e fixed battery key index on multi battery systems 2021-04-24 14:25:27 +02:00
Linus Dierheimer 2ba1fb0868 typo in battery 2021-04-24 13:17:30 +02:00
Linus Dierheimer 49e112eeae revert stupid revert 2021-04-24 13:12:40 +02:00
Linus Dierheimer c5c3cecb93 support for more than 5 batteries 2021-04-24 13:05:43 +02:00
Linus Dierheimer 025dbecc4f Merge pull request #17 from DarNCelsius/patch-2
Added support for additional window managers
2021-04-24 11:58:04 +02:00
DarN 85c49f6873 Fixed cinnamon wm name... 2021-04-24 10:39:53 +02:00
DarN adce9fc53d Added support for additional window managers
Added support for Openbox, Cinnamon, XFCE and Wayfire window managers.
2021-04-24 10:25:39 +02:00
Linus Dierheimer c697f8ee80 print 144 instead of 145 refresh rate as this rate is more common 2021-04-23 21:13:50 +02:00
Linus Dierheimer eddc01290a Small improvements to host output 2021-04-23 20:59:13 +02:00
Linus Dierheimer 283e4f56e9 added missing mutex unlocks 2021-04-23 20:44:52 +02:00
Linus Dierheimer e28126f40e better result handling of calculation functions 2021-04-22 21:41:42 +02:00
Linus Dierheimer c12484ec6b Merge pull request #13 from DarNCelsius/patch-1
Added support for Void Linux
2021-04-21 19:50:34 +02:00
DarN b1df0ef98a Added support for Void Linux 2021-04-21 19:45:57 +02:00
Linus Dierheimer a64dc74923 updated screenshot 2021-04-18 22:51:55 +02:00
Linus Dierheimer 3e9ce54f63 --nocache option added 2021-04-18 19:23:54 +02:00
Linus Dierheimer 1d47eb0c60 shell version support 2021-04-18 15:19:21 +02:00
Linus Dierheimer 3e9678c899 small x11 improovement 2021-04-17 15:07:53 +02:00
Linus Dierheimer 4e54117238 better cpu name prettifier 2021-04-17 14:37:32 +02:00
Linus Dierheimer 44ddfc2a03 updated README.md 2021-04-17 12:21:59 +02:00
Linus Dierheimer eae92b6306 Merge pull request #12 from DarNCelsius/master
Thanks for the PR.
2021-04-17 12:03:23 +02:00
DarNCelsius b7c0c18497 Merge pull request #1 from DarNCelsius/DarNCelsius-patch-1
Update logo.c
2021-04-17 11:29:19 +02:00
DarNCelsius 61188b68a4 Update logo.c
Added Manjaro to known logos
2021-04-17 11:25:38 +02:00
Linus Dierheimer 51c38a2b01 terminalfont now gives an error on unknown terminals instead of printing TTY values 2021-04-16 20:44:46 +02:00
Linus Dierheimer 7b65316483 global results are now stored in state 2021-04-16 20:22:38 +02:00
Linus Dierheimer 86abc05cd4 removed obsolete recache condition 2021-04-16 17:51:17 +02:00
Linus Dierheimer 1d878215ae unified FFformatarg printing 2021-04-16 17:46:50 +02:00
Linus Dierheimer a145700500 wayland support 2021-04-16 16:49:33 +02:00
Linus Dierheimer f27f08a6e2 updated screenshot 2021-04-15 19:22:19 +02:00
Linus Dierheimer 9bc1f2a116 much more efficient caching 2021-04-15 18:59:26 +02:00
Linus Dierheimer ed598eaa35 updated readme 2021-04-09 19:48:16 +02:00
Linus Dierheimer 0ed54eddc4 plasma color theme detection 2021-04-09 19:21:56 +02:00
Linus Dierheimer 2b55a14c16 GTK dconf backend doesn't append already set values anymore 2021-04-09 16:11:53 +02:00
Linus Dierheimer 53c781aa21 project structure refactoring 2021-04-09 14:07:05 +02:00
Linus Dierheimer 0649b6e755 format once again works for theme/icons/font 2021-04-07 21:07:32 +02:00
Linus Dierheimer 9321241830 always unlock mutex on errors 2021-04-07 18:46:51 +02:00
Linus Dierheimer c698080581 basic multithreading 2021-04-07 17:36:03 +02:00
Linus Dierheimer ed7e186f4b faster plasma detection 2021-04-07 12:55:11 +02:00
Linus Dierheimer 5f23f2b027 small refactoring 2021-04-06 11:36:05 +02:00
Linus Dierheimer c543bcc29f optional gtk detection via dconf 2021-04-05 23:42:07 +02:00
Linus Dierheimer de312adb52 better gtk detection 2021-04-05 19:25:34 +02:00
Linus Dierheimer af430bd405 fixed a bug in battery where manufacturer was printed twice instead of model 2021-04-03 23:25:01 +02:00
Linus Dierheimer 1086c059b6 updated screenshot 2021-04-03 23:12:59 +02:00
Linus Dierheimer f25bca3dab wm theme detection for kde plasma 2021-04-03 23:10:14 +02:00
Linus Dierheimer e01d03f98d dont use format string if an error occures 2021-04-03 21:51:50 +02:00
Linus Dierheimer 67465d266e more efficient memory usage 2021-04-03 12:14:25 +02:00
Linus Dierheimer 08066a76f0 all keys can now be set! 2021-04-03 11:39:59 +02:00
Linus Dierheimer a8821cf6f0 some terminal improvements 2021-04-02 16:21:52 +02:00
Linus Dierheimer 9c26a76c9d WM is once again shown in a plasma session 2021-03-28 20:36:49 +02:00
Linus Dierheimer 307fc61184 better structure looping 2021-03-28 20:09:29 +02:00
Linus Dierheimer c44bd6dbc1 better disk output 2021-03-28 15:38:52 +02:00
Linus Dierheimer 184eafce20 better cpu output 2021-03-28 13:02:40 +02:00
Linus Dierheimer efc0322ed1 print default structure / modules 2021-03-27 19:26:58 +01:00
Linus Dierheimer b3c3614b6c fixed a bug in os module with version codename 2021-03-27 18:39:13 +01:00
Linus Dierheimer 693f8a33db fixed a bug in os module where it would show apostophes around values 2021-03-27 18:38:00 +01:00
Linus Dierheimer 44549e32d9 removed remaining strcat 2021-03-27 18:35:30 +01:00
Linus Dierheimer a1e90ba35c editorconfig 2021-03-27 18:14:19 +01:00
Linus Dierheimer 46ed1b34cb much faster reading of large files 2021-03-27 17:55:16 +01:00
Linus Dierheimer 23db257af9 much more values in os-format 2021-03-27 17:48:32 +01:00
Linus Dierheimer beb2e9608c dont print line if format evaluates to an empty string 2021-03-27 15:39:56 +01:00
Linus Dierheimer 055804a055 removed ffTrimTrailingWhitespace 2021-03-27 14:22:08 +01:00
Linus Dierheimer f61ffdb149 removed ffStrbufIsEmpty 2021-03-23 19:48:52 +01:00
Linus Dierheimer a0af3b0eb6 ffStrbufPutTo 2021-03-22 20:02:32 +01:00
Linus Dierheimer 2021709d72 if host version is None, dont show it 2021-03-22 19:52:59 +01:00
Linus Dierheimer 4d736fd5d0 updated .gitignore 2021-03-22 19:16:45 +01:00
Linus Dierheimer 02c450c218 rewinding file descriptor before trying reading again 2021-03-22 19:15:51 +01:00
Linus Dierheimer 071b2c6727 print logo in ffPrintAndSaveCachedValue 2021-03-21 20:46:20 +01:00
Linus Dierheimer 2004544528 using strbuf for loading/saving cached values 2021-03-21 20:42:07 +01:00
Linus Dierheimer c783bb9d97 renamed spacer to spacing 2021-03-21 17:02:31 +01:00
Linus Dierheimer 101d19a015 ffGetFileContent now uses FFstrbuf for preventing buffer overflows 2021-03-21 16:52:17 +01:00
Linus Dierheimer 0d3500c66f command help 2021-03-21 11:18:06 +01:00
Linus Dierheimer a848798e97 Merge pull request #7 from saloniamatteo/master
Locale: implement /etc/locale.conf fallbacks
2021-03-21 09:58:49 +01:00
saloniamatteo 9d5481e83a Sane indentation: use tabs instead of spaces 2021-03-20 11:24:35 +01:00
saloniamatteo 05fe281141 Fully implement LANG fallbacks 2021-03-20 11:20:37 +01:00
saloniamatteo 3d27ecaba8 Free pointer to file 2021-03-20 10:47:49 +01:00
saloniamatteo e70f06087c Merge branch 'master' of github.com:saloniamatteo/fastfetch 2021-03-20 10:47:18 +01:00
saloniamatteo e2986b198f Free pointer to file 2021-03-20 10:46:56 +01:00
Salonia Matteo e479b62c73 Merge pull request #2 from LinusDierheimer/master
Sync from upstream pt. 2
2021-03-20 09:45:58 +00:00
saloniamatteo e531278e62 Experimental: use fallback for LANG 2021-03-20 10:39:05 +01:00
Salonia Matteo a8ca2ce825 Sync from upstream 2021-03-20 07:09:02 +00:00
Linus Dierheimer 92b1247683 print remaining logo by default 2021-03-19 21:23:15 +01:00
Linus Dierheimer dd19fcfded Merge pull request #4 from saloniamatteo/master
Thanks for this contribution. Note that i dont test on Ubuntu / Debian (yet), so probably a lot of stuff wont work on those platforms.
2021-03-19 21:03:23 +01:00
Linus Dierheimer db35000e39 Merge branch 'master' into master 2021-03-19 21:02:23 +01:00
Linus Dierheimer 1ceb5c91ac format options for every output! 2021-03-19 20:57:07 +01:00
Matteo cddfc083c3 Merge branch 'master' into master 2021-03-19 18:27:03 +00:00
saloniamatteo f358e07b84 Update logo list 2021-03-19 19:21:22 +01:00
saloniamatteo 74b315a1d1 Update logo list 2021-03-19 19:21:05 +01:00
saloniamatteo 9d28df2922 Sync with upstream 2021-03-19 19:19:46 +01:00
saloniamatteo 016acb8e9e src/logo.c: Fix potential security flaw when using printf
Warning: Format string is not a literal string, when using printf
without "%s" (eg. printf(something), instead of printf("%s", something))
2021-03-19 19:12:52 +01:00
saloniamatteo e53f84bb27 Add debian logo 2021-03-19 19:09:14 +01:00
saloniamatteo fd3215ed3b Add debian logo 2021-03-19 19:08:46 +01:00
saloniamatteo be9272c2e9 Add ubuntu logo 2021-03-19 18:45:30 +01:00
saloniamatteo eb7ce05193 Fix logo spacing 2021-03-19 17:56:30 +01:00
Linus Dierheimer 5c6bbbf677 fixed artix logo width 2021-03-19 17:53:48 +01:00
Linus Dierheimer cf9af7023f fixed bug in artix logo 2021-03-19 17:51:52 +01:00
Linus Dierheimer 370de39169 Merge pull request #3 from saloniamatteo/master
Add support for Artix
2021-03-19 17:48:34 +01:00
saloniamatteo 05f11c6c69 Add support for Artix, fix code block in README 2021-03-19 08:43:29 +01:00
saloniamatteo a0169d83e5 Add support for Artix 2021-03-19 08:39:27 +01:00
Linus Dierheimer 37dd06590a --host-format 2021-03-12 12:16:41 +01:00
Linus Dierheimer 8e9cb079b0 new screenshot 2021-03-12 10:31:39 +01:00
Linus Dierheimer a6c153da95 --os-format 2021-03-12 10:17:49 +01:00
Linus Dierheimer b9c7324aa5 resolution options 2021-03-11 22:15:48 +01:00
Linus Dierheimer c988777c79 small changes to package options 2021-03-11 19:54:34 +01:00
Linus Dierheimer 0169507489 packages options 2021-03-11 19:40:46 +01:00
Linus Dierheimer 33be85c4bc terminal font 2021-03-11 17:21:18 +01:00
Linus Dierheimer abd797a0bf added .gitattributes 2021-03-07 20:56:01 +01:00
Linus Dierheimer aa5b5f3caf kernel options 2021-03-07 20:35:17 +01:00
Linus Dierheimer 6cc99423c9 performance tests 2021-03-07 20:05:00 +01:00
Linus Dierheimer 43022c0129 updated README.md 2021-03-07 13:25:32 +01:00
Linus Dierheimer 6e11609432 some content in README.md 2021-03-07 13:12:45 +01:00
Linus Dierheimer 2240264d02 --host-version 2021-03-07 11:58:24 +01:00
Linus Dierheimer dbeaa342ba bash completion improvements 2021-03-07 11:11:21 +01:00
Linus Dierheimer 16af140f7a basic bash completion 2021-03-06 22:40:05 +01:00
Linus Dierheimer 923faa63e5 --os-architecture option 2021-03-06 11:28:38 +01:00
Linus Dierheimer bc13b51b5a support for --shell-path 2021-03-05 23:26:05 +01:00
Linus Dierheimer 9122daa63a seperator support 2021-03-05 23:00:28 +01:00
Linus Dierheimer 61b369ea19 version information in config file 2021-03-05 21:49:13 +01:00
Linus Dierheimer 22cfe4df1f basic Window Manager detection 2021-03-05 21:38:35 +01:00
Linus Dierheimer f65105d181 battery-format 2021-03-04 20:49:12 +01:00
Linus Dierheimer f67a5f3879 prettier default config 2021-03-03 21:42:40 +01:00
Linus Dierheimer c1fb9525b8 battery options 2021-03-03 21:03:12 +01:00
Linus Dierheimer b95dd4ce17 fixed a missing newline in help output 2021-03-03 20:05:21 +01:00
Linus Dierheimer db6d2eb3a3 structure and values can be set in fastfetch via command line and file! 2021-03-03 19:59:39 +01:00
Linus Dierheimer 4dffbb0bb7 battery rework 2021-03-01 19:53:20 +01:00
Linus Dierheimer 7248daaa48 loading pci libs dynamically 2021-02-28 17:38:26 +01:00
Linus Dierheimer 0617b597f9 flashfetch loads default values too now 2021-02-28 17:10:12 +01:00
Linus Dierheimer e06aab6836 use strcasecmp in some cases 2021-02-27 21:10:27 +01:00
Linus Dierheimer d1cec7d1e5 trim trailing whitespaces from keys 2021-02-27 21:04:50 +01:00
Linus Dierheimer 56751e4581 you can now load default values from files 2021-02-27 20:50:13 +01:00
Linus Dierheimer d3db1066e2 reading structure from file 2021-02-27 20:31:54 +01:00
Linus Dierheimer 0c3a562ec6 minor refactoring 2021-02-27 19:22:28 +01:00
Linus Dierheimer 1cda1eb653 refactored internal state keeping 2021-02-27 18:30:05 +01:00
Linus Dierheimer b44ab16dd1 refactored project structure 2021-02-27 16:40:05 +01:00
Linus Dierheimer 558639086a error handling in resolution.c 2021-02-27 14:46:31 +01:00
Linus Dierheimer 48a436ee78 reworked resolution 2021-02-27 14:40:03 +01:00
Linus Dierheimer 16239be51c no color options 2021-02-25 18:38:00 +01:00
Linus Dierheimer 3d902c1c86 removed testing line from CMakeLists.txt 2021-02-22 20:54:05 +01:00
Linus Dierheimer 0ec63d64fa fixed a bug in caching 2021-02-22 20:53:12 +01:00
Linus Dierheimer fea8e371e4 --version implementation 2021-02-22 20:36:25 +01:00
Linus Dierheimer 7cbe1c2359 increased possible input size for color 2021-02-22 19:34:34 +01:00
Linus Dierheimer 4b4f92eb74 fixed some compiler warnings 2021-02-22 17:14:46 +01:00
Linus Dierheimer df3dcb7ede caching of some values 2021-02-22 16:52:51 +01:00
Linus Dierheimer f14e84606f fixed a bug where the program would coredump on uptime < 60s 2021-02-22 14:01:15 +01:00
Linus Dierheimer 85bcf00cf8 cleaned main up 2021-02-22 13:45:14 +01:00
Linus Dierheimer 11b5d6e138 uint16_t for seperator, for those madmans out ther 2021-02-20 20:12:57 +01:00
Linus Dierheimer e3616d8b72 the seperator can now be set 2021-02-20 20:00:06 +01:00
Linus Dierheimer 61bac93809 setting color works 2021-02-20 19:32:57 +01:00
Linus Dierheimer 5d32a782a2 check if showErrors in ffPrintError 2021-02-20 19:08:23 +01:00
Linus Dierheimer 626badd3c8 fixed a bug where color is not set 2021-02-19 18:07:46 +01:00
Linus Dierheimer 12ed7a9812 logo system reqork 2021-02-19 18:02:36 +01:00
Linus Dierheimer f533767569 removed obsolete ffRead functions 2021-02-19 16:38:54 +01:00
Linus Dierheimer a8f165e5c9 better error handling 2021-02-19 16:23:41 +01:00
Linus Dierheimer c5a9b9d428 fixed a bug that caused segfault with -O3 2021-02-19 10:07:00 +01:00
Linus Dierheimer 41120ef582 not ignoring the result of fscanf 2021-02-18 23:04:31 +01:00
Linus Dierheimer 4b2c4a8821 added LICENSE and README 2021-02-18 22:30:16 +01:00
Linus Dierheimer ebb14afb26 initial work 2021-02-18 22:25:36 +01:00
Linus Dierheimer da5ab1c187 Initial commit 2021-02-18 22:25:20 +01:00
144 changed files with 17294 additions and 69996 deletions
+17
View File
@@ -0,0 +1,17 @@
root = true
[*]
end_of_line = lf
indent_style = space
tab_width = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.{md,fflogo}]
trim_trailing_whitespace = false
[*.{txt,fflogo}]
insert_final_newline = false
[*.yml]
tab_width = 2
+2
View File
@@ -0,0 +1,2 @@
*.h linguist-language=c
*.c linguist-language=c
+1
View File
@@ -0,0 +1 @@
custom: paypal.me/linusdierheimer
+43
View File
@@ -0,0 +1,43 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
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
```
Output of `fastfetch --load-config devinfo`:
```
//paste here
```
Output of `fastfetch --load-config devinfo-verbose`:
<!--
Note that this output will contain you public IP. If it is not relevant for the issue, feel free to remove it before uploading.
-->
```
//paste here
```
Output of `fastfetch --list-features`:
```
//paste here
```
<!--
If 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 too much work) for you, post the output of `fastfetch --show-errors --recache --multithreading false --disable-linewrap false`.
-->
+14
View File
@@ -0,0 +1,14 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
# Current state:
# Wanted state:
# Why the change is sensible:
+18
View File
@@ -0,0 +1,18 @@
---
name: Logo request
about: Request a new logo
title: ''
labels: logo request
assignees: ''
---
# OS
```
paste content of /etc/os-release here. If this file doesn't exist, describe a way to identify the distro.
```
# Ascii
```
paste ascii art here. If you leave this empty, i will try to find the logo myself.
```
+37
View File
@@ -0,0 +1,37 @@
name: manage pull requests
on: pull_request
jobs:
check:
name: manage pull request
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: checkout repository
uses: actions/checkout@v2
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
- name: configure project
run: cmake -DBUILD_TESTS=On .
- name: build project
run: cmake --build . -j$(nproc) --target package
- name: run fastfetch
run: ./fastfetch --recache --disable-linewrap false --hide-cursor false --show-errors true
- name: run flashfetch
run: ./flashfetch
- name: run tests
run: ctest
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v1
+60
View File
@@ -0,0 +1,60 @@
name: manage pushes
on:
push:
branches: [ master ]
jobs:
manage:
name: manage push
runs-on: ubuntu-latest
permissions:
contents: write
security-events: write
steps:
- name: checkout repository
uses: actions/checkout@v2
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
- name: configure project
# We reuse the build binary only for the releases.
# We set tweak version to off, because it is wrong, as git tag will happen after this step. Releases don't have a tweak, so this is ok.
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . -j$(nproc) --target package
- name: run fastfetch
run: ./fastfetch --recache --disable-linewrap false --hide-cursor false --show-errors true
- name: run flashfetch
run: ./flashfetch
- name: run tests
run: ctest
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v1
- name: get fastfetch version
id: get_version_fastfetch
run: echo "::set-output name=release::$(./fastfetch --version-raw)"
- name: get latest release version
id: get_version_release
uses: pozetroninc/github-action-get-latest-release@master
with:
repository: ${{ github.repository }}
- name: create release
if: steps.get_version_fastfetch.outputs.release != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ steps.get_version_fastfetch.outputs.release }}
commit: ${{ github.sha }}
artifacts: ./fastfetch-*.*
+7 -3
View File
@@ -1,3 +1,7 @@
/.cache
/.vscode
/build*
**/build/
**/.vscode/
**/.cache/
**/.kdev4/
cscope.*
tags
fastfetch.kdev4
+42
View File
@@ -0,0 +1,42 @@
# 1.6.3
Fixes installing presets in their own directory (#212)
# 1.6.2
Releasing this, so void linux can package fastfetch.
Logos:
* Rosa linux (#206)
* KISS linux (@draumaz, #207)
* LangitKetujuh (@hervyqa, #208)
Bugfixes:
* Using musl as libc does work now (#210)
* XBPS packages are once again printed (#209)
* configured target dirs are applied to install directories too
* empty XDG_* env vars don't cause a crash anymore
# 1.6.1
Fixes build on android (#205)
# 1.6.0
Features:
* Detect QT on more DEs than just KDE Plasma. The [Plasma] category was therefore renamed to [QT]
* Alacritty font detection
* Load `/etc/fastfetch/config.conf` before user config
* Disk: print one decimal point if size < 100GB
* `--title-fqdn` option, to print fully qualified domain name instead of host name in title
Logos:
* updated old NixOS logo
Bugfixes:
* Correctly detect GTK on DEs that store their settings in dconf
* Correctly detect NixOS packages
* Mutter WM detected once again
* Show full NixOS version in OS output
* Don't segfault if an invalid structure is given
* WSL doesn't output GPU anymore, as the name is always meaningless
+555
View File
@@ -0,0 +1,555 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs
project(fastfetch
VERSION 1.6.3
LANGUAGES C
)
#####################
# Configure options #
#####################
OPTION(ENABLE_LIBPCI "Enable libpci" ON)
OPTION(ENABLE_VULKAN "Enable vulkan" ON)
OPTION(ENABLE_WAYLAND "Enable wayland-client" ON)
OPTION(ENABLE_XCB_RANDR "Enable xcb-randr" ON)
OPTION(ENABLE_XCB "Enable xcb" ON)
OPTION(ENABLE_XRANDR "Enable xrandr" ON)
OPTION(ENABLE_X11 "Enable x11" ON)
OPTION(ENABLE_GIO "Enable gio-2.0" ON)
OPTION(ENABLE_DCONF "Enable dconf" ON)
OPTION(ENABLE_DBUS "Enable dbus-1" ON)
OPTION(ENABLE_XFCONF "Enable libxfconf-0" ON)
OPTION(ENABLE_SQLITE3 "Enable sqlite3" ON)
OPTION(ENABLE_RPM "Enable rpm" ON)
OPTION(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON)
OPTION(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON)
OPTION(ENABLE_ZLIB "Enable zlib" ON)
OPTION(ENABLE_CHAFA "Enable chafa" ON)
OPTION(ENABLE_EGL "Enable egl" ON)
OPTION(ENABLE_GLX "Enable glx" ON)
OPTION(ENABLE_OSMESA "Enable osmesa" ON)
OPTION(ENABLE_OPENCL "Enable opencl" ON)
OPTION(BUILD_TESTS "Build tests" OFF) # Also create test executables
OPTION(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds
#############################
# Compile time dependencies #
#############################
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
####################
# Compiler options #
####################
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wconversion")
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_SUPPORTED)
if(IPO_SUPPORTED)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
#######################
# Target FS structure #
#######################
if(NOT TARGET_DIR_ROOT)
if(NOT ANDROID)
set(TARGET_DIR_ROOT "")
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()
#################
# Tweak version #
#################
if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
execute_process(
COMMAND git describe --tags
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
OUTPUT_VARIABLE PROJECT_VERSION_TWEAK
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX MATCH "-[0-9]+" PROJECT_VERSION_TWEAK "${PROJECT_VERSION_TWEAK}")
endif()
#############
# Text data #
#############
function(fastfetch_load_text FILENAME OUTVAR)
file(READ "${FILENAME}" TEMP)
string(REPLACE "\n" "\\n" TEMP "${TEMP}")
string(REPLACE "\"" "\\\"" TEMP "${TEMP}")
string(REPLACE "$\\" "" TEMP "${TEMP}")
set("${OUTVAR}" "${TEMP}" PARENT_SCOPE)
endfunction(fastfetch_load_text)
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
fastfetch_load_text(src/data/config_system.txt DATATEXT_CONFIG_SYSTEM)
fastfetch_load_text(src/data/config_user.txt DATATEXT_CONFIG_USER)
fastfetch_load_text(src/data/modules.txt DATATEXT_MODULES)
fastfetch_load_text(src/data/help.txt DATATEXT_HELP)
fastfetch_load_text(src/data/help_color.txt DATATEXT_HELP_COLOR)
fastfetch_load_text(src/data/help_format.txt DATATEXT_HELP_FORMAT)
fastfetch_load_text(src/data/help_config.txt DATATEXT_HELP_CONFIG)
######################
# Configure config.h #
######################
configure_file(src/fastfetch_config.h.in fastfetch_config.h)
#######################
# libfastfetch target #
#######################
add_library(libfastfetch OBJECT
src/util/FFstrbuf.c
src/util/FFlist.c
src/util/FFvaluestore.c
src/common/init.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/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/qt.c
src/detection/gtk.c
src/detection/terminalShell.c
src/detection/vulkan.c
src/detection/media.c
src/detection/datetime.c
src/detection/temps.c
src/detection/title.c
src/detection/displayserver/displayServer.c
src/detection/displayserver/wayland.c
src/detection/displayserver/xcb.c
src/detection/displayserver/xlib.c
src/detection/displayserver/wmde.c
src/modules/break.c
src/modules/custom.c
src/modules/title.c
src/modules/separator.c
src/modules/os.c
src/modules/host.c
src/modules/kernel.c
src/modules/uptime.c
src/modules/processes.c
src/modules/packages.c
src/modules/shell.c
src/modules/resolution.c
src/modules/de.c
src/modules/wm.c
src/modules/wmtheme.c
src/modules/theme.c
src/modules/icons.c
src/modules/font.c
src/modules/cursor.c
src/modules/terminal.c
src/modules/terminalfont.c
src/modules/cpu.c
src/modules/cpuUsage.c
src/modules/gpu.c
src/modules/memory.c
src/modules/disk.c
src/modules/battery.c
src/modules/locale.c
src/modules/vulkan.c
src/modules/localip.c
src/modules/publicip.c
src/modules/player.c
src/modules/song.c
src/modules/datetime.c
src/modules/date.c
src/modules/time.c
src/modules/colors.c
src/modules/opengl.c
src/modules/opencl.c
)
if(ENABLE_LIBPCI)
pkg_check_modules(LIBPCI libpci)
if(LIBPCI_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBPCI=1)
else()
message(WARNING "Package libpci not found. Building without support.")
endif()
endif()
if(ENABLE_VULKAN)
pkg_check_modules(VULKAN vulkan)
if(VULKAN_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_VULKAN=1)
else()
message(WARNING "Package vulkan not found. Building without support.")
endif()
endif()
if(ENABLE_WAYLAND)
pkg_check_modules (WAYLAND wayland-client)
if(WAYLAND_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WAYLAND=1)
else()
message(WARNING "Package wayland-client not found. Building without support.")
endif()
endif()
if(ENABLE_XCB_RANDR)
pkg_check_modules(XCB_RANDR xcb-randr)
if(XCB_RANDR_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XCB_RANDR=1)
else()
message(WARNING "Package xcb-randr not found. Building without support.")
endif()
endif()
if(ENABLE_XCB)
pkg_check_modules (XCB xcb)
if(XCB_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XCB=1)
else()
message(WARNING "Package xcb not found. Building without support.")
endif()
endif()
if(ENABLE_XRANDR)
pkg_check_modules(XRANDR xrandr)
if(XRANDR_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XRANDR=1)
else()
message(WARNING "Package xrandr not found. Building without support.")
endif()
endif()
if(ENABLE_X11)
pkg_check_modules(X11 x11)
if(X11_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_X11=1)
else()
message(WARNING "Package x11 not found. Building without support.")
endif()
endif()
if(ENABLE_GIO)
pkg_check_modules(GIO gio-2.0)
if(GIO_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GIO=1)
else()
message(WARNING "Package gio-2.0 not found. Building without support.")
endif()
endif()
if(ENABLE_DCONF)
pkg_check_modules(DCONF dconf)
if(DCONF_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_DCONF=1)
else()
message(WARNING "Package dconf not found. Building without support.")
endif()
endif()
if(ENABLE_DBUS)
pkg_check_modules(DBUS dbus-1)
if(DBUS_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_DBUS=1)
else()
message(WARNING "Package dbus-1 not found. Building without support.")
endif()
endif()
if(ENABLE_XFCONF)
pkg_check_modules(XFCONF libxfconf-0)
if(XFCONF_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XFCONF=1)
else()
message(WARNING "Package libxfconf-0 not found. Building without support.")
endif()
endif()
if(ENABLE_SQLITE3)
pkg_check_modules(SQLITE3 sqlite3)
if(SQLITE3_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_SQLITE3=1)
else()
message(WARNING "Package sqlite3 not found. Building without support.")
endif()
endif()
if(ENABLE_RPM)
pkg_check_modules(RPM rpm)
if(RPM_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_RPM=1)
else()
message(WARNING "Package 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)
if(IMAGEMAGICK6_FOUND OR IMAGEMAGICK7_FOUND)
pkg_check_modules(CHAFA chafa>=1.10)
if(CHAFA_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CHAFA=1)
else()
message(WARNING "Package chafa>=1.10 not found. Building without support.")
endif()
else()
message(WARNING "Chafa not enabled, because neither ImageMagick6 nor ImageMagick7 were found. Building without support.")
endif()
endif()
if(ENABLE_EGL)
pkg_check_modules(EGL egl)
if(EGL_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EGL=1)
else()
message(WARNING "Package egl not found. Building without support.")
endif()
endif()
if(ENABLE_GLX)
pkg_check_modules(GLX glx)
if(GLX_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GLX=1)
else()
message(WARNING "Package glx not found. Building without support.")
endif()
endif()
if(ENABLE_OSMESA)
pkg_check_modules(OSMESA osmesa)
if(OSMESA_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_OSMESA=1)
else()
message(WARNING "Package osmesa not found. Building without support.")
endif()
endif()
if(ENABLE_OPENCL)
pkg_check_modules(OPENCL OpenCL)
if(OPENCL_FOUND)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_OPENCL=1)
else()
message(WARNING "Package opencl not found. Building without support.")
endif()
endif()
target_include_directories(libfastfetch
PUBLIC ${PROJECT_BINARY_DIR}
PUBLIC ${PROJECT_SOURCE_DIR}/src
PRIVATE ${LIBPCI_INCLUDE_DIRS}
PRIVATE ${VULKAN_INCLUDE_DIRS}
PRIVATE ${WAYLAND_INCLUDE_DIRS}
PRIVATE ${XCB_RANDR_INCLUDE_DIRS}
PRIVATE ${XCB_INCLUDE_DIRS}
PRIVATE ${XRANDR_INCLUDE_DIRS}
PRIVATE ${X11_INCLUDE_DIRS}
PRIVATE ${GIO_INCLUDE_DIRS}
PRIVATE ${DCONF_INCLUDE_DIRS}
PRIVATE ${DBUS_INCLUDE_DIRS}
PRIVATE ${XFCONF_INCLUDE_DIRS}
PRIVATE ${SQLITE3_INCLUDE_DIRS}
PRIVATE ${RPM_INCLUDE_DIRS}
PRIVATE ${IMAGEMAGICK7_INCLUDE_DIRS}
PRIVATE ${IMAGEMAGICK6_INCLUDE_DIRS}
PRIVATE ${ZLIB_INCLUDE_DIRS}
PRIVATE ${CHAFA_INCLUDE_DIRS}
PRIVATE ${VULKAN_INCLUDE_DIRS}
PRIVATE ${EGL_INCLUDE_DIRS}
PRIVATE ${GLX_INCLUDE_DIRS}
PRIVATE ${OSMESA_INCLUDE_DIRS}
PRIVATE ${OPENCL_INCLUDE_DIRS}
)
target_link_libraries(libfastfetch
PRIVATE ${CMAKE_DL_LIBS}
PRIVATE Threads::Threads
)
######################
# Executable targets #
######################
add_executable(fastfetch
src/fastfetch.c
)
target_link_libraries(fastfetch
PRIVATE libfastfetch
)
add_executable(flashfetch
src/flashfetch.c
)
target_link_libraries(flashfetch
PRIVATE libfastfetch
)
###################
# Testing targets #
###################
if (BUILD_TESTS)
add_executable(fastfetch-test-strbuf
tests/strbuf.c
)
target_link_libraries(fastfetch-test-strbuf
PRIVATE libfastfetch
)
enable_testing()
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
endif()
##################
# install target #
##################
#https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT.html
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${TARGET_DIR_USR}" CACHE PATH "..." FORCE)
endif()
if(NOT CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "${TARGET_DIR_ROOT}/etc")
endif()
include(GNUInstallDirs)
install(
TARGETS fastfetch flashfetch
DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
install(
FILES "${CMAKE_SOURCE_DIR}/src/data/config_system.txt"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/${CMAKE_PROJECT_NAME}"
RENAME "config.conf"
)
install(
FILES "${CMAKE_SOURCE_DIR}/completions/bash"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions"
RENAME "${CMAKE_PROJECT_NAME}"
)
install(
DIRECTORY "${CMAKE_SOURCE_DIR}/presets"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/${CMAKE_PROJECT_NAME}"
)
install(
FILES "${CMAKE_SOURCE_DIR}/LICENSE"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/licenses/${CMAKE_PROJECT_NAME}"
)
##################
# package target #
##################
set(CPACK_GENERATOR "DEB;RPM;TGZ;ZIP")
set(CPACK_SET_DESTDIR ON)
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_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_RPM_PACKAGE_LICENSE "MIT")
include(CPack)
+36
View File
@@ -0,0 +1,36 @@
# Development help
This file is not an official documentation!
Here i just add things that are easy to forget.
## Features i am planning to implement
### Specific
- [ ] Split the project in different libs / executables, all linking static by default:
- `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
- [ ] Better OS output for all possible combinations of /etc/os-release variables.
- [ ] Find wayland compositor by looking at \${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY:-wayland-0}
- [ ] Make LocalIP module more configurable
- [ ] Automatic migrate old config files to newer versions
- [ ] ZSH completions
- [ ] Fish completions
- [ ] 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
### General
- More presets
- More logos
- More package managers
- More DE detections
- More WM theme detections
- More terminal font detections
- Performance optimizations
- More module specific options
- Better error handling, especially the messages shown when using --show-errors
- Using package managers libraries for package count detection instead own. E.g. using libalpm instead of counting files in /var/lib/pacman/local
- Better documentation (especially default config file and the various --help options. Colored output?)
- General feature parity with neofetch, to demonstrate supremity of c
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Linus Dierheimer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+97 -16
View File
@@ -1,29 +1,110 @@
# Fastfetch Benchmark Data
# fastfetch
This branch stores continuous performance benchmark data for Fastfetch on Linux, macOS, and Windows.
fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying them in a pretty way. It is written in c to achieve much better performance, in return only Linux and Android are supported. It also uses mechanisms like multithreading and caching to finish as fast as possible.
The output on my personal machine with default configurations looks like this:
<img src="screenshots/example.png" alt="example output" width="100%"/>
The data is generated and updated automatically by GitHub Actions. Please do not edit generated benchmark files manually.
## Customization
## Benchmark Dashboard
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 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.
<https://fastfetch-cli.github.io/fastfetch/dev/bench/>
## Dependencies
## Metrics
Fastfetch dynamically loads needed libraries if they are available. Therefore its only hard dependencies are `libc` (any implementation of the c standard library), `libdl` and `libpthread`. They are all shipped with [`glibc`](https://www.gnu.org/software/libc/), which is already installed on most linux distributions, so you probably don't have to worry about it.
The benchmark data includes:
The following libraries are used if present at runtime:
* [`libpci`](https://github.com/pciutils/pciutils): GPU output.
* [`libvulkan`](https://www.vulkan.org/): Vulkan module & fallback for GPU output.
* [`libxcb-randr`](https://xcb.freedesktop.org/),
[`libXrandr`](https://gitlab.freedesktop.org/xorg/lib/libxrandr),
[`libxcb`](https://xcb.freedesktop.org/),
[`libX11`](https://gitlab.freedesktop.org/xorg/lib/libx11): At least one of them sould be present in X11 sessions for better resolution detection and faster WM detection. The `*randr` ones provide multi monitor support The `libxcb*` ones usually have better performance.
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance and output in wayland sessions. Supports different refresh rates per monitor.
* [`libGIO`](https://developer.gnome.org/gio/unstable/): Needed for values that are only stored GSettings.
* [`libDConf`](https://developer.gnome.org/dconf/unstable/): Needed for values that are only stored in DConf + Fallback for GSettings.
* [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel or kitty graphics protocol.
* [`libchafa`](https://github.com/hpjansson/chafa): Image output as ascii art.
* [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol.
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song.
* [`libEGL`](https://www.khronos.org/registry/EGL/),
[`libGLX`](https://dri.freedesktop.org/wiki/GLX/),
[`libOSMesa`](https://docs.mesa3d.org/osmesa.html): At least one of them is needed by the OpenGL module for gl context creation.
* [`libOpenCL`](https://www.khronos.org/opencl/): OpenCL module
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
* [`libsqlite3`](https://www.sqlite.org/index.html): Needed for rpm package count.
* [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE.
- Execution time for each Fastfetch module, measured in milliseconds;
- Total Fastfetch process execution time, measured in milliseconds.
## Support status
All categories not listed here should work without needing a specific implementation.
All metrics use the “smaller is better” comparison mode.
##### Available Modules
```
Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resolution, DE, WM, WMTheme, Theme, Icons, Font, Cursor, Terminal, Terminal Font, CPU, CPUUsage, GPU, Memory, Disk, Battery, Player, Song, Vulkan, OpenGL, OpenCL, LocalIP, PublicIP, DateTime, Date, Time, Locale, Colors, Break, Custom
```
## Update Workflow
##### Logos
```
Alpine, Android, Arch, Arco, Artix, Bedrock, CachyOS, CentOS, Debian, Devuan, Deepin, Endeavour, Fedora, Garuda, Gentoo, KDE Neon, KISS, Kubuntu, LangitKetujuh, Linux, Manjaro, Mint, NixOS, OpenSUSE, OpenSUSE Tumbleweed, OpenSUSE LEAP, Pop!_OS, RebornOS, RedstarOS, Rocky, Rosa, 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.
Benchmark data is generated from the `dev` branch CI workflow and updated after all platform build jobs have completed.
##### Package managers
```
Pacman, dpkg, rpm, emerge, xbps, nix, Flatpak, Snap
```
Related workflow files:
##### WM themes
```
KWin, Mutter, Muffin, Marco, XFWM, Openbox (LXDE, LXQT & without DE)
```
- `.github/workflows/build-benchmark.yml`
- `.github/workflows/ci.yml`
##### DE versions
```
KDE Plasma, Gnome, Cinnamon, Mate, XFCE4, LXQt
```
Commit information and dates are recorded automatically by the Continuous Benchmark Action.
##### Terminal fonts
```
konsole, gnome-terminal-server, tilix, xfce4-terminal, alacritty, lxterminal, TTY
```
## Building
fastfetch uses [`cmake`](https://cmake.org/) and [`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/) for building. The simplest steps to build the fastfetch and flashfetch binaries are:
```bash
mkdir -p build
cd build
cmake ..
cmake --build . --target fastfetch --target flashfetch
```
If pkg-config fails to find the headers for a library listed in [dependencies](#dependencies), fastfetch will simply build without support for that specific feature. This means, it won't look for it at runtime and just act like it isn't available.
## Packaging
### Repositories
[![Packaging status](https://repology.org/badge/vertical-allrepos/fastfetch.svg?header=)](https://repology.org/project/fastfetch/versions)
### Manual
* DEB / RPM package: `cmake --build . --target package`
* Install directly: `cmake --install . --prefix /usr/local`
## FAQ
Q: Why do you need a very performant version of neofetch?
> I like putting neofetch in my ~/.bashrc to have a system overwiew whenever i use the terminal, but the slow speed annoyed me, so i created this. Also neofetch didn't output everything correctly (e.g Font is displayed as "[Plasma], Noto Sans, 10 [GTK2/3]") and writing my own tool gave me the possibility to fine tune it to run perfectly on at least my configuration.
Q: It does not display [*] correctly for me, what can i do?
> This is most likely because your system is not implemented (yet). At the moment i am focusing more on making the core app better, than adding more configurations. Feel free to open a pull request if you want to add support for your configuration
+319
View File
@@ -0,0 +1,319 @@
#!/usr/bin/env bash
__fastfetch_complete_help()
{
local __ff_helps=(
"color"
"format"
"load-config"
"os-format"
"host-format"
"kernel-format"
"packages-format"
"shell-format"
"resolution-format"
"de-format"
"wm-format"
"theme-format"
"icons-format"
"font-format"
"terminal-format"
"terminal-font-format"
"cpu-format"
"cpu-usage-format"
"gpu-format"
"memory-format"
"disk-format"
"battery-format"
"locale-format"
"local-ip-format"
"public-ip-format"
"datetime-format"
"date-format"
"time-format"
)
COMPREPLY=($(compgen -W "${__ff_helps[*]}" -- "$CURRENT_WORD"))
}
__fastfetch_complete_bool()
{
COMPREPLY=($(compgen -W "true false" -- "$CURRENT_WORD"))
}
__fastfetch_complete_string()
{
if [[ $CURRENT_WORD != "" ]]; then
COMPREPLY=("$CURRENT_WORD")
fi
}
__fastfetch_complete_path()
{
COMPREPLY=($(compgen -A file -- "$CURRENT_WORD"))
}
__fastfetch_complete_logo()
{
COMPREPLY=($(compgen -W "$(fastfetch --list-logos-autocompletion)" -- "$CURRENT_WORD"))
}
__fastfetch_complete_option()
{
local FF_OPTIONS_ALL=(
"${FF_OPTIONS_BOOL[@]}"
"${FF_OPTIONS_STRING[@]}"
"${FF_OPTIONS_PATH[@]}"
"${FF_OPTIONS_LOGO[@]}"
)
if [[ $WORD_COUND -lt 3 ]]; then
FF_OPTIONS_ALL+=(
"${FF_OPTIONS_SINGLE[@]}"
"${FF_OPTIONS_HELP[@]}"
)
fi
for ff_word in ${COMP_WORDS[@]}; do
if [[ $ff_word == $CURRENT_WORD ]]; then
break
fi
FF_OPTIONS_ALL=("${FF_OPTIONS_ALL[@]/$ff_word}")
done
COMPREPLY=($(compgen -W "${FF_OPTIONS_ALL[*]}" -- "$CURRENT_WORD"))
}
__fastfetch_previous_matches()
{
for ff_option in "$@"; do
if [[ $ff_option == "$PREVIOUS_WORD" ]]; then
return 0
fi
done
return 1
}
__fastfetch_completion()
{
local CURRENT_WORD="${COMP_WORDS[$COMP_CWORD]}"
local PREVIOUS_WORD="${COMP_WORDS[$COMP_CWORD - 1]}"
local WORD_COUND="${#COMP_WORDS[@]}"
local FF_OPTIONS_SINGLE=(
"-v"
"--version"
"--list-logos"
"--list-modules"
"--list-presets"
"--list-features"
"--print-logos"
"--print-config-system"
"--print-config-user"
"--print-structure"
)
local FF_OPTIONS_HELP=(
"-h"
"--help"
)
local FF_OPTIONS_BOOL=(
"-r"
"--recache"
"--nocache"
"--show-errors"
"--logo-print-remaining"
"--multithreading"
"--allow-slow-operations"
"--disable-linewrap"
"--hide-cursor"
"--localip-show-ipv4"
"--localip-show-ipv6"
"--localip-show-loop"
"--escape-bedrock"
"--pipe"
"--title-fqdn"
)
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"
"--separator"
"-s"
"--structure"
"--set"
"--gl"
"--os-format"
"--os-key"
"--host-format"
"--host-key"
"--kernel-format"
"--kernel-key"
"--uptime-format"
"--uptime-key"
"--processes-format"
"--processes-key"
"--packages-format"
"--packages-key"
"--shell-format"
"--shell-key"
"--resolution-format"
"--resolution-key"
"--de-format"
"--de-key"
"--wm-format"
"--wm-key"
"--wm-theme-format"
"--wm-theme-key"
"--theme-format"
"--theme-key"
"--icons-format"
"--icons-key"
"--font-format"
"--font-key"
"--cursor-format"
"--cursor-key"
"--terminal-format"
"--terminal-key"
"--terminal-font-format"
"--terminal-font-key"
"--cpu-format"
"--cpu-key"
"--cpu-usage-format"
"--cpu-usage-key"
"--gpu-format"
"--gpu-key"
"--memory-format"
"--memory-key"
"--disk-format"
"--disk-key"
"--battery-format"
"--battery-key"
"--locale-format"
"--locale-key"
"--disk-folders"
"--disk-key"
"--local-ip-format"
"--local-ip-key"
"--public-ip-format"
"--public-ip-key"
"--player-format"
"--player-key"
"--song-format"
"--song-key"
"--datetime-key"
"--datetime-format"
"--date-format"
"--date-key"
"--time-format"
"--time-key"
"--vulkan-key"
"--vulkan-format"
"--opengl-key"
"--opengl-format"
"--opencl-key"
"--opencl-format"
"--os-error"
"--host-error"
"--kernel-error"
"--uptime-error"
"--processes-error"
"--packages-error"
"--shell-error"
"--resolution-error"
"--de-error"
"--wm-error"
"--wm-theme-error"
"--theme-error"
"--icons-error"
"--font-error"
"--cursor-error"
"--terminal-error"
"--terminal-font-error"
"--cpu-error"
"--cpu-usage-error"
"--gpu-error"
"--memory-error"
"--disk-error"
"--battery-error"
"--locale-error"
"--disk-error"
"--local-ip-error"
"--public-ip-error"
"--player-error"
"--song-error"
"--datetime-error"
"--date-error"
"--time-error"
"--vulkan-error"
"--opengl-error"
"--opencl-error"
)
local FF_OPTIONS_PATH=(
"--os-file"
"--lib-PCI"
"--lib-vulkan"
"--lib-wayland"
"--lib-xcb-randr"
"--lib-xcb"
"--lib-Xrandr"
"--lib-X11"
"--lib-gio"
"--lib-DConf"
"--lib-DBus"
"--lib-XFConf"
"--lib-sqlite3"
"--lib-rpm"
"--lib-imagemagick"
"--lib-z"
"--lib-chafa"
"--lib-egl"
"--lib-glx"
"--lib-osmesa"
"--lib-opencl"
"--battery-dir"
"--load-config"
)
local FF_OPTIONS_LOGO=(
"-l"
"--logo"
)
if __fastfetch_previous_matches "${FF_OPTIONS_SINGLE[@]}"; then
return
elif [[ $WORD_COUND -gt 3 && ( ${COMP_WORDS[$COMP_CWORD - 2]} == "--help" || ${COMP_WORDS[$COMP_CWORD - 2]} == "-h" ) ]]; then
return
elif [[ $CURRENT_WORD == "-"* ]]; then
__fastfetch_complete_option
elif __fastfetch_previous_matches "${FF_OPTIONS_HELP[@]}"; then
__fastfetch_complete_help
elif __fastfetch_previous_matches "${FF_OPTIONS_BOOL[@]}"; then
__fastfetch_complete_bool
elif __fastfetch_previous_matches "${FF_OPTIONS_STRING[@]}"; then
__fastfetch_complete_string
elif __fastfetch_previous_matches "${FF_OPTIONS_PATH[@]}"; then
__fastfetch_complete_path
elif __fastfetch_previous_matches "${FF_OPTIONS_LOGO[@]}"; then
__fastfetch_complete_logo
else
__fastfetch_complete_option
fi
}
complete -F __fastfetch_completion fastfetch
-69572
View File
File diff suppressed because it is too large Load Diff
-405
View File
@@ -1,405 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fastfetch · Benchmark</title>
<style>
:root {
color-scheme: light;
--page: #f5f7fb;
--card: #fff;
--text: #172033;
--muted: #64748b;
--border: #dbe3ef;
--accent: #2563eb;
--accent-soft: #dbeafe;
--chart-text: #334155;
--chart-grid: #cbd5e1;
}
:root[data-theme="dark"] {
color-scheme: dark;
--page: #0f172a; --card: #172033; --text: #e5edf8; --muted: #9aabc1; --border: #334155; --accent-soft: #1e3a8a;
--chart-text: #f1f5f9;
--chart-grid: #475569;
}
* { box-sizing: border-box; }
body { max-width: 1440px; margin: 0 auto; padding: 2.5rem 1.25rem 4rem; background: var(--page); color: var(--text); font: 16px/1.5 system-ui, -apple-system, sans-serif; }
header { margin-bottom: 1.75rem; }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
h1 { margin: 0; font-size: clamp(2rem, 4vw, 3rem); letter-spacing: -.04em; }
h2 { margin: 0; font-size: 1.25rem; }
p { color: var(--muted); }
.intro { margin: .6rem 0 1rem; }
.links a { color: var(--accent); font-weight: 600; text-decoration: none; }
.links a:hover { text-decoration: underline; }
.theme-toggle, .fullscreen { border: 1px solid var(--border); border-radius: .55rem; padding: .5rem .8rem; background: var(--card); color: var(--text); cursor: pointer; font: inherit; font-weight: 600; }
.theme-toggle:hover, .fullscreen:hover { border-color: var(--accent); color: var(--accent); }
.tabs { display: flex; flex-wrap: wrap; gap: .6rem; margin: 1.5rem 0; padding: .35rem; border: 1px solid var(--border); border-radius: .8rem; background: var(--card); }
.tab { border: 0; border-radius: .55rem; padding: .65rem 1.15rem; background: transparent; color: var(--muted); cursor: pointer; font: inherit; font-weight: 700; }
.tab:hover, .tab[aria-selected="true"] { background: var(--accent); color: #fff; }
.tab-panel[hidden] { display: none; }
.platform-title { display: flex; align-items: center; gap: .65rem; margin: 1.5rem 0 1rem; }
.platform-title::before { content: ''; width: .35rem; height: 1.4rem; border-radius: 1rem; background: var(--accent); }
.charts { display: flex; flex-direction: column; gap: 1.25rem; }
.chart { min-width: 0; padding: 1.25rem; border: 1px solid var(--border); border-radius: 1rem; background: var(--card); box-shadow: 0 8px 28px #0f172a0c; }
.chart:fullscreen { overflow: auto; padding: 2rem; background: var(--page); }
.chart:fullscreen .canvas-wrap { height: calc(100vh - 13rem); }
.chart-header { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .75rem; }
.chart-header span { color: var(--muted); font-size: .85rem; }
.canvas-wrap { position: relative; height: 360px; }
.chart-actions { display: flex; align-items: center; gap: .75rem; }
.legend-actions { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1rem; }
.legend-action { border: 1px solid var(--border); border-radius: .45rem; padding: .35rem .6rem; background: var(--card); color: var(--muted); cursor: pointer; font: inherit; font-size: .8rem; }
.legend-action:hover { border-color: var(--accent); color: var(--accent); }
.legend { display: flex; flex-wrap: wrap; gap: .35rem .9rem; margin-top: 1rem; }
.legend-item { display: inline-flex; align-items: center; gap: .4rem; border: 0; padding: .15rem 0; background: transparent; color: var(--text); cursor: pointer; font: inherit; font-size: .85rem; }
.legend-item.is-hidden { color: var(--muted); }
.legend-swatch { width: .75rem; height: .75rem; border-radius: 50%; }
.legend-item.is-hidden .legend-swatch { opacity: .35; }
.chart-tooltip { position: fixed; z-index: 1000; pointer-events: none; width: min(90vw, 900px); max-height: calc(100vh - 24px); overflow: hidden; padding: .7rem .85rem; border: 1px solid var(--border); border-radius: .6rem; background: var(--card); color: var(--text); box-shadow: 0 10px 30px #0f172a33; font-size: .8rem; opacity: 0; transition: opacity .1s ease; }
.chart-tooltip-title { margin-bottom: .35rem; font-weight: 700; white-space: normal; overflow-wrap: anywhere; }
.chart-tooltip-body { max-height: calc(100vh - 76px); overflow: auto; columns: 220px auto; column-gap: 1.5rem; }
.chart-tooltip-row { display: flex; align-items: center; gap: .45rem; break-inside: avoid; white-space: nowrap; }
.chart-tooltip-swatch { width: .55rem; height: .55rem; border-radius: 50%; flex: 0 0 auto; }
.empty { padding: 2rem 0; color: var(--muted); }
</style>
<script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.min.js"></script>
<script src="data.js"></script>
</head>
<body>
<header>
<div class="header-row">
<h1>Fastfetch Benchmark</h1>
<button id="theme-toggle" class="theme-toggle" type="button"></button>
</div>
<p class="intro">Performance history grouped by CPU family. Each chart contains all modules and total process time for one operating system and architecture. Module curves are available from the legend and hidden by default.</p>
<p class="links"><a href="data.js">Download raw benchmark data</a></p>
</header>
<nav id="tabs" class="tabs" aria-label="CPU architecture"></nav>
<main id="panels"></main>
<script>
(() => {
const benchmarkData = window.BENCHMARK_DATA || {};
const entries = Object.values(benchmarkData.entries || {}).flat();
const groups = new Map();
function architectureFamily(arch) {
const normalized = arch.toLowerCase();
if (/^(amd64|x86_64|x86|i[3-6]86)$/.test(normalized)) return 'Intel';
if (/^(aarch64|arm64|armv[5-8].*|arm)$/.test(normalized)) return 'ARM';
return 'Other';
}
function parseName(name) {
let match = name.match(/^fastfetch (linux|macos|windows) ([^ ]+) (module .+|total process time)$/i);
if (match) {
return { platform: match[1].toLowerCase(), arch: match[2], metric: match[3] };
}
// Keep older macOS records visible while new records use the platform field.
match = name.match(/^fastfetch ([^ ]+) (module .+|total process time)$/i);
return match ? { platform: 'macos', arch: match[1], metric: match[2] } : null;
}
function entryMetadata(entry) {
const raw = entry.commit && entry.commit.timestamp || entry.date;
const date = new Date(raw);
return {
date: Number.isNaN(date.valueOf()) ? String(entry.date || '') : date.toISOString(),
sha: entry.commit && entry.commit.id ? entry.commit.id : 'unknown'
};
}
for (const entry of entries) {
const metricsByGroup = new Map();
for (const bench of entry.benches || []) {
const parsed = parseName(bench.name);
if (!parsed) continue;
const key = `${parsed.platform} ${parsed.arch}`;
if (!metricsByGroup.has(key)) metricsByGroup.set(key, new Map());
metricsByGroup.get(key).set(parsed.metric, bench.value);
}
for (const [key, metrics] of metricsByGroup) {
if (!groups.has(key)) groups.set(key, []);
groups.get(key).push({ ...entryMetadata(entry), metrics });
}
}
const colors = [
'#2563eb', '#dc2626', '#16a34a', '#9333ea', '#ea580c', '#0891b2',
'#db2777', '#65a30d', '#4f46e5', '#ca8a04', '#0f766e', '#be123c'
];
const tabs = document.getElementById('tabs');
const panels = document.getElementById('panels');
const root = document.documentElement;
const themeToggle = document.getElementById('theme-toggle');
const savedTheme = localStorage.getItem('fastfetch-benchmark-theme');
let theme = savedTheme || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
const chartsByInstance = [];
function chartColors() {
const styles = getComputedStyle(root);
return {
text: styles.getPropertyValue('--chart-text').trim(),
grid: styles.getPropertyValue('--chart-grid').trim()
};
}
function externalTooltipHandler(context) {
const { chart, tooltip } = context;
let tooltipElement = chart.canvas.parentNode.querySelector('.chart-tooltip');
if (!tooltipElement) {
tooltipElement = document.createElement('div');
tooltipElement.className = 'chart-tooltip';
chart.canvas.parentNode.appendChild(tooltipElement);
}
if (tooltip.opacity === 0) {
tooltipElement.style.opacity = '0';
return;
}
tooltipElement.replaceChildren();
const title = document.createElement('div');
title.className = 'chart-tooltip-title';
const row = chart._benchmarkRows[tooltip.dataPoints[0].dataIndex];
title.textContent = `${new Date(row.date).toLocaleString()} · ${row.sha}`;
tooltipElement.appendChild(title);
const bodyElement = document.createElement('div');
bodyElement.className = 'chart-tooltip-body';
for (const body of [...tooltip.dataPoints].sort((a, b) => b.parsed.y - a.parsed.y)) {
const item = document.createElement('div');
item.className = 'chart-tooltip-row';
const swatch = document.createElement('span');
swatch.className = 'chart-tooltip-swatch';
swatch.style.background = body.dataset.borderColor;
const value = document.createElement('span');
value.textContent = `${body.dataset.label}: ${body.formattedValue} ms`;
item.append(swatch, value);
bodyElement.appendChild(item);
}
tooltipElement.appendChild(bodyElement);
const canvasRect = chart.canvas.getBoundingClientRect();
const margin = 12;
let left = canvasRect.left + tooltip.caretX + margin;
let top = canvasRect.top + tooltip.caretY + margin;
tooltipElement.style.left = `${left}px`;
tooltipElement.style.top = `${top}px`;
tooltipElement.style.opacity = '0';
const tooltipRect = tooltipElement.getBoundingClientRect();
if (left + tooltipRect.width > window.innerWidth - margin) left = canvasRect.left + tooltip.caretX - tooltipRect.width - margin;
if (top + tooltipRect.height > window.innerHeight - margin) top = canvasRect.top + tooltip.caretY - tooltipRect.height - margin;
tooltipElement.style.left = `${Math.max(margin, left)}px`;
tooltipElement.style.top = `${Math.max(margin, top)}px`;
tooltipElement.style.opacity = '1';
}
function updateTheme() {
root.dataset.theme = theme;
themeToggle.textContent = theme === 'dark' ? '☀ Light mode' : '☾ Dark mode';
themeToggle.setAttribute('aria-label', `Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`);
const colors = chartColors();
Chart.defaults.color = colors.text;
Chart.defaults.borderColor = colors.grid;
for (const chart of chartsByInstance) {
chart.options.scales.x.title.color = colors.text;
chart.options.scales.x.ticks.color = colors.text;
chart.options.scales.x.grid.color = colors.grid;
chart.options.scales.y.title.color = colors.text;
chart.options.scales.y.ticks.color = colors.text;
chart.options.scales.y.grid.color = colors.grid;
chart.update();
}
}
themeToggle.addEventListener('click', () => {
theme = theme === 'dark' ? 'light' : 'dark';
localStorage.setItem('fastfetch-benchmark-theme', theme);
updateTheme();
});
updateTheme();
const families = new Map();
for (const [key, rows] of groups) {
const arch = key.slice(key.lastIndexOf(' ') + 1);
const family = architectureFamily(arch);
if (!families.has(family)) families.set(family, []);
families.get(family).push({ key, rows });
}
const familyOrder = ['Intel', 'ARM', 'Other'];
const availableFamilies = familyOrder.filter(family => families.has(family));
for (const [index, family] of availableFamilies.entries()) {
const tab = document.createElement('button');
const panelId = `panel-${family.toLowerCase()}`;
tab.className = 'tab';
tab.type = 'button';
tab.id = `tab-${family.toLowerCase()}`;
tab.setAttribute('role', 'tab');
tab.textContent = family;
tab.setAttribute('aria-controls', panelId);
tab.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
tabs.appendChild(tab);
const panel = document.createElement('section');
panel.className = 'tab-panel';
panel.id = panelId;
panel.setAttribute('role', 'tabpanel');
panel.hidden = index !== 0;
panel.setAttribute('aria-labelledby', tab.id);
const title = document.createElement('h2');
title.className = 'platform-title';
title.textContent = `${family} processors`;
panel.appendChild(title);
const chartGrid = document.createElement('div');
chartGrid.className = 'charts';
panel.appendChild(chartGrid);
panels.appendChild(panel);
tab.addEventListener('click', () => {
for (const otherTab of tabs.children) otherTab.setAttribute('aria-selected', otherTab === tab ? 'true' : 'false');
for (const otherPanel of panels.children) otherPanel.hidden = otherPanel !== panel;
});
for (const { key, rows } of families.get(family).sort((a, b) => a.key.localeCompare(b.key))) {
rows.sort((a, b) => a.date.localeCompare(b.date));
const metrics = [...new Set(rows.flatMap(row => [...row.metrics.keys()]))].sort((a, b) => {
if (a === 'total process time') return -1;
if (b === 'total process time') return 1;
return a.localeCompare(b);
});
const section = document.createElement('article');
section.className = 'chart';
const chartHeader = document.createElement('div');
chartHeader.className = 'chart-header';
const chartTitle = document.createElement('h2');
chartTitle.textContent = key;
const chartActions = document.createElement('div');
chartActions.className = 'chart-actions';
const chartHint = document.createElement('span');
chartHint.textContent = `${rows.length} run${rows.length === 1 ? '' : 's'}`;
const fullscreen = document.createElement('button');
fullscreen.className = 'fullscreen';
fullscreen.type = 'button';
fullscreen.textContent = '⛶ Fullscreen';
fullscreen.addEventListener('click', () => {
if (document.fullscreenElement) document.exitFullscreen();
else section.requestFullscreen();
});
chartActions.append(chartHint, fullscreen);
chartHeader.append(chartTitle, chartActions);
const canvasWrap = document.createElement('div');
canvasWrap.className = 'canvas-wrap';
const canvas = document.createElement('canvas');
canvasWrap.appendChild(canvas);
section.append(chartHeader, canvasWrap);
chartGrid.appendChild(section);
const colorsForChart = chartColors();
const chart = new Chart(canvas, {
type: 'line',
data: {
labels: rows.map(row => row.sha.slice(0, 7)),
datasets: metrics.map((metric, index) => ({
label: metric,
data: rows.map(row => row.metrics.has(metric) ? row.metrics.get(metric) : null),
borderColor: colors[index % colors.length],
backgroundColor: colors[index % colors.length],
pointRadius: 3,
tension: 0.2,
spanGaps: true,
hidden: metric !== 'total process time'
}))
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { display: false },
tooltip: {
enabled: false,
external: externalTooltipHandler,
callbacks: {
title: tooltipItems => {
const row = rows[tooltipItems[0].dataIndex];
return `${row.date} · ${row.sha}`;
}
}
}
},
scales: {
x: { title: { display: true, text: 'Date', color: colorsForChart.text }, ticks: { color: colorsForChart.text }, grid: { color: colorsForChart.grid } },
y: { beginAtZero: true, title: { display: true, text: 'Milliseconds', color: colorsForChart.text }, ticks: { color: colorsForChart.text }, grid: { color: colorsForChart.grid } }
}
}
});
chart._benchmarkRows = rows;
chartsByInstance.push(chart);
const legendActions = document.createElement('div');
legendActions.className = 'legend-actions';
const legend = document.createElement('div');
legend.className = 'legend';
const legendItems = [];
function refreshLegend() {
legendItems.forEach((item, metricIndex) => {
item.classList.toggle('is-hidden', !chart.isDatasetVisible(metricIndex));
});
}
function setAllLegends(visible) {
metrics.forEach((metric, metricIndex) => chart.setDatasetVisibility(metricIndex, visible));
refreshLegend();
chart.update();
}
function addLegendAction(label, action) {
const button = document.createElement('button');
button.className = 'legend-action';
button.type = 'button';
button.textContent = label;
button.addEventListener('click', action);
legendActions.appendChild(button);
}
addLegendAction('Show all', () => setAllLegends(true));
addLegendAction('Toggle all', () => {
metrics.forEach((metric, metricIndex) => chart.setDatasetVisibility(metricIndex, !chart.isDatasetVisible(metricIndex)));
refreshLegend();
chart.update();
});
addLegendAction('Reset', () => {
metrics.forEach((metric, metricIndex) => chart.setDatasetVisibility(metricIndex, metric === 'total process time'));
refreshLegend();
chart.update();
});
metrics.forEach((metric, metricIndex) => {
const item = document.createElement('button');
item.className = `legend-item${chart.isDatasetVisible(metricIndex) ? '' : ' is-hidden'}`;
item.type = 'button';
item.innerHTML = `<span class="legend-swatch" style="background:${colors[metricIndex % colors.length]}"></span>${metric}`;
item.addEventListener('click', () => {
chart.setDatasetVisibility(metricIndex, !chart.isDatasetVisible(metricIndex));
item.classList.toggle('is-hidden', !chart.isDatasetVisible(metricIndex));
chart.update();
});
legendItems.push(item);
legend.appendChild(item);
});
section.append(legendActions, legend);
}
}
if (!groups.size) {
tabs.hidden = true;
panels.innerHTML = '<p class="empty">No benchmark data available.</p>';
}
})();
</script>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
--structure Title:Separator:OS:Host:Kernel:Uptime:Processes:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Player:Song:PublicIP:LocalIP:DateTime:Locale:Vulkan:OpenGL:OpenCL:Break:Colors
+3
View File
@@ -0,0 +1,3 @@
--logo arch
--os-format "Arch Linux ({12})"
--packages-format "{} (pacman)"
+4
View File
@@ -0,0 +1,4 @@
--disable-linewrap false
--multithreading false
--show-errors true
--recache
+2
View File
@@ -0,0 +1,2 @@
--load-config verbose
--load-config devinfo
+4
View File
@@ -0,0 +1,4 @@
--structure Host:Resolution:CPU:GPU:Memory:Disk:Battery
--memory-format "{?2}{2}MiB{?}"
--disk-format "{?2}{2}GB{?}"
--battery-format "{?1}{1} {?}{?2}{2} {?}{?3}({3}){?}"
+10
View File
@@ -0,0 +1,10 @@
--structure "Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Terminal:TerminalFont:CPU:GPU:Memory:Break:Colors"
--host-format "{/2}{-}{/}{2}{?3} {3}{?}"
--os-format "{3} {12}"
--resolution-format "{}x{}"
--de-format "{2} {3}"
--theme-format "{?1}{1}{?3} {3}{?} [Plasma], {?}{7}"
--terminal-font-format "{/2}{-}{/}{2}{?3} {3}{?}"
--memory-format "{/1}{-}{/}{/2}{-}{/}{}MiB / {}MiB"
--gpu-key "GPU"
--resolution-key "Resolution"
+5
View File
@@ -0,0 +1,5 @@
--structure Title:Separator:OS:Host:Kernel:Uptime:Battery:Break:Packages:Shell:Resolution:Terminal:Break:CPU:GPU:Memory:Break:Colors
--host-format "{/2}{-}{/}{2}{?3} {3}{?}"
--battery-format "{/4}{-}{/}{4}%{?5} [{5}]{?}"
--resolution-key "Resolution"
--gpu-key "GPU"
+1
View File
@@ -0,0 +1 @@
--structure OS:Kernel:Shell:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont
+31
View File
@@ -0,0 +1,31 @@
--load-config all
--os-format "System: {}; Name: {}; Pretty name: {}; ID: {}; ID like: {}; Variant: {}; Variant ID: {}; Version: {}; Version ID: {}; Version codename: {}; Build ID: {}; Architecture: {}"
--host-format "Family: "product_family: {}; product_name: {}; product_version: {}; product_sku: {}; bios_date: {}; bios_release: {}; bios_vendor: {}; bios_version: {}; board_name: {}; board_vendor: {}; board_version: {}; chassis_type: {}; chassis_vendor: {}; chassis_version: {}; sys_vendor: {}"
--kernel-format "Sysname: {}; Release: {}; Version: {}"
--uptime-format "Days: {}; Hours: {}; Minutes: {}; Seconds: {}"
--processes-format "Count: {}"
--packages-format "All: {}; pacman: {}; pacman branch: {}; dpkg: {}; rpm: {}; emerge: {}; xbps: {}; flatpak: {}; snap: {}"
--shell-format "Process name: {}; Process path: {}; Process exe: {}; Process version: {}; User path: {}; User exe: {}; User version: {}"
--resolution-format "Width: {}; Height: {}; Refresh rate: {}"
--de-format "Process name: {}; Pretty name: {}; Version: {}"
--wm-format "Process name: {}; Pretty name: {}; Protocol: {}"
--wm-theme-format "Name: {}"
--theme-format "Plasma: {}; Plasma colors: {}; Plasma colors pretty: {}; GTK2: {}; GTK3: {}; GTK4: {}; GTK: {}"
--icons-format "Plasma: {}; GTK2: {}; GTK3: {}; GTK4: {}; GTK: {}"
--font-format "Plasma raw: {}; Plasma name: {}; Plasma size: {}; Plasma styles: {}; Plasma pretty: {}; GTK2 raw: {}; GTK2 name: {}; GTK2 size: {}; GTK2 styles: {}; GTK2 pretty: {}; GTK3 raw: {}; GTK3 name: {}; GTK3 size: {}; GTK3 styles: {}; GTK3 pretty: {}; GTK4 raw: {}; GTK4 name: {}; GTK4 size: {}; GTK4 styles: {}; GTK4 pretty: {}; GTK: {}"
--cursor-format "Theme: {}; Size: {}"
--terminal-format "Process: {}; Path: {}; Exe: {}"
--terminal-font-format "Raw: {}; Name: {}; Size: {}; Styles: {}; Pretty: {}"
--cpu-format "Name: {}; Pretty: {}; Vendor: {}; Logical online: {}; Logical configured: {}; Physical: {}; Cores: {}; temperature: {}; bios: {}; scaling max: {}; scaling min: {}; info max: {}; info min: {}; cpuinfo: {}; frequency: {}"
--cpu-usage-format "Percentage: {}"
--gpu-format "Vendor: {}; Vendor pretty: {}; Name: {}; Name pretty: {}; Driver: {}; Temperature: {}"
--memory-format "Used: {}; Total: {}; Percentage: {}"
--disk-format "Used: {}; Total: {}; Files: {}; Percentage: {}"
--battery-format "Manufactor: {}; Model: {}; Technology: {}; Capacaty: {}; Status: {}"
--player-format "Name: {}"
--song-format "Song: {}; Artist: {}; Album: {}"
--datetime-format "year: {}; yearShort: {}; month: {}; monthPretty: {}; monthName: {}; monthNameShort: {}; weekNumber: {}; weekday: {}; weekdayShort: {}; dayInYear: {}; dayInMonth: {}; dayInWeek: {}; hour: {}; hourPretty: {}; hour12: {}; hour12Pretty: {}; minute: {}; minutePretty: {}; second: {}; secondPretty: {}"
--vulkan-format "driver: {}; Api Version: {}; Conformance Version: {}"
--opengl-format "version: {}; renderer: {}; vendor: {}"
--opencl-format "version: {}; device: {}; vendor: {}"
Executable
+11
View File
@@ -0,0 +1,11 @@
#!/bin/env sh
# make the script exit if any of the commands fail,
# making fastfetch not run if the build failed.
set -e
mkdir -p build/
cd build/
cmake ..
cmake --build . --target fastfetch -j$(nproc)
./fastfetch "$@"
Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+229
View File
@@ -0,0 +1,229 @@
#include "fastfetch.h"
#include "common/caching.h"
#include "common/io.h"
#include "common/printing.h"
#include <stdlib.h>
#define FF_CACHE_VALUE_EXTENSION "ffcv"
#define FF_CACHE_SPLIT_EXTENSION "ffcs"
#define FF_CACHE_EXTENSION_DATA "ffcd"
static void getCacheFilePath(const 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);
ffAppendFileBuffer(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);
ffWriteFileBuffer(path.chars, content);
ffStrbufDestroy(&path);
}
void ffCacheValidate(FFinstance* instance)
{
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 FFModuleArgs* moduleArgs)
{
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, &moduleArgs->key);
puts(content.chars + startIndex);
startIndex = nullByteIndex + 1;
++moduleCounter;
}
ffStrbufDestroy(&content);
return moduleCounter > 1;
}
static bool printCachedFormat(FFinstance* instance, const char* moduleName, const FFModuleArgs* moduleArgs, 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;
ffPrintFormat(instance, moduleName, moduleIndex, moduleArgs, numArgs, arguments);
++moduleCounter;
argumentCounter = 0;
}
startIndex = nullByteIndex + 1;
}
free(arguments);
ffStrbufDestroy(&content);
return moduleCounter > 1;
}
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFModuleArgs* moduleArgs, uint32_t numArgs)
{
if(instance->config.recache)
return false;
if(moduleArgs->outputFormat.length == 0)
return printCachedValue(instance, moduleName, moduleArgs);
else
return printCachedFormat(instance, moduleName, moduleArgs, numArgs);
}
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFcache* cache, const FFstrbuf* value, uint32_t numArgs, const FFformatarg* arguments)
{
if(moduleArgs->outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, &moduleArgs->key);
ffStrbufPutTo(value, stdout);
}
else
{
ffPrintFormat(instance, moduleName, moduleIndex, moduleArgs, 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 FFModuleArgs* moduleArgs, const FFstrbuf* value, uint32_t numArgs, const FFformatarg* arguments)
{
FFcache cache;
ffCacheOpenWrite(instance, moduleName, &cache);
ffPrintAndAppendToCache(instance, moduleName, 0, moduleArgs, &cache, value, numArgs, arguments);
ffCacheClose(&cache);
}
void ffCachingWriteData(const FFinstance* instance, const char* moduleName, size_t dataSize, const void* data)
{
FFstrbuf path;
ffStrbufInitA(&path, 128);
getCacheFilePath(instance, moduleName, FF_CACHE_EXTENSION_DATA, &path);
ffWriteFileData(path.chars, dataSize, data);
ffStrbufDestroy(&path);
}
bool ffCachingReadData(const FFinstance* instance, const char* moduleName, size_t dataSize, void* data)
{
if(instance->config.recache)
return false;
FFstrbuf path;
ffStrbufInitA(&path, 128);
getCacheFilePath(instance, moduleName, FF_CACHE_EXTENSION_DATA, &path);
ssize_t result = ffReadFileData(path.chars, dataSize, data);
ffStrbufDestroy(&path);
return result > 0 && (size_t) result == dataSize;
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#ifndef FF_INCLUDED_common_caching
#define FF_INCLUDED_common_caching
#include "fastfetch.h"
#include "common/format.h"
typedef struct FFcache
{
FILE* value;
FILE* split;
} FFcache;
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 FFModuleArgs* moduleArgs, uint32_t numArgs);
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFcache* cache, const FFstrbuf* value, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintAndWriteToCache(FFinstance* instance, const char* moduleName, const FFModuleArgs* moduleArgs, const FFstrbuf* value, uint32_t numArgs, const FFformatarg* arguments);
void ffCachingWriteData(const FFinstance* instance, const char* moduleName, size_t dataSize, const void* data);
bool ffCachingReadData(const FFinstance* instance, const char* moduleName, size_t dataSize, void* data);
#endif
+216
View File
@@ -0,0 +1,216 @@
#include "fastfetch.h"
#include "common/font.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 ffFontInitValues(FFfont* font, const char* name, const char* size)
{
fontInit(font);
ffStrbufAppendS(&font->name, name);
ffStrbufAppendS(&font->size, size);
fontInitPretty(font);
}
void ffFontInitCopy(FFfont* font, const char* name)
{
ffFontInitValues(font, name, NULL);
}
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);
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#ifndef FF_INCLUDED_common_font
#define FF_INCLUDED_common_font
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
typedef struct FFfont
{
FFstrbuf pretty;
FFstrbuf name;
FFstrbuf size;
FFlist styles;
} FFfont;
void ffFontInitQt(FFfont* font, const char* data);
void ffFontInitPango(FFfont* font, const char* data);
void ffFontInitCopy(FFfont* font, const char* name);
void ffFontInitValues(FFfont* font, const char* name, const char* size);
void ffFontDestroy(FFfont* font);
#endif
+258
View File
@@ -0,0 +1,258 @@
#include "fastfetch.h"
#include "common/format.h"
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
{
if(formatarg->type == FF_FORMAT_ARG_TYPE_INT)
ffStrbufAppendF(buffer, "%i", *(int*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_UINT)
ffStrbufAppendF(buffer, "%u", *(uint32_t*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_UINT16)
ffStrbufAppendF(buffer, "%hu", *(uint16_t*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_UINT8)
ffStrbufAppendF(buffer, "%hhu", *(uint8_t*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_STRING)
ffStrbufAppendS(buffer, (const char*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_STRBUF)
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_DOUBLE)
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
else if(formatarg->type == FF_FORMAT_ARG_TYPE_LIST)
{
const FFlist* list = formatarg->value;
for(uint32_t i = 0; i < list->length; i++)
{
ffStrbufAppend(buffer, ffListGet(list, i));
if(i < list->length - 1)
ffStrbufAppendS(buffer, ", ");
}
}
else if(formatarg->type != FF_FORMAT_ARG_TYPE_NULL)
{
fprintf(stderr, "Error: format string \"%s\": argument is not implemented: %i\n", buffer->chars, formatarg->type);
}
}
static inline uint32_t getArgumentIndex(const FFstrbuf* placeholderValue)
{
uint32_t result = UINT32_MAX;
if(placeholderValue->chars[0] != '-')
sscanf(placeholderValue->chars, "%u", &result);
return result;
}
static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start, const FFstrbuf* placeholderValue, uint32_t index, uint32_t formatStringLength)
{
ffStrbufAppendS(buffer, start);
ffStrbufAppend(buffer, placeholderValue);
if(index < formatStringLength)
ffStrbufAppendC(buffer, '}');
}
static inline void appendEmptyPlaceholder(FFstrbuf* buffer, const char* placeholder, uint32_t* argCounter, uint32_t numArgs, const FFformatarg* arguments)
{
if(*argCounter > numArgs)
ffStrbufAppendS(buffer, placeholder);
else
ffFormatAppendFormatArg(buffer, &arguments[(*argCounter)++]);
}
static inline bool formatArgSet(const FFformatarg* arg)
{
return arg->value != NULL && (
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value == *(double*)arg->value) || //NaN
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && *(const char*)arg->value != '\0') ||
(arg->type == FF_FORMAT_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0)
);
}
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments)
{
uint32_t argCounter = 0;
uint32_t numOpenIfs = 0;
uint32_t numOpenNotIfs = 0;
uint32_t numOpenColors = 0;
for(uint32_t i = 0; i < formatstr->length; ++i)
{
// if we don't have a placeholder start just copy the chars over to output buffer
if(formatstr->chars[i] != '{')
{
ffStrbufAppendC(buffer, formatstr->chars[i]);
continue;
}
// if we have an { at the end handle it as {}
if(i == formatstr->length - 1)
{
appendEmptyPlaceholder(buffer, "{", &argCounter, numArgs, arguments);
continue;
}
// jump to next char, the start of the placeholder value
++i;
// double {{ elvaluates to a single { and doesn't count as start
if(formatstr->chars[i] == '{')
{
ffStrbufAppendC(buffer, '{');
continue;
}
// placeholder is {}
if(formatstr->chars[i] == '}')
{
appendEmptyPlaceholder(buffer, "{}", &argCounter, numArgs, arguments);
continue;
}
FFstrbuf placeholderValue;
ffStrbufInit(&placeholderValue);
while(i < formatstr->length && formatstr->chars[i] != '}')
ffStrbufAppendC(&placeholderValue, formatstr->chars[i++]);
// test if for stop, if so break the loop
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '-')
{
ffStrbufDestroy(&placeholderValue);
break;
}
// test for end of an if, if so do nothing
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '?')
{
if(numOpenIfs == 0)
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
--numOpenIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
// test for end of a not if, if so do nothing
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '/')
{
if(numOpenNotIfs == 0)
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
--numOpenNotIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
// test for end of a color, if so do nothing
if(placeholderValue.length == 1 && placeholderValue.chars[0] == '#')
{
if(numOpenColors == 0)
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
else
{
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
--numOpenColors;
}
ffStrbufDestroy(&placeholderValue);
continue;
}
// test for if, if so evaluate it
if(placeholderValue.chars[0] == '?')
{
ffStrbufSubstrAfter(&placeholderValue, 0);
uint32_t index = getArgumentIndex(&placeholderValue);
// testing for an invalid index
if(index > numArgs)
{
appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length);
ffStrbufDestroy(&placeholderValue);
continue;
}
// continue normally if an format arg is set and the value is > 0
if(formatArgSet(&arguments[index - 1]))
{
++numOpenIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
// fastforward to the end of the if without printing the in between
i = ffStrbufNextIndexS(formatstr, i, "{?}") + 2; // 2 is the length of "{?}" - 1 because the loop will increament it again directly after continue
ffStrbufDestroy(&placeholderValue);
continue;
}
// test for not if, if so evaluate it
if(placeholderValue.chars[0] == '/')
{
ffStrbufSubstrAfter(&placeholderValue, 0);
uint32_t index = getArgumentIndex(&placeholderValue);
// testing for an invalid index
if(index > numArgs)
{
appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length);
ffStrbufDestroy(&placeholderValue);
continue;
}
//continue normally if an format arg is not set or the value is 0
if(!formatArgSet(&arguments[index - 1]))
{
++numOpenNotIfs;
ffStrbufDestroy(&placeholderValue);
continue;
}
// fastforward to the end of the if without printing the in between
i = ffStrbufNextIndexS(formatstr, i, "{/}") + 2; // 2 is the length of "{/}" - 1 because the loop will increament it again directly after continue
ffStrbufDestroy(&placeholderValue);
continue;
}
//test for color, if so evaluate it
if(placeholderValue.chars[0] == '#')
{
++numOpenColors;
ffStrbufSubstrAfter(&placeholderValue, 0);
ffStrbufAppendS(buffer, "\033[");
ffStrbufAppend(buffer, &placeholderValue);
ffStrbufAppendC(buffer, 'm');
ffStrbufDestroy(&placeholderValue);
continue;
}
uint32_t index = getArgumentIndex(&placeholderValue);
// test for invalid index
if(index > numArgs)
{
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
ffStrbufDestroy(&placeholderValue);
continue;
}
ffFormatAppendFormatArg(buffer, &arguments[index - 1]);
ffStrbufDestroy(&placeholderValue);
}
ffStrbufTrimRight(buffer, ' ');
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#ifndef FF_INCLUDED_common_format
#define FF_INCLUDED_common_format
typedef enum FFformatargtype
{
FF_FORMAT_ARG_TYPE_NULL = 0,
FF_FORMAT_ARG_TYPE_UINT,
FF_FORMAT_ARG_TYPE_UINT16,
FF_FORMAT_ARG_TYPE_UINT8,
FF_FORMAT_ARG_TYPE_INT,
FF_FORMAT_ARG_TYPE_STRING,
FF_FORMAT_ARG_TYPE_STRBUF,
FF_FORMAT_ARG_TYPE_DOUBLE,
FF_FORMAT_ARG_TYPE_LIST
} FFformatargtype;
typedef struct FFformatarg
{
FFformatargtype type;
const void* value;
} FFformatarg;
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments);
#endif
+431
View File
@@ -0,0 +1,431 @@
#include "fastfetch.h"
#include "common/caching.h"
#include "common/parsing.h"
#include "detection/qt.h"
#include "detection/gtk.h"
#include "detection/displayserver.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <signal.h>
#include <pthread.h>
static bool strbufEqualsAdapter(const void* first, const void* second)
{
return ffStrbufComp(second, first) == 0;
}
static void initConfigDirs(FFstate* state)
{
ffListInit(&state->configDirs, sizeof(FFstrbuf));
const char* xdgConfigHome = getenv("XDG_CONFIG_HOME");
if(ffStrSet(xdgConfigHome))
{
FFstrbuf* buffer = (FFstrbuf*) ffListAdd(&state->configDirs);
ffStrbufInitA(buffer, 64);
ffStrbufAppendS(buffer, xdgConfigHome);
ffStrbufEnsureEndsWithC(buffer, '/');
}
#define FF_ENSURE_ONLY_ONCE_IN_LIST(element) \
if(ffListFirstIndexComp(&state->configDirs, element, strbufEqualsAdapter) < state->configDirs.length - 1) \
--state->configDirs.length;
FFstrbuf* userConfigHome = ffListAdd(&state->configDirs);
ffStrbufInitA(userConfigHome, 64);
ffStrbufAppendS(userConfigHome, state->passwd->pw_dir);
ffStrbufAppendS(userConfigHome, "/.config/");
FF_ENSURE_ONLY_ONCE_IN_LIST(userConfigHome)
FFstrbuf* userHome = ffListAdd(&state->configDirs);
ffStrbufInitA(userHome, 64);
ffStrbufAppendS(userHome, state->passwd->pw_dir);
ffStrbufEnsureEndsWithC(userHome, '/');
FF_ENSURE_ONLY_ONCE_IN_LIST(userHome)
FFstrbuf xdgConfigDirs;
ffStrbufInitA(&xdgConfigDirs, 64);
ffStrbufAppendS(&xdgConfigDirs, getenv("XDG_CONFIG_DIRS"));
uint32_t startIndex = 0;
while (startIndex < xdgConfigDirs.length)
{
uint32_t colonIndex = ffStrbufNextIndexC(&xdgConfigDirs, startIndex, ':');
xdgConfigDirs.chars[colonIndex] = '\0';
if(!ffStrSet(xdgConfigDirs.chars + startIndex))
{
startIndex = colonIndex + 1;
continue;
}
FFstrbuf* buffer = (FFstrbuf*) ffListAdd(&state->configDirs);
ffStrbufInitA(buffer, 64);
ffStrbufAppendS(buffer, xdgConfigDirs.chars + startIndex);
ffStrbufEnsureEndsWithC(buffer, '/');
FF_ENSURE_ONLY_ONCE_IN_LIST(buffer);
startIndex = colonIndex + 1;
}
FFstrbuf* systemConfigHome = ffListAdd(&state->configDirs);
ffStrbufInitA(systemConfigHome, 64);
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, FASTFETCH_TARGET_DIR_ROOT"/etc/");
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfig)
#undef FF_ENSURE_ONLY_ONCE_IN_LIST
}
static void initCacheDir(FFstate* state)
{
ffStrbufInitA(&state->cacheDir, 64);
ffStrbufAppendS(&state->cacheDir, getenv("XDG_CACHE_HOME"));
if(state->cacheDir.length == 0)
{
ffStrbufAppendS(&state->cacheDir, state->passwd->pw_dir);
ffStrbufAppendS(&state->cacheDir, "/.cache/");
}
else
ffStrbufEnsureEndsWithC(&state->cacheDir, '/');
mkdir(state->cacheDir.chars, S_IRWXU | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH); //I hope everybody has a cache folder, but who knows
ffStrbufAppendS(&state->cacheDir, "fastfetch/");
mkdir(state->cacheDir.chars, S_IRWXU | S_IRGRP | S_IROTH);
}
static void initState(FFstate* state)
{
state->logoWidth = 0;
state->logoHeight = 0;
state->keysHeight = 0;
state->passwd = getpwuid(getuid());
uname(&state->utsname);
sysinfo(&state->sysinfo);
initConfigDirs(state);
initCacheDir(state);
}
static void initModuleArg(FFModuleArgs* args)
{
ffStrbufInitA(&args->key, 0);
ffStrbufInitA(&args->outputFormat, 0);
ffStrbufInitA(&args->errorFormat, 0);
}
static void defaultConfig(FFinstance* instance)
{
ffStrbufInit(&instance->config.logo.source);
instance->config.logo.type = FF_LOGO_TYPE_AUTO;
for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i)
ffStrbufInit(&instance->config.logo.colors[i]);
instance->config.logo.width = 0;
instance->config.logo.height = 0; //preserve aspect ratio
instance->config.logo.paddingLeft = 0;
instance->config.logo.paddingRight = 4;
instance->config.logo.printRemaining = true;
ffStrbufInit(&instance->config.mainColor);
ffStrbufInit(&instance->config.separator);
ffStrbufAppendS(&instance->config.separator, ": ");
instance->config.showErrors = false;
instance->config.recache = false;
instance->config.cacheSave = true;
instance->config.allowSlowOperations = false;
instance->config.disableLinewrap = true;
instance->config.hideCursor = true;
instance->config.escapeBedrock = true;
instance->config.glType = FF_GL_TYPE_AUTO;
instance->config.pipe = false;
instance->config.multithreading = true;
initModuleArg(&instance->config.os);
initModuleArg(&instance->config.host);
initModuleArg(&instance->config.kernel);
initModuleArg(&instance->config.uptime);
initModuleArg(&instance->config.processes);
initModuleArg(&instance->config.packages);
initModuleArg(&instance->config.shell);
initModuleArg(&instance->config.resolution);
initModuleArg(&instance->config.de);
initModuleArg(&instance->config.wm);
initModuleArg(&instance->config.wmTheme);
initModuleArg(&instance->config.theme);
initModuleArg(&instance->config.icons);
initModuleArg(&instance->config.font);
initModuleArg(&instance->config.cursor);
initModuleArg(&instance->config.terminal);
initModuleArg(&instance->config.terminalFont);
initModuleArg(&instance->config.cpu);
initModuleArg(&instance->config.cpuUsage);
initModuleArg(&instance->config.gpu);
initModuleArg(&instance->config.memory);
initModuleArg(&instance->config.disk);
initModuleArg(&instance->config.battery);
initModuleArg(&instance->config.locale);
initModuleArg(&instance->config.localIP);
initModuleArg(&instance->config.publicIP);
initModuleArg(&instance->config.player);
initModuleArg(&instance->config.song);
initModuleArg(&instance->config.dateTime);
initModuleArg(&instance->config.date);
initModuleArg(&instance->config.time);
initModuleArg(&instance->config.vulkan);
initModuleArg(&instance->config.openGL);
initModuleArg(&instance->config.openCL);
ffStrbufInitA(&instance->config.libPCI, 0);
ffStrbufInitA(&instance->config.libVulkan, 0);
ffStrbufInitA(&instance->config.libWayland, 0);
ffStrbufInitA(&instance->config.libXcbRandr, 0);
ffStrbufInitA(&instance->config.libXcb, 0);
ffStrbufInitA(&instance->config.libXrandr, 0);
ffStrbufInitA(&instance->config.libX11, 0);
ffStrbufInitA(&instance->config.libGIO, 0);
ffStrbufInitA(&instance->config.libDConf, 0);
ffStrbufInitA(&instance->config.libDBus, 0);
ffStrbufInitA(&instance->config.libXFConf, 0);
ffStrbufInitA(&instance->config.libSQLite3, 0);
ffStrbufInitA(&instance->config.librpm, 0);
ffStrbufInitA(&instance->config.libImageMagick, 0);
ffStrbufInitA(&instance->config.libZ, 0);
ffStrbufInitA(&instance->config.libChafa, 0);
ffStrbufInitA(&instance->config.libEGL, 0);
ffStrbufInitA(&instance->config.libGLX, 0);
ffStrbufInitA(&instance->config.libOSMesa, 0);
ffStrbufInitA(&instance->config.libOpenCL, 0);
instance->config.titleFQDN = false;
ffStrbufInitA(&instance->config.diskFolders, 0);
ffStrbufInitA(&instance->config.batteryDir, 0);
ffStrbufInitA(&instance->config.separatorString, 0);
instance->config.localIpShowIpV4 = true;
instance->config.localIpShowIpV6 = false;
instance->config.localIpShowLoop = false;
instance->config.publicIpTimeout = 0;
ffStrbufInitA(&instance->config.osFile, 0);
ffStrbufInitA(&instance->config.playerName, 0);
}
void ffInitInstance(FFinstance* instance)
{
initState(&instance->state);
defaultConfig(instance);
}
static inline void* detectPlasmaThreadMain(void* instance)
{
ffDetectQt((FFinstance*)instance);
return NULL;
}
static inline void* detectGTK2ThreadMain(void* instance)
{
ffDetectGTK2((FFinstance*)instance);
return NULL;
}
static inline void* detectGTK3ThreadMain(void* instance)
{
ffDetectGTK3((FFinstance*)instance);
return NULL;
}
static inline void* detectGTK4ThreadMain(void* instance)
{
ffDetectGTK4((FFinstance*)instance);
return NULL;
}
static inline void* connectDisplayServerThreadMain(void* instance)
{
ffConnectDisplayServer((FFinstance*)instance);
return NULL;
}
static inline void* startThreadsThreadMain(void* instance)
{
pthread_t dsThread;
pthread_create(&dsThread, NULL, connectDisplayServerThreadMain, instance);
pthread_detach(dsThread);
pthread_t gtk2Thread;
pthread_create(&gtk2Thread, NULL, detectGTK2ThreadMain, instance);
pthread_detach(gtk2Thread);
pthread_t gtk3Thread;
pthread_create(&gtk3Thread, NULL, detectGTK3ThreadMain, instance);
pthread_detach(gtk3Thread);
pthread_t gtk4Thread;
pthread_create(&gtk4Thread, NULL, detectGTK4ThreadMain, instance);
pthread_detach(gtk4Thread);
pthread_t plasmaThread;
pthread_create(&plasmaThread, NULL, detectPlasmaThreadMain, instance);
pthread_detach(plasmaThread);
return NULL;
}
void startDetectionThreads(FFinstance* instance)
{
//Android needs none of the things that are detected here
//And using gsettings sometimes hangs the program in android for some unknown reason,
//and since we don't need it we just never call it.
#ifdef __ANDROID__
return;
#endif
pthread_t startThreadsThread;
pthread_create(&startThreadsThread, NULL, startThreadsThreadMain, instance);
pthread_detach(startThreadsThread);
}
static volatile bool ffDisableLinewrap = true;
static volatile bool ffHideCursor = true;
static void resetConsole()
{
if(ffDisableLinewrap)
fputs("\033[?7h", stdout);
if(ffHideCursor)
fputs("\033[?25h", stdout);
}
static void exitSignalHandler(int signal)
{
FF_UNUSED(signal);
resetConsole();
exit(0);
}
void ffStart(FFinstance* instance)
{
if(instance->config.multithreading)
startDetectionThreads(instance);
ffDisableLinewrap = instance->config.disableLinewrap && !instance->config.pipe;
ffHideCursor = instance->config.hideCursor && !instance->config.pipe;
struct sigaction action = {};
action.sa_handler = exitSignalHandler;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
//We do the cache validation here, so we can skip it if --recache is given
if(!instance->config.recache)
ffCacheValidate(instance);
//reset everything to default before we start printing
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
if(ffHideCursor)
fputs("\033[?25l", stdout);
if(ffDisableLinewrap)
fputs("\033[?7l", stdout);
ffLogoPrint(instance);
}
void ffFinish(FFinstance* instance)
{
if(instance->config.logo.printRemaining)
ffLogoPrintRemaining(instance);
resetConsole();
}
//Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
void ffListFeatures()
{
fputs(
#ifdef FF_HAVE_LIBPCI
"libpci\n"
#endif
#ifdef FF_HAVE_VULKAN
"vulkan\n"
#endif
#ifdef FF_HAVE_WAYLAND
"wayland\n"
#endif
#ifdef FF_HAVE_XCB_RANDR
"xcb-randr\n"
#endif
#ifdef FF_HAVE_XCB
"xcb\n"
#endif
#ifdef FF_HAVE_XRANDR
"xrandr\n"
#endif
#ifdef FF_HAVE_X11
"x11\n"
#endif
#ifdef FF_HAVE_GIO
"gio\n"
#endif
#ifdef FF_HAVE_DCONF
"dconf\n"
#endif
#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
"rpm\n"
#endif
#ifdef FF_HAVE_EGL
"egl\n"
#endif
#ifdef FF_HAVE_GLX
"glx\n"
#endif
#ifdef FF_HAVE_OSMESA
"osmesa\n"
#endif
#ifdef FF_HAVE_OPENCL
"opencl\n"
#endif
""
, stdout);
}
+193
View File
@@ -0,0 +1,193 @@
#include "fastfetch.h"
#include "common/io.h"
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <poll.h>
static void createSubfolders(const char* fileName)
{
FFstrbuf path;
ffStrbufInit(&path);
while(*fileName != '\0')
{
ffStrbufAppendC(&path, *fileName);
if(*fileName == '/')
mkdir(path.chars, S_IRWXU | S_IRGRP | S_IROTH);
++fileName;
}
ffStrbufDestroy(&path);
}
bool ffWriteFDBuffer(int fd, const FFstrbuf* content)
{
return write(fd, content->chars, content->length) != -1;
}
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
{
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 = write(fd, data, dataSize) != -1;
close(fd);
return ret;
}
bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer)
{
return ffWriteFileData(fileName, buffer->length, buffer->chars);
}
bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
{
ssize_t readed = 0;
ffStrbufEnsureFree(buffer, 31); // 32 - 1 for the null terminator
uint32_t free = ffStrbufGetFree(buffer);
while(
(readed = read(fd, buffer->chars + buffer->length, free)) > 0 &&
(uint32_t) readed == free
) {
buffer->length += (uint32_t) readed;
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
free = ffStrbufGetFree(buffer);
}
// In case of failure, read returns -1. We don't want to substract the length of the buffer.
if(readed > 0)
buffer->length += (uint32_t) readed;
buffer->chars[buffer->length] = '\0';
ffStrbufTrimRight(buffer, '\n');
ffStrbufTrimRight(buffer, ' ');
return readed >= 0;
}
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
{
int fd = open(fileName, O_RDONLY);
if(fd == -1)
return -1;
ssize_t readed = read(fd, data, dataSize);
close(fd);
return readed;
}
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
{
int fd = open(fileName, O_RDONLY);
if(fd == -1)
return false;
bool ret = ffAppendFDBuffer(fd, buffer);
close(fd);
return ret;
}
bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer)
{
ffStrbufClear(buffer);
return ffAppendFileBuffer(fileName, buffer);
}
// Not thread safe!
void ffSuppressIO(bool suppress)
{
static bool init = false;
static int origOut = -1;
static int origErr = -1;
static int nullFile = -1;
if(!init)
{
if(!suppress)
return;
origOut = dup(STDOUT_FILENO);
origErr = dup(STDERR_FILENO);
nullFile = open("/dev/null", O_WRONLY);
init = true;
}
if(nullFile == -1)
return;
fflush(stdout);
fflush(stderr);
dup2(suppress ? nullFile : origOut, STDOUT_FILENO);
dup2(suppress ? nullFile : origErr, STDERR_FILENO);
}
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);
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#ifndef FF_INCLUDED_common_io
#define FF_INCLUDED_common_io
#include <sys/types.h> //mode_t
bool ffWriteFDBuffer(int fd, const FFstrbuf* content);
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer);
bool ffAppendFDBuffer(int fd, FFstrbuf* buffer);
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer);
bool ffFileExists(const char* fileName, mode_t mode);
// Not thread safe!
void ffSuppressIO(bool suppress);
void ffGetTerminalResponse(const char* request, const char* format, ...);
#endif
+56
View File
@@ -0,0 +1,56 @@
#include "fastfetch.h"
#include "common/library.h"
#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)
return dlopen(userProvidedName->chars, RTLD_LAZY);
va_list defaultNames;
va_start(defaultNames, userProvidedName);
void* result = NULL;
while(result == NULL)
{
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);
return result;
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifndef FF_INCLUDED_common_library
#define FF_INCLUDED_common_library
#include <dlfcn.h>
#define FF_LIBRARY_SYMBOL(symbolName) \
__typeof__(&symbolName) ff ## symbolName;
#define FF_LIBRARY_LOAD(libraryObjectName, userLibraryName, returnValue, ...) \
void* libraryObjectName = ffLibraryLoad(&userLibraryName, __VA_ARGS__, NULL);\
if(libraryObjectName == NULL) \
return returnValue;
#define FF_LIBRARY_LOAD_SYMBOL_ADRESS(library, symbolMapping, symbolName, returnValue) \
symbolMapping = dlsym(library, #symbolName); \
if(symbolMapping == NULL) \
{ \
dlclose(library); \
return returnValue; \
}
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADRESS(library, ff ## symbolName, symbolName, returnValue);
void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...);
#endif
+70
View File
@@ -0,0 +1,70 @@
#include "fastfetch.h"
#include "common/networking.h"
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
void ffNetworkingGetHttp(const char* host, const char* path, uint32_t timeout, FFstrbuf* buffer)
{
struct addrinfo hints = {0};
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
struct addrinfo* addr;
if(getaddrinfo(host, "80", &hints, &addr) != 0)
return;
int sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(sock == -1)
{
freeaddrinfo(addr);
return;
}
if(timeout > 0)
{
struct timeval timev;
timev.tv_sec = 0;
timev.tv_usec = timeout * 1000; //milliseconds to microseconds
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
}
if(connect(sock, addr->ai_addr, addr->ai_addrlen) == -1)
{
close(sock);
freeaddrinfo(addr);
return;
}
freeaddrinfo(addr);
FFstrbuf command;
ffStrbufInitA(&command, 64);
ffStrbufAppendS(&command, "GET ");
ffStrbufAppendS(&command, path);
ffStrbufAppendS(&command, " HTTP/1.1\nHost: ");
ffStrbufAppendS(&command, host);
ffStrbufAppendS(&command, "\r\n\r\n");
if(send(sock, command.chars, command.length, 0) == -1)
{
ffStrbufDestroy(&command);
close(sock);
return;
}
ssize_t received = recv(sock, buffer->chars + buffer->length, ffStrbufGetFree(buffer), 0);
if(received > 0)
{
buffer->length += (uint32_t) received;
buffer->chars[buffer->length] = '\0';
}
ffStrbufDestroy(&command);
close(sock);
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#ifndef FF_INCLUDED_common_networking
#define FF_INCLUDED_common_networking
#include "util/FFstrbuf.h"
void ffNetworkingGetHttp(const char* host, const char* path, uint32_t timeout, FFstrbuf* buffer);
#endif
+147
View File
@@ -0,0 +1,147 @@
#include "fastfetch.h"
#include "common/parsing.h"
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;
}
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);
}
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2)
{
if(version1->major != version2->major)
return version1->major > version2->major ? 1 : -1;
if(version1->minor != version2->minor)
return version1->minor > version2->minor ? 1 : -1;
if(version1->patch != version2->patch)
return version1->patch > version2->patch ? 1 : -1;
return 0;
}
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
{
if(version->major > 0 || version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, "%u", version->major);
if(version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->minor);
if(version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->patch);
}
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
{
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
{
if((ffStrbufIgnCaseComp(gtk2, gtk3) == 0) && (ffStrbufIgnCaseComp(gtk2, gtk4) == 0))
{
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK2/3/4]");
}
else if(ffStrbufIgnCaseComp(gtk2, gtk3) == 0)
{
ffStrbufAppend(buffer, gtk3);
ffStrbufAppendS(buffer, " [GTK2/3], ");
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK4]");
}
else if(ffStrbufIgnCaseComp(gtk3, gtk4) == 0)
{
ffStrbufAppend(buffer, gtk2);
ffStrbufAppendS(buffer, " [GTK2], ");
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK3/4]");
}
else
{
ffStrbufAppend(buffer, gtk2);
ffStrbufAppendS(buffer, " [GTK2], ");
ffStrbufAppend(buffer, gtk3);
ffStrbufAppendS(buffer, " [GTK3], ");
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK4]");
}
}
else if(gtk2->length > 0 && gtk3->length > 0)
{
if(ffStrbufIgnCaseComp(gtk2, gtk3) == 0)
{
ffStrbufAppend(buffer, gtk3);
ffStrbufAppendS(buffer, " [GTK2/3]");
}
else
{
ffStrbufAppend(buffer, gtk2);
ffStrbufAppendS(buffer, " [GTK2], ");
ffStrbufAppend(buffer, gtk3);
ffStrbufAppendS(buffer, " [GTK3]");
}
}
else if(gtk3->length > 0 && gtk4->length > 0)
{
if(ffStrbufIgnCaseComp(gtk3, gtk4) == 0)
{
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK3/4]");
}
else
{
ffStrbufAppend(buffer, gtk3);
ffStrbufAppendS(buffer, " [GTK3], ");
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK4]");
}
}
else if(gtk2->length > 0)
{
ffStrbufAppend(buffer, gtk2);
ffStrbufAppendS(buffer, " [GTK2]");
}
else if(gtk3->length > 0)
{
ffStrbufAppend(buffer, gtk3);
ffStrbufAppendS(buffer, " [GTK3]");
}
else if(gtk4->length > 0)
{
ffStrbufAppend(buffer, gtk4);
ffStrbufAppendS(buffer, " [GTK4]");
}
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#ifndef FF_INCLUDED_parsing_h
#define FF_INCLUDED_parsing_h
#include <stdint.h>
typedef struct FFVersion
{
uint32_t major;
uint32_t minor;
uint32_t patch;
} FFVersion;
#define FF_VERSION_INIT ((FFVersion) {0})
bool ffStrSet(const char* str);
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
#endif
+127
View File
@@ -0,0 +1,127 @@
#include "fastfetch.h"
#include "common/printing.h"
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
{
ffLogoPrintLine(instance);
if(!instance->config.pipe)
{
fputs(FASTFETCH_TEXT_MODIFIER_RESET FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintColor(&instance->config.mainColor);
}
//NULL check is required for modules with custom keys, e.g. disk with the folder path
if(customKeyFormat == NULL || customKeyFormat->length == 0)
{
fputs(moduleName, stdout);
if(moduleIndex > 0)
printf(" %hhu", moduleIndex);
}
else
{
FFstrbuf key;
ffStrbufInit(&key);
ffParseFormatString(&key, customKeyFormat, 1, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_UINT8, &moduleIndex}
});
ffStrbufWriteTo(&key, stdout);
ffStrbufDestroy(&key);
}
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
ffStrbufWriteTo(&instance->config.separator, stdout);
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
}
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* format, uint32_t numArgs, const FFformatarg* arguments)
{
FFstrbuf buffer;
ffStrbufInitA(&buffer, 256);
ffParseFormatString(&buffer, format, numArgs, arguments);
if(buffer.length > 0)
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
ffStrbufPutTo(&buffer, stdout);
}
ffStrbufDestroy(&buffer);
}
void ffPrintFormat(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, uint32_t numArgs, const FFformatarg* arguments)
{
ffPrintFormatString(instance, moduleName, moduleIndex, &moduleArgs->key, &moduleArgs->outputFormat, numArgs, arguments);
}
static void printError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* customErrorFormat, const char* message, va_list arguments)
{
bool hasCustomErrorFormat = customErrorFormat != NULL && customErrorFormat->length > 0;
if(!hasCustomErrorFormat && !instance->config.showErrors)
return;
if(hasCustomErrorFormat)
{
FFstrbuf error;
ffStrbufInit(&error);
ffStrbufAppendVF(&error, message, arguments);
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, customErrorFormat, 1, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &error}
});
ffStrbufDestroy(&error);
}
else
{
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
if(!instance->config.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
vprintf(message, arguments);
if(!instance->config.pipe)
puts(FASTFETCH_TEXT_MODIFIER_RESET);
}
}
void ffPrintErrorString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* customErrorFormat, const char* message, ...)
{
va_list arguments;
va_start(arguments, message);
printError(instance, moduleName, moduleIndex, customKeyFormat, customErrorFormat, message, arguments);
va_end(arguments);
}
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, const char* message, ...)
{
va_list arguments;
va_start(arguments, message);
printError(instance, moduleName, moduleIndex, &moduleArgs->key, &moduleArgs->errorFormat, message, arguments);
va_end(arguments);
}
void ffPrintColor(const FFstrbuf* colorValue)
{
//If the color is not set, this would reset in \033[m, which resets everything.
//So we only print it, if the main color is at least one char.
if(colorValue->length == 0)
return;
fputs("\033[", stdout);
ffStrbufWriteTo(colorValue, stdout);
fputc('m', stdout);
}
void ffPrintCharTimes(char c, uint32_t times)
{
for(uint32_t i = 0; i < times; i++)
putchar(c);
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#ifndef FF_INCLUDED_common_printing
#define FF_INCLUDED_common_printing
#include "fastfetch.h"
#include "common/format.h"
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat);
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* format, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintFormat(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, uint32_t numArgs, const FFformatarg* arguments);
void ffPrintErrorString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* customErrorFormat, const char* message, ...);
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, const char* message, ...);
void ffPrintColor(const FFstrbuf* colorValue);
void ffPrintCharTimes(char c, uint32_t times);
#endif
+36
View File
@@ -0,0 +1,36 @@
#include "fastfetch.h"
#include "common/processing.h"
#include "common/io.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
{
int pipes[2];
if(pipe(pipes) == -1)
return;
pid_t childPid = fork();
if(childPid == -1)
return;
//Child
if(childPid == 0)
{
dup2(pipes[1], STDOUT_FILENO);
close(pipes[0]);
close(pipes[1]);
close(STDERR_FILENO);
execvp(argv[0], argv);
exit(901);
}
//Parent
close(pipes[1]);
waitpid(childPid, NULL, 0);
ffAppendFDBuffer(pipes[0], buffer);
close(pipes[0]);
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#ifndef FF_INCLUDED_common_processing
#define FF_INCLUDED_common_processing
#include "util/FFstrbuf.h"
void ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]);
#endif
+207
View File
@@ -0,0 +1,207 @@
#include "fastfetch.h"
#include "common/properties.h"
#include <stdlib.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
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
{
FILE* file = fopen(filename, "r");
if(file == NULL)
return false;
bool valueStorage[4];
bool* unsetValues;
if(numQueries > sizeof(valueStorage) / sizeof(valueStorage[0]))
unsetValues = malloc(sizeof(bool) * numQueries);
else
unsetValues = valueStorage;
bool allSet = true;
for(uint32_t i = 0; i < numQueries; i++)
{
if((unsetValues[i] = queries[i].buffer->length == 0))
allSet = false;
}
if(allSet)
goto done;
char* line = NULL;
size_t len = 0;
while (getline(&line, &len, file) != -1)
{
for(uint32_t i = 0; i < numQueries; i++)
{
if(!unsetValues[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;
}
}
if(line != NULL)
free(line);
done:
fclose(file);
if(unsetValues != valueStorage)
free(unsetValues);
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;
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
{
//We need to copy the config dir each time, because it used by multiple threads, so we can't directly write to it.
ffStrbufSet(&baseDir, ffListGet(&instance->state.configDirs, i));
ffStrbufAppendS(&baseDir, relativeFile);
if(ffParsePropFileValues(baseDir.chars, numQueries, queries))
foundAFile = true;
bool allSet = true;
for(uint32_t k = 0; k < numQueries; k++)
{
if(queries[k].buffer->length == 0)
{
allSet = false;
break;
}
}
if(allSet)
break;
}
ffStrbufDestroy(&baseDir);
return foundAFile;
}
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
{
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#ifndef FF_INCLUDED_common_properties
#define FF_INCLUDED_common_properties
#include "util/FFstrbuf.h"
typedef struct FFpropquery
{
const char* start;
FFstrbuf* buffer;
} FFpropquery;
bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer);
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer);
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer);
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer);
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer);
#endif
+361
View File
@@ -0,0 +1,361 @@
#include "fastfetch.h"
#include "common/settings.h"
#include "common/library.h"
#include "common/io.h"
#include <pthread.h>
#include <string.h>
typedef enum FFInitState
{
FF_INITSTATE_UNINITIALIZED = 0,
FF_INITSTATE_SUCCESSFUL = 1,
FF_INITSTATE_FAILED = 2
} FFInitState;
#define FF_LIBRARY_DATA_LOAD_INIT(dataObject, userLibraryName, ...) \
static dataObject data; \
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; \
static FFInitState initState = FF_INITSTATE_UNINITIALIZED; \
pthread_mutex_lock(&mutex); \
if(initState != FF_INITSTATE_UNINITIALIZED) {\
pthread_mutex_unlock(&mutex); \
return initState == FF_INITSTATE_SUCCESSFUL ? &data : NULL; \
} \
initState = FF_INITSTATE_SUCCESSFUL; \
void* libraryHandle = ffLibraryLoad(&userLibraryName, __VA_ARGS__, NULL); \
if(libraryHandle == NULL) { \
initState = FF_INITSTATE_FAILED; \
pthread_mutex_unlock(&mutex); \
return NULL; \
} \
#define FF_LIBRARY_DATA_LOAD_SYMBOL(symbolName) \
data.ff ## symbolName = dlsym(libraryHandle, #symbolName); \
if(data.ff ## symbolName == NULL) { \
dlclose(libraryHandle); \
initState = FF_INITSTATE_FAILED; \
pthread_mutex_unlock(&mutex); \
return NULL; \
}
#define FF_LIBRARY_DATA_LOAD_RETURN \
initState = FF_INITSTATE_SUCCESSFUL; \
pthread_mutex_unlock(&mutex); \
return &data;
#define FF_LIBRARY_DATA_LOAD_ERROR \
{ \
dlclose(libraryHandle); \
initState = FF_INITSTATE_FAILED; \
pthread_mutex_unlock(&mutex); \
return NULL; \
}
#ifdef FF_HAVE_GIO
#include <gio/gio.h>
typedef struct GVariantGetters
{
FF_LIBRARY_SYMBOL(g_variant_get_string)
FF_LIBRARY_SYMBOL(g_variant_get_boolean)
FF_LIBRARY_SYMBOL(g_variant_get_int32)
} GVariantGetters;
static FFvariant getGVariantValue(GVariant* variant, FFvarianttype type, const GVariantGetters* variantGetters)
{
if(variant == NULL)
return FF_VARIANT_NULL;
else if(type == FF_VARIANT_TYPE_STRING)
return (FFvariant) {.strValue = variantGetters->ffg_variant_get_string(variant, NULL)};
else if(type == FF_VARIANT_TYPE_BOOL)
return (FFvariant) {.boolValue = (bool) variantGetters->ffg_variant_get_boolean(variant), .boolValueSet = true};
else if(type == FF_VARIANT_TYPE_INT)
return (FFvariant) {.intValue = variantGetters->ffg_variant_get_int32(variant)};
else
return FF_VARIANT_NULL;
}
typedef struct GSettingsData
{
FF_LIBRARY_SYMBOL(g_settings_schema_source_lookup)
FF_LIBRARY_SYMBOL(g_settings_schema_has_key)
FF_LIBRARY_SYMBOL(g_settings_new_full)
FF_LIBRARY_SYMBOL(g_settings_get_value)
FF_LIBRARY_SYMBOL(g_settings_get_user_value)
FF_LIBRARY_SYMBOL(g_settings_get_default_value)
FF_LIBRARY_SYMBOL(g_settings_schema_source_get_default)
GSettingsSchemaSource* schemaSource;
GVariantGetters variantGetters;
} GSettingsData;
static const GSettingsData* getGSettingsData(FFinstance* instance)
{
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)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_new_full)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_get_value)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_get_user_value)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_get_default_value)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_schema_source_get_default)
#define data data.variantGetters
FF_LIBRARY_DATA_LOAD_SYMBOL(g_variant_get_string)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_variant_get_boolean)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_variant_get_int32)
#undef data
data.schemaSource = data.ffg_settings_schema_source_get_default();
if(data.schemaSource == NULL)
FF_LIBRARY_DATA_LOAD_ERROR
FF_LIBRARY_DATA_LOAD_RETURN
}
FFvariant ffSettingsGetGSettings(FFinstance* instance, const char* schemaName, const char* path, const char* key, FFvarianttype type)
{
const GSettingsData* data = getGSettingsData(instance);
if(data == NULL)
return FF_VARIANT_NULL;
GSettingsSchema* schema = data->ffg_settings_schema_source_lookup(data->schemaSource, schemaName, true);
if(schema == NULL)
return FF_VARIANT_NULL;
if(data->ffg_settings_schema_has_key(schema, key) == false)
return FF_VARIANT_NULL;
GSettings* settings = data->ffg_settings_new_full(schema, NULL, path);
if(settings == NULL)
return FF_VARIANT_NULL;
GVariant* variant = data->ffg_settings_get_value(settings, key);
if(variant != NULL)
return getGVariantValue(variant, type, &data->variantGetters);
variant = data->ffg_settings_get_user_value(settings, key);
if(variant != NULL)
return getGVariantValue(variant, type, &data->variantGetters);
variant = data->ffg_settings_get_default_value(settings, key);
return getGVariantValue(variant, type, &data->variantGetters);
}
#else //FF_HAVE_GIO
FFvariant ffSettingsGetGSettings(FFinstance* instance, const char* schemaName, const char* path, const char* key, FFvarianttype type)
{
FF_UNUSED(instance, schemaName, path, key, type)
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_GIO
#ifdef FF_HAVE_DCONF
#include <dconf.h>
typedef struct DConfData
{
FF_LIBRARY_SYMBOL(dconf_client_read_full)
FF_LIBRARY_SYMBOL(dconf_client_new)
GVariantGetters variantGetters;
DConfClient* client;
} DConfData;
static const DConfData* getDConfData(FFinstance* instance)
{
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)
#define data data.variantGetters
FF_LIBRARY_DATA_LOAD_SYMBOL(g_variant_get_string)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_variant_get_boolean)
FF_LIBRARY_DATA_LOAD_SYMBOL(g_variant_get_int32)
#undef data
data.client = data.ffdconf_client_new();
if(data.client == NULL)
FF_LIBRARY_DATA_LOAD_ERROR
FF_LIBRARY_DATA_LOAD_RETURN
}
FFvariant ffSettingsGetDConf(FFinstance* instance, const char* key, FFvarianttype type)
{
const DConfData* data = getDConfData(instance);
if(data == NULL)
return FF_VARIANT_NULL;
GVariant* variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_FLAGS_NONE, NULL);
if(variant != NULL)
return getGVariantValue(variant, type, &data->variantGetters);
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_USER_VALUE, NULL);
if(variant != NULL)
return getGVariantValue(variant, type, &data->variantGetters);
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_DEFAULT_VALUE, NULL);
return getGVariantValue(variant, type, &data->variantGetters);
}
#else //FF_HAVE_DCONF
FFvariant ffSettingsGetDConf(FFinstance* instance, const char* key, FFvarianttype type)
{
FF_UNUSED(instance, key, type)
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_DCONF
FFvariant ffSettingsGet(FFinstance* instance, const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
{
FFvariant gsettings = ffSettingsGetGSettings(instance, gsettingsSchemaName, gsettingsPath, gsettingsKey, type);
if(
(type == FF_VARIANT_TYPE_BOOL && gsettings.boolValueSet) ||
(type != FF_VARIANT_TYPE_BOOL && gsettings.strValue != NULL)
) return gsettings;
return ffSettingsGetDConf(instance, dconfKey, type);
}
#ifdef FF_HAVE_XFCONF
#include <xfconf/xfconf.h>
typedef struct XFConfData
{
FF_LIBRARY_SYMBOL(xfconf_channel_get)
FF_LIBRARY_SYMBOL(xfconf_channel_has_property)
FF_LIBRARY_SYMBOL(xfconf_channel_get_string)
FF_LIBRARY_SYMBOL(xfconf_channel_get_bool)
FF_LIBRARY_SYMBOL(xfconf_channel_get_int)
FF_LIBRARY_SYMBOL(xfconf_init)
} XFConfData;
static const XFConfData* getXFConfData(FFinstance* instance)
{
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)
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_get_string)
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_get_bool)
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_get_int)
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_init)
if(data.ffxfconf_init(NULL) == false)
FF_LIBRARY_DATA_LOAD_ERROR
FF_LIBRARY_DATA_LOAD_RETURN
}
FFvariant ffSettingsGetXFConf(FFinstance* instance, const char* channelName, const char* propertyName, FFvarianttype type)
{
const XFConfData* data = getXFConfData(instance);
if(data == NULL)
return FF_VARIANT_NULL;
XfconfChannel* channel = data->ffxfconf_channel_get(channelName); // Never fails according to documentation but rather returns an empty channel
if(!data->ffxfconf_channel_has_property(channel, propertyName))
return FF_VARIANT_NULL;
if(type == FF_VARIANT_TYPE_INT)
return (FFvariant) {.intValue = data->ffxfconf_channel_get_int(channel, propertyName, 0)};
if(type == FF_VARIANT_TYPE_STRING)
return (FFvariant) {.strValue = data->ffxfconf_channel_get_string(channel, propertyName, NULL)};
if(type == FF_VARIANT_TYPE_BOOL)
return (FFvariant) {.boolValue = data->ffxfconf_channel_get_bool(channel, propertyName, false), .boolValueSet = true};
return FF_VARIANT_NULL;
}
#else //FF_HAVE_XFCONF
FFvariant ffSettingsGetXFConf(FFinstance* instance, const char* channelName, const char* propertyName, FFvarianttype type)
{
FF_UNUSED(instance, channelName, propertyName, type)
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_XFCONF
#ifdef FF_HAVE_SQLITE3
#include <sqlite3.h>
#include <sys/stat.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)
{
if(!ffFileExists(dbPath, S_IFREG))
return 0;
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) {
uint32_t originalLength = result->length;
ffStrbufEnsureFree(result, PROP_VALUE_MAX);
result->length += (uint32_t) __system_property_get(propName, result->chars + result->length);
return result->length > originalLength;
}
#endif
+39
View File
@@ -0,0 +1,39 @@
#pragma once
#ifndef FF_INCLUDED_common_settings
#define FF_INCLUDED_common_settings
#include "fastfetch.h"
typedef enum FFvarianttype
{
FF_VARIANT_TYPE_STRING,
FF_VARIANT_TYPE_BOOL,
FF_VARIANT_TYPE_INT
} FFvarianttype;
typedef union FFvariant
{
const char* strValue;
int32_t intValue;
struct
{
bool boolValueSet;
bool boolValue;
};
} FFvariant;
#define FF_VARIANT_NULL ((FFvariant){.strValue = NULL})
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
#endif
+16
View File
@@ -0,0 +1,16 @@
# Fastfetch system configuration
# This file sets the defaults for all users of the system.
# For more information about configuration files work,
# see the file ~/.config/fastfetch/config.conf, generated during first
# All options that can be put there (or passed as argument) can be put here too.
# This file was shipped with $"FASTFETCH_PROJECT_VERSION$".
# Use fastfetch --print-config-system > /etc/fastfetch/config.conf to overwrite this file with the current defaults
# User config option
# Sets if fastfetch should load user provided configuration.
# If this is off, fastfetch ignores the user config file and any passed arguments
# Must be true or false
# Default is true.
#--load-user-config true
+306
View File
@@ -0,0 +1,306 @@
# Fastfetch configuration
# Write every argument in different lines.
# Direct arguments will overwrite the corresponding ones in this file.
# Argument keys are not case sensitive.
# Whitespaces are trimmed at the beginning and the end.
# Empty lines or lines starting with # are ignored.
# This file was shipped with $"FASTFETCH_PROJECT_VERSION$".
# Use fastfetch --print-config-user > ~/.config/fastfetch/config.conf to overwrite this file with the current defaults
# Below some often usefull options are listed. Uncomment and modify them so they take affect.
# Note that there are a lot more options than the ones listed here, take a look at "fastfetch --help".
# Of course all of them can be made persistent here too.
# Config option:
# Load additional config files.
# Some are shipped with fastfetch, list them with "fastfetch --list-presets".
# Must be a path to a config file or the name of a shipped preset.
# The config file is completly loaded before continuing in the current file, so the placement of this option matters, as later options overwrite already set ones.
# Can be used multiple times to load multiple config files / presets.
#--load-config /path/to/config.txt
# Structure option:
# Sets the modules to use and their order.
# Must be a list of module names, separated by colons.
# List available modules with "fastfetch --list-modules".
# Get the default structure with "fastfetch --print-structure".
#--structure $"FASTFETCH_DATATEXT_STRUCTURE$"
# Multithreading option:
# Sets if fastfetch should use multiple threads to detect the values.
# Must be true or false.
# Default is true.
#--multithreading true
# 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.
# Must be true or false.
# Default is true.
#--disable-linewrap true
# Cursor option:
# Sets if fastfetch should hide the console cursor during the run.
# Must be true or false.
# Default is true.
#--hide-cursor 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
# 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
# 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
# Logo height option:
# Sets the height of the logo (in characters) if the logo is an image.
# Must be a positive integer.
# Default is 0 (keeps aspect ration).
#--logo-height 0
# Logo color options:
# Overwrite a color in the logo. Also works for user provided logos.
# In the user logo, they replace $[1-9]. Use $$ to print a single $ sign.
# Must be linux console color codes or the name of a color.
# Default is the one specified by the logo.
# Use "fastfetch --help color" to learn more and see examples.
# Valid index range is [1-9].
#--logo-color-1 red
#--logo-color-2 32
# [...]
#--logo-color-9 yellow
# 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.
#--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
# Title FQDN option:
# Sets if the title should use the fully qualified domain name.
# Must be true or false.
# Default is false.
#--title-fqdn false
# 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.
# Must be a positive integer.
# Default is 0 (disabled).
#--public-ip-timeout 0
# OS file option
# Sets the path to the file containing the operating system information.
# Should be a valid path to an existing file.
# Note that you might need to run fastfetch with --recache once for it to take affect.
# Default is /etc/os-release.
#--os-file /etc/os-release
# Player name option
# Sets the name of the player. This is also used in song detection
# Must be the exact name of the player or a dbus address (e.g. org.mpris.MediaPlayer2.spotify)
# Default is the first match starting with org.mpris.MediaPlayer2.
#--player-name spotify
# Escape bedrock option
# Sets if fastfetch should escape the bedrock jail, if it detectes that it is running in one
# Must be true or false.
# Default is true.
#--escape-bedrock true
# GL option
# Sets with opengl context creation library to use
# Must be either auto, egl, glx or osmesa
# Default is auto.
#--gl auto
# Key options:
# Sets the displayed key of a module
# Can be any string. Some of theme take an argument like a format string. See "fastfetch --help format" for help.
#--os-key OS
#--host-key Host
#--kernel-key Kernel
#--uptime-key Uptime
#--processes-key Processes
#--packages-key Packages
#--shell-key Shell
#--resolution-key Resolution {1}
#--de-key DE
#--wm-key WM
#--wm-theme-key WM Theme
#--theme-key Theme
#--icons-key Icons
#--font-key Font
#--cursor-key Cursor
#--terminal-key Terminal
#--terminal-font-key Terminal Font
#--cpu-key CPU
#--cpu-usage-key CPU Usage
#--gpu-key GPU {1}
#--memory-key Memory
#--disk-key Disk ({1})
#--battery-key Battery {1}
#--locale-key Locale
#--local-ip-key Local IP ({1})
#--public-ip-key Public IP
#--player-key Media Player
#--song-key Song
#--datetime-key Date Time
#--vulkan-key Vulkan
#--opengl-key OpenGL
#--opencl-key OpenCL
# Format options:
# Sets the format string for module values.
# For information on format strings, see "fastfetch --help format".
# To see the parameter they take and their default value, see "fastfetch --help *-format", e.g. "fastfetch --help os-format".
# An empty format string (As they are currently below) will behave as if it was not set.
#--os-format
#--host-format
#--kernel-format
#--uptime-format
#--processes-format
#--packages-format
#--shell-format
#--resolution-format
#--de-format
#--wm-format
#--wm-theme-format
#--theme-format
#--icons-format
#--font-format
#--cursor-format
#--terminal-format
#--terminal-font-format
#--cpu-format
#--cpu-usage-format
#--gpu-format
#--memory-format
#--disk-format
#--battery-format
#--locale-format
#--local-ip-format
#--public-ip-format
#--player-format
#--song-format
#--datetime-format
#--vulkan-format
#--opengl-format
#--opencl-format
# Error options:
# Sets the format string to use if an error occured
# For information on format strings, see "fastfetch --help format".
# Each of them take the error as first and only argument.
# If one of them is set, the module will appear, even if --show-errors is not given.
#--os-error
#--host-error
#--kernel-error
#--uptime-error
#--processes-error
#--packages-error
#--shell-error
#--resolution-error
#--de-error
#--wm-error
#--wm-theme-error
#--theme-error
#--icons-error
#--font-error
#--cursor-error
#--terminal-error
#--terminal-font-error
#--cpu-error
#--cpu-usage-error
#--gpu-error
#--memory-error
#--disk-error
#--battery-error
#--locale-error
#--local-ip-error
#--public-ip-error
#--player-error
#--song-error
#--datetime-error
#--vulkan-error
#--opengl-error
#--opencl-error
# Library options:
# Sets an user specific path to a library to load.
# Must be a valid path to a library.
#--lib-PCI /usr/lib/libpci.so
#--lib-vulkan /usr/lib/libvulkan.so
#--lib-wayland /usr/lib/libwayland-client.so
#--lib-xcb-randr /usr/lib/libxcb-randr.so
#--lib-xcb /usr/lib/libxcb.so
#--lib-Xrandr /usr/lib/libXrandr.so
#--lib-X11 /usr/lib/libX11.so
#--lib-gio /usr/lib/libgio-2.0.so
#--lib-DConf /usr/lib/libdconf.so
#--lib-DBus /usr/lib/libdbus-1.so
#--lib-XFConf /usr/lib/libxfconf-0.so
#--lib-sqlite3 /usr/lib/libsqlite3.so
#--lib-rpm /usr/lib/librpm.so
#--lib-imagemagick /usr/lib/libMagickCore-7.Q16HDRI.so
#--lib-z /usr/lib/libz.so
#--lib-chafa /usr/lib/libchafa.so
#--lib-egl /usr/lib/libEGL.so
#--lib-glx /usr/lib/libGLX.so
#--lib-osmesa /usr/lib/libOSMesa.so
#--lib-opencl /usr/lib/libOpenCL.so
+100
View File
@@ -0,0 +1,100 @@
Usage: fastfetch <options>
Informative options:
-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-system: prints the default system config and exits
--print-config-user: prints the default user config and exits
--print-structure: prints the default stucture and exits
General options:
-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
--escape-bedrock <?value>: on bedrock linux, sets if it should escape the bedrock jail or not
--pipe <?value>: disable logo and all escape sequences
Logo options:
-l,--logo <logo>: set the logo to use. The type is specified by --logo-type. If default: the name of a builtin logo or a path to a file
--logo-type <type>: set the type of the logo given. Must be auto, builtin, file, raw, sixel, 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
General module options:
--<module>-format <format>: Sets the format string to use for each specific module.
To see how a format string works, use fastfetch --help format.
To see help about a specific format string, use fastfetch --help <module>-format.
--<module>-key <key>: Sets the key to use for each specific module.
For modules which print multiple lines, the string is parsed as a format string with the index as first character.
--<module>-error <format>: Sets the error format string to use for each specific module.
The error is given as the first and only argument.
Setting this for a module will cause it to appear, even if --show-errors is not given.
Library options: Set the path of a library to load
--lib-PCI <path>
--lib-vulkan <path>
--lib-wayland <path>
--lib-xcb-randr <path>
--lib-xcb <path>
--lib-Xrandr <path>
--lib-X11 <path>
--lib-gio <path>
--lib-DConf <path>
--lib-DBus <path>
--lib-XFConf <path>
--lib-sqlite3 <path>
--lib-rpm <path>
--lib-imagemagick <path>
--lib-z <path>
--lib-chafa <path>
--lib-egl <path>
--lib-glx <path>
--lib-osmesa <path>
--lib-opencl <path>
Module specific options:
--title-fqdn <?value>: sets if the title should use fully qualified domain name. Default is false.
--separator-string <str>: Set the string printed by the separator module
--os-file <path>: Set the path to the file containing OS informations
--disk-folders <folders>: A colon separated list of folder paths for the disk output. Default is "/:/home"
--battery-dir <folder>: The directory where the battery folders are. Standard: /sys/class/power_supply/
--localip-show-ipv4 <?value>: Show ipv4 addresses in local ip module. Default is true
--localip-show-ipv6 <?value>: Show ipv6 addresses in local ip module. Default is false
--localip-show-loop <?value>: Show loop back addresses (127.0.0.1) in local ip module. Default is false
--public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0)
--player-name: The name of the player to use
--gl <value>: Sets the opengl context creation library to use. Must be auto, egl, glx or osmesa. Default is auto
Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci"
If a value starts with a ?, it is optional. "true" will be used if not set.
A (+) at the end indicates that more help can be printed with --help <option>
All options can be made permanent in $XDG_CONFIG_HOME/fastfetch/config.conf
+9
View File
@@ -0,0 +1,9 @@
usage: fastfetch --color <color>
<color> must be a color encoding for linux terminals. It is inserted between "ESC[" and "m".
Infos about them can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters.
Examples:
--color 35: sets the color to pink
--color 4;92: sets the color to bright Green with underline
--color 5;104: blinking text on a blue background
If no color is set, the main color of the logo will be used.
+9
View File
@@ -0,0 +1,9 @@
usage: fastfetch --load-config <file>
Loads a config file. A config file contains one flag per line. Empty lines or lines starting with # are ignored.
If the file is relative it looks in the following order:
- relative to the current working directory
- relative to ~/.local/share/fastfetch/presets/
- relative to /usr/share/fastfetch/presets/
Fastfetch provides some default presets. List them with --print-available-presets.
Note that this will only print presets fastfetch knows about and not every possible one.
+36
View File
@@ -0,0 +1,36 @@
A format string is a string that contains placeholders for values.
These placeholders begin with a '{', containing the index of the value, and end with a '}'.
For example the format string "Values: {1} ({2})", with the values "First" and "My second val", will produce
The format string can contain placeholders in any order and have multiple occurences.
To include spaces when setting from the command line, surround the whole string with double quotes (").
If the value index is missing, meaning the placeholder is "{}", an internal counter sets the value index.
This means that the format string "Values: {1} ({2})" is equivalent to "Values: {} ({})".
Note that this counter only counts empty placeholders, so the format string "{2} {} {}" will contain the second v
To make formatting easier, a double open curly brace ("{{") will be printed as a single open curly brace and not
If a value index is misformatted or wants a non-existing value, it will be printed as is, with the curly braces aro
If the last placeholder isn't closed, it will be treated like it was at the end of the format string.
To only print something if a variable is set, use "{?<index>} ... {?}".
For example, to only print a second value if it is set, use "{?2} Second value: {2}{?}".
If a "{?}" is found without an opener, it is printed as is.
To only print something if a variable is not set, do the same as with if, just replace every '?' with a '!'.
For example to print a fallback for a second value if it is not set, use "{?2}{2}{?}{/2}Second value fallback{/}"
To stop formatting at any point in the format string, use "{-}".
To print something with color, start a placeholder with a '#' and then the linux terminal color encoding.
"\\033[" at the start, and an 'm' at the end is automatically added, so don't do that.
A "{#}" is equivalent to a "{#0}" and resets everything to normal.
For example to print something pink and underline, use "{#4;35}...{#}".
Information about what the numbers mean can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Sele
Which escape codes are supported and how they look is defined by your terminal.
If a format string evaluates to an empty value, the whole line in the output will be discarded.
You can therefore use --host-format " " to disable host output.
Note that --host-format "" would evaluate as not set, and therefore use the built-in host format
Format string is also the way to go to set a fixed value - just use one without placeholders.
For example when running in headless mode, you could use "--resolution-format "Preferred".
+38
View File
@@ -0,0 +1,38 @@
Battery
Break
Colors
CPU
CPUUsage
Cursor
Date
Datetime
DE
Disk
Font
GPU
Host
Icons
Kernel
Locale
LocalIP
Memory
OS
OpenCL
OpenGL
Packages
Player
Processes
PublicIP
Resolution
Separator
Shell
Song
Terminal
TerminalFont
Theme
Time
Title
Uptime
Vulkan
WM
WMTheme
+1
View File
@@ -0,0 +1 @@
Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Resolution:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Disk:Battery:Locale:Break:Colors
+73
View File
@@ -0,0 +1,73 @@
#include "fastfetch.h"
#include "detection/datetime.h"
#include <time.h>
#include <pthread.h>
const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance)
{
FF_UNUSED(instance); //We may need it later for additional configuration
static FFDateTimeResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if (init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
const time_t t = time(NULL);
struct tm* tm = localtime(&t);
result.year = (uint16_t) (tm->tm_year + 1900);
result.yearShort = (uint8_t) (result.year % 100);
result.month = (uint8_t) (tm->tm_mon + 1);
ffStrbufInit(&result.monthPretty);
result.monthPretty.length = (uint32_t) strftime(result.monthPretty.chars, ffStrbufGetFree(&result.monthPretty), "%m", tm);
ffStrbufInit(&result.monthName);
result.monthName.length = (uint32_t) strftime(result.monthName.chars, ffStrbufGetFree(&result.monthName), "%B", tm);
ffStrbufInit(&result.monthNameShort);
result.monthNameShort.length = (uint32_t) strftime(result.monthNameShort.chars, ffStrbufGetFree(&result.monthNameShort), "%b", tm);
result.week = (uint8_t) (tm->tm_yday / 7 + 1);
ffStrbufInit(&result.weekday);
result.weekday.length = (uint32_t) strftime(result.weekday.chars, ffStrbufGetFree(&result.weekday), "%A", tm);
ffStrbufInit(&result.weekdayShort);
result.weekdayShort.length = (uint32_t) strftime(result.weekdayShort.chars, ffStrbufGetFree(&result.weekdayShort), "%a", tm);
result.dayInYear = (uint8_t) (tm->tm_yday + 1);
result.dayInMonth = (uint8_t) tm->tm_mday;
result.dayInWeek = tm->tm_wday == 0 ? 7 : (uint8_t) tm->tm_wday;
result.hour = (uint8_t) tm->tm_hour;
ffStrbufInit(&result.hourPretty);
result.hourPretty.length = (uint32_t) strftime(result.hourPretty.chars, ffStrbufGetFree(&result.hourPretty), "%H", tm);
result.hour12 = (uint8_t) (result.hour % 12);
ffStrbufInit(&result.hour12Pretty);
result.hour12Pretty.length = (uint32_t) strftime(result.hour12Pretty.chars, ffStrbufGetFree(&result.hour12Pretty), "%I", tm);
result.minute = (uint8_t) tm->tm_min;
ffStrbufInit(&result.minutePretty);
result.minutePretty.length = (uint32_t) strftime(result.minutePretty.chars, ffStrbufGetFree(&result.minutePretty), "%M", tm);
result.second = (uint8_t) tm->tm_sec;
ffStrbufInit(&result.secondPretty);
result.secondPretty.length = (uint32_t) strftime(result.secondPretty.chars, ffStrbufGetFree(&result.secondPretty), "%S", tm);
pthread_mutex_unlock(&mutex);
return &result;
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#ifndef FF_INCLUDED_detection_datetime
#define FF_INCLUDED_detection_datetime
#include "fastfetch.h"
typedef struct FFDateTimeResult
{
//Examples for 21.02.2022 - 15:18:37
uint16_t year; //2022
uint8_t yearShort; //22
uint8_t month; //2
FFstrbuf monthPretty; //02
FFstrbuf monthName; //February
FFstrbuf monthNameShort; //Feb
uint8_t week; //8
FFstrbuf weekday; //Monday
FFstrbuf weekdayShort; //Mon
uint16_t dayInYear; //52
uint8_t dayInMonth; //21
uint8_t dayInWeek; //1
uint8_t hour; //15
FFstrbuf hourPretty; //15
uint8_t hour12; //3
FFstrbuf hour12Pretty; //03
uint8_t minute; //18
FFstrbuf minutePretty; //18
uint8_t second; //37
FFstrbuf secondPretty; //37
} FFDateTimeResult;
const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance);
#endif
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifndef FF_INCLUDED_detection_displayserver
#define FF_INCLUDED_detection_displayserver
#include "fastfetch.h"
typedef struct FFResolutionResult
{
uint32_t width;
uint32_t height;
uint32_t refreshRate;
} FFResolutionResult;
typedef struct FFDisplayServerResult
{
FFstrbuf wmProcessName;
FFstrbuf wmPrettyName;
FFstrbuf wmProtocolName;
FFstrbuf deProcessName;
FFstrbuf dePrettyName;
FFstrbuf deVersion;
FFlist resolutions; //List of FFResolutionResult
} FFDisplayServerResult;
const FFDisplayServerResult* ffConnectDisplayServer(const FFinstance* instance);
#endif
+133
View File
@@ -0,0 +1,133 @@
#include "displayServer.h"
#include <pthread.h>
#include <dirent.h>
uint32_t ffdsParseRefreshRate(int32_t refreshRate)
{
if(refreshRate <= 0)
return 0;
int remainder = refreshRate % 5;
if(remainder >= 3)
refreshRate += (5 - remainder);
else
refreshRate -= remainder;
//All other typicall refresh rates are dividable by 5
if(refreshRate == 145)
refreshRate = 144;
return (uint32_t) refreshRate;
}
bool ffdsAppendResolution(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate)
{
if(width == 0 || height == 0)
return false;
FFResolutionResult* resolution = ffListAdd(&result->resolutions);
resolution->width = width;
resolution->height = height;
resolution->refreshRate = refreshRate;
return true;
}
static void parseDRM(FFDisplayServerResult* result)
{
const char* drmDirPath = "/sys/class/drm/";
DIR* dirp = opendir(drmDirPath);
if(dirp == NULL)
return;
FFstrbuf drmDir;
ffStrbufInitA(&drmDir, 64);
ffStrbufAppendS(&drmDir, drmDirPath);
uint32_t drmDirLength = drmDir.length;
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
ffStrbufAppendS(&drmDir, entry->d_name);
ffStrbufAppendS(&drmDir, "/modes");
FILE* modeFile = fopen(drmDir.chars, "r");
if(modeFile == NULL)
{
ffStrbufSubstrBefore(&drmDir, drmDirLength);
continue;
}
FFResolutionResult* resolution = ffListAdd(&result->resolutions);
resolution->width = 0;
resolution->height = 0;
resolution->refreshRate = 0;
int scanned = fscanf(modeFile, "%ix%i", &resolution->width, &resolution->height);
if(scanned < 2 || resolution->width == 0 || resolution->height == 0)
--result->resolutions.length;
fclose(modeFile);
ffStrbufSubstrBefore(&drmDir, drmDirLength);
}
closedir(dirp);
ffStrbufDestroy(&drmDir);
}
const FFDisplayServerResult* ffConnectDisplayServer(const FFinstance* instance)
{
static FFDisplayServerResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.wmProcessName);
ffStrbufInit(&result.wmPrettyName);
ffStrbufInit(&result.wmProtocolName);
ffStrbufInit(&result.deProcessName);
ffStrbufInit(&result.dePrettyName);
ffStrbufInit(&result.deVersion);
ffListInitA(&result.resolutions, sizeof(FFResolutionResult), 4);
//We try wayland as our prefered display server, as it supports the most features.
//This method can't detect the name of our WM / DE
ffdsConnectWayland(instance, &result);
//Try the x11 libs, from most feature rich to least.
//We use the resolution list to detect if a connection is needed.
//They respect wmProtocolName, and only detect resolution if it is set.
if(result.resolutions.length == 0)
ffdsConnectXcbRandr(instance, &result);
if(result.resolutions.length == 0)
ffdsConnectXrandr(instance, &result);
if(result.resolutions.length == 0)
ffdsConnectXcb(instance, &result);
if(result.resolutions.length == 0)
ffdsConnectXlib(instance, &result);
//This resolution detection method is display server independent.
//Use it if all connections failed
if(result.resolutions.length == 0)
parseDRM(&result);
//This fills in missing information about WM / DE by using env vars and iterating processes
ffdsDetectWMDE(instance, &result);
pthread_mutex_unlock(&mutex);
return &result;
}
@@ -0,0 +1,26 @@
#pragma once
#ifndef FASTFETCH_INCLUDED_DISPLAYSERVER
#define FASTFETCH_INCLUDED_DISPLAYSERVER
#include "fastfetch.h"
#include "detection/displayserver.h"
#define FF_DISPLAYSERVER_PROTOCOL_WAYLAND "Wayland"
#define FF_DISPLAYSERVER_PROTOCOL_X11 "X11"
#define FF_DISPLAYSERVER_PROTOCOL_TTY "TTY"
uint32_t ffdsParseRefreshRate(int32_t refreshRate);
bool ffdsAppendResolution(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate);
void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result);
void ffdsDetectWMDE(const FFinstance* instance, FFDisplayServerResult* result);
#endif
+181
View File
@@ -0,0 +1,181 @@
#define _GNU_SOURCE //required for struct ucred
#include "displayServer.h"
#include <stdlib.h>
#include <string.h>
#ifdef FF_HAVE_WAYLAND
#include "common/library.h"
#include "common/io.h"
#include <pthread.h>
#include <wayland-client.h>
#include <sys/socket.h>
typedef struct WaylandData
{
FFlist* results;
FF_LIBRARY_SYMBOL(wl_proxy_marshal_constructor_versioned)
FF_LIBRARY_SYMBOL(wl_proxy_add_listener)
const struct wl_interface* ffwl_output_interface;
} WaylandData;
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
{
struct ucred ucred;
socklen_t len = sizeof(struct ucred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
return;
FFstrbuf procPath;
ffStrbufInit(&procPath);
ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); //We check the cmdline for the process name, because it is not trimmed.
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
ffStrbufDestroy(&procPath);
}
static void stubListener(void* data, ...)
{
(void) data;
}
static void waylandOutputModeListener(void* data, struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate)
{
FF_UNUSED(output);
WaylandData* wldata = data;
if(!(flags & WL_OUTPUT_MODE_CURRENT) || width <= 0 || height <= 0)
return;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
FFResolutionResult* result = ffListAdd(wldata->results);
pthread_mutex_unlock(&mutex);
result->width = (uint32_t) width;
result->height = (uint32_t) height;
result->refreshRate = ffdsParseRefreshRate(refreshRate / 1000);
}
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
{
WaylandData* wldata = data;
if(strcmp(interface, wldata->ffwl_output_interface->name) == 0)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
if(output == NULL)
return;
//Needs to be static, because the scope of the function will already be lost when calling the listener
static struct wl_output_listener outputListener = {
.mode = waylandOutputModeListener,
.geometry = (void*) stubListener,
//https://lists.freedesktop.org/archives/wayland-devel/2013-July/010278.html
#if WAYLAND_VERSION_MINOR >= 2
.done = (void*) stubListener,
.scale = (void*) stubListener,
#endif
//https://lists.freedesktop.org/archives/wayland-devel/2021-December/042064.html
#if WAYLAND_VERSION_MINOR >= 20
.name = (void*) stubListener,
.description = (void*) stubListener,
#endif
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, data);
}
}
bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(wayland, instance->config.libWayland, false, "libwayland-client.so", 1)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_get_fd, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_dispatch, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_roundtrip, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_proxy_marshal_constructor, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_disconnect, false)
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_registry_interface, false)
WaylandData data;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(wayland, data.ffwl_proxy_marshal_constructor_versioned, wl_proxy_marshal_constructor_versioned, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(wayland, data.ffwl_proxy_add_listener, wl_proxy_add_listener, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(wayland, data.ffwl_output_interface, wl_output_interface, false)
struct wl_display* display = ffwl_display_connect(NULL);
if(display == NULL)
{
dlclose(wayland);
return false;
}
waylandDetectWM(ffwl_display_get_fd(display), result);
struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL);
if(registry == NULL)
{
ffwl_display_disconnect(display);
dlclose(wayland);
return false;
}
data.results = &result->resolutions;
struct wl_registry_listener registry_listener = {
.global = waylandGlobalAddListener,
.global_remove = (void*) stubListener
};
data.ffwl_proxy_add_listener(registry, (void(**)(void)) &registry_listener, &data);
ffwl_display_dispatch(display);
ffwl_display_roundtrip(display);
ffwl_display_disconnect(display); //This will also destroy our wl_registry and wl_output proxies
dlclose(wayland);
//We successfully connected to wayland and detected the resolution.
//So we can set set the session type to wayland.
//This is used as an indicator that we are running wayland by the x11 backends.
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND);
return true;
}
#endif
void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* result)
{
//Wayland requires this to be set
if(getenv("XDG_RUNTIME_DIR") == NULL)
return;
#ifdef FF_HAVE_WAYLAND
if(detectWayland(instance, result))
return;
#else
FF_UNUSED(instance);
#endif
const char* xdgSessionType = getenv("XDG_SESSION_TYPE");
//If XDG_SESSION_TYPE is set, and doesn't contain "wayland", we are probably not running in a wayland session.
if(xdgSessionType != NULL && strcasecmp(xdgSessionType, "wayland") != 0)
return;
//If XDG_SESSION_TYPE is not set, check if WAYLAND_DISPLAY or WAYLAND_SOCKET is set.
//If not, there is no indicator for a wayland session
if(xdgSessionType == NULL && getenv("WAYLAND_DISPLAY") == NULL && getenv("WAYLAND_SOCKET") == NULL)
return;
//We are probably running a wayland compositor at this point,
//but fastfetch was compiled without the required library, or loading the library failed.
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND);
}
+461
View File
@@ -0,0 +1,461 @@
#include "displayServer.h"
#include "common/io.h"
#include "common/properties.h"
#include "common/parsing.h"
#include "common/processing.h"
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
static const char* parseEnv()
{
const char* env;
env = getenv("XDG_CURRENT_DESKTOP");
if(ffStrSet(env))
return env;
env = getenv("XDG_SESSION_DESKTOP");
if(ffStrSet(env))
return env;
env = getenv("CURRENT_DESKTOP");
if(ffStrSet(env))
return env;
env = getenv("SESSION_DESKTOP");
if(ffStrSet(env))
return env;
env = getenv("DESKTOP_SESSION");
if(ffStrSet(env))
return env;
if(getenv("KDE_FULL_SESSION") != NULL || getenv("KDE_SESSION_UID") != NULL || getenv("KDE_SESSION_VERSION") != NULL)
return "KDE";
if(getenv("GNOME_DESKTOP_SESSION_ID") != NULL)
return "Gnome";
if(getenv("MATE_DESKTOP_SESSION_ID") != NULL)
return "Mate";
if(getenv("TDE_FULL_SESSION") != NULL)
return "Trinity";
if(
getenv("WAYLAND_DISPLAY") != NULL &&
ffFileExists("/mnt/wslg/", S_IFDIR)
) return "WSLg";
return NULL;
}
static void applyPrettyNameIfWM(FFDisplayServerResult* result, const char* processName)
{
if(!ffStrSet(processName))
return;
if(
strcasecmp(processName, "kwin_wayland") == 0 ||
strcasecmp(processName, "kwin_wayland_wrapper") == 0 ||
strcasecmp(processName, "kwin_x11") == 0 ||
strcasecmp(processName, "kwin_x11_wrapper") == 0 ||
strcasecmp(processName, "kwin") == 0
) ffStrbufSetS(&result->wmPrettyName, "KWin");
else if(
strcasecmp(processName, "gnome-shell") == 0 ||
strcasecmp(processName, "gnome shell") == 0 ||
strcasecmp(processName, "gnome-session-binary") == 0 ||
strcasecmp(processName, "Mutter") == 0
) ffStrbufSetS(&result->wmPrettyName, "Mutter");
else if(
strcasecmp(processName, "cinnamon-session") == 0 ||
strcasecmp(processName, "Muffin") == 0
) ffStrbufSetS(&result->wmPrettyName, "Muffin");
else if(strcasecmp(processName, "sway") == 0)
ffStrbufSetS(&result->wmPrettyName, "Sway");
else if(strcasecmp(processName, "weston") == 0)
ffStrbufSetS(&result->wmPrettyName, "Weston");
else if(strcasecmp(processName, "wayfire") == 0)
ffStrbufSetS(&result->wmPrettyName, "Wayfire");
else if(strcasecmp(processName, "openbox") == 0)
ffStrbufSetS(&result->wmPrettyName, "Openbox");
else if(strcasecmp(processName, "xfwm4") == 0)
ffStrbufSetS(&result->wmPrettyName, "Xfwm4");
else if(strcasecmp(processName, "Marco") == 0)
ffStrbufSetS(&result->wmPrettyName, "Marco");
else if(strcasecmp(processName, "xmonad") == 0)
ffStrbufSetS(&result->wmPrettyName, "XMonad");
else if( // WMs where the pretty name matches the process name
strcasecmp(processName, "dwm") == 0 ||
strcasecmp(processName, "bspwm") == 0 ||
strcasecmp(processName, "tinywm") == 0
) ffStrbufSetS(&result->wmPrettyName, processName);
if(result->wmPrettyName.length > 0 && result->wmProcessName.length == 0)
ffStrbufSetS(&result->wmProcessName, processName);
}
static void applyBetterWM(FFDisplayServerResult* result, const char* processName)
{
if(!ffStrSet(processName))
return;
//If it is a known wm, this will set the pretty name
applyPrettyNameIfWM(result, processName);
//If it isn't a known wm, we have to set the process name our self
ffStrbufSetS(&result->wmProcessName, processName);
//If it isn't a known wm, set the pretty name to the process name
if(result->wmPrettyName.length == 0)
ffStrbufAppend(&result->wmPrettyName, &result->wmProcessName);
}
static void getKDE(FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "plasmashell");
ffStrbufSetS(&result->dePrettyName, "KDE Plasma");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/xsessions/plasma5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/wayland-sessions/plasmawayland.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/wayland-sessions/plasmawayland5.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
applyBetterWM(result, getenv("KDEWM"));
}
static void getGnome(FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "gnome-shell");
ffStrbufSetS(&result->dePrettyName, "GNOME");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
}
static void getCinnamon(FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "cinnamon");
ffStrbufSetS(&result->dePrettyName, "Cinnamon");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
}
static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "mate-session");
ffStrbufSetS(&result->dePrettyName, "MATE");
FFstrbuf major;
ffStrbufInit(&major);
FFstrbuf minor;
ffStrbufInit(&minor);
FFstrbuf micro;
ffStrbufInit(&micro);
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR"/share/mate-about/mate-version.xml", 3, (FFpropquery[]) {
{"<platform>", &major},
{"<minor>", &minor},
{"<micro>", &micro}
});
ffParseSemver(&result->deVersion, &major, &minor, &micro);
ffStrbufDestroy(&major);
ffStrbufDestroy(&minor);
ffStrbufDestroy(&micro);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
ffProcessAppendStdOut(&result->deVersion, (char* const[]){
"mate-session",
"--version",
NULL
});
ffStrbufSubstrAfterFirstC(&result->deVersion, ' ');
ffStrbufTrim(&result->deVersion, ' ');
}
}
static void getXFCE4(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "xfce4-session");
ffStrbufSetS(&result->dePrettyName, "Xfce4");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
//This is somewhat slow
ffProcessAppendStdOut(&result->deVersion, (char* const[]){
"xfce4-session",
"--version",
NULL
});
ffStrbufSubstrBeforeFirstC(&result->deVersion, '(');
ffStrbufSubstrAfterFirstC(&result->deVersion, ' ');
ffStrbufTrim(&result->deVersion, ' ');
}
}
static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
{
ffStrbufSetS(&result->deProcessName, "lxqt-session");
ffStrbufSetS(&result->dePrettyName, "LXQt");
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/lib/pkgconfig/lxqt.pc", "Version:", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
if(result->deVersion.length == 0)
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
{
//This is really, really, really slow. Thank you, LXQt developers
ffProcessAppendStdOut(&result->deVersion, (char* const[]){
"lxqt-session",
"-v",
NULL
});
result->deVersion.length = 0; //don't set '\0' byte
ffParsePropLines(result->deVersion.chars , "liblxqt", &result->deVersion);
}
FFstrbuf wmProcessNameBuffer;
ffStrbufInit(&wmProcessNameBuffer);
ffParsePropFileConfig(instance, "lxqt/session.conf", "window_manager =", &wmProcessNameBuffer);
applyBetterWM(result, wmProcessNameBuffer.chars);
ffStrbufDestroy(&wmProcessNameBuffer);
}
static void applyPrettyNameIfDE(const FFinstance* instance, FFDisplayServerResult* result, const char* name)
{
if(!ffStrSet(name))
return;
else if(
strcasecmp(name, "KDE") == 0 ||
strcasecmp(name, "plasma") == 0 ||
strcasecmp(name, "plasmashell") == 0 ||
strcasecmp(name, "plasmawayland") == 0
) getKDE(result);
else if(
strcasecmp(name, "Gnome") == 0 ||
strcasecmp(name, "ubuntu:GNOME") == 0 ||
strcasecmp(name, "ubuntu") == 0 ||
strcasecmp(name, "gnome-shell") == 0
) getGnome(result);
else if(
strcasecmp(name, "X-Cinnamon") == 0 ||
strcasecmp(name, "Cinnamon") == 0
) getCinnamon(result);
else if(
strcasecmp(name, "XFCE") == 0 ||
strcasecmp(name, "X-XFCE") == 0 ||
strcasecmp(name, "XFCE4") == 0 ||
strcasecmp(name, "X-XFCE4") == 0 ||
strcasecmp(name, "xfce4-session") == 0
) getXFCE4(instance, result);
else if(
strcasecmp(name, "MATE") == 0 ||
strcasecmp(name, "X-MATE") == 0 ||
strcasecmp(name, "mate-session") == 0
) getMate(instance, result);
else if(
strcasecmp(name, "LXQt") == 0 ||
strcasecmp(name, "X-LXQT") == 0 ||
strcasecmp(name, "lxqt-session") == 0
) getLXQt(instance, result);
}
static void getWMProtocolNameFromEnv(FFDisplayServerResult* result)
{
//This is only called if all connection attempts to a display server failed
//We don't need to check for wayland here, as the wayland code will always set the protocol name to wayland
const char* env = getenv("XDG_SESSION_TYPE");
if(ffStrSet(env))
{
if(strcasecmp(env, "x11") == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
else if(strcasecmp(env, "tty") == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_TTY);
else
ffStrbufSetS(&result->wmProtocolName, env);
return;
}
env = getenv("DISPLAY");
if(ffStrSet(env))
{
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
return;
}
env = getenv("TERM");
if(ffStrSet(env))
{
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_TTY);
return;
}
}
static void getFromProcDir(const FFinstance* instance, FFDisplayServerResult* result)
{
DIR* proc = opendir("/proc");
if(proc == NULL)
return;
FFstrbuf procPath;
ffStrbufInitA(&procPath, 64);
ffStrbufAppendS(&procPath, "/proc/");
uint32_t procPathLength = procPath.length;
FFstrbuf userID;
ffStrbufInit(&userID);
ffStrbufAppendF(&userID, "%i", getuid());
FFstrbuf loginuid;
ffStrbufInit(&loginuid);
FFstrbuf processName;
ffStrbufInitA(&processName, 256); //Some processes have large command lines (looking at you chrome)
struct dirent* dirent;
while((dirent = readdir(proc)) != NULL)
{
//Match only folders starting with a number (the pid folders)
if(dirent->d_type != DT_DIR || !isdigit(dirent->d_name[0]))
continue;
ffStrbufAppendS(&procPath, dirent->d_name);
uint32_t procFolderPathLength = procPath.length;
//Don't check for processes not owend by the current user.
ffStrbufAppendS(&procPath, "/loginuid");
ffReadFileBuffer(procPath.chars, &loginuid);
if(ffStrbufComp(&userID, &loginuid) != 0)
{
ffStrbufSubstrBefore(&procPath, procPathLength);
continue;
}
ffStrbufSubstrBefore(&procPath, procFolderPathLength);
//We check the cmdline for the process name, because it is not trimmed.
ffStrbufAppendS(&procPath, "/cmdline");
ffReadFileBuffer(procPath.chars, &processName);
ffStrbufSubstrBeforeFirstC(&processName, '\0'); //Trim the arguments
ffStrbufSubstrAfterLastC(&processName, '/');
ffStrbufSubstrBefore(&procPath, procPathLength);
if(result->dePrettyName.length == 0)
applyPrettyNameIfDE(instance, result, processName.chars);
if(result->wmPrettyName.length == 0)
applyPrettyNameIfWM(result, processName.chars);
if(result->dePrettyName.length > 0 && result->wmPrettyName.length > 0)
break;
}
closedir(proc);
ffStrbufDestroy(&processName);
ffStrbufDestroy(&loginuid);
ffStrbufDestroy(&userID);
ffStrbufDestroy(&procPath);
}
void ffdsDetectWMDE(const FFinstance* instance, FFDisplayServerResult* result)
{
//If all connections failed, use the environment variables to detect protocol name
if(result->wmProtocolName.length == 0)
getWMProtocolNameFromEnv(result);
//We don't want to detect anything in TTY
//This can't happen if a connection succeeded, so we don't need to clear wmProcessName
if(ffStrbufIgnCaseCompS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_TTY) == 0)
return;
const char* env = parseEnv();
if(result->wmProcessName.length > 0)
{
//If we found the processName via display server, use it.
//This will set the pretty name if it is a known WM, otherwise the prettyName to the processName
applyPrettyNameIfWM(result, result->wmProcessName.chars);
if(result->wmPrettyName.length == 0)
ffStrbufSet(&result->wmPrettyName, &result->wmProcessName);
}
else
{
//if env is a known WM, use it
applyPrettyNameIfWM(result, env);
}
//Connecting to a display server only gives WM results, not DE results.
//If we find it in the environment, use that.
applyPrettyNameIfDE(instance, result, env);
//If WM was found by connection to the sever, and DE in the environment, we can return
//This way we never call getFromProcDir(), which has slow initalization time
if(result->dePrettyName.length > 0 && result->wmPrettyName.length > 0)
return;
//Get missing WM / DE from processes.
getFromProcDir(instance, result);
//Return if both wm and de are set, or if env doesn't contain anything
if(
(result->wmPrettyName.length > 0 && result->dePrettyName.length > 0) ||
!ffStrSet(env)
) return;
//If nothing is set, use env as WM
else if(result->wmPrettyName.length == 0 && result->dePrettyName.length == 0)
{
ffStrbufSetS(&result->wmProcessName, env);
ffStrbufSetS(&result->wmPrettyName, env);
}
//If only WM is not set, and DE doesn't equal env, use env as WM
else if(
result->wmPrettyName.length == 0 &&
ffStrbufIgnCaseCompS(&result->deProcessName, env) != 0 &&
ffStrbufIgnCaseCompS(&result->dePrettyName, env) != 0
) {
ffStrbufSetS(&result->wmProcessName, env);
ffStrbufSetS(&result->wmPrettyName, env);
}
//If only DE is not set, and WM doesn't equal env, use env as DE
else if(
result->dePrettyName.length == 0 &&
ffStrbufIgnCaseCompS(&result->wmProcessName, env) != 0 &&
ffStrbufIgnCaseCompS(&result->wmPrettyName, env) != 0
) {
ffStrbufSetS(&result->deProcessName, env);
ffStrbufSetS(&result->dePrettyName, env);
}
}
+395
View File
@@ -0,0 +1,395 @@
#include "displayServer.h"
#ifdef FF_HAVE_XCB
#include "common/library.h"
#include <stdlib.h>
#include <string.h>
#include <xcb/xcb.h>
typedef struct XcbPropertyData
{
FF_LIBRARY_SYMBOL(xcb_intern_atom)
FF_LIBRARY_SYMBOL(xcb_intern_atom_reply)
FF_LIBRARY_SYMBOL(xcb_get_property)
FF_LIBRARY_SYMBOL(xcb_get_property_reply)
FF_LIBRARY_SYMBOL(xcb_get_property_value)
FF_LIBRARY_SYMBOL(xcb_get_property_value_length)
} XcbPropertyData;
static bool xcbInitPropertyData(void* libraryHandle, XcbPropertyData* propertyData)
{
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_intern_atom, xcb_intern_atom, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_intern_atom_reply, xcb_intern_atom_reply, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property, xcb_get_property, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property_reply, xcb_get_property_reply, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property_value, xcb_get_property_value, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffxcb_get_property_value_length, xcb_get_property_value_length, false)
return true;
}
static void* xcbGetProperty(XcbPropertyData* data, xcb_connection_t* connection, xcb_window_t window, const char* request)
{
xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(connection, true, (uint16_t) strlen(request), request);
xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(connection, requestAtomCookie, NULL);
if(requestAtomReply == NULL)
return NULL;
xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 64);
free(requestAtomReply);
xcb_get_property_reply_t* propertyReply = data->ffxcb_get_property_reply(connection, propertyCookie, NULL);
if(propertyReply == NULL)
return NULL;
int length = data->ffxcb_get_property_value_length(propertyReply);
if(length <= 0)
{
free(propertyReply);
return NULL;
}
//Why are xcb property strings not null terminated???
void* replyValue = malloc((size_t) (length + 1));
memcpy(replyValue, data->ffxcb_get_property_value(propertyReply), (size_t) length);
((char*) replyValue)[length] = '\0';
free(propertyReply);
return replyValue;
}
static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connection, xcb_window_t rootWindow, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND) == 0)
return;
xcb_window_t* wmWindow = (xcb_window_t*) xcbGetProperty(data, connection, rootWindow, "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
char* wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "_NET_WM_NAME");
if(wmName == NULL)
wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "WM_NAME");
free(wmWindow);
if(wmName == NULL)
return;
if(*wmName == '\0')
{
free(wmName);
return;
}
ffStrbufSetS(&result->wmProcessName, wmName);
free(wmName);
}
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
{
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,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_screen_next,)
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_disconnect,)
XcbPropertyData propertyData;
bool propertyDataInitialized = xcbInitPropertyData(xcb, &propertyData);
xcb_connection_t* connection = ffxcb_connect(NULL, NULL);
if(connection == NULL)
{
dlclose(xcb);
return;
}
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(connection));
if(iterator.rem > 0 && propertyDataInitialized)
xcbDetectWMfromEWMH(&propertyData, connection, iterator.data->root, result);
while(iterator.rem > 0)
{
ffdsAppendResolution(
result,
(uint32_t) iterator.data->width_in_pixels,
(uint32_t) iterator.data->height_in_pixels,
0
);
ffxcb_screen_next(&iterator);
}
ffxcb_disconnect(connection);
dlclose(xcb);
//If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland.
if(result->wmProtocolName.length == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
}
#else
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
{
//Do nothing. There are other implementations coming
FF_UNUSED(instance, result)
}
#endif
#ifdef FF_HAVE_XCB_RANDR
#include <xcb/randr.h>
typedef struct XcbRandrData
{
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_modes_iterator)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_info)
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_info_reply)
FF_LIBRARY_SYMBOL(xcb_randr_mode_info_next)
FF_LIBRARY_SYMBOL(xcb_randr_get_monitors)
FF_LIBRARY_SYMBOL(xcb_randr_get_monitors_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_monitors_monitors_iterator)
FF_LIBRARY_SYMBOL(xcb_randr_monitor_info_next)
FF_LIBRARY_SYMBOL(xcb_randr_monitor_info_outputs_length)
FF_LIBRARY_SYMBOL(xcb_randr_monitor_info_outputs)
FF_LIBRARY_SYMBOL(xcb_randr_output_next)
FF_LIBRARY_SYMBOL(xcb_randr_get_output_info)
FF_LIBRARY_SYMBOL(xcb_randr_get_output_info_reply)
FF_LIBRARY_SYMBOL(xcb_randr_get_crtc_info)
FF_LIBRARY_SYMBOL(xcb_randr_get_crtc_info_reply)
//init once
xcb_connection_t* connection;
FFDisplayServerResult* result;
//init per screen
uint32_t defaultRefreshRate;
xcb_randr_get_screen_resources_reply_t* screenResources;
} XcbRandrData;
static bool xcbRandrHandleModeInfo(XcbRandrData* data, xcb_randr_mode_info_t* modeInfo)
{
uint32_t refreshRate = ffdsParseRefreshRate((int32_t) (
modeInfo->dot_clock / (uint32_t) (modeInfo->htotal * modeInfo->vtotal)
));
return ffdsAppendResolution(
data->result,
(uint32_t) modeInfo->width,
(uint32_t) modeInfo->height,
refreshRate == 0 ? data->defaultRefreshRate : refreshRate
);
}
static bool xcbRandrHandleMode(XcbRandrData* data, xcb_randr_mode_t mode)
{
//We do the check here, because we want the best fallback resolution if this call failed
if(data->screenResources == NULL)
return false;
xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_modes_iterator(data->screenResources);
while(modesIterator.rem > 0)
{
if(modesIterator.data->id == mode)
return xcbRandrHandleModeInfo(data, modesIterator.data);
data->ffxcb_randr_mode_info_next(&modesIterator);
}
return false;
}
static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc)
{
xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME);
xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL);
if(crtcInfoReply == NULL)
return false;
bool res = xcbRandrHandleMode(data, crtcInfoReply->mode);
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)
{
xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME);
xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL);
if(outputInfoReply == NULL)
return false;
bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc);
free(outputInfoReply);
return res;
}
static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor)
{
//for some reasons, we have to construct this our self
xcb_randr_output_iterator_t outputIterator = {
.index = 0,
.data = data->ffxcb_randr_monitor_info_outputs(monitor),
.rem = data->ffxcb_randr_monitor_info_outputs_length(monitor)
};
bool foundOutput = false;
while(outputIterator.rem > 0)
{
if(xcbRandrHandleOutput(data, *outputIterator.data))
foundOutput = true;
data->ffxcb_randr_output_next(&outputIterator);
};
return foundOutput ? true : ffdsAppendResolution(
data->result,
(uint32_t) monitor->width,
(uint32_t) monitor->height,
data->defaultRefreshRate
);
}
static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen)
{
xcb_randr_get_monitors_cookie_t monitorsCookie = data->ffxcb_randr_get_monitors(data->connection, screen->root, true);
xcb_randr_get_monitors_reply_t* monitorsReply = data->ffxcb_randr_get_monitors_reply(data->connection, monitorsCookie, NULL);
if(monitorsReply == NULL)
return false;
xcb_randr_monitor_info_iterator_t monitorInfoIterator = data->ffxcb_randr_get_monitors_monitors_iterator(monitorsReply);
bool foundMonitor = false;
while(monitorInfoIterator.rem > 0)
{
if(xcbRandrHandleMonitor(data, monitorInfoIterator.data))
foundMonitor = true;
data->ffxcb_randr_monitor_info_next(&monitorInfoIterator);
}
free(monitorsReply);
return foundMonitor;
}
static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
{
//Init screen info. This is used to get the default refresh rate. If this fails, default refresh rate is simply 0.
xcb_randr_get_screen_info_cookie_t screenInfoCookie = data->ffxcb_randr_get_screen_info(data->connection, screen->root);
xcb_randr_get_screen_info_reply_t* screenInfoReply = data->ffxcb_randr_get_screen_info_reply(data->connection, screenInfoCookie, NULL);
if(screenInfoReply != NULL)
{
data->defaultRefreshRate = screenInfoReply->rate;
free(screenInfoReply);
}
else
data->defaultRefreshRate = 0;
//Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible.
xcb_randr_get_screen_resources_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources(data->connection, screen->root);
data->screenResources = data->ffxcb_randr_get_screen_resources_reply(data->connection, screenResourcesCookie, NULL);
//With all the initialisation done, start the detection
bool ret = xcbRandrHandleMonitors(data, screen);
free(data->screenResources);
if(ret)
return;
//If detetction failed, fallback to screen = monitor, like in the libxcb.so implementation
ffdsAppendResolution(
data->result,
(uint32_t) screen->width_in_pixels,
(uint32_t) screen->height_in_pixels,
data->defaultRefreshRate
);
}
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result)
{
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,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_screen_next,)
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_disconnect,)
XcbRandrData data;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_resources, xcb_randr_get_screen_resources,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_resources_reply, xcb_randr_get_screen_resources_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_resources_modes_iterator, xcb_randr_get_screen_resources_modes_iterator,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_info, xcb_randr_get_screen_info,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_screen_info_reply, xcb_randr_get_screen_info_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_mode_info_next, xcb_randr_mode_info_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_monitors, xcb_randr_get_monitors,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_monitors_reply, xcb_randr_get_monitors_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_monitors_monitors_iterator, xcb_randr_get_monitors_monitors_iterator,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_monitor_info_next, xcb_randr_monitor_info_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_monitor_info_outputs_length, xcb_randr_monitor_info_outputs_length,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_monitor_info_outputs, xcb_randr_monitor_info_outputs,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_output_next, xcb_randr_output_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_output_info, xcb_randr_get_output_info,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_output_info_reply, xcb_randr_get_output_info_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_crtc_info, xcb_randr_get_crtc_info,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xcbRandr, data.ffxcb_randr_get_crtc_info_reply, xcb_randr_get_crtc_info_reply,)
XcbPropertyData propertyData;
bool propertyDataInitialized = xcbInitPropertyData(xcbRandr, &propertyData);
data.connection = ffxcb_connect(NULL, NULL);
if(data.connection == NULL)
{
dlclose(xcbRandr);
return;
}
data.result = result;
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(data.connection));
if(iterator.rem > 0 && propertyDataInitialized)
xcbDetectWMfromEWMH(&propertyData, data.connection, iterator.data->root, result);
while(iterator.rem > 0)
{
xcbRandrHandleScreen(&data, iterator.data);
ffxcb_screen_next(&iterator);
}
ffxcb_disconnect(data.connection);
dlclose(xcbRandr);
//If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland.
if(result->wmProtocolName.length == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
}
#else
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result)
{
//Do nothing. There are other implementations coming
FF_UNUSED(instance, result)
}
#endif
+315
View File
@@ -0,0 +1,315 @@
#include "displayServer.h"
#ifdef FF_HAVE_X11
#include "common/library.h"
#include "common/parsing.h"
#include <X11/Xlib.h>
typedef struct X11PropertyData
{
FF_LIBRARY_SYMBOL(XInternAtom)
FF_LIBRARY_SYMBOL(XGetWindowProperty)
} X11PropertyData;
static bool x11InitPropertyData(void* libraryHandle, X11PropertyData* propertyData)
{
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffXInternAtom, XInternAtom, false)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(libraryHandle, propertyData->ffXGetWindowProperty, XGetWindowProperty, false)
return true;
}
static unsigned char* x11GetProperty(X11PropertyData* data, Display* display, Window window, const char* request)
{
Atom requestAtom = data->ffXInternAtom(display, request, False);
if(requestAtom == None)
return NULL;
Atom actualType;
unsigned long unused;
unsigned char* result = NULL;
data->ffXGetWindowProperty(display, window, requestAtom, 0, 64, False, AnyPropertyType, &actualType, (int*) &unused, &unused, &unused, &result);
return result;
}
static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDisplayServerResult* result)
{
if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND) == 0)
return;
Window* wmWindow = (Window*) x11GetProperty(data, display, DefaultRootWindow(display), "_NET_SUPPORTING_WM_CHECK");
if(wmWindow == NULL)
return;
const char* wmName = (const char*) x11GetProperty(data, display, *wmWindow, "_NET_WM_NAME");
if(wmName == NULL)
wmName = (const char*) x11GetProperty(data, display, *wmWindow, "WM_NAME");
if(!ffStrSet(wmName))
return;
ffStrbufSetS(&result->wmProcessName, wmName);
}
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
{
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,)
X11PropertyData propertyData;
bool propertyDataInitialized = x11InitPropertyData(x11, &propertyData);
Display* display = ffXOpenDisplay(x11);
if(display == NULL)
{
dlclose(x11);
return;
}
if(propertyDataInitialized && ScreenCount(display) > 0)
x11DetectWMFromEWMH(&propertyData, display, result);
for(int i = 0; i < ScreenCount(display); i++)
{
Screen* screen = ScreenOfDisplay(display, i);
ffdsAppendResolution(
result,
(uint32_t) screen->width,
(uint32_t) screen->height,
0
);
}
ffXCloseDisplay(display);
dlclose(x11);
//If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland.
if(result->wmProtocolName.length == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
}
#else
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
{
//Do nothing. WM / DE detection will use environment vars to detect as much as possible.
FF_UNUSED(instance, result);
}
#endif //FF_HAVE_X11
#ifdef FF_HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
typedef struct XrandrData
{
FF_LIBRARY_SYMBOL(XRRGetScreenInfo)
FF_LIBRARY_SYMBOL(XRRConfigCurrentConfiguration)
FF_LIBRARY_SYMBOL(XRRConfigCurrentRate)
FF_LIBRARY_SYMBOL(XRRGetMonitors)
FF_LIBRARY_SYMBOL(XRRGetScreenResources)
FF_LIBRARY_SYMBOL(XRRGetOutputInfo)
FF_LIBRARY_SYMBOL(XRRGetCrtcInfo)
FF_LIBRARY_SYMBOL(XRRFreeCrtcInfo)
FF_LIBRARY_SYMBOL(XRRFreeOutputInfo)
FF_LIBRARY_SYMBOL(XRRFreeScreenResources)
FF_LIBRARY_SYMBOL(XRRFreeMonitors)
FF_LIBRARY_SYMBOL(XRRFreeScreenConfigInfo)
//Init once
Display* display;
FFDisplayServerResult* result;
//Init per screen
uint32_t defaultRefreshRate;
XRRScreenResources* screenResources;
} XrandrData;
static bool xrandrHandleModeInfo(XrandrData* data, XRRModeInfo* modeInfo)
{
uint32_t refreshRate = ffdsParseRefreshRate((int32_t) (
modeInfo->dotClock / (modeInfo->hTotal * modeInfo->vTotal)
));
return ffdsAppendResolution(
data->result,
(uint32_t) modeInfo->width,
(uint32_t) modeInfo->height,
refreshRate == 0 ? data->defaultRefreshRate : refreshRate
);
}
static bool xrandrHandleMode(XrandrData* data, RRMode mode)
{
for(int i = 0; i < data->screenResources->nmode; i++)
{
if(data->screenResources->modes[i].id == mode)
return xrandrHandleModeInfo(data, &data->screenResources->modes[i]);
}
return false;
}
static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc)
{
//We do the check here, because we want the best fallback resolution if this call failed
if(data->screenResources == NULL)
return false;
XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, crtc);
if(crtcInfo == NULL)
return false;
bool res = xrandrHandleMode(data, crtcInfo->mode);
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)
{
XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, data->screenResources, output);
if(outputInfo == NULL)
return false;
bool res = xrandrHandleCrtc(data, outputInfo->crtc);
data->ffXRRFreeOutputInfo(outputInfo);
return res;
}
static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo)
{
bool foundOutput = false;
for(int i = 0; i < monitorInfo->noutput; i++)
{
if(xrandrHandleOutput(data, monitorInfo->outputs[i]))
foundOutput = true;
}
return foundOutput ? true : ffdsAppendResolution(
data->result,
(uint32_t) monitorInfo->width,
(uint32_t) monitorInfo->height,
data->defaultRefreshRate
);
}
static bool xrandrHandleMonitors(XrandrData* data, Screen* screen)
{
int numberOfMonitors;
XRRMonitorInfo* monitorInfos = data->ffXRRGetMonitors(data->display, RootWindowOfScreen(screen), True, &numberOfMonitors);
if(monitorInfos == NULL)
return false;
bool foundAMonitor;
for(int i = 0; i < numberOfMonitors; i++)
{
if(xrandrHandleMonitor(data, &monitorInfos[i]))
foundAMonitor = true;
}
data->ffXRRFreeMonitors(monitorInfos);
return foundAMonitor;
}
static void xrandrHandleScreen(XrandrData* data, Screen* screen)
{
//Init screen configuration. This is used to get the default refresh rate. If this fails, default refresh rate is simply 0.
XRRScreenConfiguration* screenConfiguration = data->ffXRRGetScreenInfo(data->display, RootWindowOfScreen(screen));
if(screenConfiguration != NULL)
{
data->defaultRefreshRate = (uint32_t) data->ffXRRConfigCurrentRate(screenConfiguration);
data->ffXRRFreeScreenConfigInfo(screenConfiguration);
}
else
data->defaultRefreshRate = 0;
//Init screen resources
data->screenResources = data->ffXRRGetScreenResources(data->display, RootWindowOfScreen(screen));
bool ret = xrandrHandleMonitors(data, screen);
data->ffXRRFreeScreenResources(data->screenResources);
if(ret)
return;
//Fallback to screen
ffdsAppendResolution(
data->result,
(uint32_t) WidthOfScreen(screen),
(uint32_t) HeightOfScreen(screen),
data->defaultRefreshRate
);
}
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result)
{
FF_LIBRARY_LOAD(xrandr, instance->config.libXrandr, , "libXrandr.so", 3)
FF_LIBRARY_LOAD_SYMBOL(xrandr, XOpenDisplay,)
FF_LIBRARY_LOAD_SYMBOL(xrandr, XCloseDisplay,)
XrandrData data;
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRGetScreenInfo, XRRGetScreenInfo,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRConfigCurrentRate, XRRConfigCurrentRate,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRGetMonitors, XRRGetMonitors,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRGetScreenResources, XRRGetScreenResources,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRGetOutputInfo, XRRGetOutputInfo,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRGetCrtcInfo, XRRGetCrtcInfo,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRFreeCrtcInfo, XRRFreeCrtcInfo,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRFreeOutputInfo, XRRFreeOutputInfo,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRFreeScreenResources, XRRFreeScreenResources,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRFreeMonitors, XRRFreeMonitors,);
FF_LIBRARY_LOAD_SYMBOL_ADRESS(xrandr, data.ffXRRFreeScreenConfigInfo, XRRFreeScreenConfigInfo,);
X11PropertyData propertyData;
bool propertyDataInitialized = x11InitPropertyData(xrandr, &propertyData);
data.display = ffXOpenDisplay(NULL);
if(data.display == NULL)
{
dlclose(xrandr);
return;
}
if(propertyDataInitialized && ScreenCount(data.display) > 0)
x11DetectWMFromEWMH(&propertyData, data.display, result);
data.result = result;
for(int i = 0; i < ScreenCount(data.display); i++)
xrandrHandleScreen(&data, ScreenOfDisplay(data.display, i));
ffXCloseDisplay(data.display);
dlclose(xrandr);
//If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland.
if(result->wmProtocolName.length == 0)
ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11);
}
#else
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result)
{
//Do nothing here. There are more x11 implementaions to come.
FF_UNUSED(instance, result);
}
#endif // FF_HAVE_XRANDR
+204
View File
@@ -0,0 +1,204 @@
#include "fastfetch.h"
#include "detection/gtk.h"
#include "common/properties.h"
#include "common/settings.h"
#include "detection/displayserver.h"
#include <pthread.h>
static inline bool allPropertiesSet(FFGTKResult* result)
{
return
result->theme.length > 0 &&
result->icons.length > 0 &&
result->font.length > 0;
}
static inline void applyGTKSettings(FFGTKResult* result, const char* themeName, const char* iconsName, const char* fontName, const char* cursorTheme, int cursorSize)
{
if(result->theme.length == 0)
ffStrbufAppendS(&result->theme, themeName);
if(result->icons.length == 0)
ffStrbufAppendS(&result->icons, iconsName);
if(result->font.length == 0)
ffStrbufAppendS(&result->font, fontName);
if(result->cursor.length == 0)
ffStrbufAppendS(&result->cursor, cursorTheme);
if(result->cursorSize.length == 0 && cursorSize > 0)
ffStrbufAppendF(&result->cursorSize, "%i", cursorSize);
}
static void detectGTKFromSettings(FFinstance* instance, FFGTKResult* result)
{
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static const char* themeName = NULL;
static const char* iconsName = NULL;
static const char* fontName = NULL;
static const char* cursorTheme = NULL;
static int cursorSize = 0;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize);
return;
}
init = true;
const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance);
if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Xfce") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Xfce4") == 0)
{
themeName = ffSettingsGetXFConf(instance, "xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGetXFConf(instance, "xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGetXFConf(instance, "xsettings", "/Gtk/FontName", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGetXFConf(instance, "xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGetXFConf(instance, "xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue;
}
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Cinnamon") == 0)
{
themeName = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
}
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Mate") == 0)
{
themeName = ffSettingsGet(instance, "/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet(instance, "/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet(instance, "/org/mate/interface/font-name", "org.mate.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGet(instance, "/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
cursorSize = ffSettingsGet(instance, "/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
}
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Gnome") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Unity") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Budgie") == 0)
{
themeName = ffSettingsGet(instance, "/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
iconsName = ffSettingsGet(instance, "/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
fontName = ffSettingsGet(instance, "/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
cursorTheme = ffSettingsGet(instance, "/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
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);
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize);
}
static void detectGTKFromConfigFile(const char* filename, FFGTKResult* result)
{
ffParsePropFileValues(filename, 5, (FFpropquery[]) {
{"gtk-theme-name =", &result->theme},
{"gtk-icon-theme-name =", &result->icons},
{"gtk-font-name =", &result->font},
{"gtk-cursor-theme-name =", &result->cursor},
{"gtk-cursor-theme-size =", &result->cursorSize}
});
}
static void detectGTKFromConfigDir(FFstrbuf* configDir, const char* version, FFGTKResult* result)
{
uint32_t configDirLength = configDir->length;
// <configdir>/gtk-<version>.0/settings.ini
ffStrbufAppendS(configDir, "gtk-");
ffStrbufAppendS(configDir, version);
ffStrbufAppendS(configDir, ".0/settings.ini");
detectGTKFromConfigFile(configDir->chars, result);
ffStrbufSubstrBefore(configDir, configDirLength);
if(allPropertiesSet(result))
return;
// <configdir>/gtk-<version>.0/gtkrc
ffStrbufAppendS(configDir, "gtk-");
ffStrbufAppendS(configDir, version);
ffStrbufAppendS(configDir, ".0/gtkrc");
detectGTKFromConfigFile(configDir->chars, result);
ffStrbufSubstrBefore(configDir, configDirLength);
if(allPropertiesSet(result))
return;
// <configdir>/gtkrc-<version>.0
ffStrbufAppendS(configDir, "gtkrc-");
ffStrbufAppendS(configDir, version);
ffStrbufAppendS(configDir, ".0");
detectGTKFromConfigFile(configDir->chars, result);
ffStrbufSubstrBefore(configDir, configDirLength);
if(allPropertiesSet(result))
return;
// <configdir>/.gtkrc-<version>.0
ffStrbufAppendS(configDir, ".gtkrc-");
ffStrbufAppendS(configDir, version);
ffStrbufAppendS(configDir, ".0");
detectGTKFromConfigFile(configDir->chars, result);
ffStrbufSubstrBefore(configDir, configDirLength);
}
static void detectGTK(FFinstance* instance, const char* version, FFGTKResult* result)
{
//Mate, Cinnamon and Gnome use dconf to save theme config
//On other DEs, this will do nothing
detectGTKFromSettings(instance, result);
if(allPropertiesSet(result))
return;
//We need to do this because we use multiple threads on configDirs
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
{
ffStrbufSet(&baseDir, ffListGet(&instance->state.configDirs, i));
detectGTKFromConfigDir(&baseDir, version, result);
if(allPropertiesSet(result))
break;
}
ffStrbufDestroy(&baseDir);
}
#define FF_DETECT_GTK_IMPL(version) \
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; \
static FFGTKResult result; \
static bool init = false; \
pthread_mutex_lock(&mutex); \
if(init){ \
pthread_mutex_unlock(&mutex);\
return &result; \
} \
init = true; \
ffStrbufInit(&result.theme); \
ffStrbufInit(&result.icons); \
ffStrbufInit(&result.font); \
ffStrbufInit(&result.cursor); \
ffStrbufInit(&result.cursorSize); \
detectGTK(instance, #version, &result); \
pthread_mutex_unlock(&mutex); \
return &result;
const FFGTKResult* ffDetectGTK2(FFinstance* instance)
{
FF_DETECT_GTK_IMPL(2)
}
const FFGTKResult* ffDetectGTK3(FFinstance* instance)
{
FF_DETECT_GTK_IMPL(3)
}
const FFGTKResult* ffDetectGTK4(FFinstance* instance)
{
FF_DETECT_GTK_IMPL(4)
}
#undef FF_CALCULATE_GTK_IMPL
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#ifndef FF_INCLUDED_detection_gtk
#define FF_INCLUDED_detection_gtk
#include "fastfetch.h"
typedef struct FFGTKResult
{
FFstrbuf theme;
FFstrbuf icons;
FFstrbuf font;
FFstrbuf cursor;
FFstrbuf cursorSize;
} FFGTKResult;
const FFGTKResult* ffDetectGTK2(FFinstance* instance);
const FFGTKResult* ffDetectGTK4(FFinstance* instance);
const FFGTKResult* ffDetectGTK3(FFinstance* instance);
#endif
+370
View File
@@ -0,0 +1,370 @@
#include "fastfetch.h"
#include "detection/media.h"
#include <string.h>
#include <pthread.h>
#define FF_DBUS_MPRIS_PREFIX "org.mpris.MediaPlayer2."
#define FF_DBUS_TIMEOUT_MILLISECONDS 35
#ifdef FF_HAVE_DBUS
#include "common/library.h"
#include "common/parsing.h"
#include <dbus/dbus.h>
#define FF_DBUS_ITER_CONTINUE(iterator) \
{ \
if(!data->ffdbus_message_iter_has_next(&iterator)) \
break; \
data->ffdbus_message_iter_next(&iterator); \
continue; \
}
typedef struct DBusData
{
FF_LIBRARY_SYMBOL(dbus_message_new_method_call)
FF_LIBRARY_SYMBOL(dbus_message_iter_init)
FF_LIBRARY_SYMBOL(dbus_message_iter_init_append)
FF_LIBRARY_SYMBOL(dbus_message_iter_append_basic)
FF_LIBRARY_SYMBOL(dbus_message_iter_get_arg_type)
FF_LIBRARY_SYMBOL(dbus_message_iter_get_basic)
FF_LIBRARY_SYMBOL(dbus_message_iter_recurse)
FF_LIBRARY_SYMBOL(dbus_message_iter_has_next)
FF_LIBRARY_SYMBOL(dbus_message_iter_next)
FF_LIBRARY_SYMBOL(dbus_message_unref)
FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply)
FF_LIBRARY_SYMBOL(dbus_connection_flush)
FF_LIBRARY_SYMBOL(dbus_pending_call_block)
FF_LIBRARY_SYMBOL(dbus_pending_call_steal_reply)
FF_LIBRARY_SYMBOL(dbus_pending_call_unref)
DBusConnection *connection;
} DBusData;
static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data)
{
int argType = data->ffdbus_message_iter_get_arg_type(iter);
if(argType == DBUS_TYPE_STRING)
{
const char* value = NULL;
data->ffdbus_message_iter_get_basic(iter, &value);
if(!ffStrSet(value))
return false;
ffStrbufAppendS(result, value);
return true;
}
if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY)
return false;
DBusMessageIter subIter;
data->ffdbus_message_iter_recurse(iter, &subIter);
if(argType == DBUS_TYPE_VARIANT)
return getValue(&subIter, result, data);
//At this point we have an array
bool foundAValue = false;
while(true)
{
if(getValue(&subIter, result, data))
{
foundAValue = true;
ffStrbufAppendS(result, ", ");
}
FF_DBUS_ITER_CONTINUE(subIter);
}
if(foundAValue)
ffStrbufSubstrBefore(result, result->length - 2);
return foundAValue;
}
static DBusMessage* getReply(DBusMessage* request, DBusData* data)
{
DBusPendingCall* pendingCall = NULL;
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;
data->ffdbus_connection_flush(data->connection);
data->ffdbus_pending_call_block(pendingCall);
DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pendingCall);
data->ffdbus_pending_call_unref(pendingCall);
return reply;
}
static DBusMessage* getProperty(const char* busName, const char* objectPath, const char* interface, const char* property, DBusData* data)
{
DBusMessage* message = data->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
if(message == NULL)
return NULL;
DBusMessageIter requestIterator;
data->ffdbus_message_iter_init_append(message, &requestIterator);
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface))
{
data->ffdbus_message_unref(message);
return NULL;
}
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property))
{
data->ffdbus_message_unref(message);
return NULL;
}
return getReply(message, data);
}
static void getPropertyString(const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result, DBusData* data)
{
DBusMessage* reply = getProperty(busName, objectPath, interface, property, data);
if(reply == NULL)
return;
DBusMessageIter rootIterator;
if(!data->ffdbus_message_iter_init(reply, &rootIterator))
{
data->ffdbus_message_unref(reply);
return;
}
getValue(&rootIterator, result, data);
data->ffdbus_message_unref(reply);
}
static bool getBusProperties(const char* busName, FFMediaResult* result, DBusData* data)
{
DBusMessage* reply = getProperty(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata", data);
if(reply == NULL)
return false;
DBusMessageIter rootIterator;
if(!data->ffdbus_message_iter_init(reply, &rootIterator))
{
data->ffdbus_message_unref(reply);
return false;
}
if(data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT)
{
data->ffdbus_message_unref(reply);
return false;
}
DBusMessageIter variantIterator;
data->ffdbus_message_iter_recurse(&rootIterator, &variantIterator);
if(data->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY)
{
data->ffdbus_message_unref(reply);
return false;
}
DBusMessageIter arrayIterator;
data->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator);
while(true)
{
if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
FF_DBUS_ITER_CONTINUE(arrayIterator)
DBusMessageIter dictIterator;
data->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
if(data->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_STRING)
FF_DBUS_ITER_CONTINUE(arrayIterator)
if(!data->ffdbus_message_iter_has_next(&dictIterator))
FF_DBUS_ITER_CONTINUE(arrayIterator)
const char* key;
data->ffdbus_message_iter_get_basic(&dictIterator, &key);
data->ffdbus_message_iter_next(&dictIterator);
if(strcmp(key, "xesam:title") == 0)
getValue(&dictIterator, &result->song, data);
else if(strcmp(key, "xesam:album") == 0)
getValue(&dictIterator, &result->album, data);
else if(strcmp(key, "xesam:artist") == 0)
getValue(&dictIterator, &result->artist, data);
else if(strcmp(key, "xesam:url") == 0)
getValue(&dictIterator, &result->url, data);
if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0)
break;
FF_DBUS_ITER_CONTINUE(arrayIterator)
}
data->ffdbus_message_unref(reply);
if(result->song.length == 0)
{
ffStrbufClear(&result->artist);
ffStrbufClear(&result->album);
ffStrbufClear(&result->url);
return false;
}
//We found a song, get the player name
getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player, data);
if(result->player.length == 0)
getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player, data);
return true;
}
static void getCustomBus(FFinstance* instance, FFMediaResult* result, DBusData* data)
{
if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX))
{
ffStrbufAppendS(&result->busNameShort, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
getBusProperties(instance->config.playerName.chars, result, data);
return;
}
ffStrbufAppend(&result->busNameShort, &instance->config.playerName);
FFstrbuf busName;
ffStrbufInit(&busName);
ffStrbufAppendS(&busName, FF_DBUS_MPRIS_PREFIX);
ffStrbufAppend(&busName, &instance->config.playerName);
getBusProperties(busName.chars, result, data);
ffStrbufDestroy(&busName);
}
static void getBestBus(FFMediaResult* result, DBusData* data)
{
DBusMessage* message = data->ffdbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
if(message == NULL)
return;
DBusMessage* reply = getReply(message, data);
if(reply == NULL)
return;
DBusMessageIter rootIterator;
if(!data->ffdbus_message_iter_init(reply, &rootIterator) || data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY)
return;
DBusMessageIter arrayIterator;
data->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
while(true)
{
if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING)
FF_DBUS_ITER_CONTINUE(arrayIterator)
const char* busName;
data->ffdbus_message_iter_get_basic(&arrayIterator, &busName);
if(strncmp(busName, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0)
FF_DBUS_ITER_CONTINUE(arrayIterator)
if(getBusProperties(busName, result, data))
{
ffStrbufAppendS(&result->busNameShort, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
break;
}
FF_DBUS_ITER_CONTINUE(arrayIterator)
}
data->ffdbus_message_unref(reply);
}
static void getMedia(FFinstance* instance, FFMediaResult* result)
{
DBusData data;
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,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_init_append, dbus_message_iter_init_append,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_append_basic, dbus_message_iter_append_basic,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_get_arg_type, dbus_message_iter_get_arg_type,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_get_basic, dbus_message_iter_get_basic,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_recurse, dbus_message_iter_recurse,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_has_next, dbus_message_iter_has_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_next, dbus_message_iter_next,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_unref, dbus_message_unref,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_connection_send_with_reply, dbus_connection_send_with_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_connection_flush, dbus_connection_flush,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_pending_call_block, dbus_pending_call_block,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_pending_call_steal_reply, dbus_pending_call_steal_reply,)
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_pending_call_unref, dbus_pending_call_unref,)
data.connection = ffdbus_bus_get(DBUS_BUS_SESSION, NULL);
if(data.connection == NULL)
{
dlclose(dbus);
return;
}
if(instance->config.playerName.length > 0)
getCustomBus(instance, result, &data);
else
getBestBus(result, &data);
dlclose(dbus);
}
#endif
const FFMediaResult* ffDetectMedia(FFinstance* instance)
{
static FFMediaResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.busNameShort);
ffStrbufInit(&result.player);
ffStrbufInit(&result.song);
ffStrbufInit(&result.artist);
ffStrbufInit(&result.album);
ffStrbufInit(&result.url);
#ifdef FF_HAVE_DBUS
getMedia(instance, &result);
#endif
//Set busNameShort if a custom player was given, but loading dbus failed
if(instance->config.playerName.length > 0 && result.busNameShort.length == 0)
{
if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX))
ffStrbufAppendS(&result.busNameShort, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
else
ffStrbufAppend(&result.busNameShort, &instance->config.playerName);
}
//Set player to busNameShort, if detection failed
if(result.player.length == 0)
ffStrbufAppend(&result.player, &result.busNameShort);
pthread_mutex_unlock(&mutex);
return &result;
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#ifndef FF_INCLUDED_detection_media
#define FF_INCLUDED_detection_media
#include "fastfetch.h"
typedef struct FFMediaResult
{
FFstrbuf busNameShort; //e.g. plasma-browser-integration
FFstrbuf player; // e.g. Google Chrome
FFstrbuf song;
FFstrbuf artist;
FFstrbuf album;
FFstrbuf url;
} FFMediaResult;
const FFMediaResult* ffDetectMedia(FFinstance* instance);
#endif
+166
View File
@@ -0,0 +1,166 @@
#include "fastfetch.h"
#include "detection/os.h"
#include "common/properties.h"
#include "common/parsing.h"
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#if __ANDROID__
#include "common/settings.h"
#else
static bool parseFile(const char* fileName, FFOSResult* result)
{
if(result->id.length > 0 && result->name.length > 0 && result->prettyName.length > 0)
return true;
return ffParsePropFileValues(fileName, 13, (FFpropquery[]) {
{"NAME =", &result->name},
{"DISTRIB_DESCRIPTION =", &result->prettyName},
{"PRETTY_NAME =", &result->prettyName},
{"DISTRIB_ID =", &result->id},
{"ID =", &result->id},
{"ID_LIKE =", &result->idLike},
{"VARIANT =", &result->variant},
{"VARIANT_ID =", &result->variantID},
{"DISTRIB_RELEASE =", &result->version},
{"VERSION =", &result->version},
{"VERSION_ID =", &result->versionID},
{"VERSION_CODENAME =", &result->codename},
{"BUILD_ID =", &result->buildID}
});
}
static void getUbuntuFlavour(FFOSResult* result)
{
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if(strstr(xdgConfigDirs, "kde") != NULL || strstr(xdgConfigDirs, "plasma") != NULL)
{
ffStrbufSetS(&result->name, "Kubuntu");
ffStrbufSetS(&result->prettyName, "Kubuntu");
ffStrbufSetS(&result->id, "kubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "xfce") != NULL || strstr(xdgConfigDirs, "xubuntu") != NULL)
{
ffStrbufSetS(&result->name, "Xubuntu");
ffStrbufSetS(&result->prettyName, "Xubuntu");
ffStrbufSetS(&result->id, "xubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "lxde") != NULL || strstr(xdgConfigDirs, "lubuntu") != NULL)
{
ffStrbufSetS(&result->name, "Lubuntu");
ffStrbufSetS(&result->prettyName, "Lubuntu");
ffStrbufSetS(&result->id, "lubuntu");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "budgie") != NULL)
{
ffStrbufSetS(&result->name, "Ubuntu Budgie");
ffStrbufSetS(&result->prettyName, "Ubuntu Budgie");
ffStrbufSetS(&result->id, "ubuntu-budgie");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "mate") != NULL)
{
ffStrbufSetS(&result->name, "Ubuntu MATE");
ffStrbufSetS(&result->prettyName, "Ubuntu MATE");
ffStrbufSetS(&result->id, "ubuntu-mate");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
if(strstr(xdgConfigDirs, "studio") != NULL)
{
ffStrbufSetS(&result->name, "Ubuntu Studio");
ffStrbufSetS(&result->prettyName, "Ubuntu Studio");
ffStrbufSetS(&result->id, "ubuntu-studio");
ffStrbufSetS(&result->idLike, "ubuntu");
return;
}
}
#endif
const FFOSResult* ffDetectOS(const FFinstance* instance)
{
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static FFOSResult result;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.systemName);
ffStrbufInit(&result.name);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.id);
ffStrbufInit(&result.idLike);
ffStrbufInit(&result.variant);
ffStrbufInit(&result.variantID);
ffStrbufInit(&result.version);
ffStrbufInit(&result.versionID);
ffStrbufInit(&result.codename);
ffStrbufInit(&result.buildID);
ffStrbufInit(&result.architecture);
ffStrbufSetS(&result.systemName, instance->state.utsname.sysname);
ffStrbufSetS(&result.architecture, instance->state.utsname.machine);
#if !__ANDROID__
if(instance->config.osFile.length > 0)
{
parseFile(instance->config.osFile.chars, &result);
}
else if(instance->config.escapeBedrock && parseFile(FASTFETCH_TARGET_DIR_ROOT"/bedrock/etc/bedrock-release", &result))
{
if(result.id.length == 0)
ffStrbufAppendS(&result.id, "bedrock");
if(result.name.length == 0)
ffStrbufAppendS(&result.name, "Bedrock");
if(result.prettyName.length == 0)
ffStrbufAppendS(&result.prettyName, "Bedrock Linux");
}
else
{
parseFile(FASTFETCH_TARGET_DIR_ROOT"/etc/os-release", &result);
parseFile(FASTFETCH_TARGET_DIR_USR"/lib/os-release", &result);
parseFile(FASTFETCH_TARGET_DIR_ROOT"/etc/lsb-release", &result);
}
if(ffStrbufIgnCaseCompS(&result.id, "ubuntu") == 0)
getUbuntuFlavour(&result);
#else
ffStrbufSetS(&result.name, "Android");
ffStrbufSetS(&result.id, "android");
ffSettingsGetAndroidProperty("ro.build.version.release", &result.versionID);
ffSettingsGetAndroidProperty("ro.build.version.release", &result.version);
ffSettingsGetAndroidProperty("ro.build.version.codename", &result.codename);
ffSettingsGetAndroidProperty("ro.build.id", &result.buildID);
#endif
pthread_mutex_unlock(&mutex);
return &result;
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#ifndef FF_INCLUDED_detection_os
#define FF_INCLUDED_detection_os
#include "fastfetch.h"
typedef struct FFOSResult
{
FFstrbuf systemName;
FFstrbuf name;
FFstrbuf prettyName;
FFstrbuf id;
FFstrbuf idLike;
FFstrbuf variant;
FFstrbuf variantID;
FFstrbuf version;
FFstrbuf versionID;
FFstrbuf codename;
FFstrbuf buildID;
FFstrbuf architecture;
} FFOSResult;
const FFOSResult* ffDetectOS(const FFinstance* instance);
#endif
+162
View File
@@ -0,0 +1,162 @@
#include "fastfetch.h"
#include "detection/qt.h"
#include "common/properties.h"
#include "detection/displayserver.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
static inline bool allValuesSet(const FFQtResult* result)
{
return
result->widgetStyle.length > 0 &&
result->colorScheme.length > 0 &&
result->icons.length > 0 &&
result->font.length > 0;
}
typedef enum PlasmaCategory
{
PLASMA_CATEGORY_GENERAL,
PLASMA_CATEGORY_KDE,
PLASMA_CATEGORY_ICONS,
PLASMA_CATEGORY_OTHER
} PlasmaCategory;
static bool detectPlasmaFromFile(const char* filename, FFQtResult* result)
{
FILE* kdeglobals = fopen(filename, "r");
if(kdeglobals == NULL)
return false;
char* line = NULL;
size_t len = 0;
PlasmaCategory category = PLASMA_CATEGORY_OTHER;
while(getline(&line, &len, kdeglobals) != -1)
{
if(line[0] == '[')
{
char categoryName[32];
sscanf(line, "[%31[^]]", categoryName);
if(strcasecmp(categoryName, "General") == 0)
category = PLASMA_CATEGORY_GENERAL;
else if(strcasecmp(categoryName, "KDE") == 0)
category = PLASMA_CATEGORY_KDE;
else if(strcasecmp(categoryName, "Icons") == 0)
category = PLASMA_CATEGORY_ICONS;
else
category = PLASMA_CATEGORY_OTHER;
continue;
}
if(category == PLASMA_CATEGORY_KDE && result->widgetStyle.length == 0)
ffParsePropLine(line, "widgetStyle =", &result->widgetStyle);
else if(category == PLASMA_CATEGORY_ICONS && result->icons.length == 0)
ffParsePropLine(line, "Theme =", &result->icons);
else if(category == PLASMA_CATEGORY_GENERAL)
{
if(result->colorScheme.length == 0)
ffParsePropLine(line, "ColorScheme =", &result->colorScheme);
if(result->font.length == 0)
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)
ffParsePropLine(line, "Font =", &result->font);
}
}
if(line != NULL)
free(line);
fclose(kdeglobals);
return true;
}
static void detectPlasma(const FFinstance* instance, FFQtResult* result)
{
bool foundAFile = false;
//We need to do this because we use multiple threads on configDirs
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
{
ffStrbufSet(&baseDir, ffListGet(&instance->state.configDirs, i));
ffStrbufAppendS(&baseDir, "kdeglobals");
if(detectPlasmaFromFile(baseDir.chars, result))
foundAFile = true;
if(allValuesSet(result))
{
ffStrbufDestroy(&baseDir);
return;
}
}
ffStrbufDestroy(&baseDir);
if(!foundAFile)
return;
//In Plasma the default value is never set in the config file, but the whole key-value is discarded.
///We must set these values by our self if the file exists (it always does here)
if(result->widgetStyle.length == 0)
ffStrbufAppendS(&result->widgetStyle, "Breeze");
if(result->colorScheme.length == 0)
ffStrbufAppendS(&result->colorScheme, "BreezeLight");
if(result->icons.length == 0)
ffStrbufAppendS(&result->icons, "Breeze");
if(result->font.length == 0)
ffStrbufAppendS(&result->font, "Noto Sans, 10");
}
static void detectLXQt(const FFinstance* instance, FFQtResult* result)
{
ffParsePropFileConfigValues(instance, "lxqt/lxqt.conf", 3, (FFpropquery[]) {
{"style = ", &result->widgetStyle},
{"icon_theme = ", &result->icons},
{"font = ", &result->font}
});
}
const FFQtResult* ffDetectQt(FFinstance* instance)
{
static FFQtResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.widgetStyle);
ffStrbufInit(&result.colorScheme);
ffStrbufInit(&result.icons);
ffStrbufInit(&result.font);
const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance);
if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "KDE Plasma") == 0)
detectPlasma(instance, &result);
else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "LXQt") == 0)
detectLXQt(instance, &result);
pthread_mutex_unlock(&mutex);
return &result;
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#ifndef FF_INCLUDED_detection_qt
#define FF_INCLUDED_detection_qt
#include "fastfetch.h"
typedef struct FFQtResult
{
FFstrbuf widgetStyle;
FFstrbuf colorScheme;
FFstrbuf icons;
FFstrbuf font;
} FFQtResult;
const FFQtResult* ffDetectQt(FFinstance* instance);
#endif
+121
View File
@@ -0,0 +1,121 @@
#include "fastfetch.h"
#include "detection/temps.h"
#include "common/io.h"
#include <string.h>
#include <pthread.h>
#include <dirent.h>
static bool isTempFile(const char* name)
{
return
strncmp(name, "temp", 4) == 0 &&
name[4] >= '0' &&
name[4] <= '9' &&
strncmp(name + 5, "_input", 6) == 0;
}
static bool parseHwmonDir(FFstrbuf* dir, FFTempValue* value)
{
DIR* dirp = opendir(dir->chars);
if(dirp == NULL)
return false;
uint32_t dirLength = dir->length;
value->value = 0.0 / 0.0; //use NaN as error value
FFstrbuf valueString;
ffStrbufInit(&valueString);
struct dirent* dirent;
while((dirent = readdir(dirp)) != NULL)
{
if(!isTempFile(dirent->d_name))
continue;
ffStrbufAppendS(dir, dirent->d_name);
ffReadFileBuffer(dir->chars, &valueString);
ffStrbufSubstrBefore(dir, dirLength);
//ffStrbufToDouble() returns NaN if the string couldn't be parsed
value->value = ffStrbufToDouble(&valueString);
if(value->value != value->value)
continue;
value->value /= 1000.0; //millidegrees to degrees
break;
}
closedir(dirp);
ffStrbufDestroy(&valueString);
if(value->value != value->value)
return false;
ffStrbufAppendS(dir, "name");
ffReadFileBuffer(dir->chars, &value->name);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufAppendS(dir, "device/class");
ffReadFileBuffer(dir->chars, &value->deviceClass);
ffStrbufSubstrBefore(dir, dirLength);
return value->name.length > 0 || value->deviceClass.length > 0;
}
const FFTempsResult* ffDetectTemps(const FFinstance* instance)
{
FF_UNUSED(instance)
static FFTempsResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffListInitA(&result.values, sizeof(FFTempValue), 16);
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
ffStrbufAppendS(&baseDir, "/sys/class/hwmon/");
uint32_t baseDirLength = baseDir.length;
DIR* dirp = opendir(baseDir.chars);
if(dirp == NULL)
{
pthread_mutex_unlock(&mutex);
return &result;
}
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
if(entry->d_name[0] == '.')
continue;
ffStrbufAppendS(&baseDir, entry->d_name);
ffStrbufAppendC(&baseDir, '/');
FFTempValue* temp = ffListAdd(&result.values);
ffStrbufInit(&temp->name);
ffStrbufInit(&temp->deviceClass);
if(!parseHwmonDir(&baseDir, temp))
{
ffStrbufDestroy(&temp->name);
ffStrbufDestroy(&temp->deviceClass);
--result.values.length;
}
ffStrbufSubstrBefore(&baseDir, baseDirLength);
}
pthread_mutex_unlock(&mutex);
return &result;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#ifndef FF_INCLUDED_detection_temps
#define FF_INCLUDED_detection_temps
#include "fastfetch.h"
typedef struct FFTempValue
{
FFstrbuf name;
FFstrbuf deviceClass;
double value;
} FFTempValue;
typedef struct FFTempsResult
{
FFlist values; //List of FFTempValue
} FFTempsResult;
const FFTempsResult* ffDetectTemps(const FFinstance* instance);
#endif
+282
View File
@@ -0,0 +1,282 @@
#include "fastfetch.h"
#include "detection/terminalshell.h"
#include "common/io.h"
#include "common/parsing.h"
#include "common/processing.h"
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
static void setExeName(FFstrbuf* exe, const char** exeName)
{
uint32_t lastSlashIndex = ffStrbufLastIndexC(exe, '/');
if(lastSlashIndex < exe->length)
*exeName = exe->chars + lastSlashIndex + 1;
}
static void getProcessInformation(const char* pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName)
{
FFstrbuf cmdlineFilePath;
ffStrbufInit(&cmdlineFilePath);
ffStrbufAppendS(&cmdlineFilePath, "/proc/");
ffStrbufAppendS(&cmdlineFilePath, pid);
ffStrbufAppendS(&cmdlineFilePath, "/cmdline");
ffReadFileBuffer(cmdlineFilePath.chars, exe);
ffStrbufSubstrBeforeFirstC(exe, '\0'); //Trim the arguments
ffStrbufTrimLeft(exe, '-'); //Happens in TTY
if(exe->length == 0)
ffStrbufSet(exe, processName);
setExeName(exe, exeName);
ffStrbufDestroy(&cmdlineFilePath);
}
static void getTerminalShell(FFTerminalShellResult* result, const char* pid)
{
FFstrbuf statFilePath;
ffStrbufInit(&statFilePath);
ffStrbufAppendS(&statFilePath, "/proc/");
ffStrbufAppendS(&statFilePath, pid);
ffStrbufAppendS(&statFilePath, "/stat");
FILE* stat = fopen(statFilePath.chars, "r");
ffStrbufDestroy(&statFilePath);
if(stat == NULL)
return;
char name[256];
name[0] = '\0';
char ppid[256];
ppid[0] = '\0';
if(
fscanf(stat, "%*s (%255[^)]) %*c %255s", name, ppid) != 2 || //stat (comm) state ppid
!ffStrSet(name) ||
!ffStrSet(ppid) ||
*ppid == '-' ||
strcasecmp(ppid, "0") == 0
) {
fclose(stat);
return;
}
fclose(stat);
//Common programs that are between terminal and own process, but are not the shell
if(
strcasecmp(name, "sudo") == 0 ||
strcasecmp(name, "su") == 0 ||
strcasecmp(name, "doas") == 0 ||
strcasecmp(name, "strace") == 0 ||
strcasecmp(name, "sshd") == 0 ||
strcasecmp(name, "gdb") == 0 ||
strcasecmp(name, "guake-wrapped") == 0
) {
getTerminalShell(result, ppid);
return;
}
//Known shells
if(
strcasecmp(name, "bash") == 0 ||
strcasecmp(name, "sh") == 0 ||
strcasecmp(name, "zsh") == 0 ||
strcasecmp(name, "ksh") == 0 ||
strcasecmp(name, "fish") == 0 ||
strcasecmp(name, "dash") == 0 ||
strcasecmp(name, "git-shell") == 0
) {
ffStrbufAppendS(&result->shellProcessName, name);
getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName);
getTerminalShell(result, ppid);
return;
}
ffStrbufAppendS(&result->terminalProcessName, name);
getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName);
}
static void getTerminalFromEnv(FFTerminalShellResult* result)
{
if(
result->terminalProcessName.length > 0 &&
!ffStrbufStartsWithIgnCaseS(&result->terminalProcessName, "login") &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "(login)") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "systemd") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "init") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "(init)") != 0 &&
ffStrbufIgnCaseCompS(&result->terminalProcessName, "0") != 0
) return;
char* term = NULL;
//SSH
if(getenv("SSH_CONNECTION") != NULL)
term = getenv("SSH_TTY");
//Windows Terminal
if(!ffStrSet(term) && (
getenv("WT_SESSION") != NULL ||
getenv("WT_PROFILE_ID") != NULL
)) term = "Windows Terminal";
//Termux
if(!ffStrSet(term) && (
getenv("TERMUX_VERSION") != NULL ||
getenv("TERMUX_MAIN_PACKAGE_FORMAT") != NULL ||
getenv("TMUX_TMPDIR") != NULL
)) term = "Termux";
//Normal Terminal
if(!ffStrSet(term))
term = getenv("TERM");
//TTY
if(!ffStrSet(term) || strcasecmp(term, "linux") == 0)
term = ttyname(STDIN_FILENO);
ffStrbufSetS(&result->terminalProcessName, term);
ffStrbufSetS(&result->terminalExe, term);
setExeName(&result->terminalExe, &result->terminalExeName);
}
static void getUserShellFromEnv(FFTerminalShellResult* result)
{
ffStrbufAppendS(&result->userShellExe, getenv("SHELL"));
setExeName(&result->userShellExe, &result->userShellExeName);
//If shell detection via processes failed
if(result->shellProcessName.length == 0 && result->userShellExe.length > 0)
{
ffStrbufAppendS(&result->shellProcessName, result->userShellExeName);
ffStrbufSet(&result->shellExe, &result->userShellExe);
setExeName(&result->shellExe, &result->shellExeName);
}
}
static void getShellVersionBash(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
"env",
"-i",
exe->chars,
"--norc",
"--noprofile",
"-c",
"printf \"%s\" \"$BASH_VERSION\"",
NULL
});
ffStrbufSubstrBeforeFirstC(version, '(');
}
static void getShellVersionZsh(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
});
ffStrbufTrimRight(version, '\n');
ffStrbufSubstrBeforeLastC(version, ' ');
ffStrbufSubstrAfterFirstC(version, ' ');
}
static void getShellVersionFish(FFstrbuf* exe, FFstrbuf* version)
{
ffProcessAppendStdOut(version, (char* const[]) {
exe->chars,
"--version",
NULL
});
ffStrbufTrimRight(version, '\n');
ffStrbufSubstrAfterLastC(version, ' ');
}
static void getShellVersionGeneric(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
{
FFstrbuf command;
ffStrbufInit(&command);
ffStrbufAppendS(&command, "printf \"%s\" \"$");
ffStrbufAppendTransformS(&command, exeName, toupper);
ffStrbufAppendS(&command, "_VERSION\"");
ffProcessAppendStdOut(version, (char* const[]) {
"env",
"-i",
exe->chars,
"-c",
command.chars,
NULL
});
ffStrbufSubstrBeforeFirstC(version, '(');
ffStrbufRemoveStrings(version, 2, "-release", "release");
ffStrbufDestroy(&command);
}
static void getShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
{
if(strcasecmp(exeName, "bash") == 0)
getShellVersionBash(exe, version);
else if(strcasecmp(exeName, "zsh") == 0)
getShellVersionZsh(exe, version);
else if(strcasecmp(exeName, "fish") == 0)
getShellVersionFish(exe, version);
else
getShellVersionGeneric(exe, exeName, version);
}
const FFTerminalShellResult* ffDetectTerminalShell(FFinstance* instance)
{
FF_UNUSED(instance);
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static FFTerminalShellResult result;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.shellProcessName);
ffStrbufInitA(&result.shellExe, 128);
result.shellExeName = result.shellExe.chars;
ffStrbufInit(&result.shellVersion);
ffStrbufInit(&result.terminalProcessName);
ffStrbufInitA(&result.terminalExe, 128);
result.terminalExeName = result.terminalExe.chars;
ffStrbufInit(&result.userShellExe);
result.userShellExeName = result.userShellExe.chars;
ffStrbufInit(&result.userShellVersion);
char ppid[32];
snprintf(ppid, sizeof(ppid) - 1, "%i", getppid());
getTerminalShell(&result, ppid);
getTerminalFromEnv(&result);
getUserShellFromEnv(&result);
getShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion);
if(strcasecmp(result.shellExeName, result.userShellExeName) != 0)
getShellVersion(&result.userShellExe, result.userShellExeName, &result.userShellVersion);
else
ffStrbufSet(&result.userShellVersion, &result.shellVersion);
pthread_mutex_unlock(&mutex);
return &result;
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#ifndef FF_INCLUDED_detection_terminalshell
#define FF_INCLUDED_detection_terminalshell
#include "fastfetch.h"
typedef struct FFTerminalShellResult
{
FFstrbuf shellProcessName;
FFstrbuf shellExe;
const char* shellExeName; //pointer to a char in shellExe
FFstrbuf shellVersion;
FFstrbuf terminalProcessName;
FFstrbuf terminalExe;
const char* terminalExeName; //pointer to a char in terminalExe
FFstrbuf userShellExe;
const char* userShellExeName; //pointer to a char in userShellExe
FFstrbuf userShellVersion;
} FFTerminalShellResult;
const FFTerminalShellResult* ffDetectTerminalShell(FFinstance* instance);
#endif
+38
View File
@@ -0,0 +1,38 @@
#include "fastfetch.h"
#include "detection/title.h"
#include <limits.h>
#include <unistd.h>
#include <pthread.h>
#include <netdb.h>
const FFTitleResult* ffDetectTitle(const FFinstance* instance)
{
static FFTitleResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.userName);
ffStrbufAppendS(&result.userName, instance->state.passwd->pw_name);
ffStrbufInitA(&result.hostname, HOST_NAME_MAX);
ffStrbufAppendS(&result.hostname, instance->state.utsname.nodename);
ffStrbufInitA(&result.fqdn, HOST_NAME_MAX);
struct hostent* host = gethostbyname(result.hostname.chars);
if(host != NULL)
ffStrbufAppendS(&result.fqdn, host->h_name);
if(result.fqdn.length == 0)
ffStrbufAppend(&result.fqdn, &result.hostname);
pthread_mutex_unlock(&mutex);
return &result;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#ifndef FF_INCLUDED_detection_title
#define FF_INCLUDED_detection_title
#include "fastfetch.h"
typedef struct FFTitleResult
{
FFstrbuf userName;
FFstrbuf hostname;
FFstrbuf fqdn; //Fully qualified domain name
} FFTitleResult;
const FFTitleResult* ffDetectTitle(const FFinstance* instance);
#endif
+231
View File
@@ -0,0 +1,231 @@
#include "fastfetch.h"
#include "detection/vulkan.h"
#include <pthread.h>
#ifdef FF_HAVE_VULKAN
#include "common/library.h"
#include "common/io.h"
#include "common/parsing.h"
#include <stdlib.h>
#include <vulkan/vulkan.h>
static inline void applyVulkanVersion(uint32_t vulkanVersion, FFVersion* ffVersion)
{
ffVersion->major = VK_VERSION_MAJOR(vulkanVersion);
ffVersion->minor = VK_VERSION_MINOR(vulkanVersion);
ffVersion->patch = VK_VERSION_PATCH(vulkanVersion);
}
static void applyDriverName(VkPhysicalDeviceDriverProperties* properties, FFstrbuf* result)
{
if(!ffStrSet(properties->driverName))
return;
ffStrbufAppendS(result, properties->driverName);
if(!ffStrSet(properties->driverInfo))
return;
ffStrbufAppendS(result, " [");
ffStrbufAppendS(result, properties->driverInfo);
ffStrbufAppendC(result, ']');
}
static void detectVulkan(const FFinstance* instance, FFVulkanResult* result)
{
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", 2)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetInstanceProcAddr,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkCreateInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkDestroyInstance,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkEnumeratePhysicalDevices,)
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkGetPhysicalDeviceProperties,)
//Some drivers (nvdc) print messages to stdout
//and thats the best way i found to disable that
ffSuppressIO(true);
FFVersion instanceVersion = FF_VERSION_INIT;
//We need to get the function pointer this way, because it is only provided by vulkan 1.1 and higher.
//a dlsym would fail on 1.0 implementations
PFN_vkEnumerateInstanceVersion ffvkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) ffvkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
if(ffvkEnumerateInstanceVersion != NULL)
{
uint32_t version;
if(ffvkEnumerateInstanceVersion(&version) == VK_SUCCESS)
applyVulkanVersion(version, &instanceVersion);
}
const uint32_t projectVersion = VK_MAKE_VERSION(
FASTFETCH_PROJECT_VERSION_MAJOR,
FASTFETCH_PROJECT_VERSION_MINOR,
FASTFETCH_PROJECT_VERSION_PATCH
);
//We need to request 1.2 to get physicalDeviceDriverProperties
uint32_t requestedVkVersion = VK_API_VERSION_1_0;
if(instanceVersion.minor >= 2)
requestedVkVersion = VK_API_VERSION_1_2;
const VkApplicationInfo applicationInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = NULL,
.pApplicationName = FASTFETCH_PROJECT_NAME,
.applicationVersion = projectVersion,
.pEngineName = "vulkanPrintGPUs",
.engineVersion = projectVersion,
.apiVersion = requestedVkVersion
};
const VkInstanceCreateInfo instanceCreateInfo = {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = NULL,
.pApplicationInfo = &applicationInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = NULL,
.enabledExtensionCount = 0,
.ppEnabledExtensionNames = NULL,
.flags = 0
};
VkInstance vkInstance;
if(ffvkCreateInstance(&instanceCreateInfo, NULL, &vkInstance) != VK_SUCCESS)
{
dlclose(vulkan);
ffSuppressIO(false);
return;
}
//if instance creation succeeded, but vkEnumerateInstanceVersion didn't, this means we are running against a vulkan 1.0 implementation
//explicitly set this version, if no device is found, so we still have at least this info
if(instanceVersion.major == 0 && instanceVersion.minor == 0 && instanceVersion.patch == 0)
instanceVersion.major = 1;
uint32_t physicalDeviceCount;
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL) != VK_SUCCESS)
{
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
VkPhysicalDevice* physicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices) != VK_SUCCESS)
{
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
return;
}
PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2");
FFVersion maxDeviceApiVersion = FF_VERSION_INIT;
FFVersion maxDeviceConformanceVersion = FF_VERSION_INIT;
for(uint32_t i = 0; i < physicalDeviceCount; i++)
{
//Get device properties.
//On VK 1.2 and up, we use vkGetPhysicalDeviceProperties2, so we can put VkPhysicalDeviceDriverProperties in the pNext chain.
//This is required to get the driver name and conformance version.
VkPhysicalDeviceDriverProperties driverProperties;
driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
driverProperties.pNext = NULL;
driverProperties.driverName[0] = '\0';
driverProperties.conformanceVersion = (VkConformanceVersion) {0, 0, 0, 0};
VkPhysicalDeviceProperties2 physicalDeviceProperties;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
physicalDeviceProperties.pNext = &driverProperties;
if(ffvkGetPhysicalDeviceProperties2 != NULL)
ffvkGetPhysicalDeviceProperties2(physicalDevices[i], &physicalDeviceProperties);
else
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &physicalDeviceProperties.properties);
//If the device api version is higher than the current highest device api version, overwrite it
//In this case, also use the current device driver name as the shown driver name
FFVersion deviceAPIVersion = FF_VERSION_INIT;
applyVulkanVersion(physicalDeviceProperties.properties.apiVersion, &deviceAPIVersion);
if(ffVersionCompare(&deviceAPIVersion, &maxDeviceApiVersion) > 0)
{
maxDeviceApiVersion = deviceAPIVersion;
applyDriverName(&driverProperties, &result->driver);
}
//If the device conformance version is higher than the current highest device conformance version, overwrite it
FFVersion deviceConformanceVersion = FF_VERSION_INIT;
deviceConformanceVersion.major = driverProperties.conformanceVersion.major;
deviceConformanceVersion.minor = driverProperties.conformanceVersion.minor;
deviceConformanceVersion.patch = driverProperties.conformanceVersion.patch;
if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0)
maxDeviceConformanceVersion = deviceConformanceVersion;
//Add the device to the list of devices shown by the GPU module
//We don't want softare rasterizers to show up as physical gpu
if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
continue;
FFGPUResult* gpu = ffListAdd(&result->devices);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
gpu->temperature = 0.0 / 0.0; //NaN, no way to detect temperature using vulkan
ffStrbufAppendS(&gpu->name, physicalDeviceProperties.properties.deviceName);
}
//If the highest device version is lower than the instance version, use it as our vulkan version
//otherwise the instance version is the vulkan version
if(ffVersionCompare(&instanceVersion, &maxDeviceApiVersion) > 0)
ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion);
else
ffVersionToPretty(&instanceVersion, &result->apiVersion);
//Use the highest device conformace version as our conformance version
ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion);
free(physicalDevices);
ffvkDestroyInstance(vkInstance, NULL);
dlclose(vulkan);
ffSuppressIO(false);
}
#endif
const FFVulkanResult* ffDetectVulkan(const FFinstance* instance)
{
static FFVulkanResult result;
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static bool init = false;
pthread_mutex_lock(&mutex);
if(init)
{
pthread_mutex_unlock(&mutex);
return &result;
}
init = true;
ffStrbufInit(&result.driver);
ffStrbufInit(&result.apiVersion);
ffStrbufInit(&result.conformanceVersion);
ffListInit(&result.devices, sizeof(FFGPUResult));
#ifdef FF_HAVE_VULKAN
detectVulkan(instance, &result);
#else
FF_UNUSED(instance);
#endif
pthread_mutex_unlock(&mutex);
return &result;
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#ifndef FF_INCLUDED_detection_vulkan
#define FF_INCLUDED_detection_vulkan
#include "fastfetch.h"
typedef struct FFGPUResult
{
FFstrbuf vendor;
FFstrbuf name;
FFstrbuf driver;
double temperature;
} FFGPUResult;
typedef struct FFVulkanResult
{
FFstrbuf driver;
FFstrbuf apiVersion;
FFstrbuf conformanceVersion;
FFlist devices; //List of FFGPUResult
} FFVulkanResult;
const FFVulkanResult* ffDetectVulkan(const FFinstance* instance);
#endif
+1403
View File
File diff suppressed because it is too large Load Diff
+249
View File
@@ -0,0 +1,249 @@
#pragma once
#ifndef FASTFETCH_INCLUDED
#define FASTFETCH_INCLUDED
#include "fastfetch_config.h"
#include <stdint.h>
#include <stdbool.h>
#include <pwd.h>
#include <sys/utsname.h>
#include <sys/sysinfo.h>
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
static inline void ffUnused(int dummy, ...) { (void) dummy; }
#define FF_UNUSED(...) ffUnused(0, __VA_ARGS__);
#define FASTFETCH_TEXT_MODIFIER_BOLT "\033[1m"
#define FASTFETCH_TEXT_MODIFIER_ERROR "\033[1;31m"
#define FASTFETCH_TEXT_MODIFIER_RESET "\033[0m"
#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9)
typedef enum FFLogoType
{
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 enum FFGLType
{
FF_GL_TYPE_AUTO,
FF_GL_TYPE_EGL,
FF_GL_TYPE_GLX,
FF_GL_TYPE_OSMESA
} FFGLType;
typedef struct FFModuleArgs
{
FFstrbuf key;
FFstrbuf outputFormat;
FFstrbuf errorFormat;
} FFModuleArgs;
typedef struct FFconfig
{
struct
{
FFstrbuf source;
FFLogoType type;
FFstrbuf colors[FASTFETCH_LOGO_MAX_COLORS];
uint32_t width;
uint32_t height;
uint32_t paddingLeft;
uint32_t paddingRight;
bool printRemaining;
} logo;
FFstrbuf mainColor; //If this is empty, ffLogoPrint will set it to the main color of the logo
FFstrbuf separator;
bool showErrors;
bool recache;
bool cacheSave;
bool allowSlowOperations;
bool disableLinewrap;
bool hideCursor;
bool escapeBedrock;
FFGLType glType;
bool pipe; //disables logo and all escape sequences
bool multithreading;
FFModuleArgs os;
FFModuleArgs host;
FFModuleArgs kernel;
FFModuleArgs uptime;
FFModuleArgs processes;
FFModuleArgs packages;
FFModuleArgs shell;
FFModuleArgs resolution;
FFModuleArgs de;
FFModuleArgs wm;
FFModuleArgs wmTheme;
FFModuleArgs theme;
FFModuleArgs icons;
FFModuleArgs font;
FFModuleArgs cursor;
FFModuleArgs terminal;
FFModuleArgs terminalFont;
FFModuleArgs cpu;
FFModuleArgs cpuUsage;
FFModuleArgs gpu;
FFModuleArgs memory;
FFModuleArgs disk;
FFModuleArgs battery;
FFModuleArgs locale;
FFModuleArgs localIP;
FFModuleArgs publicIP;
FFModuleArgs player;
FFModuleArgs song;
FFModuleArgs dateTime;
FFModuleArgs date;
FFModuleArgs time;
FFModuleArgs vulkan;
FFModuleArgs openGL;
FFModuleArgs openCL;
FFstrbuf libPCI;
FFstrbuf libVulkan;
FFstrbuf libWayland;
FFstrbuf libXcbRandr;
FFstrbuf libXcb;
FFstrbuf libXrandr;
FFstrbuf libX11;
FFstrbuf libGIO;
FFstrbuf libDConf;
FFstrbuf libDBus;
FFstrbuf libXFConf;
FFstrbuf libSQLite3;
FFstrbuf librpm;
FFstrbuf libImageMagick;
FFstrbuf libZ;
FFstrbuf libChafa;
FFstrbuf libEGL;
FFstrbuf libGLX;
FFstrbuf libOSMesa;
FFstrbuf libOpenCL;
bool titleFQDN;
FFstrbuf diskFolders;
FFstrbuf batteryDir;
FFstrbuf separatorString;
bool localIpShowLoop;
bool localIpShowIpV4;
bool localIpShowIpV6;
uint32_t publicIpTimeout;
FFstrbuf osFile;
FFstrbuf playerName;
} FFconfig;
typedef struct FFstate
{
uint32_t logoWidth;
uint32_t logoHeight;
uint32_t keysHeight;
struct passwd* passwd;
struct utsname utsname;
struct sysinfo sysinfo;
FFlist configDirs;
FFstrbuf cacheDir;
} FFstate;
typedef struct FFinstance
{
FFconfig config;
FFstate state;
} FFinstance;
//////////////////////
// Init functions //
//////////////////////
//common/init.c
void ffInitInstance(FFinstance* instance);
void ffStart(FFinstance* instance);
void ffFinish(FFinstance* instance);
void ffListFeatures();
////////////////////
// Logo functions //
////////////////////
void ffLogoPrint(FFinstance* instance);
void ffLogoPrintRemaining(FFinstance* instance);
void ffLogoPrintLine(FFinstance* instance);
void ffLogoBuiltinPrint(FFinstance* instance);
void ffLogoBuiltinList();
void ffLogoBuiltinListAutocompletion();
//////////////////////
// Module functions //
//////////////////////
//Common
void ffPrintDateTimeFormat(FFinstance* instance, const char* moduleName, const FFModuleArgs* moduleArgs);
//Printing
void ffPrintCustom(FFinstance* instance, const char* key, const char* value);
void ffPrintBreak(FFinstance* instance);
void ffPrintTitle(FFinstance* instance);
void ffPrintSeparator(FFinstance* instance);
void ffPrintOS(FFinstance* instance);
void ffPrintHost(FFinstance* instance);
void ffPrintKernel(FFinstance* instance);
void ffPrintUptime(FFinstance* instance);
void ffPrintProcesses(FFinstance* instance);
void ffPrintPackages(FFinstance* instance);
void ffPrintShell(FFinstance* instance);
void ffPrintResolution(FFinstance* instance);
void ffPrintDesktopEnvironment(FFinstance* instance);
void ffPrintWM(FFinstance* instance);
void ffPrintWMTheme(FFinstance* instance);
void ffPrintTheme(FFinstance* instance);
void ffPrintIcons(FFinstance* instance);
void ffPrintFont(FFinstance* instance);
void ffPrintCursor(FFinstance* instance);
void ffPrintTerminal(FFinstance* instance);
void ffPrintTerminalFont(FFinstance* instance);
void ffPrintCPU(FFinstance* instance);
void ffPrintCPUUsage(FFinstance* instance);
void ffPrintGPU(FFinstance* instance);
void ffPrintMemory(FFinstance* instance);
void ffPrintDisk(FFinstance* instance);
void ffPrintBattery(FFinstance* instance);
void ffPrintLocale(FFinstance* instance);
void ffPrintPlayer(FFinstance* instance);
void ffPrintSong(FFinstance* instance);
void ffPrintDateTime(FFinstance* instance);
void ffPrintDate(FFinstance* instance);
void ffPrintTime(FFinstance* instance);
void ffPrintLocalIp(FFinstance* instance);
void ffPrintPublicIp(FFinstance* instance);
void ffPrintColors(FFinstance* instance);
void ffPrintVulkan(FFinstance* instance);
void ffPrintOpenGL(FFinstance* instance);
void ffPrintOpenCL(FFinstance* instance);
#endif
+24
View File
@@ -0,0 +1,24 @@
#ifndef FASTFETCH_INDLUDED_fastfetch_config_h_in
#define FASTFETCH_INDLUDED_fastfetch_config_h_in
#define FASTFETCH_PROJECT_NAME "@PROJECT_NAME@"
#define FASTFETCH_PROJECT_VERSION "@PROJECT_VERSION@"
#define FASTFETCH_PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define FASTFETCH_PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define FASTFETCH_PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define FASTFETCH_PROJECT_VERSION_TWEAK "@PROJECT_VERSION_TWEAK@"
#define FASTFETCH_TARGET_DIR_ROOT "@TARGET_DIR_ROOT@"
#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_SYSTEM "@DATATEXT_CONFIG_SYSTEM@" //Requires FASTFETCH_PROJECT_VERSION to be set
#define FASTFETCH_DATATEXT_CONFIG_USER "@DATATEXT_CONFIG_USER@" //Requires FASTFETCH_PROJECT_VERSION and FASTFETCH_DATATEXT_STRUCTURE to be set
#define FASTFETCH_DATATEXT_MODULES "@DATATEXT_MODULES@"
#define FASTFETCH_DATATEXT_HELP "@DATATEXT_HELP@"
#define FASTFETCH_DATATEXT_HELP_COLOR "@DATATEXT_HELP_COLOR@"
#define FASTFETCH_DATATEXT_HELP_FORMAT "@DATATEXT_HELP_FORMAT@"
#define FASTFETCH_DATATEXT_HELP_CONFIG "@DATATEXT_HELP_CONFIG@"
#endif // FASTFETCH_INDLUDED_fastfetch_config_h_in
+57
View File
@@ -0,0 +1,57 @@
#include "fastfetch.h"
int main(int argc, char** argv)
{
//Disable compiler warnings
FF_UNUSED(argc, argv);
FFinstance instance;
ffInitInstance(&instance); //This also applys default configuration to instance.config
//Modify instance.config here
//Does things like starting detection threads, disabling line wrap, etc
ffStart(&instance);
//Printing
ffPrintTitle(&instance);
ffPrintSeparator(&instance);
ffPrintOS(&instance);
ffPrintHost(&instance);
ffPrintKernel(&instance);
ffPrintUptime(&instance);
//ffPrintProcesses(&instance);
ffPrintPackages(&instance);
ffPrintShell(&instance);
ffPrintResolution(&instance);
ffPrintDesktopEnvironment(&instance);
ffPrintWM(&instance);
ffPrintWMTheme(&instance);
ffPrintTheme(&instance);
ffPrintIcons(&instance);
ffPrintFont(&instance);
ffPrintCursor(&instance);
ffPrintTerminal(&instance);
ffPrintTerminalFont(&instance);
ffPrintCPU(&instance);
//ffPrintCPUUsage(&instance);
ffPrintGPU(&instance);
ffPrintMemory(&instance);
ffPrintDisk(&instance);
ffPrintBattery(&instance);
//ffPrintPlayer(&instance);
//ffPrintSong(&instance);
//ffPrintLocalIp(&instance);
//ffPrintPublicIp(&instance);
ffPrintLocale(&instance);
//ffPrintDateTime(&instance);
//ffPrintDate(&instance);
//ffPrintTime(&instance);
//ffPrintVulkan(&instance);
//ffPrintOpenGL(&instance);
ffPrintBreak(&instance);
ffPrintColors(&instance);
ffFinish(&instance);
return 0;
}
+1635
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
#ifdef FF_HAVE_IMAGEMAGICK6
#include "image.h"
#include "common/library.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
+31
View File
@@ -0,0 +1,31 @@
#ifdef FF_HAVE_IMAGEMAGICK7
#include "image.h"
#include "common/library.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
+574
View File
@@ -0,0 +1,574 @@
#include "image.h"
#include "common/io.h"
#include "common/printing.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 "common/library.h"
#include <stdlib.h>
#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);
ffWriteFileBuffer(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.logo.paddingLeft + instance->config.logo.paddingRight;
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.logo.width == 0)
writeCacheUint32(requestData, instance->state.logoWidth, FF_CACHE_FILE_WIDTH);
if(instance->config.logo.height == 0)
writeCacheUint32(requestData, instance->state.logoHeight, FF_CACHE_FILE_HEIGHT);
//Write result to stdout
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
fflush(stdout);
ffWriteFDBuffer(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;
ffLogoPrintChars(instance, result.chars, false);
writeCacheStrbuf(requestData, &result, FF_CACHE_FILE_CHAFA);
ffg_string_free(str, TRUE);
ffchafa_canvas_unref(canvas);
ffchafa_canvas_config_unref(canvasConfig);
ffchafa_symbol_map_unref(symbolMap);
return true;
}
#endif
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData)
{
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
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.logo.source.chars, instance->config.logo.source.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);
ffAppendFileBuffer(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;
}
ffLogoPrintChars(instance, content.chars, false);
ffStrbufDestroy(&content);
return true;
}
static bool printCachedPixel(FFinstance* instance, FFLogoRequestData* requestData)
{
requestData->logoCharacterWidth = instance->config.logo.width;
if(requestData->logoCharacterWidth == 0)
{
requestData->logoCharacterWidth = readCachedUint32(requestData, FF_CACHE_FILE_WIDTH);
if(requestData->logoCharacterWidth == 0)
return false;
}
requestData->logoCharacterHeight = instance->config.logo.height;
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.logo.paddingLeft);
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.logo.paddingLeft + instance->config.logo.paddingRight;
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;
}
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
{
//Performance optimisation
#ifndef FF_HAVE_CHAFA
if(type == FF_LOGO_TYPE_CHAFA)
return false;
#endif
FFLogoRequestData requestData;
requestData.type = type;
requestData.characterPixelWidth = 1;
requestData.characterPixelHeight = 1;
if(
(type != FF_LOGO_TYPE_CHAFA || instance->config.logo.width == 0 || instance->config.logo.height == 0) &&
!getCharacterPixelDimensions(&requestData)
)
return false;
requestData.logoPixelWidth = simpleCeil((double) instance->config.logo.width * requestData.characterPixelWidth);
requestData.logoPixelHeight = simpleCeil((double) instance->config.logo.height * requestData.characterPixelHeight);
ffStrbufInitA(&requestData.cacheDir, PATH_MAX * 2);
ffStrbufAppend(&requestData.cacheDir, &instance->state.cacheDir);
ffStrbufAppendS(&requestData.cacheDir, "images");
ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX);
if(realpath(instance->config.logo.source.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 false;
}
ffStrbufRecalculateLength(&requestData.cacheDir);
ffStrbufEnsureEndsWithC(&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 true;
}
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 == FF_LOGO_IMAGE_RESULT_SUCCESS;
}
#else //FF_HAVE_IMAGEMAGICK{6, 7}
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
{
FF_UNUSED(instance, type);
return false;
}
#endif //FF_HAVE_IMAGEMAGICK{6, 7}
+54
View File
@@ -0,0 +1,54 @@
#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 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;
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
+417
View File
@@ -0,0 +1,417 @@
#include "logo.h"
#include "common/io.h"
#include "common/printing.h"
#include "detection/os.h"
#include "detection/terminalshell.h"
#include <ctype.h>
#include <string.h>
void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplacement)
{
uint32_t currentlineLength = 0;
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
//Use logoColor[0] as the default color
if(doColorReplacement)
ffPrintColor(&instance->config.logo.colors[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.logo.paddingRight);
//We have \r\n, skip the \r
if(*data == '\r')
++data;
putchar('\n');
++data;
ffPrintCharTimes(' ', instance->config.logo.paddingLeft);
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.logo.colors[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.logo.paddingRight);
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.logo.paddingLeft + instance->config.logo.paddingRight;
//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 logoApplyMainColor(FFinstance* instance, const FFlogo* logo)
{
if(instance->config.mainColor.length == 0)
ffStrbufAppendS(&instance->config.mainColor, logo->builtinColors[0]);
}
static bool logoHasName(const FFlogo* logo, const char* name)
{
const char** logoName = logo->names;
while(*logoName != NULL)
{
if(strcasecmp(*logoName, name) == 0)
return true;
++logoName;
}
return false;
}
static const FFlogo* logoGetBuiltin(const char* name)
{
GetLogoMethod* methods = ffLogoBuiltinGetAll();
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
if(logoHasName(logo, name))
return logo;
++methods;
}
return NULL;
}
static const FFlogo* logoGetBuiltinDetected(FFinstance* instance)
{
const FFOSResult* os = ffDetectOS(instance);
const FFlogo* logo = logoGetBuiltin(os->id.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->name.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->prettyName.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->idLike.chars);
if(logo != NULL)
return logo;
logo = logoGetBuiltin(os->systemName.chars);
if(logo != NULL)
return logo;
return ffLogoBuiltinGetUnknown();
}
static inline void logoApplyMainColorDetected(FFinstance* instance)
{
logoApplyMainColor(instance, logoGetBuiltinDetected(instance));
}
static void logoPrintStruct(FFinstance* instance, const FFlogo* logo)
{
logoApplyMainColor(instance, logo);
const char** colors = logo->builtinColors;
for(int i = 0; *colors != NULL && i < FASTFETCH_LOGO_MAX_COLORS; i++, colors++)
{
if(instance->config.logo.colors[i].length == 0)
ffStrbufAppendS(&instance->config.logo.colors[i], *colors);
}
ffLogoPrintChars(instance, logo->data, true);
}
static bool logoPrintBuiltinIfExists(FFinstance* instance, const char* name)
{
const FFlogo* logo = logoGetBuiltin(name);
if(logo == NULL)
return false;
logoPrintStruct(instance, logo);
return true;
}
static inline void logoPrintDetected(FFinstance* instance)
{
logoPrintStruct(instance, logoGetBuiltinDetected(instance));
}
static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement)
{
FFstrbuf content;
ffStrbufInitA(&content, 2047);
if(!ffAppendFileBuffer(instance->config.logo.source.chars, &content))
{
ffStrbufDestroy(&content);
return false;
}
logoApplyMainColorDetected(instance);
ffLogoPrintChars(instance, content.chars, doColorReplacement);
ffStrbufDestroy(&content);
return true;
}
static bool logoPrintImageIfExists(FFinstance* instance, FFLogoType logo)
{
if(!ffLogoPrintImageIfExists(instance, logo))
return false;
logoApplyMainColorDetected(instance);
return true;
}
static void logoPrintKnownType(FFinstance* instance)
{
bool successfull;
if(instance->config.logo.type == FF_LOGO_TYPE_BUILTIN)
successfull = logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars);
else if(instance->config.logo.type == FF_LOGO_TYPE_FILE)
successfull = logoPrintFileIfExists(instance, true);
else if(instance->config.logo.type == FF_LOGO_TYPE_RAW)
successfull = logoPrintFileIfExists(instance, false);
else //image
successfull = logoPrintImageIfExists(instance, instance->config.logo.type);
if(!successfull)
logoPrintDetected(instance);
}
void ffLogoPrint(FFinstance* instance)
{
//In pipe mode, we don't have a logo or padding.
//We also don't need to set main color, because it won't be printed anyway.
//So we can return quickly here.
if(instance->config.pipe)
{
instance->state.logoHeight = 0;
instance->state.logoWidth = 0;
return;
}
//If the source is not set, we can directly print the detected logo.
if(instance->config.logo.source.length == 0)
{
logoPrintDetected(instance);
return;
}
//If the source and source type is set to something else than auto, always print with the set type.
if(instance->config.logo.source.length > 0 && instance->config.logo.type != FF_LOGO_TYPE_AUTO)
{
logoPrintKnownType(instance);
return;
}
//If source matches the name of a builtin logo, print it and return.
if(logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars))
return;
const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(instance);
//Terminal emulators that support kitty graphics protocol.
bool supportsKitty =
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wezterm") == 0 ||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0;
//Try to load the logo as an image. If it succeeds, print it and return.
if(logoPrintImageIfExists(instance, supportsKitty ? FF_LOGO_TYPE_KITTY : FF_LOGO_TYPE_CHAFA))
return;
//Try to load the logo as a file. If it succeeds, print it and return.
if(logoPrintFileIfExists(instance, true))
return;
logoPrintDetected(instance);
}
void ffLogoPrintLine(FFinstance* instance)
{
if(instance->state.logoWidth > 0)
printf("\033[%uC", instance->state.logoWidth);
++instance->state.keysHeight;
}
void ffLogoPrintRemaining(FFinstance* instance)
{
while(instance->state.keysHeight <= instance->state.logoHeight)
{
ffLogoPrintLine(instance);
putchar('\n');
}
}
void ffLogoBuiltinPrint(FFinstance* instance)
{
GetLogoMethod* methods = ffLogoBuiltinGetAll();
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
printf("\033[%sm%s:\033[0m\n", logo->builtinColors[0], logo->names[0]);
logoPrintStruct(instance, logo);
ffLogoPrintRemaining(instance);
//reset everything
instance->state.logoHeight = 0;
instance->state.keysHeight = 0;
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
ffStrbufClear(&instance->config.logo.colors[i]);
puts("\n");
++methods;
}
}
void ffLogoBuiltinList()
{
GetLogoMethod* methods = ffLogoBuiltinGetAll();
uint32_t counter = 0;
while(*methods != NULL)
{
const FFlogo* logo = (*methods)();
const char** names = logo->names;
printf("%u)%s ", counter, counter < 10 ? " " : "");
++counter;
while(*names != NULL)
{
printf("\"%s\" ", *names);
++names;
}
putchar('\n');
++methods;
}
}
void ffLogoBuiltinListAutocompletion()
{
GetLogoMethod* methods = ffLogoBuiltinGetAll();
while(*methods != NULL)
{
printf("%s\n", (*methods)()->names[0]);
++methods;
}
}
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#ifndef FASTFETCH_INCLUDED_LOGO_logo
#define FASTFETCH_INCLUDED_LOGO_logo
#include "fastfetch.h"
typedef struct FFlogo
{
const char* data;
const char** names; //Null terminated
const char** builtinColors; //Null terminated
} FFlogo;
typedef const FFlogo*(*GetLogoMethod)();
//logo.c
void ffLogoPrintChars(FFinstance* instance, const char* data, bool doColorReplacement);
//builtin.c
const FFlogo* ffLogoBuiltinGetUnknown();
GetLogoMethod* ffLogoBuiltinGetAll();
//image/image.c
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type);
#endif
+182
View File
@@ -0,0 +1,182 @@
#include "fastfetch.h"
#include "common/io.h"
#include "common/printing.h"
#include <dirent.h>
#define FF_BATTERY_MODULE_NAME "Battery"
#define FF_BATTERY_NUM_FORMAT_ARGS 5
typedef struct BatteryResult
{
FFstrbuf manufacturer;
FFstrbuf modelName;
FFstrbuf technology;
FFstrbuf capacity;
FFstrbuf status;
} BatteryResult;
static void parseBattery(FFstrbuf* dir, FFlist* results)
{
uint32_t dirLength = dir->length;
FFstrbuf testBatteryBuffer;
ffStrbufInit(&testBatteryBuffer);
//type must exist and be "Battery"
ffStrbufAppendS(dir, "/type");
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
ffStrbufSubstrBefore(dir, dirLength);
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0)
{
ffStrbufDestroy(&testBatteryBuffer);
return;
}
//scope may not exist or must not be "Device"
ffStrbufAppendS(dir, "/scope");
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
ffStrbufSubstrBefore(dir, dirLength);
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0)
{
ffStrbufDestroy(&testBatteryBuffer);
return;
}
ffStrbufDestroy(&testBatteryBuffer);
BatteryResult* result = ffListAdd(results);
//capacity must exist and be not empty
ffStrbufInit(&result->capacity);
ffStrbufAppendS(dir, "/capacity");
ffReadFileBuffer(dir->chars, &result->capacity);
ffStrbufSubstrBefore(dir, dirLength);
if(result->capacity.length == 0)
{
ffStrbufDestroy(&result->capacity);
--results->length;
return;
}
//At this point, we have a battery. Try to get as much values as possible.
ffStrbufInit(&result->manufacturer);
ffStrbufAppendS(dir, "/manufacturer");
ffReadFileBuffer(dir->chars, &result->manufacturer);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->modelName);
ffStrbufAppendS(dir, "/model_name");
ffReadFileBuffer(dir->chars, &result->modelName);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->technology);
ffStrbufAppendS(dir, "/technology");
ffReadFileBuffer(dir->chars, &result->technology);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->status);
ffStrbufAppendS(dir, "/status");
ffReadFileBuffer(dir->chars, &result->status);
ffStrbufSubstrBefore(dir, dirLength);
}
static void printBattery(FFinstance* instance, const BatteryResult* result, uint8_t index)
{
if(instance->config.battery.outputFormat.length == 0)
{
ffPrintLogoAndKey(instance, FF_BATTERY_MODULE_NAME, index, &instance->config.battery.key);
bool showStatus =
result->status.length > 0 &&
ffStrbufIgnCaseCompS(&result->status, "Unknown") != 0;
if(result->capacity.length > 0)
{
ffStrbufWriteTo(&result->capacity, stdout);
putchar('%');
if(showStatus)
fputs(" [", stdout);
}
if(showStatus)
{
ffStrbufWriteTo(&result->status, stdout);
if(result->capacity.length > 0)
putchar(']');
}
putchar('\n');
}
else
{
ffPrintFormat(instance, FF_BATTERY_MODULE_NAME, index, &instance->config.battery, FF_BATTERY_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->technology},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->capacity},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->status}
});
}
}
void ffPrintBattery(FFinstance* instance)
{
FFstrbuf baseDir;
ffStrbufInitA(&baseDir, 64);
if(instance->config.batteryDir.length > 0)
{
ffStrbufAppend(&baseDir, &instance->config.batteryDir);
ffStrbufEndsWithC(&baseDir, '/');
}
else
{
ffStrbufAppendS(&baseDir, "/sys/class/power_supply/");
}
uint32_t baseDirLength = baseDir.length;
DIR* dirp = opendir(baseDir.chars);
if(dirp == NULL)
{
ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &instance->config.battery, "opendir(\"%s\") == NULL", baseDir.chars);
ffStrbufDestroy(&baseDir);
return;
}
FFlist results;
ffListInitA(&results, sizeof(BatteryResult), 4);
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
ffStrbufAppendS(&baseDir, entry->d_name);
parseBattery(&baseDir, &results);
ffStrbufSubstrBefore(&baseDir, baseDirLength);
}
closedir(dirp);
for(uint8_t i = 0; i < (uint8_t) results.length; i++)
{
BatteryResult* result = ffListGet(&results, i);
printBattery(instance, result, i);
ffStrbufDestroy(&result->manufacturer);
ffStrbufDestroy(&result->modelName);
ffStrbufDestroy(&result->technology);
ffStrbufDestroy(&result->capacity);
ffStrbufDestroy(&result->status);
}
if(results.length == 0)
ffPrintError(instance, FF_BATTERY_MODULE_NAME, 0, &instance->config.battery, "%s doesn't contain any battery folder", baseDir.chars);
ffListDestroy(&results);
ffStrbufDestroy(&baseDir);
}
+8
View File
@@ -0,0 +1,8 @@
#include "fastfetch.h"
#include "common/printing.h"
void ffPrintBreak(FFinstance* instance)
{
ffLogoPrintLine(instance);
putchar('\n');
}
+35
View File
@@ -0,0 +1,35 @@
#include "fastfetch.h"
#include "common/printing.h"
void ffPrintColors(FFinstance* instance)
{
if(instance->config.pipe)
{
ffLogoPrintLine(instance);
puts("████████████████████████");
ffLogoPrintLine(instance);
puts("████████████████████████");
return;
}
ffLogoPrintLine(instance);
// 4%d: Set the background color
// 3%d: Set the foreground color
for(uint8_t i = 0; i < 8; i++)
printf("\033[4%d;3%dm███", i, i);
puts(FASTFETCH_TEXT_MODIFIER_RESET);
ffLogoPrintLine(instance);
// 1: Set everything to bolt. This causes normal colors on some systems to be bright.
// 4%d: Set the backgound to the not bright color
// 3%d: Set the foreground to the not bright color
// 10%d: Set the background to the bright color
// 9%d: Set the foreground to the bright color
for(uint8_t i = 0; i < 8; i++)
printf("\033[1;4%d;3%d;10%d;9%dm███", i, i, i, i);
puts(FASTFETCH_TEXT_MODIFIER_RESET);
}
+213
View File
@@ -0,0 +1,213 @@
#include "fastfetch.h"
#include "common/io.h"
#include "common/properties.h"
#include "common/printing.h"
#include "common/caching.h"
#include "detection/temps.h"
#include <stdlib.h>
#define FF_CPU_MODULE_NAME "CPU"
#define FF_CPU_NUM_FORMAT_ARGS 15
static double getGhz(const char* policyFile, const char* cpuFile)
{
FFstrbuf content;
ffStrbufInit(&content);
ffReadFileBuffer(policyFile, &content);
if(content.length == 0)
ffReadFileBuffer(cpuFile, &content);
double herz = ffStrbufToDouble(&content);
ffStrbufDestroy(&content);
//ffStrbufToDouble failed
if(herz != herz)
return 0;
herz /= 1000.0; //to MHz
return herz / 1000.0; //to GHz
}
static double detectCPUTemp(const FFinstance* instance)
{
const FFTempsResult *temps = ffDetectTemps(instance);
for(uint32_t i = 0; i < temps->values.length; i++)
{
FFTempValue* value = ffListGet(&temps->values, i);
if(
ffStrbufFirstIndexS(&value->name, "cpu") < value->name.length ||
ffStrbufCompS(&value->name, "k10temp") == 0 ||
ffStrbufCompS(&value->name, "coretemp") == 0
) return value->value;
}
return 0.0 / 0.0; //NaN
}
void ffPrintCPU(FFinstance* instance)
{
if(ffPrintFromCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpu, FF_CPU_NUM_FORMAT_ARGS))
return;
FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
if(cpuinfo == NULL)
{
ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpu, "fopen(\"""/proc/cpuinfo\", \"r\") == NULL");
return;
}
FFstrbuf name;
ffStrbufInitA(&name, 64);
FFstrbuf vendor;
ffStrbufInitA(&vendor, 64);
FFstrbuf physicalCoresString;
ffStrbufInit(&physicalCoresString);
FFstrbuf procGhzString;
ffStrbufInit(&procGhzString);
char* line = NULL;
size_t len = 0;
while(getline(&line, &len, cpuinfo) != -1)
{
//Stop after the first CPU
if(name.length > 0 && (*line == '\0' || *line == '\n'))
break;
(void)(
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
);
}
if(line != NULL)
free(line);
fclose(cpuinfo);
double procGhz = ffStrbufToDouble(&procGhzString);
if(procGhz != procGhz)
procGhz = 0; //NaN
else
procGhz /= 1000.0; //To GHz
ffStrbufDestroy(&procGhzString);
double biosLimit = getGhz("/sys/devices/system/cpu/cpufreq/policy0/bios_limit", "/sys/devices/system/cpu/cpu0/cpufreq/bios_limit");
double scalingMaxFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq");
double scalingMinFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/scaling_min_freq", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq");
double infoMaxFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_max_freq", "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
double infoMinFreq = getGhz("/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_min_freq", "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq");
int numProcsOnline = get_nprocs();
int numProcsAvailable = get_nprocs_conf();
int physicalCores = 1;
sscanf(physicalCoresString.chars, "%i", &physicalCores);
ffStrbufDestroy(&physicalCoresString);
//The current get_nprocs* returns 1 on failure. It also makes no sense to have a (1) as count
int numProcs = numProcsOnline;
if(numProcs <= 1)
numProcs = numProcsAvailable;
if(numProcs <= 1)
numProcs = physicalCores;
double ghz = biosLimit;
if(ghz == 0)
ghz = scalingMaxFreq;
if(ghz == 0)
ghz = infoMaxFreq;
if(ghz == 0)
ghz = procGhz;
if(ghz == 0)
ghz = scalingMinFreq;
if(ghz == 0)
ghz = infoMinFreq;
if(
name.length == 0 &&
vendor.length == 0 &&
numProcs <= 1 &&
ghz <= 0
) {
ffStrbufDestroy(&name);
ffStrbufDestroy(&vendor);
ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpu, "No CPU info found in /proc/cpuinfo");
return;
}
FFstrbuf namePretty;
ffStrbufInitA(&namePretty, 64);
ffStrbufAppend(&namePretty, &name);
const char* removeStrings[] = {
"(R)", "(r)", "(TM)", "(tm)",
" CPU", " FPU", " APU", " Processor",
" Dual-Core", " Quad-Core", " Six-Core", " Eight-Core", " Ten-Core",
" 2-Core", " 4-Core", " 6-Core", " 8-Core", " 10-Core", " 12-Core", " 14-Core", " 16-Core"
};
ffStrbufRemoveStringsA(&namePretty, sizeof(removeStrings) / sizeof(removeStrings[0]), removeStrings);
ffStrbufSubstrBeforeFirstC(&namePretty, '@'); //Cut the speed output in the name as we append our own
ffStrbufTrimRight(&namePretty, ' '); //If we removed the @ in previous step there was most likely a space before it
double cpuTemp;
if(instance->config.cpu.outputFormat.length > 0)
cpuTemp = detectCPUTemp(instance);
FFstrbuf cpu;
ffStrbufInitA(&cpu, 128);
if(namePretty.length > 0)
ffStrbufAppend(&cpu, &namePretty);
else if(name.length > 0)
ffStrbufAppend(&cpu, &name);
else if(vendor.length > 0)
{
ffStrbufAppend(&cpu, &vendor);
ffStrbufAppendS(&cpu, " CPU");
}
else
ffStrbufAppendS(&cpu, "CPU");
if(numProcs > 1)
ffStrbufAppendF(&cpu, " (%i)", numProcs);
if(ghz > 0)
ffStrbufAppendF(&cpu, " @ %.9gGHz", ghz);
ffPrintAndWriteToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpu, &cpu, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &name},
{FF_FORMAT_ARG_TYPE_STRBUF, &namePretty},
{FF_FORMAT_ARG_TYPE_STRBUF, &vendor},
{FF_FORMAT_ARG_TYPE_INT, &numProcsOnline},
{FF_FORMAT_ARG_TYPE_INT, &numProcsAvailable},
{FF_FORMAT_ARG_TYPE_INT, &physicalCores},
{FF_FORMAT_ARG_TYPE_INT, &numProcs},
{FF_FORMAT_ARG_TYPE_DOUBLE, &cpuTemp},
{FF_FORMAT_ARG_TYPE_DOUBLE, &biosLimit},
{FF_FORMAT_ARG_TYPE_DOUBLE, &scalingMaxFreq},
{FF_FORMAT_ARG_TYPE_DOUBLE, &scalingMinFreq},
{FF_FORMAT_ARG_TYPE_DOUBLE, &infoMaxFreq},
{FF_FORMAT_ARG_TYPE_DOUBLE, &infoMinFreq},
{FF_FORMAT_ARG_TYPE_DOUBLE, &procGhz},
{FF_FORMAT_ARG_TYPE_DOUBLE, &ghz}
});
ffStrbufDestroy(&cpu);
ffStrbufDestroy(&namePretty);
ffStrbufDestroy(&name);
ffStrbufDestroy(&vendor);
}

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