master ohmu/fastfetch-openbsd / src / detection / wallpaper / wallpaper_linux.c
ohmu  ·  2026-10-15
  1#include "wallpaper.h"
  2#include "common/debug.h"
  3#include "common/io.h"
  4#include "common/settings.h"
  5#include "detection/displayserver/displayserver.h"
  6#include "detection/gtk_qt/gtk_qt.h"
  7
  8static const char* detectCosmicComp(FFstrbuf* result) {
  9    FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(FF_LIST_FIRST(FFstrbuf, instance.state.platform.configDirs));
 10    ffStrbufAppendS(&path, "cosmic/com.system76.CosmicBackground/v1/");
 11    uint32_t basePathLength = path.length;
 12
 13    FF_STRBUF_AUTO_DESTROY backgrounds = ffStrbufCreate();
 14    ffStrbufAppendS(&path, "backgrounds");
 15    bool sharedWallpaper = true;
 16    FF_STRBUF_AUTO_DESTROY monitorName = ffStrbufCreate();
 17    if (ffReadFileBuffer(path.chars, &backgrounds)) {
 18        FF_STRBUF_AUTO_DESTROY cleaned = ffStrbufCreateCopy(&backgrounds);
 19        ffStrbufRemoveStrings(&cleaned, 4, (const char*[]){ " ", "\n", "\r", "\t" });
 20
 21        if (!ffStrbufEqualS(&cleaned, "[]")) {
 22            const char* firstQuote = strchr(backgrounds.chars, '"');
 23            if (firstQuote != nullptr) {
 24                const char* secondQuote = strchr(firstQuote + 1, '"');
 25                if (secondQuote != nullptr && secondQuote > firstQuote + 1) {
 26                    ffStrbufAppendNS(&monitorName, (uint32_t) (secondQuote - firstQuote - 1), firstQuote + 1);
 27                    sharedWallpaper = false;
 28                }
 29            }
 30        }
 31    }
 32    ffStrbufSubstrBefore(&path, basePathLength);
 33
 34    if (sharedWallpaper) {
 35        ffStrbufAppendS(&path, "all");
 36    } else {
 37        ffStrbufAppendS(&path, "output.");
 38        ffStrbufAppend(&path, &monitorName);
 39    }
 40
 41    FF_STRBUF_AUTO_DESTROY output = ffStrbufCreate();
 42    if (!ffReadFileBuffer(path.chars, &output)) {
 43        FF_DEBUG("Failed to read \"%s\"", path.chars);
 44        return "Failed to read COSMIC wallpaper config";
 45    }
 46
 47    const char* sourceStart = strstr(output.chars, "source:");
 48    if (sourceStart == nullptr) {
 49        FF_DEBUG("The COSMIC wallpaper config does not contain \"source:\"");
 50        return "COSMIC wallpaper config doesn't contain source";
 51    }
 52
 53    const char* pathStart = strstr(sourceStart, "Path(");
 54    if (pathStart == nullptr) {
 55        FF_DEBUG("The COSMIC wallpaper source does not contain \"Path(\"");
 56        return "COSMIC wallpaper source is not a Path value";
 57    }
 58
 59    pathStart += strlen("Path(");
 60    while (*pathStart == ' ' || *pathStart == '\t') {
 61        ++pathStart;
 62    }
 63
 64    if (*pathStart != '\'' && *pathStart != '"') {
 65        FF_DEBUG("The COSMIC wallpaper Path does not start with a quote");
 66        return "COSMIC wallpaper Path format is invalid";
 67    }
 68
 69    char quote = *pathStart;
 70    ++pathStart;
 71    const char* pathEnd = strchr(pathStart, quote);
 72    if (pathEnd == nullptr || pathEnd == pathStart) {
 73        FF_DEBUG("The COSMIC wallpaper path is empty");
 74        return "COSMIC wallpaper path is empty";
 75    }
 76
 77    ffStrbufAppendNS(result, (uint32_t) (pathEnd - pathStart), pathStart);
 78    return nullptr;
 79}
 80
 81// Android compiles this file next to wallpaper_android.c, which owns ffDetectWallpaper and calls
 82// this one only while the display server is not SurfaceFlinger -- so the entry point has to step
 83// aside there. Same arrangement as terminalfont_linux.c and terminalfont_android.c.
 84const char*
 85#ifdef __ANDROID__
 86ffDetectWallpaperLinux
 87#else
 88ffDetectWallpaper
 89#endif
 90    (FFstrbuf* result) {
 91    const FFDisplayServerResult* wm = ffConnectDisplayServer();
 92    if (ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_COSMIC_COMP)) {
 93        return detectCosmicComp(result);
 94    }
 95
 96    const FFstrbuf* wallpaper = nullptr;
 97    const FFGTKResult* gtk = ffDetectGTK4();
 98    if (gtk->wallpaper.length) {
 99        wallpaper = &gtk->wallpaper;
100    } else {
101        const FFQtResult* qt = ffDetectQt();
102        if (qt->wallpaper.length) {
103            wallpaper = &qt->wallpaper;
104        }
105    }
106
107    if (!wallpaper) {
108        FF_DEBUG("Neither GTK nor Qt reported a wallpaper path");
109        return "Failed to detect the current wallpaper path";
110    }
111
112    if (ffStrbufStartsWithS(wallpaper, "file:///")) {
113        ffStrbufAppendS(result, wallpaper->chars + strlen("file://"));
114    } else {
115        ffStrbufAppend(result, wallpaper);
116    }
117    return nullptr;
118}