From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/de/de_linux.c | 284 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 src/detection/de/de_linux.c (limited to 'src/detection/de/de_linux.c') diff --git a/src/detection/de/de_linux.c b/src/detection/de/de_linux.c new file mode 100644 index 0000000..de7a220 --- /dev/null +++ b/src/detection/de/de_linux.c @@ -0,0 +1,284 @@ +#include "de.h" + +#include "common/dbus.h" +#include "common/io.h" +#include "common/library.h" +#include "common/parsing.h" +#include "common/properties.h" +#include "common/processing.h" +#include "common/binary.h" +#include "common/path.h" +#include "detection/displayserver/displayserver.h" + +#include +#ifdef __FreeBSD__ + #include + #ifndef _PATH_LOCALBASE + #define _PATH_LOCALBASE "/usr/local" + #endif +#elif __OpenBSD__ + #define _PATH_LOCALBASE "/usr/local" +#elif __NetBSD__ + #define _PATH_LOCALBASE "/usr/pkg" +#endif + +static void getKDE(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { +#ifdef _PATH_LOCALBASE + ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result); + if (result->length == 0) { + ffParsePropFile(_PATH_LOCALBASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result); + } +#else + ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result); + if (result->length == 0) { + ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result); + } +#endif + + if (result->length == 0) { + ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result); + } + if (result->length == 0) { + ffParsePropFileData("xsessions/plasma5.desktop", "X-KDE-PluginInfo-Version =", result); + } + + if (result->length == 0) { + ffParsePropFileData("wayland-sessions/plasmawayland.desktop", "X-KDE-PluginInfo-Version =", result); + } + if (result->length == 0) { + ffParsePropFileData("wayland-sessions/plasmawayland5.desktop", "X-KDE-PluginInfo-Version =", result); + } + + if (result->length == 0) { + if (ffProcessAppendStdOut(result, (char* const[]) { "plasmashell", "--version", NULL }) == NULL) { // plasmashell 5.27.5 + ffStrbufSubstrAfterLastC(result, ' '); + } + } +} + +static const char* getGnomeByDbus(FF_A_UNUSED FFstrbuf* result) { +#ifdef FF_HAVE_DBUS + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; + if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) { + return "ffDBusLoadData() failed"; + } + + ffDBusGetPropertyString(&dbus, "org.gnome.Shell", "/org/gnome/Shell", "org.gnome.Shell", "ShellVersion", result); + return NULL; +#else // FF_HAVE_DBUS + return "ffDBusLoadData() failed: dbus support not compiled in"; +#endif // FF_HAVE_DBUS +} + +static void getGnome(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + getGnomeByDbus(result); + + if (result->length == 0) { + if (ffProcessAppendStdOut(result, (char* const[]) { "gnome-shell", "--version", NULL }) == NULL) { // GNOME Shell 44.1 + ffStrbufSubstrAfterLastC(result, ' '); + } + } +} + +static void getCinnamon(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + ffStrbufSetS(result, getenv("CINNAMON_VERSION")); + + if (result->length == 0) { + ffParsePropFileData("applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", result); + } + + if (result->length == 0) { + if (ffProcessAppendStdOut(result, (char* const[]) { "cinnamon", "--version", NULL }) == NULL) { // Cinnamon 6.2.2 + ffStrbufSubstrAfterLastC(result, ' '); + } + } +} + +static void getMate(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + FF_STRBUF_AUTO_DESTROY major = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY minor = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY micro = ffStrbufCreate(); + + ffParsePropFileDataValues("mate-about/mate-version.xml", 3, (FFpropquery[]) { { "", &major }, { "", &minor }, { "", µ } }); + + ffParseSemver(result, &major, &minor, µ); + + if (result->length == 0) { + ffProcessAppendStdOut(result, (char* const[]) { "mate-session", "--version", NULL }); + + ffStrbufSubstrAfterFirstC(result, ' '); + ffStrbufTrim(result, ' '); + } +} + +static const char* getXfce4ByLib(FFstrbuf* result) { +#ifndef FF_DISABLE_DLOPEN + const char* xfce_version_string(void); // from `xfce4/libxfce4util/xfce-misutils.h + FF_LIBRARY_LOAD_MESSAGE(xfce4util, "libxfce4util" FF_LIBRARY_EXTENSION, 7); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xfce4util, xfce_version_string); + ffStrbufSetS(result, ffxfce_version_string()); + return NULL; +#else + FF_UNUSED(result); + return "dlopen is disabled"; +#endif +} + +static void getXFCE4(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + getXfce4ByLib(result); + + if (result->length == 0) { + // This is somewhat slow + ffProcessAppendStdOut(result, (char* const[]) { "xfce4-session", "--version", NULL }); + + ffStrbufSubstrBeforeFirstC(result, ')'); + ffStrbufSubstrAfterLastC(result, ' '); + ffStrbufTrim(result, ' '); + } +} + +static void getLXQt(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + ffParsePropFileData("gconfig/lxqt.pc", "Version:", result); + + if (result->length == 0) { + ffParsePropFileData("cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", result); + } + if (result->length == 0) { + ffParsePropFileData("cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", result); + } + + if (result->length == 0) { + // This is really, really, really slow. Thank you, LXQt developers + ffProcessAppendStdOut(result, (char* const[]) { "lxqt-session", "-v", NULL }); + + result->length = 0; // don't set '\0' byte + ffParsePropLines(result->chars, "liblxqt", result); + } +} + +static void getBudgie(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + ffParsePropFileData("budgie/budgie-version.xml", "", result); +} + +static void getUnity(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + if (ffParsePropFile("/usr/bin/unity", "parser = OptionParser(version= \"%prog ", result)) { + ffStrbufSubstrBeforeFirstC(result, '"'); + } +} + +static bool extractTdeVersion(const char* line, uint32_t len, void* userdata) { + int count = 0; + sscanf(line, "R%*d.%*d.%*d%n", &count); + if (count == 0) { + return true; + } + + ffStrbufSetNS((FFstrbuf*) userdata, len, line); + return false; +} + +static const char* getTrinity(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); + const char* error = ffFindExecutableInPath("tde-config", &path); + if (error) { + return "Failed to find tde-config path"; + } + + ffStrbufSubstrBeforeLastC(&path, '/'); + ffStrbufAppendS(&path, "/../lib/libtdecore.so"); + + if (ffBinaryExtractStrings(path.chars, extractTdeVersion, result, strlen("R0.0.0")) == NULL) { + return NULL; + } + + ffStrbufClear(&path); + if (ffProcessAppendStdOut(&path, (char* const[]) { "tde-config", "--version", NULL }) == NULL) { + ffParsePropLines(path.chars, "TDE: ", result); + return NULL; + } + + return "All methods failed"; +} + +static const char* getCosmic(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + if (ffProcessAppendStdOut(result, (char* const[]) { "cosmic-comp", "--version", NULL }) == NULL) { + // cosmic-comp 0.1.0 (git commit fa88002ba41d2edec25dd7ffdee9719fbb928fc0) + ffStrbufSubstrAfterFirstC(result, ' '); + ffStrbufSubstrBeforeFirstC(result, ' '); + return NULL; + } + + return "All methods failed"; +} + +static const char* getEnlightenmentByDbus(FF_A_UNUSED FFstrbuf* result) { +#ifdef FF_HAVE_DBUS + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; + if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) { + return "ffDBusLoadData() failed"; + } + + DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.enlightenment.wm.service", "/org/enlightenment/wm/RemoteObject", "org.enlightenment.wm.Core", "Version", NULL, NULL); + if (!reply) { + return "ffDBusGetMethodReply() failed"; + } + + DBusMessageIter rootIterator; + if (!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator)) { + dbus.lib->ffdbus_message_unref(reply); + return "dbus_message_iter_init() failed"; + } + if (!ffDBusGetString(&dbus, &rootIterator, result)) { + dbus.lib->ffdbus_message_unref(reply); + return "ffDBusGetString() failed"; + } + dbus.lib->ffdbus_message_unref(reply); + + return NULL; +#else // FF_HAVE_DBUS + return "ffDBusLoadData() failed: dbus support not compiled in"; +#endif // FF_HAVE_DBUS +} + +static void getEnlightenment(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) { + getEnlightenmentByDbus(result); + + if (result->length == 0) { + if (ffProcessAppendStdOut(result, (char* const[]) { "enlightenment", "--version", NULL }) == NULL) { // ...\nVersion: 0.27.1\n... + ffStrbufSubstrAfterFirstS(result, "Version: "); + ffStrbufSubstrBeforeFirstC(result, '\n'); + } + } +} +const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOptions* options) { + if (!instance.config.general.detectVersion) { + return "Disabled by config"; + } + + if (ffStrbufEqualS(deName, FF_DE_PRETTY_PLASMA)) { + getKDE(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_GNOME)) { + getGnome(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_CINNAMON)) { + getCinnamon(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_XFCE4)) { + getXFCE4(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_MATE)) { + getMate(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_LXQT)) { + getLXQt(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_BUDGIE)) { + getBudgie(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_UNITY)) { + getUnity(result, options); + } else if (ffStrbufEqualS(deName, "trinity")) { + getTrinity(result, options); + } else if (ffStrbufEqualS(deName, "COSMIC")) { + getCosmic(result, options); + } else if (ffStrbufEqualS(deName, FF_DE_PRETTY_ENLIGHTENMENT)) { + getEnlightenment(result, options); + } else { + return "Unsupported DE"; + } + return NULL; +} -- cgit v1.2.3