448 lines
13 KiB
Markdown
448 lines
13 KiB
Markdown
# Dynamic Theme Switcher Module
|
|
|
|
A NixOS module that automatically generates and applies color themes from wallpapers using pywal16, with integrated wpaperd wallpaper management and support for GTK, Qt/Kvantum, Ghostty, and other applications.
|
|
|
|
## Features
|
|
|
|
- **Integrated Wallpaper Management**: Built-in wpaperd integration with configurable rotation modes
|
|
- **Automatic Color Extraction**: Uses pywal16 with configurable backends (haishoku, colorthief, etc.) to extract color palettes from wallpapers
|
|
- **Multi-Application Support**: Generates themes for GTK 3.0, GTK 4.0, Qt/Kvantum, Ghostty terminal, and more
|
|
- **Time-Based Switching**: Automatically switches between light and dark themes based on configured times
|
|
- **Flexible Rotation Modes**: Choose between continuous rotation, switch-only, or hybrid modes
|
|
- **Manual Control**: Provides scripts for manual theme switching
|
|
- **Synchronized Wallpaper & Theme**: Wallpaper and color theme always match
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
theme_switcher/
|
|
├── default.nix # Main module configuration
|
|
├── templates/
|
|
│ ├── gtk-3.0.css # GTK 3.0 theme template
|
|
│ ├── gtk-4.0.css # GTK 4.0 theme template
|
|
│ └── PywalTheme.kvconfig # Kvantum Qt theme template
|
|
├── OUTLINE.md # Implementation specification
|
|
└── README.md # This file
|
|
```
|
|
|
|
## Installation
|
|
|
|
### 1. Import the Module
|
|
|
|
Add the module to your host configuration:
|
|
|
|
```nix
|
|
# In your host's configuration.nix or desktop-configuration.nix
|
|
imports = [
|
|
../../shared/modules/services/theme_switcher
|
|
];
|
|
```
|
|
|
|
### 2. Enable and Configure
|
|
|
|
```nix
|
|
services.themeSwitcher = {
|
|
enable = true;
|
|
user = "yourUsername";
|
|
|
|
# Optional: Customize settings
|
|
backend = "haishoku"; # Color extraction backend
|
|
lightTime = "06:00:00"; # Switch to light theme at 6 AM
|
|
darkTime = "18:00:00"; # Switch to dark theme at 6 PM
|
|
enableAutoSwitch = true; # Enable automatic time-based switching
|
|
|
|
# Wallpaper rotation settings
|
|
rotation = {
|
|
mode = "continuous"; # Options: continuous, switch-only, hybrid
|
|
interval = "5m"; # Rotation interval (for continuous mode)
|
|
};
|
|
|
|
# Wpaperd configuration
|
|
wpaperd = {
|
|
enable = true;
|
|
mode = "center"; # Options: center, fit, stretch, tile
|
|
transition.effect = "fade";
|
|
transition.duration = 300; # milliseconds
|
|
};
|
|
};
|
|
```
|
|
|
|
**Note:** If you were previously using the separate `wallpaper-rotator` module, you should disable it to avoid conflicts.
|
|
|
|
### 3. Wallpaper Directory Structure
|
|
|
|
Ensure your wallpaper directory has Light and Dark subdirectories:
|
|
|
|
```
|
|
wallpapers/
|
|
├── Light/
|
|
│ ├── wallpaper1.jpg
|
|
│ ├── wallpaper2.jpg
|
|
│ └── ...
|
|
└── Dark/
|
|
├── wallpaper1.jpg
|
|
├── wallpaper2.jpg
|
|
└── ...
|
|
```
|
|
|
|
### 4. Rebuild Your System
|
|
|
|
```bash
|
|
sudo nixos-rebuild switch --flake .#hostname
|
|
```
|
|
|
|
## Configuration Options
|
|
|
|
### Core Options
|
|
|
|
#### `services.themeSwitcher.enable`
|
|
- **Type**: boolean
|
|
- **Default**: false
|
|
- **Description**: Enable the dynamic theme switcher with integrated wallpaper management
|
|
|
|
#### `services.themeSwitcher.user`
|
|
- **Type**: string
|
|
- **Required**: yes
|
|
- **Description**: Username for which to apply theme switching
|
|
|
|
#### `services.themeSwitcher.wallpaperPath`
|
|
- **Type**: string
|
|
- **Default**: `${homeDirectory}/nixos/shared/modules/services/wallpapers`
|
|
- **Description**: Path to wallpaper directories (must contain Light/ and Dark/ subdirectories)
|
|
|
|
#### `services.themeSwitcher.backend`
|
|
- **Type**: enum
|
|
- **Default**: `"haishoku"`
|
|
- **Options**: `"haishoku"`, `"modern_colorthief"`, `"fast_colorthief"`, `"colorthief"`, `"colorz"`, `"wal"`
|
|
- **Description**: Pywal color extraction backend algorithm
|
|
|
|
#### `services.themeSwitcher.lightTime`
|
|
- **Type**: string
|
|
- **Default**: `"06:00:00"`
|
|
- **Description**: Time to switch to light theme (HH:MM:SS format)
|
|
|
|
#### `services.themeSwitcher.darkTime`
|
|
- **Type**: string
|
|
- **Default**: `"18:00:00"`
|
|
- **Description**: Time to switch to dark theme (HH:MM:SS format)
|
|
|
|
#### `services.themeSwitcher.enableAutoSwitch`
|
|
- **Type**: boolean
|
|
- **Default**: true
|
|
- **Description**: Enable automatic time-based theme switching via systemd timer
|
|
|
|
### Rotation Options
|
|
|
|
#### `services.themeSwitcher.rotation.mode`
|
|
- **Type**: enum
|
|
- **Default**: `"continuous"`
|
|
- **Options**:
|
|
- `"continuous"`: Rotate wallpapers every interval AND regenerate theme each time
|
|
- `"switch-only"`: Only change wallpaper at light/dark switch times (6 AM/6 PM)
|
|
- `"hybrid"`: Rotate wallpapers but only regenerate theme at switch times (not yet implemented)
|
|
- **Description**: Wallpaper rotation and theme generation behavior
|
|
|
|
#### `services.themeSwitcher.rotation.interval`
|
|
- **Type**: string
|
|
- **Default**: `"5m"`
|
|
- **Example**: `"30s"`, `"10m"`, `"1h"`
|
|
- **Description**: How often to rotate wallpapers in continuous mode
|
|
|
|
#### `services.themeSwitcher.rotation.sorting`
|
|
- **Type**: enum
|
|
- **Default**: `"random"`
|
|
- **Options**: `"random"`
|
|
- **Description**: Wallpaper selection method (currently only random is supported)
|
|
|
|
### Wpaperd Integration Options
|
|
|
|
#### `services.themeSwitcher.wpaperd.enable`
|
|
- **Type**: boolean
|
|
- **Default**: true
|
|
- **Description**: Enable wpaperd wallpaper daemon integration
|
|
|
|
#### `services.themeSwitcher.wpaperd.mode`
|
|
- **Type**: enum
|
|
- **Default**: `"center"`
|
|
- **Options**: `"center"`, `"fit"`, `"fit-border-color"`, `"stretch"`, `"tile"`
|
|
- **Description**: How to display wallpapers when size differs from display resolution
|
|
|
|
#### `services.themeSwitcher.wpaperd.transition.effect`
|
|
- **Type**: string
|
|
- **Default**: `"fade"`
|
|
- **Example**: `"simple"`, `"fade"`
|
|
- **Description**: Wallpaper transition effect name
|
|
|
|
#### `services.themeSwitcher.wpaperd.transition.duration`
|
|
- **Type**: integer
|
|
- **Default**: 300
|
|
- **Description**: Transition duration in milliseconds
|
|
|
|
## Manual Usage
|
|
|
|
### Apply Theme Manually
|
|
|
|
The module installs `apply-theme.sh` to `~/.local/bin/`:
|
|
|
|
```bash
|
|
# Apply light theme with random wallpaper from Light/ directory
|
|
~/.local/bin/apply-theme.sh --light
|
|
|
|
# Apply dark theme with random wallpaper from Dark/ directory
|
|
~/.local/bin/apply-theme.sh --dark
|
|
|
|
# Apply theme with specific wallpaper
|
|
~/.local/bin/apply-theme.sh --light --wallpaper-path /path/to/wallpaper.jpg
|
|
```
|
|
|
|
### Check Systemd Timer Status
|
|
|
|
```bash
|
|
# View timer status
|
|
systemctl --user status theme-switcher.timer
|
|
|
|
# List upcoming timer events
|
|
systemctl --user list-timers | grep theme
|
|
|
|
# Manually trigger theme switch
|
|
systemctl --user start theme-switcher.service
|
|
|
|
# View service logs
|
|
journalctl --user -u theme-switcher.service
|
|
```
|
|
|
|
### Test Pywal Color Extraction
|
|
|
|
```bash
|
|
# Test light theme generation
|
|
wal -i ~/nixos/shared/modules/services/wallpapers/Light/IU-Light.jpg --backend haishoku -l -n
|
|
|
|
# Test dark theme generation
|
|
wal -i ~/nixos/shared/modules/services/wallpapers/Dark/IU-Dark.jpg --backend haishoku -n
|
|
|
|
# View generated colors
|
|
cat ~/.cache/wal/colors.json
|
|
|
|
# View generated templates
|
|
ls -la ~/.cache/wal/
|
|
```
|
|
|
|
## Generated Files
|
|
|
|
After running the theme switcher, pywal generates the following files:
|
|
|
|
### Pywal Cache (`~/.cache/wal/`)
|
|
- `colors.json` - Extracted color palette in JSON format
|
|
- `colors.sh` - Shell script with color variables
|
|
- `ghostty.conf` - Ghostty terminal theme (auto-reloads)
|
|
- `gtk-3.0.css` - GTK 3.0 theme (from custom template)
|
|
- `gtk-4.0.css` - GTK 4.0 theme (from custom template)
|
|
- `PywalTheme.kvconfig` - Kvantum Qt theme (from custom template)
|
|
|
|
### User Configuration
|
|
- `~/.config/gtk-3.0/gtk.css` - Symlink to pywal-generated GTK3 theme
|
|
- `~/.config/gtk-4.0/gtk.css` - Symlink to pywal-generated GTK4 theme
|
|
- `~/.config/Kvantum/PywalTheme/PywalTheme.kvconfig` - Kvantum theme copy
|
|
|
|
## Integration with Existing Themes
|
|
|
|
When enabling this module, you should adjust your existing theme configuration:
|
|
|
|
### Before (Static Catppuccin Theme)
|
|
```nix
|
|
gtk = {
|
|
enable = true;
|
|
theme = {
|
|
name = "catppuccin-macchiato-lavender-compact+rimless";
|
|
package = pkgs.catppuccin-gtk.override { ... };
|
|
};
|
|
};
|
|
|
|
qt = {
|
|
enable = true;
|
|
platformTheme.name = "kvantum";
|
|
style.name = "kvantum";
|
|
};
|
|
|
|
xdg.configFile."Kvantum/kvantum.kvconfig".source = ...;
|
|
```
|
|
|
|
### After (Dynamic Pywal Theme)
|
|
```nix
|
|
# The theme switcher module automatically sets:
|
|
# - gtk.enable = true
|
|
# - qt.enable = true
|
|
# - qt.platformTheme.name = "kvantum"
|
|
# - qt.style.name = "kvantum"
|
|
|
|
# You can still keep static icon and cursor themes:
|
|
gtk.iconTheme = {
|
|
name = "Papirus-Dark";
|
|
package = pkgs.catppuccin-papirus-folders;
|
|
};
|
|
|
|
gtk.cursorTheme = {
|
|
name = "Bibata-Modern-Classic";
|
|
package = pkgs.bibata-cursors;
|
|
};
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Theme Not Applying
|
|
```bash
|
|
# Check if pywal generated files
|
|
ls -la ~/.cache/wal/
|
|
|
|
# Check systemd service status
|
|
systemctl --user status theme-switcher.service
|
|
|
|
# View detailed logs
|
|
journalctl --user -u theme-switcher.service -n 50
|
|
|
|
# Manually run apply-theme.sh with verbose output
|
|
~/.local/bin/apply-theme.sh --light
|
|
```
|
|
|
|
### Kvantum Theme Not Working
|
|
```bash
|
|
# Check if Kvantum theme was created
|
|
ls -la ~/.config/Kvantum/PywalTheme/
|
|
|
|
# Manually set Kvantum theme
|
|
kvantummanager --set PywalTheme
|
|
|
|
# Check if Qt applications are using Kvantum
|
|
echo $QT_STYLE_OVERRIDE # Should be "kvantum"
|
|
```
|
|
|
|
### Colors Don't Match Wallpaper
|
|
Try a different pywal backend:
|
|
```nix
|
|
services.themeSwitcher.backend = "modern_colorthief"; # or "fast_colorthief", "colorthief", etc.
|
|
```
|
|
|
|
### GTK Applications Not Updating
|
|
```bash
|
|
# Check if GTK CSS files exist
|
|
ls -la ~/.config/gtk-3.0/gtk.css
|
|
ls -la ~/.config/gtk-4.0/gtk.css
|
|
|
|
# Restart GTK applications for changes to take effect
|
|
```
|
|
|
|
## Supported Applications
|
|
|
|
### Automatically Themed
|
|
- **GTK 3 Applications**: Nautilus, GNOME Calculator, etc.
|
|
- **GTK 4 Applications**: GNOME Text Editor, newer GNOME apps
|
|
- **Qt Applications**: KDE apps when using Kvantum
|
|
- **Ghostty Terminal**: Auto-reloads on config change
|
|
- **Waybar**: If using pywal template (built-in)
|
|
- **Rofi**: If using pywal template (built-in)
|
|
- **Hyprland/Sway**: If using pywal template (built-in)
|
|
|
|
### Manual Integration Required
|
|
- **Firefox**: Use pywal-firefox extension
|
|
- **VSCode**: Use pywal theme extension
|
|
- **Other Applications**: Check if pywal templates exist in `~/.cache/wal/`
|
|
|
|
## Advanced Usage
|
|
|
|
### Custom Pywal Templates
|
|
|
|
To add your own templates, create files in `~/.config/wal/templates/`:
|
|
|
|
```bash
|
|
# Template file: ~/.config/wal/templates/myapp.conf
|
|
# Use pywal template variables
|
|
background = {background}
|
|
foreground = {foreground}
|
|
color0 = {color0}
|
|
...
|
|
color15 = {color15}
|
|
```
|
|
|
|
After running `apply-theme.sh`, find your generated file in `~/.cache/wal/myapp.conf`.
|
|
|
|
### Disable Automatic Switching
|
|
|
|
To use manual control only:
|
|
```nix
|
|
services.themeSwitcher = {
|
|
enable = true;
|
|
user = "username";
|
|
enableAutoSwitch = false; # Disable timer
|
|
};
|
|
```
|
|
|
|
Then use `~/.local/bin/apply-theme.sh` manually as needed.
|
|
|
|
### Rotation Modes Explained
|
|
|
|
#### Continuous Mode (Default)
|
|
- Wallpaper rotates every interval (e.g., 5 minutes)
|
|
- Theme is regenerated from each new wallpaper
|
|
- Wallpaper and theme always match
|
|
- **Resource usage**: Moderate (pywal runs every interval)
|
|
- **Best for**: Users who want frequently changing, perfectly matched themes
|
|
|
|
#### Switch-Only Mode
|
|
- Wallpaper changes only at light/dark switch times (6 AM / 6 PM)
|
|
- Theme is generated once per switch
|
|
- Wallpaper and theme always match
|
|
- **Resource usage**: Minimal (pywal runs twice per day)
|
|
- **Best for**: Users who prefer consistent themes throughout the day
|
|
|
|
#### Hybrid Mode (Future)
|
|
- Wallpaper rotates every interval
|
|
- Theme is generated only at switch times
|
|
- Wallpaper and theme may not match mid-day
|
|
- **Not yet implemented**
|
|
|
|
### Migration from wallpaper-rotator Module
|
|
|
|
If you were previously using the separate `wallpaper-rotator` module:
|
|
|
|
1. **Disable the old module** in your configuration:
|
|
```nix
|
|
# Comment out or remove:
|
|
# services.wallpaperRotator.enable = true;
|
|
```
|
|
|
|
2. **Enable themeSwitcher** with equivalent settings:
|
|
```nix
|
|
services.themeSwitcher = {
|
|
enable = true;
|
|
user = "yourUsername";
|
|
rotation.interval = "5m"; # Same as old duration setting
|
|
wpaperd.mode = "center"; # Same as old mode setting
|
|
};
|
|
```
|
|
|
|
3. **Rebuild** your system - wpaperd will now be managed by themeSwitcher
|
|
|
|
## Technical Details
|
|
|
|
- **Pywal Template Syntax**: `{background}`, `{foreground}`, `{color0}`-`{color15}`, `{cursor}`, `{wallpaper}`
|
|
- **Template Location**: `~/.config/wal/templates/filename.ext`
|
|
- **Output Location**: `~/.cache/wal/filename.ext`
|
|
- **Color Extraction**: 16-color palette using pywal16
|
|
- **GTK Reload**: Automatic via gsettings changes
|
|
- **Kvantum Reload**: May require app restart
|
|
- **Ghostty Reload**: Automatic on config file change
|
|
|
|
## Future Enhancements
|
|
|
|
- Direct wpaperd integration (trigger theme change on wallpaper rotation)
|
|
- Per-monitor theme configuration
|
|
- Additional application templates (Firefox, VSCode, etc.)
|
|
- Theme preview before applying
|
|
- Fallback color schemes for monochrome wallpapers
|
|
|
|
## Credits
|
|
|
|
- Built for NixOS using home-manager
|
|
- Uses [pywal16](https://github.com/eylles/pywal16) for color extraction
|
|
- Based on [pywal](https://github.com/dylanaraps/pywal) original concept
|