summaryrefslogtreecommitdiffstats
path: root/src/detection/gtk_qt
diff options
context:
space:
mode:
Diffstat (limited to 'src/detection/gtk_qt')
-rw-r--r--src/detection/gtk_qt/gtk.c206
-rw-r--r--src/detection/gtk_qt/gtk_qt.h25
-rw-r--r--src/detection/gtk_qt/qt.c209
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;
+}