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 = >k->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}