Global: adds general cache layer

This commit is contained in:
李通洲
2026-09-21 22:46:40 +08:00
parent 2f74d6be4d
commit 7f3209181e
14 changed files with 728 additions and 207 deletions
+42 -14
View File
@@ -1,4 +1,5 @@
#include "displayserver.h"
#include "common/FFcache.h"
FFDisplayResult* ffdsAppendDisplay(
FFDisplayServerResult* result,
@@ -50,18 +51,45 @@ FFDisplayResult* ffdsAppendDisplay(
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds);
const FFDisplayServerResult* ffConnectDisplayServer() {
static FFDisplayServerResult result;
static bool initialized = false;
if (!initialized) {
initialized = true;
ffStrbufInit(&result.wmProcessName);
ffStrbufInit(&result.wmPrettyName);
ffStrbufInit(&result.wmProtocolName);
ffStrbufInit(&result.deProcessName);
ffStrbufInit(&result.dePrettyName);
ffListInit(&result.displays);
ffConnectDisplayServerImpl(&result);
}
return &result;
static FFDisplayServerResult result;
static void initDisplayServerResult(void* storage) {
FFDisplayServerResult* ds = storage;
ffStrbufInit(&ds->wmProcessName);
ffStrbufInit(&ds->wmPrettyName);
ffStrbufInit(&ds->wmProtocolName);
ffStrbufInit(&ds->deProcessName);
ffStrbufInit(&ds->dePrettyName);
ffListInit(&ds->displays);
ffConnectDisplayServerImpl(ds);
}
static void destroyDisplayServerResult(void* storage) {
FFDisplayServerResult* ds = storage;
ffStrbufDestroy(&ds->wmProcessName);
ffStrbufDestroy(&ds->wmPrettyName);
ffStrbufDestroy(&ds->wmProtocolName);
ffStrbufDestroy(&ds->deProcessName);
ffStrbufDestroy(&ds->dePrettyName);
// Every display owns its name and serial, which are lost if the list is dropped as a whole
FF_LIST_FOR_EACH (FFDisplayResult, display, ds->displays) {
ffStrbufDestroy(&display->name);
ffStrbufDestroy(&display->serial);
}
ffListDestroy(&ds->displays);
}
static FFcacheEntry ffCacheEntryDisplayServer = {
.name = "displayServer",
.storage = &result,
.init = initDisplayServerResult,
.destroy = destroyDisplayServerResult,
};
const FFDisplayServerResult* ffConnectDisplayServer() {
return ffCacheGet(&ffCacheEntryDisplayServer);
}
+117 -47
View File
@@ -1,7 +1,7 @@
#include "fastfetch.h"
#include "common/properties.h"
#include "common/thread.h"
#include "common/settings.h"
#include "common/FFcache.h"
#include "detection/gtk_qt/gtk_qt.h"
#include "detection/displayserver/displayserver.h"
@@ -11,29 +11,42 @@ static inline bool allPropertiesSet(FFGTKResult* result) {
result->font.length > 0;
}
static inline void applyGTKSettings(FFGTKResult* result, const char* themeName, const char* iconsName, const char* fontName, const char* cursorTheme, int cursorSize, const char* wallpaper) {
// The values read from the desktop settings daemons, shared by the GTK2/3/4 results. They are
// owned copies on purpose: `settings.c` hands out strings it leaks deliberately (see the
// "Leaks value.chars" notes there), so borrowing them past a `--dynamic-interval` round would
// leak one set per round. Copying them also lets `destroy` release them.
typedef struct FFGTKSettings {
FFstrbuf theme;
FFstrbuf icons;
FFstrbuf font;
FFstrbuf cursor;
FFstrbuf wallpaper;
int32_t cursorSize;
} FFGTKSettings;
static inline void applyGTKSettings(FFGTKResult* result, const FFGTKSettings* settings) {
if (result->theme.length == 0) {
ffStrbufAppendS(&result->theme, themeName);
ffStrbufAppend(&result->theme, &settings->theme);
}
if (result->icons.length == 0) {
ffStrbufAppendS(&result->icons, iconsName);
ffStrbufAppend(&result->icons, &settings->icons);
}
if (result->font.length == 0) {
ffStrbufAppendS(&result->font, fontName);
ffStrbufAppend(&result->font, &settings->font);
}
if (result->cursor.length == 0) {
ffStrbufAppendS(&result->cursor, cursorTheme);
ffStrbufAppend(&result->cursor, &settings->cursor);
}
if (result->cursorSize.length == 0 && cursorSize > 0) {
ffStrbufAppendF(&result->cursorSize, "%i", cursorSize);
if (result->cursorSize.length == 0 && settings->cursorSize > 0) {
ffStrbufAppendSInt(&result->cursorSize, settings->cursorSize);
}
if (result->wallpaper.length == 0) {
ffStrbufAppendS(&result->wallpaper, wallpaper);
ffStrbufAppend(&result->wallpaper, &settings->wallpaper);
}
}
@@ -43,22 +56,23 @@ static bool testXfconfWallpaperPropKey([[maybe_unused]] void* data, const char*
return count == 0;
}
static void detectGTKFromSettings(FFGTKResult* result) {
static const char* themeName = nullptr;
static const char* iconsName = nullptr;
static const char* fontName = nullptr;
static const char* cursorTheme = nullptr;
static int cursorSize = 0;
static const char* wallpaper = nullptr;
static FFGTKSettings gtkSettings;
static bool init = false;
static void initGTKSettings(void* storage) {
FFGTKSettings* settings = storage;
if (init) {
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper);
return;
}
ffStrbufInit(&settings->theme);
ffStrbufInit(&settings->icons);
ffStrbufInit(&settings->font);
ffStrbufInit(&settings->cursor);
ffStrbufInit(&settings->wallpaper);
init = true;
const char* themeName = nullptr;
const char* iconsName = nullptr;
const char* fontName = nullptr;
const char* cursorTheme = nullptr;
int cursorSize = 0;
const char* wallpaper = nullptr;
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
@@ -98,14 +112,14 @@ static void detectGTKFromSettings(FFGTKResult* result) {
wallpaper = ffSettingsGetGnome("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", nullptr, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
} else if (
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_ENLIGHTENMENT)) {
ffEnlightenmentSettings settings = {};
if (ffSettingsGetEnlightenmentProperty(&settings)) {
themeName = settings.theme;
iconsName = settings.icon_theme;
fontName = settings.font;
cursorTheme = settings.use_e_cursor ? "Enlightenment" : "Application";
cursorSize = settings.cursor_size;
wallpaper = settings.desktop_default_background;
ffEnlightenmentSettings enlightenmentSettings = {};
if (ffSettingsGetEnlightenmentProperty(&enlightenmentSettings)) {
themeName = enlightenmentSettings.theme;
iconsName = enlightenmentSettings.icon_theme;
fontName = enlightenmentSettings.font;
cursorTheme = enlightenmentSettings.use_e_cursor ? "Enlightenment" : "Application";
cursorSize = enlightenmentSettings.cursor_size;
wallpaper = enlightenmentSettings.desktop_default_background;
}
}
} else {
@@ -121,9 +135,34 @@ static void detectGTKFromSettings(FFGTKResult* result) {
cursorSize = ffSettingsGetDConf("/org/gnome/desktop/interface/cursor-size", FF_VARIANT_TYPE_INT).intValue;
}
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper);
// The strings above are owned by `settings.c`, which leaks them on purpose, so copy them into
// the cache instead of borrowing them: this runs again on every `--dynamic-interval` round.
ffStrbufSetS(&settings->theme, themeName);
ffStrbufSetS(&settings->icons, iconsName);
ffStrbufSetS(&settings->font, fontName);
ffStrbufSetS(&settings->cursor, cursorTheme);
ffStrbufSetS(&settings->wallpaper, wallpaper);
settings->cursorSize = cursorSize;
}
static void destroyGTKSettings(void* storage) {
FFGTKSettings* settings = storage;
ffStrbufDestroy(&settings->theme);
ffStrbufDestroy(&settings->icons);
ffStrbufDestroy(&settings->font);
ffStrbufDestroy(&settings->cursor);
ffStrbufDestroy(&settings->wallpaper);
settings->cursorSize = 0;
}
static FFcacheEntry ffCacheEntryGTKSettings = {
.name = "gtk-settings",
.storage = &gtkSettings,
.init = initGTKSettings,
.destroy = destroyGTKSettings,
};
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 } });
}
@@ -172,7 +211,7 @@ static void detectGTKFromConfigDir(FFstrbuf* configDir, const char* version, FFG
static void detectGTK(const char* version, FFGTKResult* result) {
// Mate, Cinnamon, GNOME, Unity, Budgie use dconf to save theme config
// On other DEs, this will do nothing
detectGTKFromSettings(result);
applyGTKSettings(result, ffCacheGet(&ffCacheEntryGTKSettings));
if (allPropertiesSet(result)) {
return;
}
@@ -189,20 +228,51 @@ static void detectGTK(const char* version, FFGTKResult* result) {
}
}
#define FF_DETECT_GTK_IMPL(version) \
static FFGTKResult result; \
static bool init = false; \
if (init) \
return &result; \
init = true; \
ffStrbufInit(&result.theme); \
ffStrbufInit(&result.icons); \
ffStrbufInit(&result.font); \
ffStrbufInit(&result.cursor); \
ffStrbufInit(&result.cursorSize); \
ffStrbufInit(&result.wallpaper); \
detectGTK(#version, &result); \
return &result;
static void initGTKResult(const char* version, FFGTKResult* result) {
ffStrbufInit(&result->theme);
ffStrbufInit(&result->icons);
ffStrbufInit(&result->font);
ffStrbufInit(&result->cursor);
ffStrbufInit(&result->cursorSize);
ffStrbufInit(&result->wallpaper);
detectGTK(version, result);
}
static void destroyGTKResult(void* storage) {
FFGTKResult* result = storage;
ffStrbufDestroy(&result->theme);
ffStrbufDestroy(&result->icons);
ffStrbufDestroy(&result->font);
ffStrbufDestroy(&result->cursor);
ffStrbufDestroy(&result->cursorSize);
ffStrbufDestroy(&result->wallpaper);
}
static void initGTK2Result(void* storage) {
initGTKResult("2", storage);
}
static void initGTK3Result(void* storage) {
initGTKResult("3", storage);
}
static void initGTK4Result(void* storage) {
initGTKResult("4", storage);
}
// Each version gets its own result and its own entry, so a refresh drops all three (each one is
// then rebuilt on demand, in the same lazy order as a single-shot run). They share the single
// `gtk-settings` entry above, which keeps a round at one settings query instead of three.
#define FF_DETECT_GTK_IMPL(version) \
static FFGTKResult result; \
static FFcacheEntry entry = { \
.name = "gtk" #version, \
.storage = &result, \
.init = initGTK##version##Result, \
.destroy = destroyGTKResult, \
}; \
return ffCacheGet(&entry);
const FFGTKResult* ffDetectGTK2(void) {
FF_DETECT_GTK_IMPL(2)
@@ -216,4 +286,4 @@ const FFGTKResult* ffDetectGTK4(void) {
FF_DETECT_GTK_IMPL(4)
}
#undef FF_CALCULATE_GTK_IMPL
#undef FF_DETECT_GTK_IMPL
+36 -21
View File
@@ -1,7 +1,7 @@
#include "fastfetch.h"
#include "common/properties.h"
#include "common/thread.h"
#include "common/strutil.h"
#include "common/FFcache.h"
#include "detection/gtk_qt/gtk_qt.h"
#include "detection/displayserver/displayserver.h"
@@ -172,38 +172,53 @@ static void detectKvantum(FFQtResult* result) {
});
}
const FFQtResult* ffDetectQt(void) {
static FFQtResult result;
static FFQtResult result;
static bool init = false;
if (init) {
return &result;
}
init = true;
static void initQtResult(void* storage) {
FFQtResult* qt = storage;
ffStrbufInit(&result.widgetStyle);
ffStrbufInit(&result.colorScheme);
ffStrbufInit(&result.icons);
ffStrbufInit(&result.font);
ffStrbufInit(&result.wallpaper);
ffStrbufInit(&qt->widgetStyle);
ffStrbufInit(&qt->colorScheme);
ffStrbufInit(&qt->icons);
ffStrbufInit(&qt->font);
ffStrbufInit(&qt->wallpaper);
const FFDisplayServerResult* wmde = ffConnectDisplayServer();
if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA)) {
detectPlasma(&result);
detectPlasma(qt);
} else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT)) {
detectLXQt(&result);
detectLXQt(qt);
} else {
const char* qPlatformTheme = getenv("QT_QPA_PLATFORMTHEME");
if (qPlatformTheme && (ffStrEquals(qPlatformTheme, "qt5ct") || ffStrEquals(qPlatformTheme, "qt6ct"))) {
detectQtCt(qPlatformTheme[2], &result);
detectQtCt(qPlatformTheme[2], qt);
}
}
if (ffStrbufEqualS(&result.widgetStyle, "kvantum") || ffStrbufEqualS(&result.widgetStyle, "kvantum-dark")) {
ffStrbufClear(&result.widgetStyle);
detectKvantum(&result);
if (ffStrbufEqualS(&qt->widgetStyle, "kvantum") || ffStrbufEqualS(&qt->widgetStyle, "kvantum-dark")) {
ffStrbufClear(&qt->widgetStyle);
detectKvantum(qt);
}
return &result;
}
static void destroyQtResult(void* storage) {
FFQtResult* qt = storage;
ffStrbufDestroy(&qt->widgetStyle);
ffStrbufDestroy(&qt->colorScheme);
ffStrbufDestroy(&qt->icons);
ffStrbufDestroy(&qt->font);
ffStrbufDestroy(&qt->wallpaper);
}
static FFcacheEntry ffCacheEntryQt = {
.name = "qt",
.storage = &result,
.init = initQtResult,
.destroy = destroyQtResult,
};
const FFQtResult* ffDetectQt(void) {
return ffCacheGet(&ffCacheEntryQt);
}
+43 -5
View File
@@ -1,19 +1,53 @@
#include "media.h"
#include "common/FFcache.h"
#include "common/io.h"
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover);
static FFMediaResult result;
// The cover file of this run, if there is one. It is tracked here rather than in `result` because
// the cached result is dropped between `--dynamic-interval` rounds, while the file has to stay on
// disk for the whole run: the `kitty-direct` logo type lets the terminal open it by path, and the
// logo is replayed from the line cache on every round.
static FFstrbuf coverFile;
static bool coverFileRegistered = false;
static void removeMediaCoverFile(void) {
if (result.cover.length > 0) {
ffRemoveFile(result.cover.chars);
ffStrbufDestroy(&result.cover);
if (coverFile.length > 0) {
ffRemoveFile(coverFile.chars);
ffStrbufDestroy(&coverFile);
}
}
static void destroyMediaResult(void* storage) {
FFMediaResult* media = storage;
ffStrbufDestroy(&media->error);
ffStrbufDestroy(&media->playerId);
ffStrbufDestroy(&media->player);
ffStrbufDestroy(&media->song);
ffStrbufDestroy(&media->artist);
ffStrbufDestroy(&media->album);
ffStrbufDestroy(&media->url);
ffStrbufDestroy(&media->status);
ffStrbufDestroy(&media->cover);
media->length = 0;
media->position = 0;
media->removeCoverAfterUse = false;
}
// `saveCover` asks for a side effect and is not part of the cache identity, so the entry cannot be
// initialized through `init(void*)`: the first caller of a generation decides, and the callers that
// follow reuse its result, as they did when the result was cached for the whole run.
static FFcacheEntry ffCacheEntryMedia = {
.name = "media",
.storage = &result,
.destroy = destroyMediaResult,
};
const FFMediaResult* ffDetectMedia(bool saveCover) {
if (result.error.chars == nullptr) {
if (ffCacheBeginInit(&ffCacheEntryMedia)) {
ffStrbufInit(&result.error);
ffStrbufInit(&result.playerId);
ffStrbufInit(&result.player);
@@ -37,7 +71,11 @@ const FFMediaResult* ffDetectMedia(bool saveCover) {
ffStrbufTrimRightSpace(&result.player);
if (saveCover && result.removeCoverAfterUse) {
atexit(removeMediaCoverFile);
ffStrbufSet(&coverFile, &result.cover);
if (!coverFileRegistered) {
coverFileRegistered = true;
atexit(removeMediaCoverFile);
}
}
}
+43 -16
View File
@@ -1,21 +1,48 @@
#include "os.h"
#include "common/FFcache.h"
void ffDetectOSImpl(FFOSResult* os);
const FFOSResult* ffDetectOS(void) {
static FFOSResult result;
if (result.name.chars == nullptr) {
ffStrbufInit(&result.name);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.id);
ffStrbufInit(&result.version);
ffStrbufInit(&result.versionID);
ffStrbufInit(&result.codename);
ffStrbufInit(&result.buildID);
ffStrbufInit(&result.idLike);
ffStrbufInit(&result.variant);
ffStrbufInit(&result.variantID);
ffDetectOSImpl(&result);
}
return &result;
static FFOSResult result;
static void initOSResult(void* storage) {
FFOSResult* os = storage;
ffStrbufInit(&os->name);
ffStrbufInit(&os->prettyName);
ffStrbufInit(&os->id);
ffStrbufInit(&os->version);
ffStrbufInit(&os->versionID);
ffStrbufInit(&os->codename);
ffStrbufInit(&os->buildID);
ffStrbufInit(&os->idLike);
ffStrbufInit(&os->variant);
ffStrbufInit(&os->variantID);
ffDetectOSImpl(os);
}
static void destroyOSResult(void* storage) {
FFOSResult* os = storage;
ffStrbufDestroy(&os->name);
ffStrbufDestroy(&os->prettyName);
ffStrbufDestroy(&os->id);
ffStrbufDestroy(&os->version);
ffStrbufDestroy(&os->versionID);
ffStrbufDestroy(&os->codename);
ffStrbufDestroy(&os->buildID);
ffStrbufDestroy(&os->idLike);
ffStrbufDestroy(&os->variant);
ffStrbufDestroy(&os->variantID);
}
static FFcacheEntry ffCacheEntryOS = {
.name = "os",
.storage = &result,
.init = initOSResult,
.destroy = destroyOSResult,
};
const FFOSResult* ffDetectOS(void) {
return ffCacheGet(&ffCacheEntryOS);
}
@@ -1,4 +1,5 @@
#include "terminalshell.h"
#include "common/FFcache.h"
#include "common/io.h"
#include "common/parsing.h"
#include "common/processing.h"
@@ -376,22 +377,43 @@ static void setTerminalInfoDetails(FFTerminalResult* result) {
#define FF_EXE_PATH_LEN 260
#endif
const FFShellResult* ffDetectShell() {
static FFShellResult result;
static bool init = false;
if (init) {
return &result;
}
init = true;
static FFShellResult shellResult;
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN);
result.exeName = result.exe.chars;
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.version);
result.pid = 0;
result.ppid = 0;
result.tty = -1;
static void destroyShellResult(void* storage) {
FFShellResult* result = storage;
ffStrbufDestroy(&result->processName);
ffStrbufDestroy(&result->exe);
result->exeName = result->exe.chars; // `exeName` points into `exe`, which is empty again
ffStrbufDestroy(&result->exePath);
ffStrbufDestroy(&result->prettyName);
ffStrbufDestroy(&result->version);
result->pid = 0;
result->ppid = 0;
result->tty = -1;
}
static FFcacheEntry ffCacheEntryShell = {
.name = "shell",
.storage = &shellResult,
.destroy = destroyShellResult,
};
const FFShellResult* ffDetectShell() {
FFShellResult* result = &shellResult;
if (!ffCacheBeginInit(&ffCacheEntryShell)) {
return result;
}
ffStrbufInit(&result->processName);
ffStrbufInitA(&result->exe, FF_EXE_PATH_LEN);
result->exeName = result->exe.chars;
ffStrbufInit(&result->exePath);
ffStrbufInit(&result->version);
result->pid = 0;
result->ppid = 0;
result->tty = -1;
pid_t ppid = getppid();
@@ -401,49 +423,70 @@ const FFShellResult* ffDetectShell() {
ffProcessGetBasicInfoLinux(ppid, &_, &ppid, nullptr);
}
ppid = getShellInfo(&result, ppid);
getUserShellFromEnv(&result);
ppid = getShellInfo(result, ppid);
getUserShellFromEnv(result);
if (result.processName.length > 0) {
setShellInfoDetails(&result);
if (result->processName.length > 0) {
setShellInfoDetails(result);
if (instance.config.general.detectVersion) {
fftsGetShellVersion(result.exePath.length > 0 ? &result.exePath : &result.exe, result.exeName, &result.version);
fftsGetShellVersion(result->exePath.length > 0 ? &result->exePath : &result->exe, result->exeName, &result->version);
}
}
return &result;
return result;
}
const FFTerminalResult* ffDetectTerminal() {
static FFTerminalResult result;
static bool init = false;
if (init) {
return &result;
}
init = true;
static FFTerminalResult terminalResult;
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN);
result.exeName = result.exe.chars;
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.version);
ffStrbufInitS(&result.tty, ttyname(STDOUT_FILENO));
result.pid = 0;
result.ppid = 0;
static void destroyTerminalResult(void* storage) {
FFTerminalResult* result = storage;
ffStrbufDestroy(&result->processName);
ffStrbufDestroy(&result->exe);
result->exeName = result->exe.chars; // `exeName` points into `exe`, which is empty again
ffStrbufDestroy(&result->exePath);
ffStrbufDestroy(&result->prettyName);
ffStrbufDestroy(&result->version);
ffStrbufDestroy(&result->tty);
result->pid = 0;
result->ppid = 0;
}
static FFcacheEntry ffCacheEntryTerminal = {
.name = "terminal",
.storage = &terminalResult,
.destroy = destroyTerminalResult,
};
const FFTerminalResult* ffDetectTerminal() {
FFTerminalResult* result = &terminalResult;
if (!ffCacheBeginInit(&ffCacheEntryTerminal)) {
return result;
}
ffStrbufInit(&result->processName);
ffStrbufInitA(&result->exe, FF_EXE_PATH_LEN);
result->exeName = result->exe.chars;
ffStrbufInit(&result->exePath);
ffStrbufInit(&result->version);
ffStrbufInitS(&result->tty, ttyname(STDOUT_FILENO));
result->pid = 0;
result->ppid = 0;
pid_t ppid = (pid_t) ffDetectShell()->ppid;
if (ppid) {
ppid = getTerminalInfo(&result, ppid);
ppid = getTerminalInfo(result, ppid);
}
getTerminalFromEnv(&result);
getTerminalFromEnv(result);
if (result.processName.length > 0) {
setTerminalInfoDetails(&result);
if (result->processName.length > 0) {
setTerminalInfoDetails(result);
if (instance.config.general.detectVersion) {
fftsGetTerminalVersion(&result.processName, result.exePath.length > 0 ? &result.exePath : &result.exe, &result.version);
fftsGetTerminalVersion(&result->processName, result->exePath.length > 0 ? &result->exePath : &result->exe, &result->version);
}
}
return &result;
return result;
}
@@ -1,4 +1,5 @@
#include "terminalshell.h"
#include "common/FFcache.h"
#include "common/io.h"
#include "common/processing.h"
#include "common/thread.h"
@@ -293,27 +294,48 @@ static void setTerminalInfoDetails(FFTerminalResult* result) {
}
}
const FFShellResult* ffDetectShell(void) {
static FFShellResult result;
static bool init = false;
if (init) {
return &result;
}
init = true;
static FFShellResult shellResult;
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, MAX_PATH);
result.exeName = "";
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.version);
result.pid = 0;
result.ppid = 0;
result.tty = -1;
static void destroyShellResult(void* storage) {
FFShellResult* result = storage;
ffStrbufDestroy(&result->processName);
ffStrbufDestroy(&result->exe);
result->exeName = ""; // The `exe` buffer is empty again, so nothing points into it
ffStrbufDestroy(&result->exePath);
ffStrbufDestroy(&result->prettyName);
ffStrbufDestroy(&result->version);
result->pid = 0;
result->ppid = 0;
result->tty = -1;
}
static FFcacheEntry ffCacheEntryShell = {
.name = "shell",
.storage = &shellResult,
.destroy = destroyShellResult,
};
const FFShellResult* ffDetectShell(void) {
FFShellResult* result = &shellResult;
if (!ffCacheBeginInit(&ffCacheEntryShell)) {
return result;
}
ffStrbufInit(&result->processName);
ffStrbufInitA(&result->exe, MAX_PATH);
result->exeName = "";
ffStrbufInit(&result->exePath);
ffStrbufInit(&result->prettyName);
ffStrbufInit(&result->version);
result->pid = 0;
result->ppid = 0;
result->tty = -1;
uint32_t ppid;
if (!ffProcessGetInfoWindows(0, &ppid, nullptr, nullptr, nullptr, nullptr, nullptr)) {
return &result;
return result;
}
const char* ignoreParent = getenv("FFTS_IGNORE_PARENT");
@@ -321,60 +343,81 @@ const FFShellResult* ffDetectShell(void) {
ffProcessGetInfoWindows(ppid, &ppid, nullptr, nullptr, nullptr, nullptr, nullptr);
}
ppid = getShellInfo(&result, ppid);
ppid = getShellInfo(result, ppid);
if (result.processName.length > 0) {
setShellInfoDetails(&result);
if (result->processName.length > 0) {
setShellInfoDetails(result);
char tmp[MAX_PATH];
strcpy(tmp, result.exeName);
strcpy(tmp, result->exeName);
char* ext = strrchr(tmp, '.');
if (ext) {
*ext = '\0';
}
if (instance.config.general.detectVersion) {
fftsGetShellVersion(result.exePath.length > 0 ? &result.exePath : &result.exe, tmp, &result.version);
fftsGetShellVersion(result->exePath.length > 0 ? &result->exePath : &result->exe, tmp, &result->version);
}
}
return &result;
return result;
}
const FFTerminalResult* ffDetectTerminal(void) {
static FFTerminalResult result;
static bool init = false;
if (init) {
return &result;
}
init = true;
static FFTerminalResult terminalResult;
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, MAX_PATH);
result.exeName = "";
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.version);
ffStrbufInit(&result.tty);
result.pid = 0;
result.ppid = 0;
static void destroyTerminalResult(void* storage) {
FFTerminalResult* result = storage;
ffStrbufDestroy(&result->processName);
ffStrbufDestroy(&result->exe);
result->exeName = ""; // The `exe` buffer is empty again, so nothing points into it
ffStrbufDestroy(&result->exePath);
ffStrbufDestroy(&result->prettyName);
ffStrbufDestroy(&result->version);
ffStrbufDestroy(&result->tty);
result->pid = 0;
result->ppid = 0;
}
static FFcacheEntry ffCacheEntryTerminal = {
.name = "terminal",
.storage = &terminalResult,
.destroy = destroyTerminalResult,
};
const FFTerminalResult* ffDetectTerminal(void) {
FFTerminalResult* result = &terminalResult;
if (!ffCacheBeginInit(&ffCacheEntryTerminal)) {
return result;
}
ffStrbufInit(&result->processName);
ffStrbufInitA(&result->exe, MAX_PATH);
result->exeName = "";
ffStrbufInit(&result->exePath);
ffStrbufInit(&result->prettyName);
ffStrbufInit(&result->version);
ffStrbufInit(&result->tty);
result->pid = 0;
result->ppid = 0;
uint32_t ppid = ffDetectShell()->ppid;
if (ppid) {
getTerminalInfo(&result, ppid);
getTerminalInfo(result, ppid);
}
if (result.processName.length == 0) {
getTerminalFromEnv(&result);
if (result->processName.length == 0) {
getTerminalFromEnv(result);
}
if (result.processName.length == 0) {
detectDefaultTerminal(&result);
if (result->processName.length == 0) {
detectDefaultTerminal(result);
}
if (result.processName.length > 0) {
setTerminalInfoDetails(&result);
if (result->processName.length > 0) {
setTerminalInfoDetails(result);
if (instance.config.general.detectVersion) {
fftsGetTerminalVersion(&result.processName, result.exePath.length > 0 ? &result.exePath : &result.exe, &result.version);
fftsGetTerminalVersion(&result->processName, result->exePath.length > 0 ? &result->exePath : &result->exe, &result->version);
}
}
return &result;
return result;
}