1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
import ".."
import "ListFile.js" as LF
// The wallpapers the companion blushes at, and what wallp has on each
// monitor. The companion reads both; the wallpaper picker toggles entries.
// What is on each monitor is read from wallp's own files here rather than
// through the appearance module's Wallpapers, which scans every wallpaper
// on creation, and the companion runs all session.
Singleton {
id: root
readonly property string home: Quickshell.env("HOME")
readonly property string defaultPath:
(Quickshell.env("XDG_CONFIG_HOME") || root.home + "/.config") + "/keystone/companion-blush.txt"
readonly property string path:
Prefs.companionBlushFile !== "" ? Prefs.companionBlushFile.replace(/^~(?=\/|$)/, root.home) : root.defaultPath
property string listText: ""
readonly property var paths: LF.parse(root.listText)
function listed(p) { return p !== "" && root.paths.indexOf(p) >= 0; }
// The wallpaper on a monitor, by connector name; "" for one wallp does
// not set.
property var outputs: ({})
property string wallH: ""
property string wallV: ""
function on(monitor) {
const w = root.outputs[monitor];
return w === "H" ? root.wallH : w === "V" ? root.wallV : "";
}
// ponytail: a list file created by hand after start may not be watched
// until a restart (the watch is on a path that did not exist); the
// heart writes through the process below, which sets listText itself.
FileView {
path: root.path
watchChanges: true
printErrors: false
onFileChanged: reload()
onLoaded: root.listText = text()
onLoadFailed: root.listText = ""
}
FileView {
path: root.home + "/.config/wallp/wallp.conf"
watchChanges: true
printErrors: false
onFileChanged: reload()
onLoaded: root.outputs = LF.outputs(text())
}
FileView {
path: root.home + "/.config/wallp/wall_h"
watchChanges: true
printErrors: false
onFileChanged: reload()
onLoaded: root.wallH = text().trim()
}
FileView {
path: root.home + "/.config/wallp/wall_v"
watchChanges: true
printErrors: false
onFileChanged: reload()
onLoaded: root.wallV = text().trim()
}
// Through cat rather than FileView.setText, because the list can become
// empty and setText("") on a path the view has not loaded writes no
// file (AGENTS.md).
function toggle(p) {
writer.data = LF.toggle(root.listText, p);
root.listText = writer.data;
writer.command = ["sh", "-c", 'mkdir -p "$(dirname "$1")" && cat > "$1"', "sh", root.path];
writer.stdinEnabled = true;
writer.running = false;
writer.running = true;
}
Process {
id: writer
property string data: ""
onStarted: {
writer.write(writer.data);
writer.stdinEnabled = false;
}
onExited: code => { if (code !== 0) console.warn("Admired: writing", root.path, "failed"); }
}
}
|