Phase 4: Daemon Mode & gar Integration
Goal
Implement daemon mode with IPC server, integrate with gar window manager for workspace-aware wallpapers.
Tasks
4.1 Daemon Mode
- Daemonize process (fork, setsid, etc.)
- PID file management
- Signal handling (SIGHUP for reload, SIGTERM for shutdown)
- Graceful shutdown with resource cleanup
4.2 IPC Server
- Unix socket at
$XDG_RUNTIME_DIR/garbg.sock - JSON lines protocol
- Command parsing and dispatch
- Response serialization
- Client connection management
4.3 IPC Commands
-
set- Set wallpaper -
next/prev- Slideshow navigation -
random- Random wallpaper from source -
reload- Reload configuration -
pause/resume- Animation/slideshow control -
status- Get current state -
subscribe- Event subscription
4.4 gar IPC Client
- Connect to gar's IPC socket
- Subscribe to workspace events
- Subscribe to monitor events
- Parse gar's JSON event format
4.5 Per-Workspace Wallpapers
- Map workspace ID to wallpaper config
- Switch wallpaper on workspace change
- Smooth transition (instant, per design decision)
- Fallback to default wallpaper
4.6 Slideshow/Rotation
- Timer-based rotation
- Configurable interval
- Random or sequential ordering
- Per-source playlist management
Deliverables
garbg daemonstarts background daemongarbgctl set /path/to/image.pngsends command to daemon- Changing workspaces in gar changes wallpaper
- Slideshow rotates wallpapers at configured interval
IPC Protocol
Commands (Client -> Server)
{"command": "set", "source": "/path/to/image.png", "mode": "fill"}
{"command": "next"}
{"command": "prev"}
{"command": "random"}
{"command": "reload"}
{"command": "pause"}
{"command": "resume"}
{"command": "status"}
{"command": "subscribe", "events": ["wallpaper_changed", "slideshow_advanced"]}
Responses (Server -> Client)
{"success": true}
{"success": true, "data": {"current": "/path/to/image.png", "mode": "fill", "paused": false}}
{"success": false, "error": "File not found"}
Events (Server -> Subscribed Clients)
{"event": "wallpaper_changed", "source": "/path/to/new.png", "workspace": 1}
{"event": "slideshow_advanced", "current": 5, "total": 20}
{"event": "error", "message": "Failed to fetch remote image"}
gar Event Handling
// Subscribe to gar workspace events
let subscribe_msg = json!({
"command": "subscribe",
"events": ["workspace"]
});
// Handle workspace change
fn handle_gar_event(&mut self, event: GarEvent) {
match event {
GarEvent::Workspace { current, .. } => {
if let Some(config) = self.config.workspaces.get(¤t) {
self.set_wallpaper(&config.source, config.mode);
}
}
_ => {}
}
}
Files Modified/Created
/garbg/garbg/src/daemon/mod.rs- Daemon module/garbg/garbg/src/daemon/state.rs- Daemon state management/garbg/garbg/src/daemon/event_loop.rs- Main event loop/garbg/garbg/src/daemon/signals.rs- Signal handling/garbg/garbg/src/ipc/mod.rs- IPC module/garbg/garbg/src/ipc/server.rs- IPC server/garbg/garbg/src/ipc/protocol.rs- Command/Response types/garbg/garbg/src/ipc/gar_client.rs- gar IPC client
View source
| 1 | # Phase 4: Daemon Mode & gar Integration |
| 2 | |
| 3 | ## Goal |
| 4 | Implement daemon mode with IPC server, integrate with gar window manager for workspace-aware wallpapers. |
| 5 | |
| 6 | ## Tasks |
| 7 | |
| 8 | ### 4.1 Daemon Mode |
| 9 | - [ ] Daemonize process (fork, setsid, etc.) |
| 10 | - [ ] PID file management |
| 11 | - [ ] Signal handling (SIGHUP for reload, SIGTERM for shutdown) |
| 12 | - [ ] Graceful shutdown with resource cleanup |
| 13 | |
| 14 | ### 4.2 IPC Server |
| 15 | - [ ] Unix socket at `$XDG_RUNTIME_DIR/garbg.sock` |
| 16 | - [ ] JSON lines protocol |
| 17 | - [ ] Command parsing and dispatch |
| 18 | - [ ] Response serialization |
| 19 | - [ ] Client connection management |
| 20 | |
| 21 | ### 4.3 IPC Commands |
| 22 | - [ ] `set` - Set wallpaper |
| 23 | - [ ] `next` / `prev` - Slideshow navigation |
| 24 | - [ ] `random` - Random wallpaper from source |
| 25 | - [ ] `reload` - Reload configuration |
| 26 | - [ ] `pause` / `resume` - Animation/slideshow control |
| 27 | - [ ] `status` - Get current state |
| 28 | - [ ] `subscribe` - Event subscription |
| 29 | |
| 30 | ### 4.4 gar IPC Client |
| 31 | - [ ] Connect to gar's IPC socket |
| 32 | - [ ] Subscribe to workspace events |
| 33 | - [ ] Subscribe to monitor events |
| 34 | - [ ] Parse gar's JSON event format |
| 35 | |
| 36 | ### 4.5 Per-Workspace Wallpapers |
| 37 | - [ ] Map workspace ID to wallpaper config |
| 38 | - [ ] Switch wallpaper on workspace change |
| 39 | - [ ] Smooth transition (instant, per design decision) |
| 40 | - [ ] Fallback to default wallpaper |
| 41 | |
| 42 | ### 4.6 Slideshow/Rotation |
| 43 | - [ ] Timer-based rotation |
| 44 | - [ ] Configurable interval |
| 45 | - [ ] Random or sequential ordering |
| 46 | - [ ] Per-source playlist management |
| 47 | |
| 48 | ## Deliverables |
| 49 | - `garbg daemon` starts background daemon |
| 50 | - `garbgctl set /path/to/image.png` sends command to daemon |
| 51 | - Changing workspaces in gar changes wallpaper |
| 52 | - Slideshow rotates wallpapers at configured interval |
| 53 | |
| 54 | ## IPC Protocol |
| 55 | |
| 56 | ### Commands (Client -> Server) |
| 57 | |
| 58 | ```json |
| 59 | {"command": "set", "source": "/path/to/image.png", "mode": "fill"} |
| 60 | {"command": "next"} |
| 61 | {"command": "prev"} |
| 62 | {"command": "random"} |
| 63 | {"command": "reload"} |
| 64 | {"command": "pause"} |
| 65 | {"command": "resume"} |
| 66 | {"command": "status"} |
| 67 | {"command": "subscribe", "events": ["wallpaper_changed", "slideshow_advanced"]} |
| 68 | ``` |
| 69 | |
| 70 | ### Responses (Server -> Client) |
| 71 | |
| 72 | ```json |
| 73 | {"success": true} |
| 74 | {"success": true, "data": {"current": "/path/to/image.png", "mode": "fill", "paused": false}} |
| 75 | {"success": false, "error": "File not found"} |
| 76 | ``` |
| 77 | |
| 78 | ### Events (Server -> Subscribed Clients) |
| 79 | |
| 80 | ```json |
| 81 | {"event": "wallpaper_changed", "source": "/path/to/new.png", "workspace": 1} |
| 82 | {"event": "slideshow_advanced", "current": 5, "total": 20} |
| 83 | {"event": "error", "message": "Failed to fetch remote image"} |
| 84 | ``` |
| 85 | |
| 86 | ## gar Event Handling |
| 87 | |
| 88 | ```rust |
| 89 | // Subscribe to gar workspace events |
| 90 | let subscribe_msg = json!({ |
| 91 | "command": "subscribe", |
| 92 | "events": ["workspace"] |
| 93 | }); |
| 94 | |
| 95 | // Handle workspace change |
| 96 | fn handle_gar_event(&mut self, event: GarEvent) { |
| 97 | match event { |
| 98 | GarEvent::Workspace { current, .. } => { |
| 99 | if let Some(config) = self.config.workspaces.get(¤t) { |
| 100 | self.set_wallpaper(&config.source, config.mode); |
| 101 | } |
| 102 | } |
| 103 | _ => {} |
| 104 | } |
| 105 | } |
| 106 | ``` |
| 107 | |
| 108 | ## Files Modified/Created |
| 109 | - `/garbg/garbg/src/daemon/mod.rs` - Daemon module |
| 110 | - `/garbg/garbg/src/daemon/state.rs` - Daemon state management |
| 111 | - `/garbg/garbg/src/daemon/event_loop.rs` - Main event loop |
| 112 | - `/garbg/garbg/src/daemon/signals.rs` - Signal handling |
| 113 | - `/garbg/garbg/src/ipc/mod.rs` - IPC module |
| 114 | - `/garbg/garbg/src/ipc/server.rs` - IPC server |
| 115 | - `/garbg/garbg/src/ipc/protocol.rs` - Command/Response types |
| 116 | - `/garbg/garbg/src/ipc/gar_client.rs` - gar IPC client |