2023-10-30 22:46:38 +08:00
|
|
|
#include "de.h"
|
|
|
|
|
|
2026-01-06 09:48:38 +08:00
|
|
|
#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"
|
2023-10-30 22:46:38 +08:00
|
|
|
#include "detection/displayserver/displayserver.h"
|
|
|
|
|
|
2023-10-31 23:43:29 +08:00
|
|
|
#include <ctype.h>
|
2025-06-02 10:19:36 +08:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
|
#include <paths.h>
|
2025-06-03 21:44:06 +08:00
|
|
|
#ifndef _PATH_LOCALBASE
|
|
|
|
|
#define _PATH_LOCALBASE "/usr/local"
|
|
|
|
|
#endif
|
|
|
|
|
#elif __OpenBSD__
|
|
|
|
|
#define _PATH_LOCALBASE "/usr/local"
|
|
|
|
|
#elif __NetBSD__
|
|
|
|
|
#define _PATH_LOCALBASE "/usr/pkg"
|
2025-06-02 10:19:36 +08:00
|
|
|
#endif
|
2023-10-31 23:43:29 +08:00
|
|
|
|
2023-10-31 09:54:12 +08:00
|
|
|
static void getKDE(FFstrbuf* result, FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
2025-06-03 21:44:06 +08:00
|
|
|
#ifdef _PATH_LOCALBASE
|
2025-06-02 10:19:36 +08:00
|
|
|
ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
2023-10-30 22:46:38 +08:00
|
|
|
if(result->length == 0)
|
2025-06-02 10:19:36 +08:00
|
|
|
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
|
|
|
|
|
|
2024-04-17 21:02:32 +08:00
|
|
|
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);
|
|
|
|
|
|
2023-10-30 22:46:38 +08:00
|
|
|
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);
|
|
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
if(result->length == 0)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
if (ffProcessAppendStdOut(result, (char* const[]){
|
|
|
|
|
"plasmashell",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
}) == NULL) // plasmashell 5.27.5
|
|
|
|
|
ffStrbufSubstrAfterLastC(result, ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 23:38:43 +08:00
|
|
|
static const char* getGnomeByDbus(FF_MAYBE_UNUSED FFstrbuf* result)
|
2024-04-17 19:00:45 +08:00
|
|
|
{
|
2024-04-22 18:22:00 +03:00
|
|
|
#ifdef FF_HAVE_DBUS
|
2024-04-17 19:00:45 +08:00
|
|
|
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;
|
2024-04-22 18:22:00 +03:00
|
|
|
#else // FF_HAVE_DBUS
|
|
|
|
|
return "ffDBusLoadData() failed: dbus support not compiled in";
|
|
|
|
|
#endif // FF_HAVE_DBUS
|
2024-04-17 19:00:45 +08:00
|
|
|
}
|
|
|
|
|
|
2023-10-31 09:54:12 +08:00
|
|
|
static void getGnome(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
2024-04-22 23:38:43 +08:00
|
|
|
getGnomeByDbus(result);
|
2023-10-30 22:46:38 +08:00
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
if (result->length == 0)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
if (ffProcessAppendStdOut(result, (char* const[]){
|
|
|
|
|
"gnome-shell",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
}) == NULL) // GNOME Shell 44.1
|
|
|
|
|
ffStrbufSubstrAfterLastC(result, ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-31 09:54:12 +08:00
|
|
|
static void getCinnamon(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
2024-07-03 09:09:06 +08:00
|
|
|
ffStrbufSetS(result, getenv("CINNAMON_VERSION"));
|
|
|
|
|
|
|
|
|
|
if (result->length == 0)
|
|
|
|
|
ffParsePropFileData("applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", result);
|
|
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
if (result->length == 0)
|
2024-07-03 09:09:06 +08:00
|
|
|
{
|
|
|
|
|
if (ffProcessAppendStdOut(result, (char* const[]){
|
|
|
|
|
"cinnamon",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
}) == NULL) // Cinnamon 6.2.2
|
|
|
|
|
ffStrbufSubstrAfterLastC(result, ' ');
|
|
|
|
|
}
|
2023-10-30 22:46:38 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
static void getMate(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
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[]) {
|
|
|
|
|
{"<platform>", &major},
|
|
|
|
|
{"<minor>", &minor},
|
|
|
|
|
{"<micro>", µ}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ffParseSemver(result, &major, &minor, µ);
|
|
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
if(result->length == 0)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
ffProcessAppendStdOut(result, (char* const[]){
|
|
|
|
|
"mate-session",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ffStrbufSubstrAfterFirstC(result, ' ');
|
|
|
|
|
ffStrbufTrim(result, ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-11 16:36:12 +08:00
|
|
|
static const char* getXfce4ByLib(FFstrbuf* result)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
2024-05-24 14:40:14 +08:00
|
|
|
#ifndef FF_DISABLE_DLOPEN
|
2023-12-11 16:36:12 +08:00
|
|
|
const char* xfce_version_string(void); // from `xfce4/libxfce4util/xfce-misutils.h
|
2026-01-05 14:51:27 +08:00
|
|
|
FF_LIBRARY_LOAD_MESSAGE(xfce4util, "libxfce4util" FF_LIBRARY_EXTENSION, 7);
|
2023-12-11 16:36:12 +08:00
|
|
|
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xfce4util, xfce_version_string);
|
|
|
|
|
ffStrbufSetS(result, ffxfce_version_string());
|
|
|
|
|
return NULL;
|
2024-05-24 14:40:14 +08:00
|
|
|
#else
|
|
|
|
|
FF_UNUSED(result);
|
|
|
|
|
return "dlopen is disabled";
|
|
|
|
|
#endif
|
2023-12-11 16:36:12 +08:00
|
|
|
}
|
2023-10-30 22:46:38 +08:00
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
static void getXFCE4(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
2023-12-11 16:36:12 +08:00
|
|
|
{
|
|
|
|
|
getXfce4ByLib(result);
|
2023-10-30 22:46:38 +08:00
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
if(result->length == 0)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
//This is somewhat slow
|
|
|
|
|
ffProcessAppendStdOut(result, (char* const[]){
|
|
|
|
|
"xfce4-session",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
});
|
|
|
|
|
|
2023-12-11 16:36:12 +08:00
|
|
|
ffStrbufSubstrBeforeFirstC(result, ')');
|
|
|
|
|
ffStrbufSubstrAfterLastC(result, ' ');
|
2023-10-30 22:46:38 +08:00
|
|
|
ffStrbufTrim(result, ' ');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-31 09:54:12 +08:00
|
|
|
static void getLXQt(FFstrbuf* result, FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
if(result->length == 0)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
//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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-31 09:54:12 +08:00
|
|
|
static void getBudgie(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
|
|
|
|
ffParsePropFileData("budgie/budgie-version.xml", "<str>", result);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-27 14:31:05 +08:00
|
|
|
static void getUnity(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
|
|
|
|
{
|
|
|
|
|
if (ffParsePropFile("/usr/bin/unity", "parser = OptionParser(version= \"%prog ", result))
|
|
|
|
|
ffStrbufSubstrBeforeFirstC(result, '"');
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 18:19:23 +08:00
|
|
|
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, 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;
|
|
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
ffStrbufClear(&path);
|
|
|
|
|
ffProcessAppendStdOut(&path, (char* const[]){
|
|
|
|
|
"tde-config",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
});
|
2025-08-21 18:19:23 +08:00
|
|
|
|
2026-01-19 10:55:30 +08:00
|
|
|
ffParsePropLines(path.chars , "TDE: ", result);
|
|
|
|
|
return NULL;
|
2025-08-21 18:19:23 +08:00
|
|
|
|
|
|
|
|
return "All methods failed";
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-28 19:50:23 +08:00
|
|
|
static const char* getCosmic(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
|
|
|
|
{
|
|
|
|
|
if (ffProcessAppendStdOut(result, (char* const[]){
|
|
|
|
|
"cosmic-comp",
|
|
|
|
|
"--version",
|
|
|
|
|
NULL
|
|
|
|
|
}) == NULL) {
|
|
|
|
|
// cosmic-comp 0.1.0 (git commit fa88002ba41d2edec25dd7ffdee9719fbb928fc0)
|
|
|
|
|
ffStrbufSubstrAfterFirstC(result, ' ');
|
2026-01-01 22:29:11 +08:00
|
|
|
ffStrbufSubstrBeforeFirstC(result, ' ');
|
2025-12-28 19:50:23 +08:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "All methods failed";
|
|
|
|
|
}
|
2025-08-21 18:19:23 +08:00
|
|
|
|
2023-10-31 09:54:12 +08:00
|
|
|
const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOptions* options)
|
2023-10-30 22:46:38 +08:00
|
|
|
{
|
2024-07-10 21:55:37 +08:00
|
|
|
if (!instance.config.general.detectVersion) return "Disabled by config";
|
|
|
|
|
|
2023-10-30 22:46:38 +08:00
|
|
|
if (ffStrbufEqualS(deName, FF_DE_PRETTY_PLASMA))
|
2023-10-31 09:54:12 +08:00
|
|
|
getKDE(result, options);
|
2023-11-17 22:23:36 +01:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_GNOME))
|
2023-10-31 09:54:12 +08:00
|
|
|
getGnome(result, options);
|
2023-10-30 22:46:38 +08:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_CINNAMON))
|
2023-10-31 09:54:12 +08:00
|
|
|
getCinnamon(result, options);
|
2023-10-30 22:46:38 +08:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_XFCE4))
|
2023-10-31 09:54:12 +08:00
|
|
|
getXFCE4(result, options);
|
2023-10-30 22:46:38 +08:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_MATE))
|
2023-10-31 09:54:12 +08:00
|
|
|
getMate(result, options);
|
2023-10-30 22:46:38 +08:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_LXQT))
|
2023-10-31 09:54:12 +08:00
|
|
|
getLXQt(result, options);
|
2023-10-30 22:46:38 +08:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_BUDGIE))
|
2023-10-31 09:54:12 +08:00
|
|
|
getBudgie(result, options);
|
2024-08-27 14:31:05 +08:00
|
|
|
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_UNITY))
|
|
|
|
|
getUnity(result, options);
|
2025-08-21 18:19:23 +08:00
|
|
|
else if (ffStrbufEqualS(deName, "trinity"))
|
|
|
|
|
getTrinity(result, options);
|
2025-12-28 19:50:23 +08:00
|
|
|
else if (ffStrbufEqualS(deName, "COSMIC"))
|
|
|
|
|
getCosmic(result, options);
|
2023-10-30 22:46:38 +08:00
|
|
|
else
|
|
|
|
|
return "Unsupported DE";
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|