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}