-
-
Notifications
You must be signed in to change notification settings - Fork 1
Theme Architecture Codegen
How a project JSON becomes a runnable Conky theme folder.
Project (nodes, edges, canvas, props)
│
▼
builder.build_project()
│
├── scripts/ (families used by the graph)
├── images/ fonts/ (copied assets)
├── render.lua (framework + per-node emission)
├── conky.conf (window + hooks + lua_load)
├── start.sh (setsid, lock, daemon loops)
├── theme.json
└── README.md
Live Preview uses the same builder path into a temp/workdir, then runs Conky — not a separate renderer.
| Piece | Role |
|---|---|
| NodeInstance |
id, type, x/y (editor only), props, z, visible, locked, click region fields |
| Edge |
src_node → dst_node + dst_prop (one wire per bindable prop) |
| CanvasSettings | width, height, alignment, gaps, fps, stats_hz, window_type, transparency |
| Groups / labels | Editor-only; ignored by codegen |
Hidden visuals (visible: false) are skipped entirely by codegen. Unused sources are not polled.
Sources that need external scripts belong to a family (weather, sensors, custom id, …).
| Mode | Who polls | start.sh role |
|---|---|---|
| execi | Conky (execi / equivalent in generated paths) |
No background loop for that family |
| daemon | Background shell loop |
while true; do sleep N; script; done under setsid |
| Album art | Always treated as daemon-style (writes an image file) | Loop per album-art node interval |
daemon_families_used(project) collects intervals from wired sources (and album art). If several nodes share a family, the shortest interval wins so data is never staler than requested.
Scripts write cache files (often key/value or single values). render.lua reads caches with safe parsers so a missing file (script not run yet) does not crash the draw.
Generated by conky_conf_gen after session resolution:
| Step | Detail |
|---|---|
window_type |
Canvas auto → discovery.resolve_window_type() (session-specific default, usually normal) |
own_window* |
Undecorated / below / sticky / skip taskbar hints |
| size |
minimum_width/height from Canvas |
| timing |
update_interval from FPS |
| lua_load | Self-locating: resolves render.lua next to the conf via debug.getinfo so the folder is relocatable |
| lua_draw_hook_post |
main_draw (draw after Conky’s own pass) |
| lua_mouse_hook | Emitted only if the project has clickable nodes |
| empty conky.text | All visible HUD content comes from Lua/Cairo |
Optional Wayland/session warning is embedded as a conf comment when detection reports a problem.
Rough layers:
FRAMEWORK_LUA -- shared helpers, caches, surface, images
+ plugin lua_helpers -- once per plugin type used
+ logic expressions -- bound props as Lua expressions
+ visual draw bodies -- per visible visual node, z-order
+ main_draw() -- refresh sources, create cr, draw all, destroy if needed
+ mouse_handler() -- optional click regions
| Store | Purpose |
|---|---|
| IMAGE_CACHE | PNG/SVG handles; false = known missing (warn once) |
| CACHE_KV | Parsed script cache files, refreshed on source refresh |
| HIST | Ring buffers for history graphs keyed by node id |
| Plugin tables | e.g. _cs_plugin_smooth[slot] for EMA / rate-limit / peak-hold |
Logic nodes become expressions (or small IIFEs) substituted into consumers. Evaluation order follows edge dependency so inputs exist before use.
get_draw_surface()
→ conky_surface() if available (Conky owns → do NOT destroy)
→ else cairo_xlib_surface_create (we own → must destroy)
Wrong ownership caused historical segfaults; the framework encodes the branch explicitly. Works for X11 and Wayland-with-layer-shell builds that expose conky_surface().
-
pcallaround parse/draw where appropriate -
safe_number/safe_parsefallbacks - Missing cache → previous/zero rather than aborting the whole HUD
Not OS threads inside Conky for daemon scripts; separate shell processes in one process group:
setsid
├── conky -c conky.conf
├── script_family_a.sh (initial run)
├── (while sleep N; do script_family_a; done) &
└── … same for other daemon families
| Mechanism | Role |
|---|---|
| setsid | Session leader; Manager can signal the whole group |
PID file under $XDG_RUNTIME_DIR
|
Single-instance lock; re-start replaces old HUD |
| DIR | Theme directory (relocatable) |
execi-only themes may have no poller loops — Conky alone is enough.
Studio’s Manager uses QProcess.startDetached on start.sh so themes survive quitting the editor.
| Asset | Behaviour |
|---|---|
| Image paths in props | Copied into images/ / assets when resolved at build |
| Fonts | Listed/copied when the build collects them |
| Script files | Generated or copied into scripts/ with mode bits |
Absolute host paths in the project JSON are a sharing hazard; the built folder is the portable artifact.
| Path | Output location | Runner |
|---|---|---|
| Live Preview | Temp / preview workdir | Studio-controlled Conky process + log |
| Build to Folder | User-chosen directory | Manual ./start.sh
|
| Build & Install | ~/.config/conky/<name>/ |
Manager Start → start.sh |
Same codegen; different destination and process ownership.
- Graph = what to sample and what to draw.
- Codegen = how Conky is told to do it every frame.
- start.sh = how long-running helpers stay alive beside Conky.
- Caches = async data into a sync draw loop without blocking Cairo.
There is no hidden Studio runtime on the user’s desktop after install — only Conky + shell + Lua.