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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property var userOptions: ({})
function read(path, fallback) {
const parts = path.split(".");
let current = userOptions;
for (const part of parts) {
if (current === null || current === undefined || typeof current !== "object" || !(part in current)) {
return fallback;
}
current = current[part];
}
return current === undefined || current === null ? fallback : current;
}
function readInt(path, fallback) {
const value = read(path, fallback);
const parsed = Number(value);
return Number.isInteger(parsed) ? parsed : fallback;
}
function readReal(path, fallback) {
const value = read(path, fallback);
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : fallback;
}
function readBool(path, fallback) {
const value = read(path, fallback);
return typeof value === "boolean" ? value : fallback;
}
function readString(path, fallback) {
const value = read(path, fallback);
if (typeof value !== "string")
return fallback;
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : fallback;
}
property QtObject options: QtObject {
property QtObject appearance: QtObject {
property string colorSource: root.readString(
"appearance.colorSource",
root.readBool("appearance.useMatugenColors", false) ? "matugen" : "default"
)
property bool useMatugenColors: colorSource === "matugen"
property QtObject caelestia: QtObject {
property bool autoRefresh: root.readBool("appearance.caelestia.autoRefresh", true)
property int refreshInterval: root.readInt("appearance.caelestia.refreshInterval", 2000)
property string accentProfile: root.readString("appearance.caelestia.accentProfile", "vibrant")
}
property QtObject rounding: QtObject {
property int unsharpen: root.readInt("appearance.rounding.unsharpen", 2)
property int verysmall: root.readInt("appearance.rounding.verysmall", 8)
property int small: root.readInt("appearance.rounding.small", 12)
property int normal: root.readInt("appearance.rounding.normal", 17)
property int large: root.readInt("appearance.rounding.large", 23)
property int full: root.readInt("appearance.rounding.full", 9999)
property int screenRounding: root.readInt("appearance.rounding.screenRounding", large)
property int windowRounding: root.readInt("appearance.rounding.windowRounding", 18)
}
property QtObject font: QtObject {
property QtObject family: QtObject {
property string main: root.readString("appearance.font.family.main", "sans-serif")
property string title: root.readString("appearance.font.family.title", "sans-serif")
property string expressive: root.readString("appearance.font.family.expressive", "sans-serif")
}
property QtObject pixelSize: QtObject {
property int smaller: root.readInt("appearance.font.pixelSize.smaller", 12)
property int small: root.readInt("appearance.font.pixelSize.small", 15)
property int normal: root.readInt("appearance.font.pixelSize.normal", 16)
property int larger: root.readInt("appearance.font.pixelSize.larger", 19)
property int huge: root.readInt("appearance.font.pixelSize.huge", 22)
}
}
property QtObject animation: QtObject {
property QtObject duration: QtObject {
property int elementMove: root.readInt("appearance.animation.duration.elementMove", 500)
property int elementMoveEnter: root.readInt("appearance.animation.duration.elementMoveEnter", 400)
property int elementMoveFast: root.readInt("appearance.animation.duration.elementMoveFast", 200)
}
}
property QtObject sizes: QtObject {
property real elevationMargin: root.readReal("appearance.sizes.elevationMargin", 10)
}
}
property QtObject overview: QtObject {
property int rows: root.readInt("overview.rows", 2)
property int columns: root.readInt("overview.columns", 5)
property real scale: root.readReal("overview.scale", 0.16)
property bool enable: root.readBool("overview.enable", true)
property bool hideEmptyRows: root.readBool("overview.hideEmptyRows", false)
property bool closeOnFocusLoss: root.readBool("overview.closeOnFocusLoss", true)
property bool useWorkspaceMap: root.readBool("overview.useWorkspaceMap", false)
property var workspaceMap: root.read("overview.workspaceMap", [])
property bool orderRightLeft: root.readBool("overview.orderRightLeft", false)
property bool orderBottomUp: root.readBool("overview.orderBottomUp", false)
property bool previewsEnabled: root.readBool("overview.previewsEnabled", true)
property string previewMode: root.readString("overview.previewMode", "live")
property bool includeInactiveMonitorPreviews: root.readBool("overview.includeInactiveMonitorPreviews", true)
property int previewRecaptureDelayMs: root.readInt("overview.previewRecaptureDelayMs", 60)
property bool showSpecialWorkspaces: root.readBool("overview.showSpecialWorkspaces", false)
property var specialWorkspaces: root.read("overview.specialWorkspaces", [])
property int specialWorkspaceColumns: root.readInt("overview.specialWorkspaceColumns", columns)
property string emptyWorkspaceWallpaper: root.readString("overview.emptyWorkspaceWallpaper", "")
property string specialEmptyWorkspaceWallpaper: root.readString("overview.specialEmptyWorkspaceWallpaper", "")
property real workspaceSpacing: root.readReal("overview.workspaceSpacing", 5)
property real backgroundPadding: root.readReal("overview.backgroundPadding", 10)
property real workspaceNumberBaseSize: root.readReal("overview.workspaceNumberBaseSize", 250)
property QtObject effects: QtObject {
property bool enableBackdrop: root.readBool("overview.effects.enableBackdrop", false)
property real backdropOpacity: root.readReal("overview.effects.backdropOpacity", 0.28)
property real panelOpacity: root.readReal("overview.effects.panelOpacity", 0.92)
property real workspaceOpacity: root.readReal("overview.effects.workspaceOpacity", 0.86)
property real emptyWorkspaceWallpaperOverlayOpacity: root.readReal("overview.effects.emptyWorkspaceWallpaperOverlayOpacity", 0.18)
property real windowOverlayOpacity: root.readReal("overview.effects.windowOverlayOpacity", 0.22)
property bool enableBlur: root.readBool("overview.effects.enableBlur", false)
property bool glassMode: root.readBool("overview.effects.glassMode", false)
property real glassTintStrength: root.readReal("overview.effects.glassTintStrength", 0.35)
property real glassBorderOpacity: root.readReal("overview.effects.glassBorderOpacity", 0.72)
property real glassShineOpacity: root.readReal("overview.effects.glassShineOpacity", 0.14)
}
}
property QtObject position: QtObject {
property int topMargin: root.readInt("position.topMargin", 100)
}
property QtObject windowPreview: QtObject {
property bool showIcons: root.readBool("windowPreview.showIcons", true)
property real iconToWindowRatio: root.readReal("windowPreview.iconToWindowRatio", 0.25)
property real iconToWindowRatioCompact: root.readReal("windowPreview.iconToWindowRatioCompact", 0.45)
property real xwaylandIndicatorToIconRatio: root.readReal("windowPreview.xwaylandIndicatorToIconRatio", 0.35)
property real inactiveMonitorOpacity: root.readReal("windowPreview.inactiveMonitorOpacity", 0.4)
property bool cropToFill: root.readBool("windowPreview.cropToFill", false)
}
property QtObject hacks: QtObject {
property int arbitraryRaceConditionDelay: root.readInt("hacks.arbitraryRaceConditionDelay", 150)
property int hyprlandEventDebounceMs: root.readInt("hacks.hyprlandEventDebounceMs", 40)
}
}
Process {
id: loadUserConfig
command: [
"sh",
"-lc",
"cfg=\"${XDG_CONFIG_HOME:-$HOME/.config}/quickshell/overview/config.json\"; [ -r \"$cfg\" ] && cat \"$cfg\""
]
stdout: StdioCollector {
id: configCollector
onStreamFinished: {
const payload = configCollector.text.trim();
if (!payload)
return;
try {
const parsed = JSON.parse(payload);
if (typeof parsed === "object" && parsed !== null) {
root.userOptions = parsed;
} else {
console.warn("overview: config.json must contain a JSON object; ignoring file");
}
} catch (error) {
console.warn("overview: failed to parse user config.json; using defaults", error);
}
}
}
}
Component.onCompleted: {
loadUserConfig.running = true;
}
}
|