#include "fastfetch.h" #include "common/init.h" #include "common/parsing.h" #include "common/thread.h" #include "common/textModifier.h" #include "detection/displayserver/displayserver.h" #include "detection/terminaltheme/terminaltheme.h" #include "logo/logo.h" #include #include #include #ifdef _WIN32 #include #include "common/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->dynamicInterval = 0; #if !FF_MODULE_DISABLE_TERMINALTHEME { // 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; } } #endif } 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 defaultConfig(); initState(&instance.state); } static volatile bool ffDisableLinewrap = false; static volatile bool ffHideCursor = false; #ifdef _WIN32 static volatile UINT oldCp = CP_UTF8; #endif static void resetConsole(void) { if (ffDisableLinewrap) { fputs("\033[?7h", stdout); } if (ffHideCursor) { fputs("\033[?25h", stdout); } if (instance.state.dynamicInterval > 0) { fputs("\033[?1049l", stdout); // Disable alternate buffer } #if defined(_WIN32) fflush(stdout); if (oldCp != CP_UTF8) { SetConsoleOutputCP(oldCp); } #endif } #ifdef _WIN32 BOOL WINAPI consoleHandler(FF_A_UNUSED DWORD signal) { resetConsole(); exit(0); } #else static void exitSignalHandler(FF_A_UNUSED int signal) { resetConsole(); exit(0); } #endif void ffStart(void) { ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe; ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe; #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; if (GetConsoleMode(hStdout, &mode)) { SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); oldCp = GetConsoleOutputCP(); if (oldCp != CP_UTF8) { SetConsoleOutputCP(CP_UTF8); } } #else if (instance.config.display.noBuffer) { setvbuf(stdout, NULL, _IONBF, 0); } struct sigaction action; sigemptyset(&action.sa_mask); action.sa_flags = 0; 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) { 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); } } 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); } void ffDestroyInstance(void) { destroyConfig(); destroyState(); } #if FF_HAVE_LUA #include #endif #if FF_HAVE_QUICKJS #include #define FF_STR_INDIR(x) #x #define FF_STR(x) FF_STR_INDIR(x) #endif // 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_EET "eet\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_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_VA "va\n" #endif #if FF_HAVE_VDPAU "vdpau\n" #endif #if FF_USE_SYSTEM_YYJSON "System yyjson\n" #endif #if FF_HAVE_LINUX_VIDEODEV2 "linux/videodev2\n" #endif #if FF_HAVE_EMBEDDED_PCIIDS "Embedded pciids\n" #endif #if FF_ENABLE_WCWIDTH "Embedded wcwidth\n" #endif #if FF_HAVE_WINRT "WinRT headers\n" #endif #if FF_WIN81_COMPAT "Windows 8.1 Compatibility\n" #endif #if FF_APPLE_MEMSIZE_USABLE "Apple memsize_usable\n" #endif #if FF_HAVE_LUA LUA_VERSION "\n" #endif #if FF_HAVE_QUICKJS "QuickJS " FF_STR(QJS_VERSION_MAJOR) "." FF_STR(QJS_VERSION_MINOR) "." FF_STR(QJS_VERSION_PATCH) QJS_VERSION_SUFFIX "\n" #endif "", stdout); }