diff options
Diffstat (limited to 'src/detection/gtk_qt')
| -rw-r--r-- | src/detection/gtk_qt/gtk.c | 206 | ||||
| -rw-r--r-- | src/detection/gtk_qt/gtk_qt.h | 25 | ||||
| -rw-r--r-- | src/detection/gtk_qt/qt.c | 209 |
3 files changed, 440 insertions, 0 deletions
diff --git a/src/detection/gtk_qt/gtk.c b/src/detection/gtk_qt/gtk.c new file mode 100644 index 0000000..05a8db1 --- /dev/null +++ b/src/detection/gtk_qt/gtk.c @@ -0,0 +1,206 @@ +#include "fastfetch.h" +#include "common/properties.h" +#include "common/thread.h" +#include "common/settings.h" +#include "detection/gtk_qt/gtk_qt.h" +#include "detection/displayserver/displayserver.h" + +static inline bool allPropertiesSet(FFGTKResult* result) { + return result->theme.length > 0 && + result->icons.length > 0 && + 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) { + if (result->theme.length == 0) { + ffStrbufAppendS(&result->theme, themeName); + } + + if (result->icons.length == 0) { + ffStrbufAppendS(&result->icons, iconsName); + } + + if (result->font.length == 0) { + ffStrbufAppendS(&result->font, fontName); + } + + if (result->cursor.length == 0) { + ffStrbufAppendS(&result->cursor, cursorTheme); + } + + if (result->cursorSize.length == 0 && cursorSize > 0) { + ffStrbufAppendF(&result->cursorSize, "%i", cursorSize); + } + + if (result->wallpaper.length == 0) { + ffStrbufAppendS(&result->wallpaper, wallpaper); + } +} + +static bool testXfconfWallpaperPropKey(FF_A_UNUSED void* data, const char* key) { + int count = 0; + sscanf(key, "/backdrop/screen0/monitor%*[^/]/workspace0/last-image%n", &count); + return count == 0; +} + +static void detectGTKFromSettings(FFGTKResult* result) { + static const char* themeName = NULL; + static const char* iconsName = NULL; + static const char* fontName = NULL; + static const char* cursorTheme = NULL; + static int cursorSize = 0; + static const char* wallpaper = NULL; + + static bool init = false; + + if (init) { + applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper); + return; + } + + init = true; + + const FFDisplayServerResult* wmde = ffConnectDisplayServer(); + + if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4)) { + themeName = ffSettingsGetXFConf("xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue; + iconsName = ffSettingsGetXFConf("xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue; + fontName = ffSettingsGetXFConf("xsettings", "/Gtk/FontName", FF_VARIANT_TYPE_STRING).strValue; + cursorTheme = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue; + cursorSize = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue; + wallpaper = ffSettingsGetXFConfFirstMatch("xfce4-desktop", "/backdrop/screen0", FF_VARIANT_TYPE_STRING, NULL, testXfconfWallpaperPropKey).strValue; + } else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON)) { + themeName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; + iconsName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; + fontName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; + cursorTheme = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; + cursorSize = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; + wallpaper = ffSettingsGetGnome("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue; + } else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_MATE)) { + themeName = ffSettingsGetGnome("/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; + iconsName = ffSettingsGetGnome("/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; + fontName = ffSettingsGetGnome("/org/mate/interface/font-name", "org.mate.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; + cursorTheme = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; + cursorSize = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; + wallpaper = ffSettingsGetGnome("/org/mate/desktop/background", "org.mate.background", NULL, "picture-filename", FF_VARIANT_TYPE_STRING).strValue; + } else if ( + ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) || + ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) || + ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) || + ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) || + ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_NEBIDE)) { + themeName = ffSettingsGetGnome("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; + iconsName = ffSettingsGetGnome("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; + fontName = ffSettingsGetGnome("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; + cursorTheme = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; + cursorSize = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; + wallpaper = ffSettingsGetGnome("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", NULL, "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; + } + } + + applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper); +} + +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 } }); +} + +static void detectGTKFromConfigDir(FFstrbuf* configDir, const char* version, FFGTKResult* result) { + uint32_t configDirLength = configDir->length; + + // <configdir>/gtk-<version>.0/settings.ini + ffStrbufAppendS(configDir, "gtk-"); + ffStrbufAppendS(configDir, version); + ffStrbufAppendS(configDir, ".0/settings.ini"); + detectGTKFromConfigFile(configDir->chars, result); + ffStrbufSubstrBefore(configDir, configDirLength); + if (allPropertiesSet(result)) { + return; + } + + // <configdir>/gtk-<version>.0/gtkrc + ffStrbufAppendS(configDir, "gtk-"); + ffStrbufAppendS(configDir, version); + ffStrbufAppendS(configDir, ".0/gtkrc"); + detectGTKFromConfigFile(configDir->chars, result); + ffStrbufSubstrBefore(configDir, configDirLength); + if (allPropertiesSet(result)) { + return; + } + + // <configdir>/gtkrc-<version>.0 + ffStrbufAppendS(configDir, "gtkrc-"); + ffStrbufAppendS(configDir, version); + ffStrbufAppendS(configDir, ".0"); + detectGTKFromConfigFile(configDir->chars, result); + ffStrbufSubstrBefore(configDir, configDirLength); + if (allPropertiesSet(result)) { + return; + } + + // <configdir>/.gtkrc-<version>.0 + ffStrbufAppendS(configDir, ".gtkrc-"); + ffStrbufAppendS(configDir, version); + ffStrbufAppendS(configDir, ".0"); + detectGTKFromConfigFile(configDir->chars, result); + ffStrbufSubstrBefore(configDir, configDirLength); +} + +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); + if (allPropertiesSet(result)) { + return; + } + + // We need to do this because we use multiple threads on configDirs + FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64); + + FF_LIST_FOR_EACH (FFstrbuf, configDir, instance.state.platform.configDirs) { + ffStrbufSet(&baseDir, configDir); + detectGTKFromConfigDir(&baseDir, version, result); + if (allPropertiesSet(result)) { + break; + } + } +} + +#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; + +const FFGTKResult* ffDetectGTK2(void) { + FF_DETECT_GTK_IMPL(2) +} + +const FFGTKResult* ffDetectGTK3(void) { + FF_DETECT_GTK_IMPL(3) +} + +const FFGTKResult* ffDetectGTK4(void) { + FF_DETECT_GTK_IMPL(4) +} + +#undef FF_CALCULATE_GTK_IMPL diff --git a/src/detection/gtk_qt/gtk_qt.h b/src/detection/gtk_qt/gtk_qt.h new file mode 100644 index 0000000..b831bb6 --- /dev/null +++ b/src/detection/gtk_qt/gtk_qt.h @@ -0,0 +1,25 @@ +#pragma once + +#include "fastfetch.h" + +typedef struct FFGTKResult { + FFstrbuf theme; + FFstrbuf icons; + FFstrbuf font; + FFstrbuf cursor; + FFstrbuf cursorSize; + FFstrbuf wallpaper; +} FFGTKResult; + +typedef struct FFQtResult { + FFstrbuf widgetStyle; + FFstrbuf colorScheme; + FFstrbuf icons; + FFstrbuf font; + FFstrbuf wallpaper; +} FFQtResult; + +const FFGTKResult* ffDetectGTK2(void); +const FFGTKResult* ffDetectGTK4(void); +const FFGTKResult* ffDetectGTK3(void); +const FFQtResult* ffDetectQt(void); diff --git a/src/detection/gtk_qt/qt.c b/src/detection/gtk_qt/qt.c new file mode 100644 index 0000000..26c8b58 --- /dev/null +++ b/src/detection/gtk_qt/qt.c @@ -0,0 +1,209 @@ +#include "fastfetch.h" +#include "common/properties.h" +#include "common/thread.h" +#include "common/strutil.h" +#include "detection/gtk_qt/gtk_qt.h" +#include "detection/displayserver/displayserver.h" + +#include <stdlib.h> +#include <string.h> + +static inline bool allValuesSet(const FFQtResult* result) { + return result->widgetStyle.length > 0 && + result->colorScheme.length > 0 && + result->icons.length > 0 && + result->font.length > 0 && + result->wallpaper.length > 0; +} + +typedef enum FF_A_PACKED PlasmaCategory { + PLASMA_CATEGORY_GENERAL, + PLASMA_CATEGORY_KDE, + PLASMA_CATEGORY_ICONS, + PLASMA_CATEGORY_OTHER +} PlasmaCategory; + +static bool detectPlasmaFromFile(const char* filename, FFQtResult* result) { + FILE* kdeglobals = fopen(filename, "r"); + if (kdeglobals == NULL) { + return false; + } + + char* line = NULL; + size_t len = 0; + + PlasmaCategory category = PLASMA_CATEGORY_OTHER; + + while (getline(&line, &len, kdeglobals) != -1) { + if (line[0] == '[') { + char categoryName[32]; + sscanf(line, "[%31[^]]", categoryName); + + if (ffStrEqualsIgnCase(categoryName, "General")) { + category = PLASMA_CATEGORY_GENERAL; + } else if (ffStrEqualsIgnCase(categoryName, "KDE")) { + category = PLASMA_CATEGORY_KDE; + } else if (ffStrEqualsIgnCase(categoryName, "Icons")) { + category = PLASMA_CATEGORY_ICONS; + } else { + category = PLASMA_CATEGORY_OTHER; + } + + continue; + } + + if (category == PLASMA_CATEGORY_KDE && result->widgetStyle.length == 0) { + ffParsePropLine(line, "widgetStyle =", &result->widgetStyle); + } else if (category == PLASMA_CATEGORY_ICONS && result->icons.length == 0) { + ffParsePropLine(line, "Theme =", &result->icons); + } else if (category == PLASMA_CATEGORY_GENERAL) { + if (result->colorScheme.length == 0) { + ffParsePropLine(line, "ColorScheme =", &result->colorScheme); + } + + if (result->font.length == 0) { + ffParsePropLine(line, "font =", &result->font); + } + + // Before plasma 5.23, "Font" was the key instead of "font". Since a lot of distros ship older versions, we test for both. + if (result->font.length == 0) { + ffParsePropLine(line, "Font =", &result->font); + } + } + } + + free(line); + + fclose(kdeglobals); + + return true; +} + +static void detectPlasma(FFQtResult* result) { + bool foundAFile = false; + + // We need to do this because we use multiple threads on configDirs + FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64); + + FF_LIST_FOR_EACH (FFstrbuf, configDir, instance.state.platform.configDirs) { + ffStrbufSet(&baseDir, configDir); + ffStrbufAppendS(&baseDir, "kdeglobals"); + + if (detectPlasmaFromFile(baseDir.chars, result)) { + foundAFile = true; + } + + ffStrbufSet(&baseDir, configDir); + ffStrbufAppendS(&baseDir, "plasma-org.kde.plasma.desktop-appletsrc"); + + ffParsePropFile(baseDir.chars, "Image=", &result->wallpaper); + + if (allValuesSet(result)) { + return; + } + } + + if (!foundAFile) { + return; + } + + // In Plasma the default value is never set in the config file, but the whole key-value is discarded. + /// We must set these values by our self if the file exists (it always does here) + if (result->widgetStyle.length == 0) { + ffStrbufAppendS(&result->widgetStyle, "Breeze"); + } + + if (result->colorScheme.length == 0) { + ffStrbufAppendS(&result->colorScheme, "BreezeLight"); + } + + if (result->icons.length == 0) { + ffStrbufAppendS(&result->icons, "Breeze"); + } + + if (result->font.length == 0) { + ffStrbufAppendS(&result->font, "Noto Sans, 10"); + } +} + +static void detectLXQt(FFQtResult* result) { + ffParsePropFileConfigValues("lxqt/lxqt.conf", 3, (FFpropquery[]) { { "style = ", &result->widgetStyle }, { "icon_theme = ", &result->icons }, { "font = ", &result->font } }); + + ffParsePropFileConfig("pcmanfm-qt/lxqt/settings.conf", "Wallpaper=", &result->wallpaper); +} + +static void detectQtCt(char qver, FFQtResult* result) { + // qt5ct and qt6ct are technically separate applications, but they're both + // by the same author and qt6ct understands qt5ct in qt6 applications as well. + char file[] = "qtXct/qtXct.conf"; + file[2] = file[8] = qver; + + FF_STRBUF_AUTO_DESTROY font = ffStrbufCreate(); + + ffParsePropFileConfigValues(file, 3, (FFpropquery[]) { { "style=", &result->widgetStyle }, { "icon_theme=", &result->icons }, { "general=", &font } }); + + if (ffStrbufStartsWithC(&font, '@')) { + // See QVariant notes on https://doc.qt.io/qt-5/qsettings.html and + // https://github.com/fastfetch-cli/fastfetch/issues/1053#issuecomment-2197254769 + // Thankfully, newer versions use the more common font encoding. + ffStrbufSetNS(&font, 5, file); + } else if (qver == '5') { + // #1864 + const char* p = font.chars; + + while (*p) { + if (p[0] == '\\' && p[1] == 'x' && isxdigit(p[2]) && isxdigit(p[3]) && isxdigit(p[4]) && isxdigit(p[5])) { + uint32_t codepoint = (uint32_t) strtoul((char[]) { p[2], p[3], p[4], p[5], '\0' }, NULL, 16); + ffStrbufAppendUtf32CodePoint(&result->font, codepoint); + p += 6; + } else { + ffStrbufAppendC(&result->font, *p++); + } + } + } else { + ffStrbufDestroy(&result->font); + ffStrbufInitMove(&result->font, &font); + } +} + +static void detectKvantum(FFQtResult* result) { + ffParsePropFileConfigValues("Kvantum/kvantum.kvconfig", 1, (FFpropquery[]) { + { "theme=", &result->widgetStyle }, + }); +} + +const FFQtResult* ffDetectQt(void) { + static FFQtResult result; + + static bool init = false; + if (init) { + return &result; + } + init = true; + + ffStrbufInit(&result.widgetStyle); + ffStrbufInit(&result.colorScheme); + ffStrbufInit(&result.icons); + ffStrbufInit(&result.font); + ffStrbufInit(&result.wallpaper); + + const FFDisplayServerResult* wmde = ffConnectDisplayServer(); + + if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA)) { + detectPlasma(&result); + } else if (ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT)) { + detectLXQt(&result); + } else { + const char* qPlatformTheme = getenv("QT_QPA_PLATFORMTHEME"); + if (qPlatformTheme && (ffStrEquals(qPlatformTheme, "qt5ct") || ffStrEquals(qPlatformTheme, "qt6ct"))) { + detectQtCt(qPlatformTheme[2], &result); + } + } + + if (ffStrbufEqualS(&result.widgetStyle, "kvantum") || ffStrbufEqualS(&result.widgetStyle, "kvantum-dark")) { + ffStrbufClear(&result.widgetStyle); + detectKvantum(&result); + } + + return &result; +} |