#include "common/font.h"
#include "terminalfont.h"
#include "common/settings.h"
#include "common/properties.h"
#include "common/parsing.h"
#include "common/io.h"
#include "common/processing.h"
#include "common/mallocHelper.h"
#include "common/strutil.h"
#include "common/binary.h"
#include "detection/terminalshell/terminalshell.h"
#include "detection/displayserver/displayserver.h"

static const char* getSystemMonospaceFont(void) {
    const FFDisplayServerResult* wmde = ffConnectDisplayServer();

    if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, "Cinnamon")) {
        const char* systemMonospaceFont = ffSettingsGetGnome("/org/cinnamon/desktop/interface/monospace-font-name", "org.cinnamon.desktop.interface", nullptr, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
        if (ffStrSet(systemMonospaceFont)) {
            return systemMonospaceFont;
        }
    } else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, "Mate")) {
        const char* systemMonospaceFont = ffSettingsGetGnome("/org/mate/interface/monospace-font-name", "org.mate.interface", nullptr, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
        if (ffStrSet(systemMonospaceFont)) {
            return systemMonospaceFont;
        }
    }

    return ffSettingsGetGnome("/org/gnome/desktop/interface/monospace-font-name", "org.gnome.desktop.interface", nullptr, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue;
}

static void detectKgx(FFTerminalFontResult* terminalFont) {
    // kgx (gnome console) doesn't support profiles
    if (!ffSettingsGetGnome("/org/gnome/Console/use-system-font", "org.gnome.Console", nullptr, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) {
        FF_AUTO_FREE const char* fontName = ffSettingsGetGnome("/org/gnome/Console/custom-font", "org.gnome.Console", nullptr, "custom-font", FF_VARIANT_TYPE_STRING).strValue;
        if (ffStrSet(fontName)) {
            ffFontInitPango(&terminalFont->font, fontName);
        } else {
            ffStrbufAppendF(&terminalFont->error, "Couldn't get terminal font from GSettings (org.gnome.Console::custom-font)");
        }
    } else {
        FF_AUTO_FREE const char* fontName = getSystemMonospaceFont();
        if (ffStrSet(fontName)) {
            ffFontInitPango(&terminalFont->font, fontName);
        } else {
            ffStrbufAppendS(&terminalFont->error, "Couldn't get system monospace font name from GSettings / DConf");
        }
    }
}

static void detectPtyxis(FFTerminalFontResult* terminalFont) {
    if (!ffSettingsGetGnome("/org/gnome/Ptyxis/use-system-font", "org.gnome.Ptyxis", nullptr, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) {
        FF_AUTO_FREE const char* fontName = ffSettingsGetGnome("/org/gnome/Ptyxis/font-name", "org.gnome.Ptyxis", nullptr, "font-name", FF_VARIANT_TYPE_STRING).strValue;
        if (ffStrSet(fontName)) {
            ffFontInitPango(&terminalFont->font, fontName);
        } else {
            ffStrbufAppendF(&terminalFont->error, "Couldn't get terminal font from GSettings (org.gnome.Ptyxis::font-name)");
        }
    } else {
        FF_AUTO_FREE const char* fontName = getSystemMonospaceFont();
        if (ffStrSet(fontName)) {
            ffFontInitPango(&terminalFont->font, fontName);
        } else {
            ffStrbufAppendS(&terminalFont->error, "Couldn't get system monospace font name from GSettings / DConf");
        }
    }
}

static void detectFromGSettings(const char* profilePath, const char* profileList, const char* profile, const char* defaultProfileKey, FFTerminalFontResult* terminalFont) {
    FF_AUTO_FREE const char* defaultProfile = ffSettingsGetGSettings(profileList, nullptr, defaultProfileKey, FF_VARIANT_TYPE_STRING).strValue;
    if (!ffStrSet(defaultProfile)) {
        ffStrbufAppendF(&terminalFont->error, "Could not get default profile from gsettings: %s", profileList);
        return;
    }

    FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateA(128);
    ffStrbufAppendS(&path, profilePath);
    ffStrbufAppendS(&path, defaultProfile);
    ffStrbufAppendC(&path, '/');

    if (!ffSettingsGetGSettings(profile, path.chars, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) {
        FF_AUTO_FREE const char* fontName = ffSettingsGetGSettings(profile, path.chars, "font", FF_VARIANT_TYPE_STRING).strValue;
        if (ffStrSet(fontName)) {
            ffFontInitPango(&terminalFont->font, fontName);
        } else {
            ffStrbufAppendF(&terminalFont->error, "Couldn't get terminal font from GSettings (%s::%s::font)", profile, path.chars);
        }
    } else {
        FF_AUTO_FREE const char* fontName = getSystemMonospaceFont();
        if (ffStrSet(fontName)) {
            ffFontInitPango(&terminalFont->font, fontName);
        } else {
            ffStrbufAppendS(&terminalFont->error, "Couldn't get system monospace font name from GSettings / DConf");
        }
    }
}

static void detectFromConfigFile(const char* configFile, const char* start, FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    ffParsePropFileConfig(configFile, start, &fontName);

    if (fontName.length == 0) {
        ffStrbufAppendF(&terminalFont->error, "Couldn't find %s in .config/%s", start, configFile);
    } else {
        ffFontInitPango(&terminalFont->font, fontName.chars);
    }
}

static void detectKonsole(FFTerminalFontResult* terminalFont, const char* rcFile) {
    FF_STRBUF_AUTO_DESTROY profile = ffStrbufCreate();
    if (!ffParsePropFileConfig(rcFile, "DefaultProfile =", &profile)) {
        ffStrbufAppendF(&terminalFont->error, "Configuration \".config/%s\" doesn't exist", rcFile);
        return;
    }

    if (profile.length == 0) {
        ffStrbufAppendS(&terminalFont->error, "Built-in profile is used");
        return;
    }

    FF_STRBUF_AUTO_DESTROY profilePath = ffStrbufCreateA(32);
    ffStrbufAppendS(&profilePath, "konsole/");
    ffStrbufAppend(&profilePath, &profile);

    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    ffParsePropFileData(profilePath.chars, "Font =", &fontName);

    if (fontName.length == 0) {
        ffStrbufAppendF(&terminalFont->error, "Couldn't find \"Font=%%[^\\n]\" in \"%s\"", profilePath.chars);
    } else {
        ffFontInitQt(&terminalFont->font, fontName.chars);
    }
}

static void detectXFCETerminal(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY useSysFont = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();

    const char* path = "xfce4/xfconf/xfce-perchannel-xml/xfce4-terminal.xml";
    bool configFound = ffParsePropFileConfigValues(path, 2, (FFpropquery[]) { { "<property name=\"font-use-system\" type=\"bool\" value=\"", &useSysFont }, { "<property name=\"font-name\" type=\"string\" value=\"", &fontName } });

    if (configFound) {
        ffStrbufSubstrBeforeLastC(&useSysFont, '"');
        ffStrbufSubstrBeforeLastC(&fontName, '"');
    } else {
        path = "xfce4/terminal/terminalrc";
        configFound = ffParsePropFileConfigValues(path, 2, (FFpropquery[]) { { "FontUseSystem = ", &useSysFont }, { "FontName = ", &fontName } });
    }

    if (configFound && (useSysFont.length == 0 || ffStrbufIgnCaseEqualS(&useSysFont, "false"))) {
        if (fontName.length == 0) {
            ffStrbufAppendF(&terminalFont->error, "Couldn't find FontName in %s", path);
        } else {
            ffFontInitPango(&terminalFont->font, fontName.chars);
        }
    } else {
        const char* systemFontName = ffSettingsGetXFConf("xsettings", "/Gtk/MonospaceFontName", FF_VARIANT_TYPE_STRING).strValue;
        if (ffStrSet(systemFontName)) {
            ffFontInitPango(&terminalFont->font, systemFontName);
        } else {
            ffStrbufAppendS(&terminalFont->error, "Couldn't find xsettings::/Gtk/MonospaceFontName in XFConf");
        }
    }
}

static void detectDeepinTerminal(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

    FF_STRBUF_AUTO_DESTROY profile = ffStrbufCreateA(64);
    ffSearchUserConfigFile(&instance.state.platform.configDirs, "deepin/deepin-terminal/config.conf", &profile);
    FILE* file = fopen(profile.chars, "r");

    if (file) {
        char* line = nullptr;
        size_t len = 0;

        for (int count = 0; getline(&line, &len, file) != -1 && count < 2;) {
            if (ffStrEquals(line, "[basic.interface.font]\n")) {
                if (getline(&line, &len, file) != -1) {
                    ffParsePropLine(line, "value=", &fontName);
                }
                ++count;
            } else if (ffStrEquals(line, "[basic.interface.font_size]\n")) {
                if (getline(&line, &len, file) != -1) {
                    ffParsePropLine(line, "value=", &fontSize);
                }
                ++count;
            }
        }

        free(line);
        fclose(file);
    }

    if (fontName.length == 0) {
        ffStrbufAppendS(&fontName, "Noto Sans Mono");
    }
    if (fontSize.length == 0) {
        ffStrbufAppendS(&fontSize, "11");
    }

    ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}

static void detectFootTerminal(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate();

    if (!ffParsePropFileConfig("foot/foot.ini", "font=", &font) || !ffStrSet(font.chars)) {
        ffFontInitValues(&terminalFont->font, "monospace", "8");
        return;
    }

    // Sarasa Term SC Nerd:size=8
    uint32_t colon = ffStrbufFirstIndexC(&font, ':');
    if (colon == font.length) {
        ffFontInitValues(&terminalFont->font, font.chars, "8");
        return;
    }
    uint32_t equal = ffStrbufNextIndexS(&font, colon, "size=");
    font.chars[colon] = '\0';
    if (equal == font.length) {
        ffFontInitValues(&terminalFont->font, font.chars, "8");
        return;
    }
    uint32_t size = equal + (uint32_t) strlen("size=");
    uint32_t comma = ffStrbufNextIndexC(&font, size, ',');
    if (comma < font.length) {
        font.chars[comma] = '\0';
    }
    ffFontInitValues(&terminalFont->font, font.chars, &font.chars[size]);
    if (comma < font.length) {
        ffFontInitValues(&terminalFont->fallback, &font.chars[comma + 1], nullptr);
    }
}

static void detectQTerminal(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

    ffParsePropFileConfigValues("qterminal.org/qterminal.ini", 2, (FFpropquery[]) {
                                                                      { "fontFamily=", &fontName },
                                                                      { "fontSize=", &fontSize },
                                                                  });

    if (fontName.length == 0) {
        ffStrbufAppendS(&fontName, "monospace");
    }
    if (fontSize.length == 0) {
        ffStrbufAppendS(&fontSize, "12");
    }
    ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}

static void detectXterm(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

    ffParsePropFileHomeValues(".Xresources", 2, (FFpropquery[]) {
                                                    { "xterm*faceName:", &fontName },
                                                    { "xterm*faceSize:", &fontSize },
                                                });

    if (fontName.length == 0) {
        ffParsePropFileHomeValues(".Xresources", 2, (FFpropquery[]) {
                                                        { "xterm.vt100.faceName:", &fontName },
                                                        { "xterm.vt100.faceSize:", &fontSize },
                                                    });
    }

    if (fontName.length == 0) {
        ffStrbufAppendS(&fontName, "fixed");
    }
    if (fontSize.length == 0) {
        ffStrbufAppendS(&fontSize, "8.0");
    }
    ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}

static bool extractStTermFont(const char* str, [[maybe_unused]] uint32_t len, void* userdata) {
    if (!ffStrContains(str, "size=")) {
        return true;
    }
    ffStrbufSetNS((FFstrbuf*) userdata, len, str);
    return false;
}

static void detectSt(FFTerminalFontResult* terminalFont, const FFTerminalResult* terminal) {
    FF_STRBUF_AUTO_DESTROY size = ffStrbufCreateF("/proc/%u/cmdline", terminal->pid);
    FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate();
    if (!ffAppendFileBuffer(size.chars, &font)) {
        ffStrbufAppendF(&terminalFont->error, "Failed to open %s", size.chars);
        return;
    }

    const char* p = memmem(font.chars, font.length, "\0-f", sizeof("\0-f")); // find parameter of `-f`
    if (p) {
        // st was executed with `-f` parameter
        ffStrbufSubstrAfter(&font, (uint32_t) (p + (sizeof("\0-f") - 1) - font.chars));
        ffStrbufRecalculateLength(&font);
    } else {
        ffStrbufClear(&font);

        const char* error = ffBinaryExtractStrings(terminal->exePath.chars, extractStTermFont, &font, (uint32_t) strlen("size=0"));
        if (error) {
            ffStrbufAppendS(&terminalFont->error, error);
            return;
        }
        if (font.length == 0) {
            ffStrbufAppendS(&terminalFont->error, "No font config found in st binary");
            return;
        }
    }

    // JetBrainsMono Nerd Font Mono:pixelsize=12:antialias=true:autohint=true

    uint32_t index = ffStrbufFirstIndexC(&font, ':');
    if (index != font.length) {
        uint32_t sIndex = ffStrbufNextIndexS(&font, index + 1, "size=");
        if (sIndex != font.length) {
            sIndex += (uint32_t) strlen("size=");
            uint32_t sIndexEnd = ffStrbufNextIndexC(&font, sIndex, ':');
            ffStrbufSetNS(&size, sIndexEnd - sIndex, font.chars + sIndex);
        }
        ffStrbufSubstrBefore(&font, index);
    } else {
        ffStrbufClear(&size);
    }
    ffFontInitValues(&terminalFont->font, font.chars, size.chars);
}

static void detectWarp(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);

    FF_LIST_FOR_EACH (FFstrbuf, dirPrefix, instance.state.platform.configDirs) {
        // We need to copy the dir each time, because it used by multiple threads, so we can't directly write to it.
        ffStrbufSet(&baseDir, dirPrefix);
        ffStrbufAppendS(&baseDir, "warp-terminal/user_preferences.json");

        yyjson_doc* doc = yyjson_read_file(baseDir.chars, YYJSON_READ_INSITU | YYJSON_READ_ALLOW_TRAILING_COMMAS | YYJSON_READ_ALLOW_COMMENTS, nullptr, nullptr);
        if (!doc) {
            continue;
        }

        yyjson_val* prefs = yyjson_obj_get(yyjson_doc_get_root(doc), "prefs");
        if (yyjson_is_obj(prefs)) {
            const char* fontName = yyjson_get_str(yyjson_obj_get(prefs, "FontName"));
            if (!fontName) {
                fontName = "Hack";
            }
            const char* fontSize = yyjson_get_str(yyjson_obj_get(prefs, "FontSize"));
            if (!fontSize) {
                fontSize = "13";
            }

            ffFontInitValues(&terminalFont->font, fontName, fontSize);
        }
        yyjson_doc_free(doc);
        return;
    }
}

static void detectTerminator(FFTerminalFontResult* result) {
    FF_STRBUF_AUTO_DESTROY useSystemFont = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();

    if (!ffParsePropFileConfigValues("terminator/config", 2, (FFpropquery[]) {
                                                                 { "use_system_font =", &useSystemFont },
                                                                 { "font =", &fontName },
                                                             }) ||
        ffStrbufIgnCaseEqualS(&useSystemFont, "True")) {
        FF_AUTO_FREE const char* fontName = getSystemMonospaceFont();
        if (ffStrSet(fontName)) {
            ffFontInitPango(&result->font, fontName);
        } else {
            ffStrbufAppendS(&result->error, "Couldn't get system monospace font name from GSettings / DConf");
        }
        return;
    }

    if (fontName.length == 0) {
        ffFontInitValues(&result->font, "Mono", "10");
    } else {
        ffFontInitPango(&result->font, fontName.chars);
    }
}

static void detectWestonTerminal(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY size = ffStrbufCreate();
    ffParsePropFileConfigValues("weston.ini", 2, (FFpropquery[]) {
                                                     { "font=", &font },
                                                     { "font-size=", &size },
                                                 });
    if (!font.length) {
        ffStrbufSetStatic(&font, "DejaVu Sans Mono");
    }
    if (!size.length) {
        ffStrbufSetStatic(&size, "14");
    }
    ffFontInitValues(&terminalFont->font, font.chars, size.chars);
}

static void detectKmscon(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

    ffParsePropFileConfigValues("kmscon/kmscon.conf", 2, (FFpropquery[]){
                                                             { "font-size=", &fontSize },
                                                             { "font-name=", &fontName },
                                                         });

    if (fontName.length == 0) {
        ffStrbufSetStatic(&fontName, "Hack Nerd Font");
    }
    if (fontSize.length == 0) {
        ffStrbufSetStatic(&fontSize, "18");
    }
    ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}

static void detectUrxvt(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();

    if (!(ffParsePropFileHomeValues(".Xresources", 1, (FFpropquery[]) {
                                                          { "URxvt.font:", &buffer },
                                                      }) ||
            ffParsePropFileHomeValues(".Xdefaults", 1, (FFpropquery[]) {
                                                           { "URxvt.font:", &buffer },
                                                       }))) {
        ffStrbufAppendS(&terminalFont->error, "Could not find URxvt.font in .Xresources or .Xdefaults");
        return;
    }

    uint32_t index = 0;

    char* line = nullptr;
    size_t len = 0;
    while (ffStrbufGetdelim(&line, &len, ',', &buffer)) {
        FFfont* font = index == 0 ? &terminalFont->font : &terminalFont->fallback;
        if (line[0] == '-') {
            ffFontInitXlfd(font, line);
        } else if (ffStrStartsWith(line, "xft:")) {
            ffFontInitXft(font, line + 4);
        } else {
            ffStrbufAppendF(&terminalFont->error, "Unknown URxvt font format: %s", line);
            continue;
        }
        index++;
        if (index > 1) {
            break;
        }
    }
}

static bool detectCosmicTerm(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();

    FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir);
    ffStrbufAppendS(&path, ".config/cosmic/com.system76.CosmicTerm/v1/");
    uint32_t baseLen = path.length;

    ffStrbufAppendS(&path, "font_name");
    ffReadFileBuffer(path.chars, &fontName);
    ffStrbufTrim(&path, '"');
    ffStrbufSubstrBefore(&path, baseLen);
    if (fontName.length == 0) {
        ffStrbufSetStatic(&fontName, "Noto Sans Mono");
    }

    ffStrbufAppendS(&path, "font_size");
    if (ffReadFileBuffer(path.chars, &fontSize)) {
        ffStrbufAppendS(&fontSize, "px");
    }
    ffStrbufSubstrBefore(&path, baseLen);
    if (fontSize.length == 0) {
        ffStrbufSetStatic(&fontSize, "14px");
    }

    ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);

    return true;
}

#ifdef __HAIKU__
static void detectHaikuTerminal(FFTerminalFontResult* terminalFont) {
    FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate();
    FF_STRBUF_AUTO_DESTROY size = ffStrbufCreate();
    ffParsePropFileConfigValues("Terminal/Default", 2, (FFpropquery[]) {
                                                           { "\"Half Font Family\" , ", &font },
                                                           { "\"Half Font Size\" , ", &size },
                                                       });
    if (!font.length) {
        ffStrbufSetStatic(&font, "Noto Sans Mono");
    }
    if (!size.length) {
        ffStrbufSetStatic(&size, "12");
    }
    ffFontInitValues(&terminalFont->font, font.chars, size.chars);
}
#endif

bool
#ifdef __ANDROID__
ffDetectTerminalFontPlatformLinux
#else
ffDetectTerminalFontPlatform
#endif
    (const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) {
    if (ffStrbufIgnCaseEqualS(&terminal->processName, "konsole")) {
        detectKonsole(terminalFont, "konsolerc");
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "yakuake")) {
        detectKonsole(terminalFont, "yakuakerc");
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "xfce4-terminal")) {
        detectXFCETerminal(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "lxterminal")) {
        detectFromConfigFile("lxterminal/lxterminal.conf", "fontname =", terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "tilix")) {
        detectFromGSettings("/com/gexperts/Tilix/profiles/", "com.gexperts.Tilix.ProfilesList", "com.gexperts.Tilix.Profile", "default", terminalFont);
    } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "gnome-terminal")) {
        detectFromGSettings("/org/gnome/terminal/legacy/profiles:/:", "org.gnome.Terminal.ProfilesList", "org.gnome.Terminal.Legacy.Profile", "default", terminalFont);
    } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "ptyxis-agent")) {
        detectPtyxis(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "kgx")) {
        detectKgx(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "mate-terminal")) {
        detectFromGSettings("/org/mate/terminal/profiles/", "org.mate.terminal.global", "org.mate.terminal.profile", "default-profile", terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "deepin-terminal")) {
        detectDeepinTerminal(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "foot")) {
        detectFootTerminal(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "qterminal")) {
        detectQTerminal(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "xterm")) {
        detectXterm(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "st")) {
        detectSt(terminalFont, terminal);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "warp")) {
        detectWarp(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "weston-terminal")) {
        detectWestonTerminal(terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "kmscon")) {
        detectKmscon(terminalFont);
    } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "terminator")) {
        detectTerminator(terminalFont);
    } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "sakura")) {
        detectFromConfigFile("sakura/sakura.conf", "font=", terminalFont);
    } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "cosmic-term")) {
        detectCosmicTerm(terminalFont);
    }
#ifdef __HAIKU__
    else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "Terminal")) {
        detectHaikuTerminal(terminalFont);
    }
#endif
    else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "termite")) {
        detectFromConfigFile("termite/config", "font =", terminalFont);
    } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "rxvt") || ffStrbufIgnCaseEqualS(&terminal->processName, "urxvt") || ffStrbufIgnCaseEqualS(&terminal->processName, "urxvtd")) {
        detectUrxvt(terminalFont);
    } else {
        return false;
    }
    return true;
}
