master ohmu/fastfetch-openbsd / src / common / impl / init.c
ohmu  ·  2026-10-15
  1#include "fastfetch.h"
  2#include "common/init.h"
  3#include "common/parsing.h"
  4#include "common/thread.h"
  5#include "common/textModifier.h"
  6#include "common/strutil.h"
  7#include "detection/displayserver/displayserver.h"
  8#include "logo/logo.h"
  9
 10#include <stdlib.h>
 11#include <unistd.h>
 12#include <locale.h>
 13#ifdef _WIN32
 14    #include <windows.h>
 15    #include "common/windows/unicode.h"
 16#else
 17    #include <signal.h>
 18#endif
 19#if __linux__
 20    #include <linux/version.h>
 21#endif
 22
 23FFinstance instance; // Global singleton
 24
 25static void initState(FFstate* state) {
 26    state->logoWidth = 0;
 27    state->logoHeight = 0;
 28    state->keysHeight = 0;
 29    state->titleFqdn = false;
 30
 31    ffPlatformInit(&state->platform);
 32    state->dynamicInterval = 0;
 33}
 34
 35static void defaultConfig(void) {
 36    ffOptionsInitLogo(&instance.config.logo);
 37    ffOptionsInitGeneral(&instance.config.general);
 38    ffOptionsInitDisplay(&instance.config.display);
 39}
 40
 41#ifdef _WIN32
 42static UINT oldCp = CP_UTF8;
 43void resetConsoleCP(void) {
 44    if (oldCp != CP_UTF8) {
 45        SetConsoleOutputCP(oldCp);
 46    }
 47}
 48#endif
 49
 50void ffInitInstance(void) {
 51#ifdef _WIN32
 52    // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
 53    setlocale(LC_ALL, ".UTF8");
 54
 55    HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 56    DWORD mode = 0;
 57    if (GetConsoleMode(hStdout, &mode)) {
 58        SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
 59        oldCp = GetConsoleOutputCP();
 60        if (oldCp != CP_UTF8) {
 61            SetConsoleOutputCP(CP_UTF8);
 62            atexit(resetConsoleCP);
 63        }
 64    }
 65#else
 66    // Never use `setlocale(LC_ALL, "")`
 67    setlocale(LC_TIME, "");
 68#endif
 69
 70    defaultConfig();
 71    initState(&instance.state);
 72
 73#ifdef _WIN32
 74    instance.state.platform.initCP = oldCp;
 75#endif
 76}
 77
 78static volatile bool ffDisableLinewrap = false;
 79static volatile bool ffHideCursor = false;
 80
 81static void resetConsole(void) {
 82    if (ffDisableLinewrap) {
 83        fputs("\033[?7h", stdout);
 84    }
 85
 86    if (ffHideCursor) {
 87        fputs("\033[?25h", stdout);
 88    }
 89
 90    if (instance.state.dynamicInterval > 0) {
 91        fputs("\033[?1049l", stdout); // Disable alternate buffer
 92    }
 93
 94#if defined(_WIN32)
 95    fflush(stdout);
 96#endif
 97}
 98
 99#ifdef _WIN32
100BOOL WINAPI consoleHandler([[maybe_unused]] DWORD signal) {
101    resetConsole();
102    exit(0);
103}
104#else
105static void exitSignalHandler([[maybe_unused]] int signal) {
106    resetConsole();
107    exit(0);
108}
109#endif
110
111void ffStart(void) {
112    ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe;
113    ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe;
114
115#ifdef _WIN32
116    SetErrorMode(SEM_FAILCRITICALERRORS);
117    if (instance.config.display.noBuffer) {
118        setvbuf(stdout, nullptr, _IONBF, 0);
119    } else {
120        setvbuf(stdout, nullptr, _IOFBF, 4096);
121    }
122    SetConsoleCtrlHandler(consoleHandler, TRUE);
123#else
124    if (instance.config.display.noBuffer) {
125        setvbuf(stdout, nullptr, _IONBF, 0);
126    }
127    struct sigaction action;
128    sigemptyset(&action.sa_mask);
129    action.sa_flags = 0;
130    action.sa_handler = exitSignalHandler;
131    sigaction(SIGINT, &action, nullptr);
132    sigaction(SIGTERM, &action, nullptr);
133    sigaction(SIGQUIT, &action, nullptr);
134    sigset_t newmask;
135    sigemptyset(&newmask);
136    sigaddset(&newmask, SIGCHLD);
137    sigprocmask(SIG_BLOCK, &newmask, nullptr);
138#endif
139
140    // reset everything to default before we start printing
141    if (!instance.config.display.pipe) {
142        fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
143    }
144
145    if (ffHideCursor) {
146        fputs("\033[?25l", stdout);
147    }
148
149    if (ffDisableLinewrap) {
150        fputs("\033[?7l", stdout);
151    }
152
153    if (instance.state.dynamicInterval > 0) {
154        fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
155        fflush(stdout);
156    }
157}
158
159void ffFinish(void) {
160    resetConsole();
161}
162
163static void destroyConfig(void) {
164    ffOptionsDestroyLogo(&instance.config.logo);
165    ffOptionsDestroyGeneral(&instance.config.general);
166    ffOptionsDestroyDisplay(&instance.config.display);
167}
168
169static void destroyState(void) {
170    ffPlatformDestroy(&instance.state.platform);
171}
172
173void ffDestroyInstance(void) {
174    destroyConfig();
175    destroyState();
176}
177
178#if FF_HAVE_LUA
179    #include <lua.h>
180#endif
181
182// Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
183void ffListFeatures(void) {
184    fputs(
185#if __linux__
186        "linux-headers " FF_STR(LINUX_VERSION_MAJOR) "." FF_STR(LINUX_VERSION_PATCHLEVEL) "." FF_STR(LINUX_VERSION_SUBLEVEL) "\n"
187#endif
188#if FF_HAVE_THREADS
189        "threads\n"
190#endif
191#if FF_HAVE_VULKAN
192        "vulkan\n"
193#endif
194#if FF_HAVE_WAYLAND
195        "wayland\n"
196#endif
197#if FF_HAVE_XCB_RANDR
198        "xcb-randr\n"
199#endif
200#if FF_HAVE_XRANDR
201        "xrandr\n"
202#endif
203#if FF_HAVE_DRM
204        "drm\n"
205#endif
206#if FF_HAVE_GIO
207        "gio\n"
208#endif
209#if FF_HAVE_DCONF
210        "dconf\n"
211#endif
212#if FF_HAVE_EET
213        "eet\n"
214#endif
215#if FF_HAVE_DBUS
216        "dbus\n"
217#endif
218#if FF_HAVE_IMAGEMAGICK7
219        "imagemagick7\n"
220#endif
221#if FF_HAVE_IMAGEMAGICK6
222        "imagemagick6\n"
223#endif
224#if FF_HAVE_CHAFA
225        "chafa\n"
226#endif
227#if FF_HAVE_ZLIB
228        "zlib\n"
229#endif
230#if FF_HAVE_SQLITE3
231        "sqlite3\n"
232#endif
233#if FF_HAVE_RPM
234        "rpm\n"
235#endif
236#if FF_HAVE_EGL
237        "egl\n"
238#endif
239#if FF_HAVE_GLX
240        "glx\n"
241#endif
242#if FF_HAVE_OPENCL
243        "opencl\n"
244#endif
245#if FF_HAVE_FREETYPE
246        "freetype\n"
247#endif
248#if FF_HAVE_ELF || __sun || (__FreeBSD__ && !__DragonFly__) || __OpenBSD__ || __NetBSD__
249        "libelf\n"
250#endif
251#if FF_HAVE_LIBZFS
252        "libzfs\n"
253#endif
254#if FF_HAVE_VADRM
255        "va-drm\n"
256#endif
257#if FF_HAVE_VAX11
258        "va-x11\n"
259#endif
260#if FF_HAVE_VDPAU
261        "vdpau\n"
262#endif
263#if FF_USE_SYSTEM_YYJSON
264        "System yyjson\n"
265#endif
266#if FF_HAVE_LINUX_VIDEODEV2
267        "linux/videodev2\n"
268#endif
269#if FF_HAVE_EMBEDDED_PCIIDS
270        "Embedded pciids\n"
271#endif
272#if FF_ENABLE_WCWIDTH
273        "Embedded wcwidth\n"
274#endif
275#if FF_HAVE_SIXEL
276        "Embedded sixel\n"
277#endif
278#if FF_HAVE_WINRT
279        "WinRT headers\n"
280#endif
281#if FF_WIN81_COMPAT
282        "Windows 8.1 Compatibility\n"
283#endif
284#if FF_APPLE_MEMSIZE_USABLE
285        "Apple memsize_usable\n"
286#endif
287#if FF_HAVE_LUA
288        LUA_VERSION "\n"
289#endif
290        "",
291        stdout);
292}