Phase 5: Polish & Integration
Goal
Complete the user experience with Lua integration, CLI tool, multi-monitor support, and configuration hot-reload.
Tasks
5.1 Lua Module for gar
- Create shared library loadable by gar's Lua
- Expose
garbg.set()function - Expose
garbg.next(),garbg.prev(),garbg.random() - Expose
garbg.config()for declarative setup - Handle IPC connection from Lua context
5.2 garbgctl CLI Tool
-
garbgctl set <source>- Set wallpaper -
garbgctl next/prev- Slideshow control -
garbgctl random- Random wallpaper -
garbgctl status- Show current state -
garbgctl reload- Reload config -
garbgctl pause/resume- Animation control - Pretty-printed output with colors
5.3 Multi-Monitor Support
- Detect monitors via RandR
- Per-monitor wallpaper configuration
- Handle monitor hotplug events
- Composite wallpapers for spanning setups
- Independent slideshows per monitor
5.4 Configuration Hot-Reload
- Watch config file with inotify
- Parse and validate new config
- Apply changes without restart
- SIGHUP trigger for manual reload
- Report config errors via IPC
5.5 Error Handling & Logging
- Structured logging with tracing
- Log levels (error, warn, info, debug, trace)
- Journal/syslog integration for daemon
- User-friendly error messages
- Detailed errors for debugging
5.6 Documentation
- Man page for garbg
- Man page for garbgctl
- Example configurations
- Integration guide for gar
Deliverables
- Lua module works in gar's init.lua
- garbgctl provides full control over daemon
- Multi-monitor setups work correctly
- Config changes apply without restart
Lua Integration Example
-- ~/.config/gar/init.lua
local garbg = require("garbg")
-- Declarative configuration
garbg.config({
default = {
source = "~/Pictures/wallpapers",
mode = "fill",
slideshow = {
enabled = true,
interval = 300,
shuffle = true,
},
},
workspaces = {
[1] = "~/Pictures/workspace1.png",
[2] = { source = "~/Videos/loop.mp4", mode = "fill" },
[3] = "github://user/repo/wallpapers/ws3.png",
},
monitors = {
["DP-1"] = { source = "~/Pictures/wide/", mode = "fill" },
},
})
-- Keybinds
gar.bind("mod+w", function() garbg.next() end)
gar.bind("mod+shift+w", function() garbg.random() end)
-- React to workspace changes
gar.on("workspace", function(event)
garbg.switch_workspace(event.current)
end)
garbgctl Usage
# Set wallpaper
garbgctl set ~/Pictures/wallpaper.png
garbgctl set github://user/repo/wallpapers --random
# Slideshow control
garbgctl next
garbgctl prev
garbgctl random
# Animation control
garbgctl pause
garbgctl resume
# Status and management
garbgctl status
garbgctl reload
# Output example
$ garbgctl status
garbg daemon v0.1.0
Status: running
Current: ~/Pictures/wallpaper.png
Mode: fill
Slideshow: enabled (5m interval, 12/50)
Animation: playing
Monitors: DP-1, HDMI-1
Multi-Monitor Configuration
# ~/.config/garbg/config.toml
[[monitors]]
name = "DP-1"
source = "~/Pictures/wide/"
mode = "fill"
slideshow = true
interval = "10m"
[[monitors]]
name = "HDMI-1"
source = "~/Pictures/vertical/"
mode = "fit"
# Spanning mode (single wallpaper across all monitors)
[spanning]
enabled = false
source = "~/Pictures/ultrawide.png"
mode = "fill"
Files Modified/Created
/garbg/garbg/src/lua/mod.rs- Lua module/garbg/garbg/src/lua/api.rs- Lua API functions/garbg/garbgctl/src/main.rs- CLI implementation/garbg/garbg/src/x11/monitors.rs- RandR implementation/garbg/garbg/src/config/watch.rs- Config file watching/garbg/docs/garbg.1.md- Man page source/garbg/docs/garbgctl.1.md- Man page source/garbg/config/default.toml- Example configuration
View source
| 1 | # Phase 5: Polish & Integration |
| 2 | |
| 3 | ## Goal |
| 4 | Complete the user experience with Lua integration, CLI tool, multi-monitor support, and configuration hot-reload. |
| 5 | |
| 6 | ## Tasks |
| 7 | |
| 8 | ### 5.1 Lua Module for gar |
| 9 | - [ ] Create shared library loadable by gar's Lua |
| 10 | - [ ] Expose `garbg.set()` function |
| 11 | - [ ] Expose `garbg.next()`, `garbg.prev()`, `garbg.random()` |
| 12 | - [ ] Expose `garbg.config()` for declarative setup |
| 13 | - [ ] Handle IPC connection from Lua context |
| 14 | |
| 15 | ### 5.2 garbgctl CLI Tool |
| 16 | - [ ] `garbgctl set <source>` - Set wallpaper |
| 17 | - [ ] `garbgctl next` / `prev` - Slideshow control |
| 18 | - [ ] `garbgctl random` - Random wallpaper |
| 19 | - [ ] `garbgctl status` - Show current state |
| 20 | - [ ] `garbgctl reload` - Reload config |
| 21 | - [ ] `garbgctl pause` / `resume` - Animation control |
| 22 | - [ ] Pretty-printed output with colors |
| 23 | |
| 24 | ### 5.3 Multi-Monitor Support |
| 25 | - [ ] Detect monitors via RandR |
| 26 | - [ ] Per-monitor wallpaper configuration |
| 27 | - [ ] Handle monitor hotplug events |
| 28 | - [ ] Composite wallpapers for spanning setups |
| 29 | - [ ] Independent slideshows per monitor |
| 30 | |
| 31 | ### 5.4 Configuration Hot-Reload |
| 32 | - [ ] Watch config file with inotify |
| 33 | - [ ] Parse and validate new config |
| 34 | - [ ] Apply changes without restart |
| 35 | - [ ] SIGHUP trigger for manual reload |
| 36 | - [ ] Report config errors via IPC |
| 37 | |
| 38 | ### 5.5 Error Handling & Logging |
| 39 | - [ ] Structured logging with tracing |
| 40 | - [ ] Log levels (error, warn, info, debug, trace) |
| 41 | - [ ] Journal/syslog integration for daemon |
| 42 | - [ ] User-friendly error messages |
| 43 | - [ ] Detailed errors for debugging |
| 44 | |
| 45 | ### 5.6 Documentation |
| 46 | - [ ] Man page for garbg |
| 47 | - [ ] Man page for garbgctl |
| 48 | - [ ] Example configurations |
| 49 | - [ ] Integration guide for gar |
| 50 | |
| 51 | ## Deliverables |
| 52 | - Lua module works in gar's init.lua |
| 53 | - garbgctl provides full control over daemon |
| 54 | - Multi-monitor setups work correctly |
| 55 | - Config changes apply without restart |
| 56 | |
| 57 | ## Lua Integration Example |
| 58 | |
| 59 | ```lua |
| 60 | -- ~/.config/gar/init.lua |
| 61 | local garbg = require("garbg") |
| 62 | |
| 63 | -- Declarative configuration |
| 64 | garbg.config({ |
| 65 | default = { |
| 66 | source = "~/Pictures/wallpapers", |
| 67 | mode = "fill", |
| 68 | slideshow = { |
| 69 | enabled = true, |
| 70 | interval = 300, |
| 71 | shuffle = true, |
| 72 | }, |
| 73 | }, |
| 74 | workspaces = { |
| 75 | [1] = "~/Pictures/workspace1.png", |
| 76 | [2] = { source = "~/Videos/loop.mp4", mode = "fill" }, |
| 77 | [3] = "github://user/repo/wallpapers/ws3.png", |
| 78 | }, |
| 79 | monitors = { |
| 80 | ["DP-1"] = { source = "~/Pictures/wide/", mode = "fill" }, |
| 81 | }, |
| 82 | }) |
| 83 | |
| 84 | -- Keybinds |
| 85 | gar.bind("mod+w", function() garbg.next() end) |
| 86 | gar.bind("mod+shift+w", function() garbg.random() end) |
| 87 | |
| 88 | -- React to workspace changes |
| 89 | gar.on("workspace", function(event) |
| 90 | garbg.switch_workspace(event.current) |
| 91 | end) |
| 92 | ``` |
| 93 | |
| 94 | ## garbgctl Usage |
| 95 | |
| 96 | ```bash |
| 97 | # Set wallpaper |
| 98 | garbgctl set ~/Pictures/wallpaper.png |
| 99 | garbgctl set github://user/repo/wallpapers --random |
| 100 | |
| 101 | # Slideshow control |
| 102 | garbgctl next |
| 103 | garbgctl prev |
| 104 | garbgctl random |
| 105 | |
| 106 | # Animation control |
| 107 | garbgctl pause |
| 108 | garbgctl resume |
| 109 | |
| 110 | # Status and management |
| 111 | garbgctl status |
| 112 | garbgctl reload |
| 113 | |
| 114 | # Output example |
| 115 | $ garbgctl status |
| 116 | garbg daemon v0.1.0 |
| 117 | Status: running |
| 118 | Current: ~/Pictures/wallpaper.png |
| 119 | Mode: fill |
| 120 | Slideshow: enabled (5m interval, 12/50) |
| 121 | Animation: playing |
| 122 | Monitors: DP-1, HDMI-1 |
| 123 | ``` |
| 124 | |
| 125 | ## Multi-Monitor Configuration |
| 126 | |
| 127 | ```toml |
| 128 | # ~/.config/garbg/config.toml |
| 129 | |
| 130 | [[monitors]] |
| 131 | name = "DP-1" |
| 132 | source = "~/Pictures/wide/" |
| 133 | mode = "fill" |
| 134 | slideshow = true |
| 135 | interval = "10m" |
| 136 | |
| 137 | [[monitors]] |
| 138 | name = "HDMI-1" |
| 139 | source = "~/Pictures/vertical/" |
| 140 | mode = "fit" |
| 141 | |
| 142 | # Spanning mode (single wallpaper across all monitors) |
| 143 | [spanning] |
| 144 | enabled = false |
| 145 | source = "~/Pictures/ultrawide.png" |
| 146 | mode = "fill" |
| 147 | ``` |
| 148 | |
| 149 | ## Files Modified/Created |
| 150 | - `/garbg/garbg/src/lua/mod.rs` - Lua module |
| 151 | - `/garbg/garbg/src/lua/api.rs` - Lua API functions |
| 152 | - `/garbg/garbgctl/src/main.rs` - CLI implementation |
| 153 | - `/garbg/garbg/src/x11/monitors.rs` - RandR implementation |
| 154 | - `/garbg/garbg/src/config/watch.rs` - Config file watching |
| 155 | - `/garbg/docs/garbg.1.md` - Man page source |
| 156 | - `/garbg/docs/garbgctl.1.md` - Man page source |
| 157 | - `/garbg/config/default.toml` - Example configuration |