#include "fastfetch.h" #include "common/init.h" #include "common/parsing.h" #include "common/thread.h" #include "detection/displayserver/displayserver.h" #include "detection/terminaltheme/terminaltheme.h" #include "util/textModifier.h" #include "logo/logo.h" #include #include #include #ifdef _WIN32 #include #include "util/windows/unicode.h" #else #include #endif FFinstance instance; // Global singleton static void initState(FFstate* state) { state->logoWidth = 0; state->logoHeight = 0; state->keysHeight = 0; state->terminalLightTheme = false; state->titleFqdn = false; ffPlatformInit(&state->platform); state->configDoc = NULL; state->resultDoc = NULL; state->dynamicInterval = 0; { // don't enable bright color if the terminal is in light mode FFTerminalThemeResult result; if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark) state->terminalLightTheme = true; } } static void defaultConfig(void) { ffOptionsInitLogo(&instance.config.logo); ffOptionsInitGeneral(&instance.config.general); ffOptionsInitDisplay(&instance.config.display); } void ffInitInstance(void) { #ifdef _WIN32 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat> setlocale(LC_ALL, ".UTF8"); #else // Never use `setlocale(LC_ALL, "")` setlocale(LC_TIME, ""); #endif initState(&instance.state); defaultConfig(); } static volatile bool ffDisableLinewrap = true; static volatile bool ffHideCursor = true; static void resetConsole(void) { if(ffDisableLinewrap) fputs("\033[?7h", stdout); if(ffHideCursor) fputs("\033[?25h", stdout); #if defined(_WIN32) fflush(stdout); #endif if(instance.state.dynamicInterval > 0) fputs("\033[?1049l", stdout); // Disable alternate buffer } #ifdef _WIN32 BOOL WINAPI consoleHandler(FF_MAYBE_UNUSED DWORD signal) { resetConsole(); exit(0); } #else static void exitSignalHandler(FF_MAYBE_UNUSED int signal) { resetConsole(); exit(0); } #endif void ffStart(void) { ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc; ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc; #ifdef _WIN32 SetErrorMode(SEM_FAILCRITICALERRORS); if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0); else setvbuf(stdout, NULL, _IOFBF, 4096); SetConsoleCtrlHandler(consoleHandler, TRUE); HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); DWORD mode = 0; GetConsoleMode(hStdout, &mode); SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); SetConsoleOutputCP(CP_UTF8); #else if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0); struct sigaction action = { .sa_handler = exitSignalHandler }; sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); sigaction(SIGQUIT, &action, NULL); sigset_t newmask; sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); sigprocmask(SIG_BLOCK, &newmask, NULL); #endif //reset everything to default before we start printing if(!instance.config.display.pipe && !instance.state.resultDoc) fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout); if(ffHideCursor) fputs("\033[?25l", stdout); if(ffDisableLinewrap) fputs("\033[?7l", stdout); if(instance.state.dynamicInterval > 0) { fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer fflush(stdout); } ffLogoPrint(); } void ffFinish(void) { resetConsole(); } static void destroyConfig(void) { ffOptionsDestroyLogo(&instance.config.logo); ffOptionsDestroyGeneral(&instance.config.general); ffOptionsDestroyDisplay(&instance.config.display); } static void destroyState(void) { ffPlatformDestroy(&instance.state.platform); yyjson_doc_free(instance.state.configDoc); yyjson_mut_doc_free(instance.state.resultDoc); ffStrbufDestroy(&instance.state.genConfigPath); } void ffDestroyInstance(void) { destroyConfig(); destroyState(); } //Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets void ffListFeatures(void) { fputs( #if FF_HAVE_THREADS "threads\n" #endif #if FF_HAVE_VULKAN "vulkan\n" #endif #if FF_HAVE_WAYLAND "wayland\n" #endif #if FF_HAVE_XCB_RANDR "xcb-randr\n" #endif #if FF_HAVE_XRANDR "xrandr\n" #endif #if FF_HAVE_DRM "drm\n" #endif #if FF_HAVE_DRM_AMDGPU "drm_amdgpu\n" #endif #if FF_HAVE_GIO "gio\n" #endif #if FF_HAVE_DCONF "dconf\n" #endif #if FF_HAVE_DBUS "dbus\n" #endif #if FF_HAVE_IMAGEMAGICK7 "imagemagick7\n" #endif #if FF_HAVE_IMAGEMAGICK6 "imagemagick6\n" #endif #if FF_HAVE_CHAFA "chafa\n" #endif #if FF_HAVE_ZLIB "zlib\n" #endif #if FF_HAVE_SQLITE3 "sqlite3\n" #endif #if FF_HAVE_RPM "rpm\n" #endif #if FF_HAVE_EGL "egl\n" #endif #if FF_HAVE_GLX "glx\n" #endif #if FF_HAVE_OPENCL "opencl\n" #endif #if FF_HAVE_FREETYPE "freetype\n" #endif #if FF_HAVE_PCIACCESS "libpciaccess\n" #endif #if FF_HAVE_PULSE "libpulse\n" #endif #if FF_HAVE_DDCUTIL "libddcutil\n" #endif #if FF_HAVE_ELF || __sun || (__FreeBSD__ && !__DragonFly__) || __OpenBSD__ || __NetBSD__ "libelf\n" #endif #if FF_HAVE_LIBZFS "libzfs\n" #endif #if FF_HAVE_DIRECTX_HEADERS "Directx Headers\n" #endif #if FF_USE_SYSTEM_YYJSON "System yyjson\n" #endif #if FF_HAVE_LINUX_VIDEODEV2 "linux/videodev2\n" #endif #if FF_HAVE_LINUX_WIRELESS "linux/wireless\n" #endif #if FF_HAVE_EMBEDDED_PCIIDS "Embedded pciids\n" #endif "" , stdout); }