#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 static void getKDE(FFstrbuf* result, [[maybe_unused]] FFDEOptions* options) { ffParsePropFile(FF_PATH_PKG_BASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result); if (result->length == 0) { ffParsePropFile(FF_PATH_PKG_BASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result); } 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", nullptr }) == nullptr) { // plasmashell 5.27.5 ffStrbufSubstrAfterLastC(result, ' '); } } } static const char* getGnomeByDbus([[maybe_unused]] FFstrbuf* result) { #ifdef FF_HAVE_DBUS FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != nullptr) { return "ffDBusLoadData() failed"; } ffDBusGetPropertyString(&dbus, "org.gnome.Shell", "/org/gnome/Shell", "org.gnome.Shell", "ShellVersion", result); return nullptr; #else // FF_HAVE_DBUS return "ffDBusLoadData() failed: dbus support not compiled in"; #endif // FF_HAVE_DBUS } static void getGnome(FFstrbuf* result, [[maybe_unused]] FFDEOptions* options) { getGnomeByDbus(result); if (result->length == 0) { if (ffProcessAppendStdOut(result, (char* const[]) { "gnome-shell", "--version", nullptr }) == nullptr) { // GNOME Shell 44.1 ffStrbufSubstrAfterLastC(result, ' '); } } } static void getCinnamon(FFstrbuf* result, [[maybe_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", nullptr }) == nullptr) { // Cinnamon 6.2.2 ffStrbufSubstrAfterLastC(result, ' '); } } } static void getMate(FFstrbuf* result, [[maybe_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", nullptr }); 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 nullptr; #else FF_UNUSED(result); return "dlopen is disabled"; #endif } static void getXFCE4(FFstrbuf* result, [[maybe_unused]] FFDEOptions* options) { getXfce4ByLib(result); if (result->length == 0) { // This is somewhat slow ffProcessAppendStdOut(result, (char* const[]) { "xfce4-session", "--version", nullptr }); ffStrbufSubstrBeforeFirstC(result, ')'); ffStrbufSubstrAfterLastC(result, ' '); ffStrbufTrim(result, ' '); } } static void getLXQt(FFstrbuf* result, [[maybe_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", nullptr }); result->length = 0; // don't set '\0' byte ffParsePropLines(result->chars, "liblxqt", result); } } static void getBudgie(FFstrbuf* result, [[maybe_unused]] FFDEOptions* options) { ffParsePropFileData("budgie/budgie-version.xml", "", result); } static void getUnity(FFstrbuf* result, [[maybe_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, [[maybe_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")) == nullptr) { return nullptr; } ffStrbufClear(&path); if (ffProcessAppendStdOut(&path, (char* const[]) { "tde-config", "--version", nullptr }) == nullptr) { ffParsePropLines(path.chars, "TDE: ", result); return nullptr; } return "All methods failed"; } static const char* getCosmic(FFstrbuf* result, [[maybe_unused]] FFDEOptions* options) { if (ffProcessAppendStdOut(result, (char* const[]) { "cosmic-comp", "--version", nullptr }) == nullptr) { // cosmic-comp 0.1.0 (git commit fa88002ba41d2edec25dd7ffdee9719fbb928fc0) ffStrbufSubstrAfterFirstC(result, ' '); ffStrbufSubstrBeforeFirstC(result, ' '); return nullptr; } return "All methods failed"; } static const char* getEnlightenmentByDbus([[maybe_unused]] FFstrbuf* result) { #ifdef FF_HAVE_DBUS FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != nullptr) { return "ffDBusLoadData() failed"; } DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.enlightenment.wm.service", "/org/enlightenment/wm/RemoteObject", "org.enlightenment.wm.Core", "Version", nullptr, nullptr); 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 nullptr; #else // FF_HAVE_DBUS return "ffDBusLoadData() failed: dbus support not compiled in"; #endif // FF_HAVE_DBUS } static void getEnlightenment(FFstrbuf* result, [[maybe_unused]] FFDEOptions* options) { getEnlightenmentByDbus(result); if (result->length == 0) { if (ffProcessAppendStdOut(result, (char* const[]) { "enlightenment", "--version", nullptr }) == nullptr) { // ...\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 nullptr; }