Compare commits
43 Commits
3ddeb31eeb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e38480e320 | |||
| 86d27b80d8 | |||
| ca62a6bd19 | |||
| 66e65b91ea | |||
| 642ff1820e | |||
| 438296b01b | |||
| 20c8ecb0bd | |||
| c784df06fd | |||
| 3b2ccc8417 | |||
| d9966d8f38 | |||
| eb58a62168 | |||
| c74f623232 | |||
| 8224513e07 | |||
| 87a2314170 | |||
| 82a84e00cc | |||
| 5f2c19346c | |||
| 86b48a65c7 | |||
| e8599dd250 | |||
| d4d1e0a5d4 | |||
| 6268fe3b00 | |||
| 5c62858c37 | |||
| 93de9d3665 | |||
| d7b5343864 | |||
| 3d0222abe9 | |||
| 077c938388 | |||
| 20977180da | |||
| 422ca50e45 | |||
| cdd29be844 | |||
| 01c02381ce | |||
| aaedafac2d | |||
| 22eceb0fd0 | |||
| 67b23f68e2 | |||
| 845b24f943 | |||
| f4f6080e3e | |||
| f258504147 | |||
| b57a2c6c6f | |||
| 7af9e4d4b2 | |||
| f544ea67fe | |||
| 778b01fed9 | |||
| 9b27f664bd | |||
| 98fcca1a7a | |||
| 3c9d9e9529 | |||
| 0dfa99f638 |
48
.github/copilot-instructions.md
vendored
Normal file
48
.github/copilot-instructions.md
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
# Copilot Instructions for EmergentMind's Nix-Config
|
||||
|
||||
## Project Overview
|
||||
- This is a modular, flake-based NixOS configuration system for managing multiple hosts, users, and environments (NixOS, Darwin, Home Manager).
|
||||
- The repo is structured for maximum composability: core logic is split into `hosts/`, `home/`, `modules/`, and `overlays/` with heavy use of imports and attribute sets.
|
||||
- Secrets are managed via a private `nix-secrets` repo and sops-nix, integrated as a flake input (see docs/secretsmgmt.md).
|
||||
|
||||
## Key Architectural Patterns
|
||||
- **Host configs**: Each host (machine) has its own directory under `hosts/nixos/` or `hosts/darwin/`, with a `default.nix` that imports shared and host-specific modules.
|
||||
- **User configs**: User-level Home Manager configs live in `home/<user>/<host>.nix` and are imported by host configs.
|
||||
- **Common logic**: Shared modules for users and hosts are in `hosts/common/` and `home/exampleSecondUser/common/` etc.
|
||||
- **Optional features**: Features like desktops, shells, and services are split into `common/optional/` submodules and imported as needed.
|
||||
- **Installer**: The `nixos-installer/` flake provides a minimal environment and scripts for bootstrapping new machines.
|
||||
|
||||
## Developer Workflows
|
||||
- **Build & switch**: Use `just` commands (see `justfile`) for common workflows, e.g. `just switch`, `just iso`, or run `nixos-rebuild switch --flake .#<hostname>`.
|
||||
- **Testing**: Tests are in `tests/` and use `bats` for shell scripts. Run with `just test`.
|
||||
- **Secrets**: To update secrets, edit the `nix-secrets` repo and re-pull as a flake input.
|
||||
- **Installer**: See `nixos-installer/README.md` for remote install and ISO generation.
|
||||
|
||||
## Project-Specific Conventions
|
||||
- **Imports**: Always use relative imports and `lib.flatten` for lists of modules.
|
||||
- **pkgs**: Always passed as an argument; use `with pkgs; [...]` for package lists.
|
||||
- **Shells**: Shell configs (fish, zsh, nushell) are in `home/panotaka/common/core/shell/` and imported as needed.
|
||||
- **Hyprland**: Desktop config is modularized; plugins and settings are split into separate files (see `home/panotaka/common/optional/desktops/hyprland/`).
|
||||
- **Keybinds**: For Hyprland, keybinds can be set in feature modules (e.g. hyprlock) using `wayland.windowManager.hyprland.keybinds`.
|
||||
- **Packages**: Each feature module (e.g. hyprlock, hypridle) is responsible for adding its own package to `home.packages`.
|
||||
|
||||
## Integration Points
|
||||
- **Secrets**: sops-nix, private flake input, see `docs/secretsmgmt.md`.
|
||||
- **Disk layout**: Uses disko for declarative disk partitioning, see `hosts/common/disks/`.
|
||||
- **Theming**: Stylix is used for theming, imported as a flake input.
|
||||
- **Remote install**: `nixos-installer/` flake and scripts for remote/automated setup.
|
||||
|
||||
## Examples
|
||||
- To add a new desktop feature, create a module in `common/optional/desktops/` and import it in the host or user config.
|
||||
- To add a new shell, create a module in `common/core/shell/` and import it in the user config.
|
||||
- To add a new host, create a directory in `hosts/nixos/` and a matching user config in `home/<user>/`.
|
||||
|
||||
## Key Files & Directories
|
||||
- `flake.nix`, `flake.lock`: Flake entrypoints
|
||||
- `hosts/`, `home/`, `modules/`, `overlays/`: Core config structure
|
||||
- `nixos-installer/`: Bootstrap/installer logic
|
||||
- `docs/secretsmgmt.md`: Secrets management details
|
||||
- `justfile`: Common developer commands
|
||||
|
||||
---
|
||||
If you are unsure about a pattern, check for similar logic in the `common/optional/` or `common/core/` directories, and follow the import structure used in host/user configs.
|
||||
43
docs/lxqt-niri-setup.md
Normal file
43
docs/lxqt-niri-setup.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Example: Enabling LXQt with Niri Window Manager
|
||||
|
||||
To use LXQt with Niri as the window manager in your NixOS configuration, add the following to your host configuration:
|
||||
|
||||
```nix
|
||||
{
|
||||
imports = lib.flatten [
|
||||
# ... other imports ...
|
||||
"hosts/common/optional/lxqt-niri.nix"
|
||||
"hosts/common/optional/gdm.nix" # or sddm.nix for SDDM display manager
|
||||
# ... other imports ...
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
## What this provides
|
||||
|
||||
- **LXQt Desktop Environment**: Full LXQt suite including panel, file manager, settings tools, and applications
|
||||
- **Niri Window Manager**: Modern tiling Wayland compositor with smooth animations
|
||||
- **Qt Theming**: Proper Qt theming integration with LXQt themes and Kvantum support
|
||||
- **System Integration**: Audio (PipeWire), network management, power management, and hardware support
|
||||
- **XDG Portals**: Screen sharing and file picker integration for Wayland applications
|
||||
|
||||
## Session Selection
|
||||
|
||||
After adding this configuration and rebuilding your system, you'll see "LXQt (Niri)" as an option in your display manager's session selection menu.
|
||||
|
||||
## Additional Notes
|
||||
|
||||
- The configuration enables X11 server support for compatibility with X11-only applications
|
||||
- Network management is handled through NetworkManager with Qt frontend
|
||||
- Audio is configured with PipeWire for low-latency audio
|
||||
- The setup includes proper polkit integration for system authentication dialogs
|
||||
- Bluetooth support is enabled by default
|
||||
|
||||
## Customization
|
||||
|
||||
You can further customize the LXQt-Niri experience by:
|
||||
|
||||
- Adding additional LXQt applications to your user packages
|
||||
- Configuring Niri-specific settings through its configuration files
|
||||
- Using LXQt's appearance settings to customize themes and styling
|
||||
- Adding additional Qt applications that integrate well with the LXQt environment
|
||||
185
docs/uwsm-migration-summary.md
Normal file
185
docs/uwsm-migration-summary.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# UWSM Migration Complete ✅
|
||||
|
||||
## Summary
|
||||
|
||||
The Niri desktop environment has been **fully migrated** to UWSM (Universal Wayland Session Manager) for comprehensive systemd-based session management.
|
||||
|
||||
## What Changed
|
||||
|
||||
### 1. Session Launch (Host-Level)
|
||||
|
||||
**Before:**
|
||||
- Manual desktop entry files in `/etc/wayland-sessions/`
|
||||
- Manual UWSM package installation
|
||||
|
||||
**After:**
|
||||
```nix
|
||||
programs.uwsm = {
|
||||
enable = true;
|
||||
waylandCompositors.niri = {
|
||||
prettyName = "Niri";
|
||||
comment = "Niri scrollable-tiling Wayland compositor managed by UWSM";
|
||||
binPath = "/run/current-system/sw/bin/niri-session";
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Startup Applications (Home-Manager)
|
||||
|
||||
**Before:** Using `programs.niri.settings.spawn-at-startup`
|
||||
|
||||
**After:** Using `systemd.user.services` with proper targets
|
||||
|
||||
| Service | Type | Purpose |
|
||||
|---------|------|---------|
|
||||
| `nm-applet` | simple | Network manager tray icon |
|
||||
| `zenbook-autostart` | oneshot | Initial display setup |
|
||||
| `zenbook-delayed-setup` | oneshot | Secondary setup after delay |
|
||||
| `zenbook-inotify-monitor` | simple | DRM status change monitor |
|
||||
| `zenbook-udev-monitor` | simple | udev event monitor |
|
||||
|
||||
All services:
|
||||
- `PartOf = ["graphical-session.target"]` - proper lifecycle
|
||||
- `After = ["graphical-session.target"]` - correct ordering
|
||||
- `WantedBy = ["graphical-session.target"]` - auto-start
|
||||
- `Restart` policies for resilience
|
||||
|
||||
### 3. Application Launches (Keybinds)
|
||||
|
||||
**Before:** Direct binary execution
|
||||
```nix
|
||||
programs.niri.settings.binds."Mod+Return".action.spawn = ["${pkgs.fuzzel}/bin/fuzzel"];
|
||||
```
|
||||
|
||||
**After:** UWSM app wrapper
|
||||
```nix
|
||||
programs.niri.settings.binds."Mod+Return".action.spawn = ["uwsm" "app" "--" "${pkgs.fuzzel}/bin/fuzzel"];
|
||||
```
|
||||
|
||||
All keybinds now use `uwsm app --`:
|
||||
- `Mod+Return` → fuzzel launcher
|
||||
- `Mod+L` → swaylock
|
||||
- `Mod+Z` → zenbook-set-displays
|
||||
|
||||
### 4. Fuzzel Launcher Configuration
|
||||
|
||||
Fuzzel now has `launch-prefix` configured:
|
||||
```nix
|
||||
settings.main.launch-prefix = "uwsm app -- ";
|
||||
```
|
||||
|
||||
This means apps launched from fuzzel are automatically placed in the correct systemd slice.
|
||||
|
||||
## Benefits Achieved
|
||||
|
||||
1. **✅ Environment Variable Inheritance**
|
||||
- Login shell → PAM → systemd → compositor → applications
|
||||
- All environment properly propagated
|
||||
|
||||
2. **✅ Systemd Integration**
|
||||
- All services bound to `graphical-session.target`
|
||||
- Proper dependency ordering and lifecycle management
|
||||
|
||||
3. **✅ Application Slicing**
|
||||
- Apps launched via `uwsm app --` go into `app-graphical.slice`
|
||||
- Better resource management and isolation
|
||||
|
||||
4. **✅ Clean Shutdown**
|
||||
- Proper cleanup when session ends
|
||||
- Services stopped in correct order
|
||||
|
||||
5. **✅ Resilience**
|
||||
- Services auto-restart on failure
|
||||
- Configurable restart policies
|
||||
|
||||
6. **✅ Standards Compliance**
|
||||
- Follows systemd graphical session standards
|
||||
- Compatible with XDG autostart (if needed)
|
||||
|
||||
## How to Use
|
||||
|
||||
### From Display Manager
|
||||
|
||||
Select **"Niri"** from your display manager (GDM, SDDM, etc.)
|
||||
|
||||
The session is now automatically launched via UWSM with full session management.
|
||||
|
||||
### From TTY
|
||||
|
||||
```bash
|
||||
# Launch via UWSM
|
||||
uwsm start niri
|
||||
```
|
||||
|
||||
### Verify UWSM is Active
|
||||
|
||||
```bash
|
||||
# Check UWSM status
|
||||
uwsm status
|
||||
|
||||
# List UWSM-managed units
|
||||
systemctl --user list-units 'wayland-*'
|
||||
|
||||
# Check graphical session services
|
||||
systemctl --user list-units --type=service | grep graphical
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
```bash
|
||||
# Check specific service
|
||||
systemctl --user status nm-applet
|
||||
|
||||
# View logs
|
||||
journalctl --user -u zenbook-inotify-monitor -f
|
||||
|
||||
# List all services in graphical session
|
||||
systemctl --user list-dependencies graphical-session.target
|
||||
```
|
||||
|
||||
## Files Modified
|
||||
|
||||
| File | Changes |
|
||||
|------|---------|
|
||||
| `hosts/common/optional/niri.nix` | Added `programs.uwsm` module |
|
||||
| `home/.../niri/waybar.nix` | nm-applet → systemd service |
|
||||
| `home/.../niri/zenbook-screen.nix` | All tools → systemd services, keybind uses `uwsm app` |
|
||||
| `home/.../niri/fuzzel.nix` | Keybind + launch-prefix use `uwsm app` |
|
||||
| `home/.../niri/swaylock.nix` | Keybind uses `uwsm app` |
|
||||
| `docs/uwsm-niri-integration.md` | Updated documentation |
|
||||
|
||||
## Testing
|
||||
|
||||
After rebuilding:
|
||||
|
||||
1. Log out and select "Niri" from display manager
|
||||
2. Log in and verify all components work:
|
||||
- Waybar appears with tray icons
|
||||
- nm-applet icon visible in tray
|
||||
- `Mod+Return` opens fuzzel
|
||||
- `Mod+L` locks screen
|
||||
- Zenbook displays configured correctly
|
||||
|
||||
3. Check systemd services:
|
||||
```bash
|
||||
systemctl --user status nm-applet waybar zenbook-autostart
|
||||
```
|
||||
|
||||
4. Launch an app from fuzzel and verify it's in the right slice:
|
||||
```bash
|
||||
systemctl --user list-units --type=service | grep app-
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
See `docs/uwsm-niri-integration.md` for:
|
||||
- Detailed UWSM concepts
|
||||
- Troubleshooting guide
|
||||
- Advanced configuration options
|
||||
- Environment variable management
|
||||
|
||||
## References
|
||||
|
||||
- [UWSM GitHub](https://github.com/vladimir-csp/uwsm)
|
||||
- [NixOS UWSM Module](https://mynixos.com/nixpkgs/options/programs.uwsm)
|
||||
- [UWSM Documentation](https://github.com/vladimir-csp/uwsm/blob/master/README.md)
|
||||
248
docs/uwsm-niri-integration.md
Normal file
248
docs/uwsm-niri-integration.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# UWSM Integration with Niri
|
||||
|
||||
## Status: ✅ FULLY INTEGRATED
|
||||
|
||||
This Niri configuration has been **fully migrated** to use UWSM (Universal Wayland Session Manager) for comprehensive systemd-based session management.
|
||||
|
||||
All components now use UWSM:
|
||||
- ✅ Session launch via `programs.uwsm.waylandCompositors`
|
||||
- ✅ Startup applications via `systemd.user.services` with `graphical-session.target`
|
||||
- ✅ Application launches via `uwsm app --` wrapper (for proper systemd slice placement)
|
||||
- ✅ Fuzzel launcher configured with UWSM launch-prefix
|
||||
|
||||
## Overview
|
||||
|
||||
UWSM (Universal Wayland Session Manager) is a systemd-based session manager that provides:
|
||||
|
||||
1. **Proper environment variable inheritance** - Ensures environment variables from login shells, PAM, and system profiles are properly propagated to the Wayland session and all child processes
|
||||
2. **Systemd integration** - Wraps the compositor in proper systemd units with lifecycle management
|
||||
3. **XDG autostart support** - Handles XDG autostart applications with proper slices and dependencies
|
||||
4. **Clean startup/shutdown** - Manages session lifecycle with proper cleanup on exit
|
||||
5. **Session binding** - Can bind session lifecycle to login shell PID for proper TTY management
|
||||
|
||||
## Benefits for Niri
|
||||
|
||||
Currently, our Niri setup uses:
|
||||
- `programs.niri.settings.spawn-at-startup` for starting applications like nm-applet
|
||||
- `programs.waybar.systemd.enable = true` for waybar systemd service
|
||||
- Manual systemd user services for various components
|
||||
|
||||
With UWSM:
|
||||
- All startup applications would be managed consistently through systemd units
|
||||
- Environment variables would be properly inherited from login shell → PAM → systemd → compositor → applications
|
||||
- Better integration with systemd targets (`graphical-session.target`, etc.)
|
||||
- Proper cleanup on logout/shutdown
|
||||
- XDG autostart applications would work automatically
|
||||
- Better compatibility with applications that expect standard Wayland session management
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### 1. Host-Level Changes (`hosts/common/optional/niri.nix`)
|
||||
|
||||
Add UWSM package and configure it:
|
||||
|
||||
```nix
|
||||
environment.systemPackages = with pkgs; [
|
||||
uwsm
|
||||
];
|
||||
```
|
||||
|
||||
Enable UWSM mode for Niri (if the niri-flake supports it), or configure it manually.
|
||||
|
||||
### 2. User-Level Changes (`home/panotaka/common/optional/desktops/niri/`)
|
||||
|
||||
#### Option A: Use UWSM's systemd units (Recommended)
|
||||
|
||||
Remove manual `spawn-at-startup` entries and rely on:
|
||||
- Systemd user services with `WantedBy=graphical-session.target`
|
||||
- XDG autostart desktop entries
|
||||
- UWSM's built-in environment preparation
|
||||
|
||||
#### Option B: Hybrid Approach
|
||||
|
||||
Keep some `spawn-at-startup` for compositor-specific tools, but use UWSM for:
|
||||
- Environment variable management
|
||||
- Session lifecycle binding
|
||||
- XDG autostart apps
|
||||
|
||||
### 3. Migration Path
|
||||
|
||||
1. **Phase 1**: Add UWSM package and test manual invocation
|
||||
```bash
|
||||
uwsm start -o niri
|
||||
systemctl --user start wayland-wm@niri.service
|
||||
```
|
||||
|
||||
2. **Phase 2**: Migrate startup applications to systemd services
|
||||
- Convert `spawn-at-startup` entries to `systemd.user.services`
|
||||
- Use `WantedBy = ["graphical-session.target"]` for dependency
|
||||
|
||||
3. **Phase 3**: Create UWSM desktop entry for display managers
|
||||
```desktop
|
||||
[Desktop Entry]
|
||||
Name=Niri (with UWSM)
|
||||
Comment=Niri Wayland compositor with UWSM session management
|
||||
Exec=uwsm start -D niri -N Niri -C "Niri compositor" -- niri
|
||||
Type=Application
|
||||
DesktopNames=niri
|
||||
```
|
||||
|
||||
4. **Phase 4**: Configure environment finalization
|
||||
- Have Niri execute `uwsm finalize` in its config to propagate compositor-specific variables
|
||||
|
||||
## Current State
|
||||
|
||||
### What Uses `spawn-at-startup` Currently:
|
||||
- `Restart` policies for resilience
|
||||
|
||||
#### 3. Application Launches → UWSM App Wrapper
|
||||
|
||||
All applications launched from Niri now use `uwsm app --` wrapper:
|
||||
|
||||
- **Fuzzel launcher**: `uwsm app -- fuzzel`
|
||||
- Also configured with `launch-prefix = "uwsm app -- "` so apps launched from fuzzel are properly managed
|
||||
- **Swaylock**: `uwsm app -- swaylock` (Mod+L keybind)
|
||||
- **Zenbook tools**: `uwsm app -- zenbook-set-displays` (Mod+Z keybind)
|
||||
|
||||
This ensures all applications are placed in the correct systemd slices (`app-graphical.slice`) and inherit proper environment variables.
|
||||
|
||||
### Files Modified
|
||||
|
||||
1. **`hosts/common/optional/niri.nix`**
|
||||
- Replaced manual desktop entries with `programs.uwsm` module
|
||||
- Configured Niri as a UWSM-managed compositor
|
||||
|
||||
2. **`home/panotaka/common/optional/desktops/niri/waybar.nix`**
|
||||
- Migrated nm-applet from spawn-at-startup to systemd.user.services.nm-applet
|
||||
|
||||
3. **`home/panotaka/common/optional/desktops/niri/zenbook-screen.nix`**
|
||||
- Migrated all zenbook display management tools to systemd services:
|
||||
- zenbook-autostart (oneshot initial setup)
|
||||
- zenbook-delayed-setup (delayed secondary setup)
|
||||
- zenbook-inotify-monitor (long-running DRM status watcher)
|
||||
- zenbook-udev-monitor (long-running udev event watcher)
|
||||
- Updated Mod+Z keybind to use `uwsm app --`
|
||||
|
||||
4. **`home/panotaka/common/optional/desktops/niri/fuzzel.nix`**
|
||||
- Updated keybind to launch fuzzel via `uwsm app --`
|
||||
- Added `launch-prefix = "uwsm app -- "` to fuzzel config
|
||||
|
||||
5. **`home/panotaka/common/optional/desktops/niri/swaylock.nix`**
|
||||
- Updated Mod+L keybind to launch swaylock via `uwsm app --`
|
||||
|
||||
### Files Modified
|
||||
|
||||
1. **`home/panotaka/common/optional/desktops/niri/waybar.nix`**
|
||||
- Migrated nm-applet from spawn-at-startup to systemd.user.services.nm-applet
|
||||
|
||||
2. **`home/panotaka/common/optional/desktops/niri/zenbook-screen.nix`**
|
||||
|
||||
### What Already Uses Systemd:
|
||||
- `programs.waybar.systemd.enable = true`
|
||||
- polkit-kde-authentication-agent-1
|
||||
|
||||
## Recommendation
|
||||
|
||||
For now, I recommend a **soft introduction** of UWSM:
|
||||
|
||||
1. **Add UWSM package** to the system so it's available
|
||||
2. **Document how to use it** (this file)
|
||||
3. **Keep current setup** working as-is
|
||||
4. **Provide opt-in migration path** for users who want systemd-managed session
|
||||
|
||||
Later, when fully tested, we can:
|
||||
- Make UWSM the default
|
||||
- Migrate all startup apps to systemd services
|
||||
- Remove manual `spawn-at-startup` entries
|
||||
- Add UWSM desktop entry for GDM/SDDM
|
||||
|
||||
### Systemd User Services (graphical-session.target)
|
||||
|
||||
These services start automatically when the graphical session begins:
|
||||
|
||||
- **waybar** (via programs.waybar.systemd.enable)
|
||||
- **nm-applet** (network manager applet for tray)
|
||||
- **polkit-kde-authentication-agent-1** (authentication dialogs)
|
||||
- **zenbook-autostart** (initial display setup)
|
||||
- **zenbook-delayed-setup** (secondary setup after delay)
|
||||
- **zenbook-inotify-monitor** (DRM status change monitoring)
|
||||
- **zenbook-udev-monitor** (udev event monitoring)
|
||||
|
||||
## Monitoring and Debugging
|
||||
|
||||
### Check Service Status
|
||||
|
||||
```bash
|
||||
# List all graphical session services
|
||||
systemctl --user list-units --type=service | grep graphical
|
||||
|
||||
# Check specific service
|
||||
systemctl --user status nm-applet
|
||||
systemctl --user status zenbook-autostart
|
||||
|
||||
# View logs
|
||||
journalctl --user -u nm-applet -f
|
||||
journalctl --user -u zenbook-inotify-monitor -f
|
||||
```
|
||||
|
||||
### UWSM Session Management
|
||||
|
||||
```bash
|
||||
# Check current UWSM session
|
||||
uwsm status
|
||||
|
||||
# List UWSM-managed units
|
||||
systemctl --user list-units 'wayland-*'
|
||||
|
||||
# Stop session cleanly
|
||||
uwsm stop
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Service Not Starting
|
||||
|
||||
```bash
|
||||
# Check why service failed
|
||||
systemctl --user status <service-name>
|
||||
journalctl --user -u <service-name> -n 50
|
||||
|
||||
# Manually start for testing
|
||||
systemctl --user start <service-name>
|
||||
```
|
||||
|
||||
### Environment Variables Missing
|
||||
|
||||
UWSM should automatically propagate environment variables. If something is missing:
|
||||
|
||||
```bash
|
||||
# Check what's in systemd's environment
|
||||
systemctl --user show-environment
|
||||
|
||||
# Manually import if needed (shouldn't be necessary with UWSM)
|
||||
systemctl --user import-environment VARIABLE_NAME
|
||||
```
|
||||
|
||||
## Testing UWSM
|
||||
|
||||
To test UWSM without changing your current setup:
|
||||
|
||||
```bash
|
||||
# Generate units without starting
|
||||
uwsm start -o niri
|
||||
|
||||
# Check generated units
|
||||
systemctl --user list-units 'wayland-*'
|
||||
|
||||
# Start manually
|
||||
systemctl --user start wayland-wm@niri.service
|
||||
|
||||
# Stop
|
||||
uwsm stop
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- UWSM GitHub: https://github.com/vladimir-csp/uwsm
|
||||
- UWSM in NixOS: Available as `pkgs.uwsm`
|
||||
- Hyprland UWSM integration: `programs.hyprland.withUWSM` option exists in nixpkgs
|
||||
825
flake.lock
generated
825
flake.lock
generated
File diff suppressed because it is too large
Load Diff
47
flake.nix
47
flake.nix
@@ -60,7 +60,10 @@
|
||||
# ========= Overlays =========
|
||||
#
|
||||
# Custom modifications/overrides to upstream packages.
|
||||
overlays = import ./overlays {inherit inputs;};
|
||||
overlays = import ./overlays {
|
||||
inherit inputs;
|
||||
inherit lib;
|
||||
};
|
||||
|
||||
#
|
||||
# ========= Host Configurations =========
|
||||
@@ -111,18 +114,18 @@
|
||||
#
|
||||
# NOTE(starter): As with typical flake-based configs, you'll need to update the nixOS, hm,
|
||||
# and darwin version numbers below when new releases are available.
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
# The next two inputs are for pinning nixpkgs to stable vs unstable regardless of what the above is set to.
|
||||
# This is particularly useful when an upcoming stable release is in beta because you can effectively
|
||||
# keep 'nixpkgs-stable' set to stable for critical packages while setting 'nixpkgs' to the beta branch to
|
||||
# get a jump start on deprecation changes.
|
||||
# See also 'stable-packages' and 'unstable-packages' overlays at 'overlays/default.nix"
|
||||
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.11";
|
||||
nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
hardware.url = "github:nixos/nixos-hardware";
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager/release-24.11";
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
@@ -141,7 +144,7 @@
|
||||
};
|
||||
|
||||
nixos-hardware = {
|
||||
url = "github:NixOS/nixos-hardware/master";
|
||||
url = "github:NixOS/nixos-hardware";
|
||||
};
|
||||
|
||||
nix4vscode = {
|
||||
@@ -154,15 +157,34 @@
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
devenv.url = "github:cachix/devenv";
|
||||
|
||||
stylix = {
|
||||
url = "github:danth/stylix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
#
|
||||
# ========= Extra Applications =========
|
||||
#
|
||||
zen-browser = {
|
||||
url = "github:0xc000022070/zen-browser-flake";
|
||||
inputs = {
|
||||
home-manager.follows = "home-manager";
|
||||
nixpkgs.follows = "nixpkgs";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
niri = {
|
||||
url = "github:sodiboo/niri-flake";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
ags = {
|
||||
url = "github:aylur/ags";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
caelestia-shell = {
|
||||
url = "github:caelestia-dots/shell";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
#
|
||||
@@ -179,4 +201,13 @@
|
||||
};
|
||||
*/
|
||||
};
|
||||
|
||||
nixConfig = {
|
||||
extra-substituters = [
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
extra-trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
{pkgs, ...}: {
|
||||
imports = [
|
||||
#################### Required Configs ####################
|
||||
common/core # required
|
||||
@@ -7,9 +6,7 @@
|
||||
#################### Host-specific Optional Configs ####################
|
||||
];
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
home.packages = with pkgs; [
|
||||
vlc
|
||||
;
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
}: {
|
||||
imports = lib.flatten [
|
||||
(lib.custom.scanPaths ./.)
|
||||
(map lib.custom.relativeToRoot [
|
||||
@@ -16,16 +15,13 @@
|
||||
username = lib.mkDefault "exampleSecondUser";
|
||||
homeDirectory = lib.mkDefault "/home/${config.home.username}";
|
||||
stateVersion = lib.mkDefault "24.11";
|
||||
sessionPath = [ "$HOME/.local/bin" ];
|
||||
sessionPath = ["$HOME/.local/bin"];
|
||||
};
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
|
||||
home.packages = with pkgs; [
|
||||
# Packages that don't have custom configs go here
|
||||
nix-tree
|
||||
;
|
||||
};
|
||||
];
|
||||
|
||||
nix = {
|
||||
package = lib.mkDefault pkgs.nix;
|
||||
|
||||
24
home/panotaka/.local/bin/fuzzel-power-menu.sh
Normal file
24
home/panotaka/.local/bin/fuzzel-power-menu.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
choices="lock\nsleep\npoweroff\nreboot"
|
||||
|
||||
selected=$(echo -e "$choices" | ${pkgs.fuzzel}/bin/fuzzel --dmenu --prompt " ")
|
||||
|
||||
case "$selected" in
|
||||
lock)
|
||||
uwsm app -- ${pkgs.swaylock}/bin/swaylock
|
||||
;;
|
||||
sleep)
|
||||
systemctl suspend
|
||||
;;
|
||||
poweroff)
|
||||
systemctl poweroff
|
||||
;;
|
||||
reboot)
|
||||
systemctl reboot
|
||||
;;
|
||||
*)
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
@@ -10,10 +10,12 @@
|
||||
#
|
||||
# FIXME(starter): add or remove any optional config directories or files ehre
|
||||
common/optional/browsers
|
||||
common/optional/desktops
|
||||
common/optional/desktops/niri
|
||||
common/optional/desktops/niri/zenbook-screen.nix
|
||||
common/optional/comms
|
||||
common/optional/media
|
||||
common/optional/coding
|
||||
common/optional/games
|
||||
common/optional/productivity
|
||||
];
|
||||
}
|
||||
|
||||
@@ -19,18 +19,17 @@ in {
|
||||
./${platform}.nix
|
||||
|
||||
# FIXME(starter): add/edit as desired
|
||||
./fish.nix
|
||||
./bash.nix
|
||||
./direnv.nix
|
||||
./fonts.nix
|
||||
./kitty.nix
|
||||
./ghostty.nix
|
||||
./git.nix
|
||||
./ssh.nix
|
||||
./shell
|
||||
];
|
||||
|
||||
inherit hostSpec;
|
||||
|
||||
services.ssh-agent.enable = true;
|
||||
#services.ssh-agent.enable = true;
|
||||
|
||||
home = {
|
||||
username = lib.mkDefault config.hostSpec.username;
|
||||
@@ -39,15 +38,9 @@ in {
|
||||
sessionPath = [
|
||||
"$HOME/.local/bin"
|
||||
];
|
||||
sessionVariables = {
|
||||
FLAKE = "$HOME/src/nix/nix-config";
|
||||
SHELL = "bash";
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
home.packages = with pkgs; [
|
||||
# FIXME(starter): add/edit as desired
|
||||
# Packages that don't have custom configs go here
|
||||
curl
|
||||
@@ -58,8 +51,7 @@ in {
|
||||
usbutils
|
||||
unzip # zip extraction
|
||||
unrar # rar extraction
|
||||
;
|
||||
};
|
||||
];
|
||||
|
||||
nix = {
|
||||
package = lib.mkDefault pkgs.nix;
|
||||
|
||||
@@ -1,7 +1,41 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
{pkgs, ...}: {
|
||||
fonts.fontconfig.enable = true;
|
||||
home.packages = [
|
||||
pkgs.noto-fonts
|
||||
home.packages = with pkgs; [
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-emoji
|
||||
noto-fonts-extra
|
||||
liberation_ttf
|
||||
dejavu_fonts
|
||||
fira-code
|
||||
fira-mono
|
||||
jetbrains-mono
|
||||
source-code-pro
|
||||
hack-font
|
||||
roboto
|
||||
roboto-mono
|
||||
font-awesome
|
||||
material-design-icons
|
||||
inter
|
||||
ibm-plex
|
||||
sarasa-gothic
|
||||
unifont
|
||||
dina-font
|
||||
# proggyfonts - removed due to collision with dina-font fonts.dir
|
||||
terminus_font
|
||||
mplus-outline-fonts.osdnRelease
|
||||
open-sans
|
||||
# Droid fonts are now in android-fonts-droid
|
||||
# droid-sans
|
||||
# droid-serif
|
||||
# droid-sans-mono
|
||||
cantarell-fonts
|
||||
recursive
|
||||
# google-fonts - removed due to collision with jetbrains-mono
|
||||
# Microsoft fonts
|
||||
corefonts
|
||||
vistafonts
|
||||
# webcore-fonts - removed package
|
||||
cascadia-code
|
||||
];
|
||||
}
|
||||
|
||||
9
home/panotaka/common/core/ghostty.nix
Normal file
9
home/panotaka/common/core/ghostty.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
programs.ghostty = {
|
||||
# Enable Ghostty (adjust package/settings in host/home files if needed)
|
||||
enable = true;
|
||||
# Example: set a specific package or settings here if desired
|
||||
# package = pkgs.ghostty; # uncomment to pin package
|
||||
# settings = { theme = "default"; };
|
||||
};
|
||||
}
|
||||
@@ -10,6 +10,12 @@
|
||||
package = pkgs.gitAndTools.gitFull;
|
||||
userName = "Thomas Syms";
|
||||
userEmail = "thomassyms@gmail.com";
|
||||
lfs.enable = true;
|
||||
extraConfig = {
|
||||
credential.helper = "${
|
||||
pkgs.git.override {withLibsecret = true;}
|
||||
}/bin/git-credential-libsecret";
|
||||
};
|
||||
|
||||
ignores = [
|
||||
".csvignore"
|
||||
@@ -24,4 +30,18 @@
|
||||
".direnv"
|
||||
];
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
gh
|
||||
];
|
||||
|
||||
home.file.".config/gh-copilot/config.yml".text = lib.generators.toYAML {} {
|
||||
optional_analytics = false;
|
||||
suggest_execute_confirm_default = true;
|
||||
};
|
||||
|
||||
home.shellAliases = {
|
||||
copilot-suggest = "gh copilot suggest";
|
||||
copilot-explain = "gh copilot explain";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = [ pkgs.screen ];
|
||||
home.file.".screenrc".text = ''
|
||||
startup_message off
|
||||
defbce on
|
||||
setenv TERM xterm-256color
|
||||
'';
|
||||
}
|
||||
6
home/panotaka/common/core/shell/atuin.nix
Normal file
6
home/panotaka/common/core/shell/atuin.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
programs.atuin = {
|
||||
enable = true;
|
||||
flags = ["--disable-up-arrow"];
|
||||
};
|
||||
}
|
||||
5
home/panotaka/common/core/shell/autojump.nix
Normal file
5
home/panotaka/common/core/shell/autojump.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{...}: {
|
||||
programs.autojump = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
5
home/panotaka/common/core/shell/bat.nix
Normal file
5
home/panotaka/common/core/shell/bat.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
programs.bat = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
5
home/panotaka/common/core/shell/btop.nix
Normal file
5
home/panotaka/common/core/shell/btop.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
programs.btop = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
9
home/panotaka/common/core/shell/carapace.nix
Normal file
9
home/panotaka/common/core/shell/carapace.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
programs.carapace = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
enableNushellIntegration = true;
|
||||
enableFishIntegration = true;
|
||||
};
|
||||
}
|
||||
5
home/panotaka/common/core/shell/common.nix
Normal file
5
home/panotaka/common/core/shell/common.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = with pkgs; [
|
||||
# oterm removed
|
||||
];
|
||||
}
|
||||
22
home/panotaka/common/core/shell/default.nix
Normal file
22
home/panotaka/common/core/shell/default.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
# FIXME(starter): customize your bash preferences here
|
||||
{
|
||||
imports = [
|
||||
./atuin.nix
|
||||
./autojump.nix
|
||||
./bash.nix
|
||||
./bat.nix
|
||||
./btop.nix
|
||||
./carapace.nix
|
||||
./common.nix
|
||||
./devenv.nix
|
||||
./direnv.nix
|
||||
./eza.nix
|
||||
./fish.nix
|
||||
./lazydocker.nix
|
||||
./lazygit.nix
|
||||
./rip.nix
|
||||
./tldr.nix
|
||||
./zellij.nix
|
||||
./zoxide.nix
|
||||
];
|
||||
}
|
||||
3
home/panotaka/common/core/shell/devenv.nix
Normal file
3
home/panotaka/common/core/shell/devenv.nix
Normal file
@@ -0,0 +1,3 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = [pkgs.devenv];
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
#enableFishIntegration = true;
|
||||
nix-direnv.enable = true; # better than native direnv nix functionality - https://github.com/nix-community/nix-direnv
|
||||
};
|
||||
}
|
||||
14
home/panotaka/common/core/shell/eza.nix
Normal file
14
home/panotaka/common/core/shell/eza.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{...}: {
|
||||
programs.eza = {
|
||||
enable = true;
|
||||
extraOptions = [
|
||||
"--group-directories-first"
|
||||
"--header"
|
||||
];
|
||||
icons = "auto";
|
||||
};
|
||||
|
||||
home.shellAliases = {
|
||||
l = "eza -1 --group-directories-first";
|
||||
};
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
home.packages = with pkgs; [
|
||||
grc
|
||||
;
|
||||
};
|
||||
];
|
||||
|
||||
programs.fish = {
|
||||
enable = true;
|
||||
7
home/panotaka/common/core/shell/lazydocker.nix
Normal file
7
home/panotaka/common/core/shell/lazydocker.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
programs.lazydocker.enable = true;
|
||||
|
||||
home.shellAliases = {
|
||||
ldocker = "lazydocker";
|
||||
};
|
||||
}
|
||||
7
home/panotaka/common/core/shell/lazygit.nix
Normal file
7
home/panotaka/common/core/shell/lazygit.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
programs.lazygit.enable = true;
|
||||
|
||||
home.shellAliases = {
|
||||
lgit = "lazygit";
|
||||
};
|
||||
}
|
||||
6
home/panotaka/common/core/shell/nushell.nix
Normal file
6
home/panotaka/common/core/shell/nushell.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
programs.nushell = {
|
||||
enable = true;
|
||||
configFile.source = null; # Use default config, or set to a custom file if desired
|
||||
};
|
||||
}
|
||||
5
home/panotaka/common/core/shell/rip.nix
Normal file
5
home/panotaka/common/core/shell/rip.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = with pkgs; [
|
||||
rm-improved
|
||||
];
|
||||
}
|
||||
11
home/panotaka/common/core/shell/tldr.nix
Normal file
11
home/panotaka/common/core/shell/tldr.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = with pkgs; [
|
||||
#tlrc
|
||||
];
|
||||
|
||||
services.tldr-update = {
|
||||
enable = true;
|
||||
package = pkgs.tlrc;
|
||||
period = "weekly";
|
||||
};
|
||||
}
|
||||
16
home/panotaka/common/core/shell/zellij.nix
Normal file
16
home/panotaka/common/core/shell/zellij.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
programs.zellij = {
|
||||
enable = true;
|
||||
enableBashIntegration = false;
|
||||
enableZshIntegration = false;
|
||||
enableFishIntegration = false;
|
||||
settings = {
|
||||
#simplified_ui = true;
|
||||
pane_frames = false;
|
||||
default_mode = "locked";
|
||||
copy_on_select = false;
|
||||
show_startup_tips = false;
|
||||
show_release_notes = false;
|
||||
};
|
||||
};
|
||||
}
|
||||
9
home/panotaka/common/core/shell/zoxide.nix
Normal file
9
home/panotaka/common/core/shell/zoxide.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
programs.zoxide = {
|
||||
enable = true;
|
||||
enableBashIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
enableNushellIntegration = true;
|
||||
enableFishIntegration = true;
|
||||
};
|
||||
}
|
||||
19
home/panotaka/common/core/shell/zsh.nix
Normal file
19
home/panotaka/common/core/shell/zsh.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{pkgs, ...}: {
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
enableCompletion = true;
|
||||
syntaxHighlighting.enable = true;
|
||||
autosuggestions.enable = true;
|
||||
history = {
|
||||
save = 10000;
|
||||
share = true;
|
||||
};
|
||||
plugins = [
|
||||
{
|
||||
name = "zsh-autopair";
|
||||
src = pkgs.zsh-autopair;
|
||||
}
|
||||
# Add more plugins here as needed
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
# FIXME(starter): adjust to you security requirements
|
||||
{
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
programs.ssh =
|
||||
{
|
||||
{config, ...}: {
|
||||
programs.ssh = {
|
||||
enable = true;
|
||||
|
||||
# Global SSH settings
|
||||
addKeysToAgent = "yes";
|
||||
controlMaster = "auto";
|
||||
controlPath = "${config.home.homeDirectory}/.ssh/sockets/S.%r@%h:%p";
|
||||
controlPersist = "20m";
|
||||
# Avoids infinite hang if control socket connection interrupted. ex: vpn goes down/up
|
||||
serverAliveCountMax = 3;
|
||||
serverAliveInterval = 5; # 3 * 5s
|
||||
hashKnownHosts = true;
|
||||
addKeysToAgent = "yes";
|
||||
|
||||
# Set default values for all hosts
|
||||
matchBlocks."*" = {};
|
||||
};
|
||||
home.file = {
|
||||
".ssh/config.d/.keep".text = "# Managed by Home Manager";
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
{inputs, ...}: {
|
||||
{
|
||||
inputs,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# home.nix
|
||||
imports = [
|
||||
inputs.zen-browser.homeModules.beta
|
||||
# or inputs.zen-browser.homeModules.twilight
|
||||
# or inputs.zen-browser.homeModules.twilight-official
|
||||
inputs.zen-browser.homeModules.default
|
||||
# inputs.zen-browser.homeModules.twilight
|
||||
# inputs.zen-browser.homeModules.twilight-official
|
||||
];
|
||||
|
||||
programs.zen-browser = {
|
||||
@@ -19,6 +23,13 @@
|
||||
DontCheckDefaultBrowser = true;
|
||||
NoDefaultBookmarks = true;
|
||||
OfferToSaveLogins = false;
|
||||
EnableTrackingProtection = {
|
||||
Value = true;
|
||||
Locked = true;
|
||||
Cryptomining = true;
|
||||
Fingerprinting = true;
|
||||
};
|
||||
};
|
||||
nativeMessagingHosts = [pkgs.firefoxpwa];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
./zed.nix
|
||||
];
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
home.packages = with pkgs; [
|
||||
hoppscotch
|
||||
;
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
"GitHub.copilot"
|
||||
"GitHub.copilot-chat"
|
||||
];
|
||||
userSettings = {
|
||||
# Enable Copilot Next Edit Suggestions
|
||||
"github.copilot.nextEditSuggestions.enabled" = true;
|
||||
# Other useful Copilot settings
|
||||
"github.copilot.enable" = {
|
||||
"*" = true;
|
||||
};
|
||||
"github.copilot.inlineSuggest.enable" = true;
|
||||
"github.copilot.advanced" = {
|
||||
"inlineSuggest.enableAutoTrigger" = true;
|
||||
"inlineSuggest.showEditorCompletions" = true;
|
||||
};
|
||||
# Add more Copilot-specific settings as needed
|
||||
};
|
||||
};
|
||||
# Playwright support for NixOS (see https://nixos.wiki/wiki/Playwright)
|
||||
home.packages = [
|
||||
pkgs.playwright-driver.browsers
|
||||
];
|
||||
# Set Playwright environment variables globally for the user
|
||||
home.sessionVariables = {
|
||||
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
|
||||
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = "true";
|
||||
PLAYWRIGHT_NODEJS_PATH = "${pkgs.nodejs}/bin/node";
|
||||
# Replace 'chromium-rev' with the actual revision if needed
|
||||
PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH = "${pkgs.playwright-driver.browsers}/chromium-<chromium-rev>/chrome-linux/chrome";
|
||||
};
|
||||
# Deploy mcp.json to ~/.config/Code/User/mcp.json using toJSON
|
||||
home.file.".config/Code/User/mcp.json" = {
|
||||
text = builtins.toJSON {
|
||||
servers = {
|
||||
context7 = {
|
||||
type = "stdio";
|
||||
command = "bun";
|
||||
args = ["x" "-y" "@upstash/context7-mcp"];
|
||||
};
|
||||
};
|
||||
inputs = [];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,69 +1,81 @@
|
||||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./javascript.nix
|
||||
./latex.nix
|
||||
./markdown.nix
|
||||
./nix.nix
|
||||
./rust.nix
|
||||
];
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
imports = lib.custom.scanPaths ./languages ++ [./completion/copilot.nix];
|
||||
|
||||
home.packages = with pkgs; [];
|
||||
|
||||
programs.vscode = {
|
||||
enable = true;
|
||||
package = pkgs.vscodium;
|
||||
enableUpdateCheck = false; # Disable VSCode self-update and let Home Manager to manage VSCode versions instead.
|
||||
enableExtensionUpdateCheck = false; # Disable extensions auto-update and let nix4vscode manage updates and extensions
|
||||
# Extensions
|
||||
extensions = pkgs.nix4vscode.forVscode [
|
||||
# General extensions
|
||||
|
||||
## Code Completion
|
||||
"continue.continue"
|
||||
#rooveterinaryinc.roo-cline
|
||||
|
||||
## Development Environment
|
||||
"ms-toolsai.jupyter"
|
||||
"ms-vscode-remote.remote-containers"
|
||||
|
||||
## Error Checking
|
||||
"usernamehw.errorlens"
|
||||
|
||||
## Export and Visualisation
|
||||
"ibm.output-colorizer"
|
||||
"nobuhito.printcode"
|
||||
"pnp.polacode"
|
||||
|
||||
## Git
|
||||
"lamartire.git-indicators"
|
||||
"mhutchie.git-graph"
|
||||
|
||||
## Miscelaneous
|
||||
package = pkgs.vscode;
|
||||
enableUpdateCheck = false; # Let Home Manager manage VSCode versions
|
||||
enableExtensionUpdateCheck = false; # Let nix4vscode manage extensions
|
||||
mutableExtensionsDir = false;
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# --- General ---
|
||||
"britesnow.vscode-toggle-quotes"
|
||||
"mrmlnc.vscode-duplicate"
|
||||
"qcz.text-power-tools"
|
||||
|
||||
# Language extensions
|
||||
|
||||
## CSV
|
||||
# --- Development ---
|
||||
"ms-toolsai.jupyter"
|
||||
"ms-vscode-remote.remote-containers"
|
||||
# --- Error Checking ---
|
||||
"usernamehw.errorlens"
|
||||
# --- Output & Visualization ---
|
||||
"ibm.output-colorizer"
|
||||
"pnp.polacode"
|
||||
# --- Git ---
|
||||
"lamartire.git-indicators"
|
||||
"mhutchie.git-graph"
|
||||
# --- Languages ---
|
||||
"mechatroner.rainbow-csv"
|
||||
|
||||
## Golang
|
||||
"golang.go"
|
||||
|
||||
## Python
|
||||
"ms-python.python"
|
||||
|
||||
## SVG
|
||||
"jock.svg"
|
||||
"redhat.vscode-yaml"
|
||||
"mkhl.direnv"
|
||||
];
|
||||
# Settings
|
||||
userSettings = {
|
||||
# --- Privacy & Telemetry ---
|
||||
"telemetry.feedback.enabled" = false;
|
||||
"github.copilot.enableTelemetry" = false;
|
||||
"telemetry.telemetryLevel" = "off";
|
||||
"telemetry.enableTelemetry" = false;
|
||||
"telemetry.enableCrashReporter" = false;
|
||||
"telemetry.disableFeedback" = true;
|
||||
"workbench.enableExperiments" = false;
|
||||
"workbench.settings.enableNaturalLanguageSearch" = false;
|
||||
# --- Updates & Recommendations ---
|
||||
"extensions.autoUpdate" = false;
|
||||
"extensions.ignoreRecommendations" = true;
|
||||
# --- UI ---
|
||||
"editor.linkedEditing" = true;
|
||||
"editor.inlineSuggest.enabled" = true;
|
||||
"continue.enableTabAutocomplete" = true;
|
||||
|
||||
"window.menuBarVisibility" = "toggle";
|
||||
#"github.copilot.editor.enableAutoCompletions" = true;
|
||||
"window.commandCenter" = false;
|
||||
"window.titleBarStyle" = "native";
|
||||
"workbench.navigationControl.enabled" = false;
|
||||
"workbench.layoutControl.enabled" = false;
|
||||
|
||||
# --- Extension-specific telemetry opt-outs ---
|
||||
"code-runner.enableAppInsights" = false;
|
||||
"docker-explorer.enableTelemetry" = false;
|
||||
"gitlens.showWelcomeOnInstall" = false;
|
||||
"gitlens.showWhatsNewAfterUpgrades" = false;
|
||||
"java.help.showReleaseNotes" = false;
|
||||
"julia.enableTelemetry" = false;
|
||||
"Lua.telemetry.enable" = false;
|
||||
"material-icon-theme.showWelcomeMessage" = false;
|
||||
"pros.showWelcomeOnStartup" = false;
|
||||
"redhat.telemetry.enabled" = false;
|
||||
"sonarlint.disableTelemetry" = true;
|
||||
"terraform.telemetry.enabled" = false;
|
||||
"vsicons.dontShowNewVersionMessage" = true;
|
||||
"workbench.welcomePage.walkthroughs.openOnInstall" = false;
|
||||
"nixEnvSelector.useFlakes" = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# CSV language support
|
||||
"mechatroner.rainbow-csv"
|
||||
];
|
||||
userSettings = {
|
||||
# Add CSV-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for CSV development
|
||||
home.packages = with pkgs; [
|
||||
# Add CSV-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# Godot language support
|
||||
"geequlim.godot-tools"
|
||||
];
|
||||
userSettings = {
|
||||
# Add Godot-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for Godot development
|
||||
home.packages = with pkgs; [
|
||||
godot
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# Go language support
|
||||
"golang.go"
|
||||
];
|
||||
userSettings = {
|
||||
# Add Go-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for Go development
|
||||
home.packages = with pkgs; [
|
||||
# Add Go-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscode [
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# General
|
||||
"christian-kohler.npm-intellisense"
|
||||
"dbaeumer.vscode-eslint"
|
||||
@@ -47,6 +47,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for JavaScript development
|
||||
home.packages = with pkgs; [
|
||||
deno
|
||||
pnpm
|
||||
@@ -1,6 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscode [
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# General
|
||||
"james-yu.latex-workshop"
|
||||
];
|
||||
@@ -25,4 +25,9 @@
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for LaTeX development
|
||||
home.packages = with pkgs; [
|
||||
# Add LaTeX-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscode [
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# General
|
||||
"bpruitt-goddard.mermaid-markdown-syntax-highlighting"
|
||||
"davidanson.vscode-markdownlint"
|
||||
@@ -12,4 +12,9 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for Markdown development
|
||||
home.packages = with pkgs; [
|
||||
# Add Markdown-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = with pkgs; [
|
||||
nil
|
||||
alejandra
|
||||
deadnix
|
||||
];
|
||||
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscode [
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# Nix language support
|
||||
"jnoortheen.nix-ide"
|
||||
"kamadorueda.alejandra"
|
||||
];
|
||||
@@ -15,4 +10,11 @@
|
||||
"nix.serverPath" = "nil";
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for Nix development
|
||||
home.packages = with pkgs; [
|
||||
nil
|
||||
alejandra
|
||||
deadnix
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# Python language support
|
||||
"ms-python.python"
|
||||
];
|
||||
userSettings = {
|
||||
# Add Python-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for Python development
|
||||
home.packages = with pkgs; [
|
||||
# Add Python-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# Rust language support
|
||||
"barbosshack.crates-io"
|
||||
"tamasfe.even-better-toml"
|
||||
"rust-lang.rust-analyzer"
|
||||
];
|
||||
userSettings = {
|
||||
# Add Rust-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for Rust development
|
||||
home.packages = with pkgs; [
|
||||
cargo
|
||||
rustc
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# SVG language support
|
||||
"jock.svg"
|
||||
];
|
||||
userSettings = {
|
||||
# Add SVG-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for SVG development
|
||||
home.packages = with pkgs; [
|
||||
# Add SVG-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
|
||||
# YAML language support
|
||||
"redhat.vscode-yaml"
|
||||
];
|
||||
userSettings = {
|
||||
# Add YAML-specific settings here
|
||||
};
|
||||
};
|
||||
|
||||
# Additional packages for YAML development
|
||||
home.packages = with pkgs; [
|
||||
# Add YAML-related CLI tools here
|
||||
];
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{pkgs, ...}: {
|
||||
programs.vscode = {
|
||||
extensions =
|
||||
pkgs.nix4vscode.forVscode
|
||||
[
|
||||
# General
|
||||
"serayuzgur.crates"
|
||||
"tamasfe.even-better-toml"
|
||||
"rust-lang.rust-analyzer"
|
||||
];
|
||||
userSettings = {
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
cargo
|
||||
rustc
|
||||
];
|
||||
}
|
||||
@@ -1,5 +1,25 @@
|
||||
{pkgs, ...}: {
|
||||
programs.zed-editor = {
|
||||
enable = true;
|
||||
extensions = [
|
||||
"context7.context7"
|
||||
];
|
||||
userSettings = {
|
||||
agent = {
|
||||
default_model = {
|
||||
provider = "copilot_chat";
|
||||
model = "gpt-4.1";
|
||||
};
|
||||
inline_alternatives = [
|
||||
{
|
||||
provider = "copilot_chat";
|
||||
model = "gpt-4.1";
|
||||
}
|
||||
];
|
||||
};
|
||||
features = {
|
||||
edit_prediction_provider = "copilot";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
{pkgs, ...}: {
|
||||
#imports = [ ./foo.nix ];
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
home.packages = with pkgs; [
|
||||
teams-for-linux
|
||||
signal-desktop
|
||||
discord
|
||||
;
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
11
home/panotaka/common/optional/desktops/cosmic/default.nix
Normal file
11
home/panotaka/common/optional/desktops/cosmic/default.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# Home Manager module for enabling the COSMIC desktop environment
|
||||
# Follows the pattern of gnome/kde modules
|
||||
|
||||
# Optionally, add more configuration here as COSMIC matures
|
||||
# e.g., settings, extensions, etc.
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
{pkgs, ...}: {
|
||||
imports = [
|
||||
# Packages with custom configs go here
|
||||
|
||||
@@ -7,8 +6,7 @@
|
||||
#./fonts.nix
|
||||
./gtk.nix
|
||||
];
|
||||
home.packages = [
|
||||
pkgs.pavucontrol # gui for pulseaudio server and volume controls
|
||||
pkgs.galculator # gtk based calculator
|
||||
home.packages = with pkgs; [
|
||||
gnome-software
|
||||
];
|
||||
}
|
||||
|
||||
113
home/panotaka/common/optional/desktops/gnome/default.nix
Normal file
113
home/panotaka/common/optional/desktops/gnome/default.nix
Normal file
@@ -0,0 +1,113 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
inputs,
|
||||
...
|
||||
}: {
|
||||
# GNOME desktop packages
|
||||
home.packages = with pkgs; [
|
||||
gnome-tweaks
|
||||
dconf-editor
|
||||
gnome-control-center # GNOME Settings app for display configuration
|
||||
# Note: gnome-monitor-config might not be available as a standalone package
|
||||
# It's usually part of mutter/gnome-shell, we'll use gdbus calls instead
|
||||
inotify-tools # for watching USB changes
|
||||
iio-sensor-proxy # for rotation detection (includes monitor-sensor)
|
||||
xdotool # for monitor focus detection
|
||||
papers
|
||||
|
||||
# GNOME Extensions
|
||||
gnomeExtensions.dash-to-dock
|
||||
gnomeExtensions.blur-my-shell
|
||||
gnomeExtensions.user-themes
|
||||
gnomeExtensions.vitals
|
||||
gnomeExtensions.appindicator
|
||||
gnomeExtensions.tray-icons-reloaded
|
||||
gnomeExtensions.caffeine
|
||||
gnomeExtensions.clipboard-indicator
|
||||
gnomeExtensions.launch-new-instance
|
||||
gnomeExtensions.paperwm
|
||||
gnomeExtensions.just-perfection
|
||||
gnomeExtensions.touchpad-gesture-customization
|
||||
];
|
||||
|
||||
# GNOME desktop settings via dconf
|
||||
dconf.settings = {
|
||||
"org/gnome/desktop/interface" = {
|
||||
enable-hot-corners = false;
|
||||
color-scheme = lib.mkForce "prefer-dark";
|
||||
};
|
||||
|
||||
"org/gnome/desktop/wm/preferences" = {
|
||||
button-layout = "appmenu:minimize,maximize,close";
|
||||
};
|
||||
|
||||
# Enable GNOME Extensions
|
||||
"org/gnome/shell" = {
|
||||
enabled-extensions = [
|
||||
"dash-to-dock@micxgx.gmail.com"
|
||||
"blur-my-shell@aunetx"
|
||||
"user-theme@gnome-shell-extensions.gcampax.github.com"
|
||||
"Vitals@CoreCoding.com"
|
||||
"appindicatorsupport@rgcjonas.gmail.com"
|
||||
"trayIconsReloaded@selfmade.pl"
|
||||
"caffeine@patapon.info"
|
||||
"clipboard-indicator@tudmotu.com"
|
||||
"launch-new-instance@gnome-shell-extensions.gcampax.github.com"
|
||||
"paperwm@paperwm.github.com"
|
||||
"just-perfection@just-perfection"
|
||||
"touchpad-gesture-customization@rexhsu"
|
||||
];
|
||||
};
|
||||
|
||||
# Enable natural scrolling on touchpad
|
||||
"org/gnome/desktop/peripherals/touchpad" = {
|
||||
natural-scroll = true;
|
||||
two-finger-scrolling-enabled = true;
|
||||
tap-to-click = true;
|
||||
};
|
||||
|
||||
# Disable middle-click paste
|
||||
"org/gnome/desktop/interface" = {
|
||||
gtk-enable-primary-paste = false;
|
||||
};
|
||||
|
||||
# Enable fractional scaling for HiDPI displays and VRR support
|
||||
"org/gnome/mutter" = {
|
||||
experimental-features = ["scale-monitor-framebuffer" "variable-refresh-rate"];
|
||||
};
|
||||
|
||||
# Settings for Just Perfection extension (hide panel, disable overview/hot-corner)
|
||||
"org/gnome/shell/extensions/just-perfection" = {
|
||||
# --- Visibility ---
|
||||
panel-visibility = false; # Hides the entire top bar (panel)
|
||||
# panel-in-session-visibility = false; # Alternative if the above doesn't work
|
||||
|
||||
# --- Behavior ---
|
||||
activities-overview = false; # Disables the overview
|
||||
super-key-action = "disabled"; # Prevents Super key from opening overview
|
||||
hot-corner = false; # Disables the top-left hot corner
|
||||
|
||||
# --- Icons (if you decide to keep the panel) ---
|
||||
# activities-button = false; # Hides the "Activities" button
|
||||
};
|
||||
|
||||
# PaperWM extension settings placeholder
|
||||
"org/gnome/shell/extensions/paperwm" = {
|
||||
# Add any PaperWM-specific dconf keys here if needed
|
||||
};
|
||||
|
||||
# Ensure the standard GNOME screen lock shortcut is active
|
||||
"org/gnome/settings-daemon/plugins/media-keys" = {
|
||||
screensaver = ["<Super>l"];
|
||||
};
|
||||
|
||||
# Keybindings for window management
|
||||
"org/gnome/desktop/wm/keybindings" = {
|
||||
close = ["<Super>q"];
|
||||
};
|
||||
};
|
||||
|
||||
# Note: Monitor workspace management is now handled by the custom GNOME extension
|
||||
# instead of a systemd service with a shell script
|
||||
}
|
||||
673
home/panotaka/common/optional/desktops/gnome/zenbook-screen.nix
Normal file
673
home/panotaka/common/optional/desktops/gnome/zenbook-screen.nix
Normal file
@@ -0,0 +1,673 @@
|
||||
{pkgs, ...}: let
|
||||
# Configuration constants
|
||||
duoConfig = {
|
||||
# For 3K model (adjust as needed)
|
||||
prefered_resolution = "2880x1800@120.000";
|
||||
ui_scale = 1.5;
|
||||
y_offset = 1200; # height of resolution / ui_scale (1800/1.5 = 1200)
|
||||
backlight = "card1-eDP-2-backlight";
|
||||
|
||||
# USB ID for ZenBook Duo keyboard dock detection
|
||||
dock_usb_id = "0b05:1b2c";
|
||||
|
||||
# Display device identifiers
|
||||
primary_display = "eDP-1";
|
||||
secondary_display = "eDP-2";
|
||||
|
||||
# Touchscreen/tablet device IDs
|
||||
primary_touch_id = "04f3:425b";
|
||||
secondary_touch_id = "04f3:425a";
|
||||
|
||||
# For 1080p model (uncomment if needed)
|
||||
# prefered_resolution = "1920x1200@60.003";
|
||||
# ui_scale = 1;
|
||||
# y_offset = 1200;
|
||||
};
|
||||
|
||||
# Core display management script with separated concerns
|
||||
duoScript = pkgs.writeShellScript "duo" ''
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Import configuration
|
||||
PREFERRED_RESOLUTION="${duoConfig.prefered_resolution}"
|
||||
UI_SCALE="${toString duoConfig.ui_scale}"
|
||||
Y_OFFSET="${toString duoConfig.y_offset}"
|
||||
BACKLIGHT="${duoConfig.backlight}"
|
||||
DOCK_USB_ID="${duoConfig.dock_usb_id}"
|
||||
PRIMARY_DISPLAY="${duoConfig.primary_display}"
|
||||
SECONDARY_DISPLAY="${duoConfig.secondary_display}"
|
||||
PRIMARY_TOUCH_ID="${duoConfig.primary_touch_id}"
|
||||
SECONDARY_TOUCH_ID="${duoConfig.secondary_touch_id}"
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
|
||||
}
|
||||
|
||||
# Error handling
|
||||
handle_error() {
|
||||
log "ERROR: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Utility functions
|
||||
suenv() {
|
||||
sudo /usr/bin/env "$@"
|
||||
}
|
||||
|
||||
retry_command() {
|
||||
local retries=$1
|
||||
shift
|
||||
local count=0
|
||||
until "$@"; do
|
||||
count=$((count + 1))
|
||||
if [ $count -ge $retries ]; then
|
||||
return 1
|
||||
fi
|
||||
log "Command failed, retrying ($count/$retries)..."
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
# ===== DETECTION LOGIC =====
|
||||
|
||||
# Check if external displays are connected
|
||||
has_external_displays() {
|
||||
local external_count
|
||||
external_count=$(${pkgs.gnome-monitor-config}/bin/gnome-monitor-config list 2>/dev/null | \
|
||||
grep "display-name" | grep -v "Built-in display" | wc -l)
|
||||
[ "$external_count" -gt 0 ]
|
||||
}
|
||||
|
||||
# Get list of active external displays
|
||||
get_active_external_displays() {
|
||||
${pkgs.gnome-monitor-config}/bin/gnome-monitor-config list 2>/dev/null | \
|
||||
grep -vE 'eDP-[12]' | \
|
||||
sed -nE 's/Monitor \[ (.+) \] ON/\1/p'
|
||||
}
|
||||
|
||||
# Check if dock is connected (determines single vs dual screen mode)
|
||||
is_dock_connected() {
|
||||
${pkgs.usbutils}/bin/lsusb 2>/dev/null | grep -q "$DOCK_USB_ID"
|
||||
}
|
||||
|
||||
# Get current internal display status
|
||||
get_internal_display_status() {
|
||||
local monitors_on
|
||||
monitors_on=$(${pkgs.gnome-monitor-config}/bin/gnome-monitor-config list 2>/dev/null | \
|
||||
grep -E "Monitor \\[ eDP-. \\] ON" || true)
|
||||
|
||||
local count
|
||||
count=$(echo "$monitors_on" | grep -v -E "^$" | wc -l)
|
||||
|
||||
case "$count" in
|
||||
0) echo "none" ;;
|
||||
1)
|
||||
if echo "$monitors_on" | grep -q "Monitor \[ $PRIMARY_DISPLAY \] ON"; then
|
||||
echo "top"
|
||||
elif echo "$monitors_on" | grep -q "Monitor \[ $SECONDARY_DISPLAY \] ON"; then
|
||||
echo "bottom"
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
;;
|
||||
2) echo "both" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get device orientation from accelerometer
|
||||
get_orientation() {
|
||||
# This would typically come from iio-sensor-proxy
|
||||
# For now, return normal as default
|
||||
echo "normal"
|
||||
}
|
||||
|
||||
# Determine optimal display configuration based on current state
|
||||
determine_optimal_config() {
|
||||
local has_external dock_connected orientation current_status
|
||||
|
||||
has_external=$(has_external_displays && echo "true" || echo "false")
|
||||
dock_connected=$(is_dock_connected && echo "true" || echo "false")
|
||||
orientation=$(get_orientation)
|
||||
current_status=$(get_internal_display_status)
|
||||
|
||||
log "State: external=$has_external, dock=$dock_connected, orientation=$orientation, current=$current_status"
|
||||
|
||||
# Determine internal display configuration based on orientation and dock status
|
||||
# External displays don't affect internal display arrangement
|
||||
case "$orientation" in
|
||||
"normal")
|
||||
if [ "$dock_connected" = "true" ]; then
|
||||
echo "top-only"
|
||||
else
|
||||
echo "both-stacked"
|
||||
fi
|
||||
;;
|
||||
"left-up")
|
||||
echo "both-left"
|
||||
;;
|
||||
"right-up")
|
||||
echo "both-right"
|
||||
;;
|
||||
"bottom-up")
|
||||
echo "bottom-only"
|
||||
;;
|
||||
*)
|
||||
echo "both-stacked" # Safe default
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ===== MONITOR CONFIGURATION LOGIC =====
|
||||
|
||||
# Apply display configuration with error handling
|
||||
apply_display_config() {
|
||||
local config_name="$1"
|
||||
log "Applying display configuration: $config_name"
|
||||
|
||||
case "$config_name" in
|
||||
"top-only")
|
||||
retry_command 3 ${pkgs.gnome-monitor-config}/bin/gnome-monitor-config set \
|
||||
-LpM "$PRIMARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -x 0 -y 0
|
||||
;;
|
||||
"bottom-only")
|
||||
retry_command 3 ${pkgs.gnome-monitor-config}/bin/gnome-monitor-config set \
|
||||
-LpM "$SECONDARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -x 0 -y 0
|
||||
;;
|
||||
"both-stacked")
|
||||
retry_command 3 ${pkgs.gnome-monitor-config}/bin/gnome-monitor-config set \
|
||||
-LpM "$PRIMARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -x 0 -y 0 \
|
||||
-LM "$SECONDARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -x 0 -y "$Y_OFFSET"
|
||||
;;
|
||||
"both-left")
|
||||
retry_command 3 ${pkgs.gnome-monitor-config}/bin/gnome-monitor-config set \
|
||||
-LpM "$SECONDARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -t left -x 0 -y 0 \
|
||||
-LM "$PRIMARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -t left -x "$Y_OFFSET" -y 0
|
||||
;;
|
||||
"both-right")
|
||||
retry_command 3 ${pkgs.gnome-monitor-config}/bin/gnome-monitor-config set \
|
||||
-LM "$PRIMARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -t right -x 0 -y 0 \
|
||||
-LpM "$SECONDARY_DISPLAY" -m "$PREFERRED_RESOLUTION" -s "$UI_SCALE" -t right -x "$Y_OFFSET" -y 0
|
||||
;;
|
||||
*)
|
||||
handle_error "Unknown display configuration: $config_name"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Update tablet/touchscreen mappings after successful display config
|
||||
update_tablet_mappings "$config_name"
|
||||
}
|
||||
|
||||
# Update tablet and touchscreen mappings based on display config
|
||||
update_tablet_mappings() {
|
||||
local config="$1"
|
||||
log "Updating tablet mappings for configuration: $config"
|
||||
|
||||
# Always map primary touch to primary display and secondary to secondary
|
||||
for device_type in tablets touchscreens; do
|
||||
${pkgs.dconf}/bin/dconf write "/org/gnome/desktop/peripherals/$device_type/$PRIMARY_TOUCH_ID/output" \
|
||||
"['SDC', '0x419d', '0x00000000', '$PRIMARY_DISPLAY']" 2>/dev/null || true
|
||||
${pkgs.dconf}/bin/dconf write "/org/gnome/desktop/peripherals/$device_type/$SECONDARY_TOUCH_ID/output" \
|
||||
"['SDC', '0x419d', '0x00000000', '$SECONDARY_DISPLAY']" 2>/dev/null || true
|
||||
done
|
||||
}
|
||||
|
||||
# ===== EVENT HANDLING & WATCHERS =====
|
||||
|
||||
# Handle display change events
|
||||
handle_display_change() {
|
||||
log "Display change detected"
|
||||
sleep 1 # Allow hardware to stabilize
|
||||
|
||||
local optimal_config
|
||||
optimal_config=$(determine_optimal_config)
|
||||
apply_display_config "$optimal_config"
|
||||
}
|
||||
|
||||
# Handle orientation change events
|
||||
handle_orientation_change() {
|
||||
local new_orientation="$1"
|
||||
log "Orientation changed to: $new_orientation"
|
||||
|
||||
# Always reconfigure internal displays when orientation changes
|
||||
# External displays don't affect the need to maintain proper internal layout
|
||||
local optimal_config
|
||||
optimal_config=$(determine_optimal_config)
|
||||
apply_display_config "$optimal_config"
|
||||
}
|
||||
|
||||
# Watch for USB device changes (dock connect/disconnect)
|
||||
watch_usb_changes() {
|
||||
log "Starting USB device watcher"
|
||||
while ${pkgs.inotify-tools}/bin/inotifywait -e attrib /dev/bus/usb/*/ 2>/dev/null; do
|
||||
handle_display_change
|
||||
done
|
||||
}
|
||||
|
||||
# Watch for orientation changes
|
||||
watch_orientation_changes() {
|
||||
log "Starting orientation watcher"
|
||||
${pkgs.iio-sensor-proxy}/bin/monitor-sensor --accel 2>/dev/null | \
|
||||
${pkgs.coreutils}/bin/stdbuf -oL grep "orientation" | \
|
||||
${pkgs.coreutils}/bin/stdbuf -oL cut -d: -f2 | \
|
||||
${pkgs.coreutils}/bin/stdbuf -oL sed 's/[ )]//g' | \
|
||||
while read -r orientation; do
|
||||
handle_orientation_change "$orientation"
|
||||
done
|
||||
}
|
||||
|
||||
# ===== BACKLIGHT MANAGEMENT =====
|
||||
|
||||
# Sync backlight between displays
|
||||
sync_backlight() {
|
||||
if [ -r "/sys/class/backlight/intel_backlight/brightness" ] && [ -w "/sys/class/backlight/$BACKLIGHT/brightness" ]; then
|
||||
cat "/sys/class/backlight/intel_backlight/brightness" | \
|
||||
suenv tee "/sys/class/backlight/$BACKLIGHT/brightness" >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Watch backlight changes
|
||||
watch_backlight() {
|
||||
log "Starting backlight watcher"
|
||||
sync_backlight # Initial sync
|
||||
while ${pkgs.inotify-tools}/bin/inotifywait -e modify "/sys/class/backlight/intel_backlight/brightness" 2>/dev/null; do
|
||||
sync_backlight
|
||||
done
|
||||
}
|
||||
|
||||
# ===== MAIN COMMAND INTERFACE =====
|
||||
|
||||
case "''${1:-}" in
|
||||
# Automatic configuration
|
||||
"auto"|"configure")
|
||||
optimal_config=$(determine_optimal_config)
|
||||
apply_display_config "$optimal_config"
|
||||
;;
|
||||
|
||||
# Manual display configurations
|
||||
"top")
|
||||
apply_display_config "top-only"
|
||||
;;
|
||||
"bottom")
|
||||
apply_display_config "bottom-only"
|
||||
;;
|
||||
"both"|"normal")
|
||||
apply_display_config "both-stacked"
|
||||
;;
|
||||
"left-up")
|
||||
apply_display_config "both-left"
|
||||
;;
|
||||
"right-up")
|
||||
apply_display_config "both-right"
|
||||
;;
|
||||
|
||||
# Toggle between configurations
|
||||
"toggle")
|
||||
current_status=$(get_internal_display_status)
|
||||
case "$current_status" in
|
||||
"both") apply_display_config "top-only" ;;
|
||||
"top"|"bottom") apply_display_config "both-stacked" ;;
|
||||
*) apply_display_config "both-stacked" ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
# Status reporting
|
||||
"status")
|
||||
echo "Internal: $(get_internal_display_status)"
|
||||
if has_external_displays; then
|
||||
echo "External: $(get_active_external_displays | tr '\n' '+')"
|
||||
fi
|
||||
echo "Dock: $(is_dock_connected && echo "connected" || echo "disconnected")"
|
||||
;;
|
||||
|
||||
# Event watchers
|
||||
"watch-displays")
|
||||
watch_usb_changes
|
||||
;;
|
||||
"watch-orientation")
|
||||
watch_orientation_changes
|
||||
;;
|
||||
"watch-backlight")
|
||||
watch_backlight
|
||||
;;
|
||||
|
||||
# Utility functions
|
||||
"sync-backlight")
|
||||
sync_backlight
|
||||
;;
|
||||
"set-tablet-mapping")
|
||||
update_tablet_mappings "both-stacked"
|
||||
;;
|
||||
"toggle-bottom-touch")
|
||||
path="/org/gnome/desktop/peripherals/touchscreens/$SECONDARY_TOUCH_ID/output"
|
||||
if [ -z "$(${pkgs.dconf}/bin/dconf read "$path" 2>/dev/null || true)" ]; then
|
||||
${pkgs.dconf}/bin/dconf write "$path" "['SDC', '0x419d', '0x00000000', '$SECONDARY_DISPLAY']"
|
||||
else
|
||||
${pkgs.dconf}/bin/dconf reset "$path"
|
||||
fi
|
||||
;;
|
||||
"bat-limit")
|
||||
echo "''${2:-80}" | suenv tee /sys/class/power_supply/BAT0/charge_control_end_threshold
|
||||
;;
|
||||
"set-kb-backlight")
|
||||
suenv ${zenbook-kb-backlight}/bin/zenbook-kb-backlight "''${2:-1}"
|
||||
;;
|
||||
|
||||
# Deprecated aliases for backward compatibility
|
||||
"set-displays")
|
||||
log "DEPRECATED: Use 'auto' instead of 'set-displays'"
|
||||
"$0" auto
|
||||
;;
|
||||
"bottom-up")
|
||||
log "DEPRECATED: Use specific orientation commands"
|
||||
apply_display_config "bottom-only"
|
||||
;;
|
||||
"status-internal")
|
||||
get_internal_display_status
|
||||
;;
|
||||
|
||||
# Help
|
||||
"help"|"-h"|"--help"|"")
|
||||
cat << EOF
|
||||
ZenBook Duo Display Management Tool
|
||||
|
||||
USAGE: duo <command> [options]
|
||||
|
||||
AUTOMATIC CONFIGURATION:
|
||||
auto, configure Automatically configure displays based on current state
|
||||
|
||||
MANUAL CONFIGURATION:
|
||||
top Enable only top display
|
||||
bottom Enable only bottom display
|
||||
both, normal Enable both displays in stacked configuration
|
||||
left-up Both displays rotated left
|
||||
right-up Both displays rotated right
|
||||
toggle Toggle between single and dual display modes
|
||||
|
||||
STATUS & MONITORING:
|
||||
status Show current display and device status
|
||||
watch-displays Monitor for display/dock changes
|
||||
watch-orientation Monitor for orientation changes
|
||||
watch-backlight Monitor and sync backlight changes
|
||||
|
||||
UTILITIES:
|
||||
sync-backlight Manually sync backlight between displays
|
||||
set-tablet-mapping Update tablet/touchscreen mappings
|
||||
toggle-bottom-touch Toggle bottom touchscreen mapping
|
||||
bat-limit [0-100] Set battery charge limit (default: 80)
|
||||
set-kb-backlight [0-3] Set keyboard backlight level
|
||||
|
||||
help Show this help message
|
||||
EOF
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown command: $1"
|
||||
echo "Use 'duo help' for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
|
||||
# Keyboard backlight control script
|
||||
zenbook-kb-backlight = pkgs.python3Packages.buildPythonApplication {
|
||||
pname = "zenbook-kb-backlight";
|
||||
version = "1.0.0";
|
||||
format = "other";
|
||||
|
||||
src = pkgs.writeText "zenbook-kb-backlight.py" ''
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import usb.core
|
||||
import usb.util
|
||||
import sys
|
||||
import time
|
||||
|
||||
# USB vendor and product IDs for ZenBook Duo 2024
|
||||
VENDOR_ID = 0x0b05 # ASUS
|
||||
PRODUCT_ID = 0x19b6 # ZenBook Duo specific
|
||||
|
||||
def find_keyboard_device():
|
||||
"""Find the ZenBook Duo keyboard device"""
|
||||
devices = usb.core.find(find_all=True, idVendor=VENDOR_ID)
|
||||
for device in devices:
|
||||
if device.idProduct == PRODUCT_ID:
|
||||
return device
|
||||
return None
|
||||
|
||||
def set_backlight(brightness):
|
||||
"""Set keyboard backlight brightness (0-3)"""
|
||||
device = find_keyboard_device()
|
||||
if not device:
|
||||
print("ZenBook Duo keyboard device not found")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Detach kernel driver if it's attached
|
||||
if device.is_kernel_driver_active(0):
|
||||
device.detach_kernel_driver(0)
|
||||
|
||||
# Set configuration
|
||||
device.set_configuration()
|
||||
|
||||
# Send backlight control command
|
||||
# This is a generic HID command structure for keyboard backlight
|
||||
# Values might need adjustment based on actual hardware
|
||||
device.ctrl_transfer(
|
||||
bmRequestType=0x21, # USB_TYPE_CLASS | USB_RECIP_INTERFACE
|
||||
bRequest=0x09, # HID SET_REPORT
|
||||
wValue=0x0301, # Report type and ID
|
||||
wIndex=0, # Interface
|
||||
data_or_wLength=[0x5d, 0xba, brightness, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||||
)
|
||||
return True
|
||||
|
||||
except usb.core.USBError as e:
|
||||
print(f"USB Error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: zenbook-kb-backlight <brightness>")
|
||||
print("Brightness levels: 0 (off), 1 (low), 2 (medium), 3 (high)")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
brightness = int(sys.argv[1])
|
||||
if brightness < 0 or brightness > 3:
|
||||
raise ValueError("Brightness must be between 0 and 3")
|
||||
|
||||
if set_backlight(brightness):
|
||||
print(f"Keyboard backlight set to level {brightness}")
|
||||
else:
|
||||
print("Failed to set keyboard backlight")
|
||||
sys.exit(1)
|
||||
|
||||
except ValueError as e:
|
||||
print(f"Invalid brightness value: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
'';
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [pyusb];
|
||||
|
||||
dontUnpack = true;
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
cp $src $out/bin/zenbook-kb-backlight
|
||||
chmod +x $out/bin/zenbook-kb-backlight
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "ZenBook keyboard backlight control utility";
|
||||
license = pkgs.lib.licenses.mit;
|
||||
};
|
||||
};
|
||||
|
||||
# Combined package with both scripts
|
||||
zenbook-duo-tools = pkgs.stdenv.mkDerivation {
|
||||
pname = "zenbook-duo-tools";
|
||||
version = "1.0.0";
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp ${duoScript} $out/bin/duo
|
||||
cp ${zenbook-kb-backlight}/bin/zenbook-kb-backlight $out/bin/zenbook-kb-backlight
|
||||
chmod +x $out/bin/*
|
||||
'';
|
||||
};
|
||||
in {
|
||||
# Install the ZenBook Duo tools
|
||||
home.packages = with pkgs; [
|
||||
zenbook-duo-tools
|
||||
gnome-settings-daemon
|
||||
gnome-monitor-config
|
||||
inotify-tools
|
||||
usbutils
|
||||
dconf
|
||||
iio-sensor-proxy
|
||||
];
|
||||
|
||||
# Systemd user services for automatic display management
|
||||
systemd.user.services = {
|
||||
zenbook-display-startup = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Display Setup on Startup";
|
||||
After = ["graphical-session.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo auto";
|
||||
RemainAfterExit = true;
|
||||
# Add some delay to ensure graphics are ready
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 2";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
|
||||
zenbook-display-watcher = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Display Watcher";
|
||||
After = ["graphical-session.target" "zenbook-display-startup.service"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
Requires = ["zenbook-display-startup.service"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo watch-displays";
|
||||
Restart = "always";
|
||||
RestartSec = "10";
|
||||
# Prevent rapid restarts
|
||||
StartLimitInterval = "60";
|
||||
StartLimitBurst = "3";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
|
||||
zenbook-orientation-watcher = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Orientation Watcher";
|
||||
After = ["graphical-session.target" "zenbook-display-startup.service"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
Requires = ["zenbook-display-startup.service"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo watch-orientation";
|
||||
Restart = "always";
|
||||
RestartSec = "10";
|
||||
StartLimitInterval = "60";
|
||||
StartLimitBurst = "3";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
|
||||
zenbook-backlight-sync = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Backlight Sync";
|
||||
After = ["graphical-session.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo watch-backlight";
|
||||
Restart = "always";
|
||||
RestartSec = "5";
|
||||
# This is less critical, allow more restarts
|
||||
StartLimitInterval = "300";
|
||||
StartLimitBurst = "10";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# Shell aliases for convenience (generic across all shells)
|
||||
home.shellAliases = {
|
||||
# Main commands
|
||||
duo = "${zenbook-duo-tools}/bin/duo";
|
||||
duo-auto = "${zenbook-duo-tools}/bin/duo auto";
|
||||
duo-status = "${zenbook-duo-tools}/bin/duo status";
|
||||
duo-help = "${zenbook-duo-tools}/bin/duo help";
|
||||
|
||||
# Display configurations
|
||||
duo-toggle = "${zenbook-duo-tools}/bin/duo toggle";
|
||||
duo-both = "${zenbook-duo-tools}/bin/duo both";
|
||||
duo-top = "${zenbook-duo-tools}/bin/duo top";
|
||||
duo-bottom = "${zenbook-duo-tools}/bin/duo bottom";
|
||||
|
||||
# Utilities
|
||||
duo-sync-backlight = "${zenbook-duo-tools}/bin/duo sync-backlight";
|
||||
zenbook-kb = "${zenbook-duo-tools}/bin/zenbook-kb-backlight";
|
||||
|
||||
# Backward compatibility
|
||||
duo-normal = "${zenbook-duo-tools}/bin/duo both"; # Alias for legacy 'normal' command
|
||||
};
|
||||
|
||||
# GNOME specific configuration
|
||||
dconf.settings = {
|
||||
# Enable tablet/touchscreen support for specific device IDs
|
||||
"org/gnome/desktop/peripherals/tablets/${duoConfig.primary_touch_id}" = {
|
||||
output = ["SDC" "0x419d" "0x00000000" duoConfig.primary_display];
|
||||
};
|
||||
|
||||
"org/gnome/desktop/peripherals/tablets/${duoConfig.secondary_touch_id}" = {
|
||||
output = ["SDC" "0x419d" "0x00000000" duoConfig.secondary_display];
|
||||
};
|
||||
|
||||
"org/gnome/desktop/peripherals/touchscreens/${duoConfig.primary_touch_id}" = {
|
||||
output = ["SDC" "0x419d" "0x00000000" duoConfig.primary_display];
|
||||
};
|
||||
|
||||
"org/gnome/desktop/peripherals/touchscreens/${duoConfig.secondary_touch_id}" = {
|
||||
output = ["SDC" "0x419d" "0x00000000" duoConfig.secondary_display];
|
||||
};
|
||||
|
||||
# Custom keybind for ZenBook display configuration
|
||||
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/zenbook-displays" = {
|
||||
name = "ZenBook Display Configuration";
|
||||
command = "${zenbook-duo-tools}/bin/duo auto";
|
||||
binding = "<Super>z";
|
||||
};
|
||||
|
||||
"org/gnome/settings-daemon/plugins/media-keys" = {
|
||||
custom-keybindings = [
|
||||
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/zenbook-displays/"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,14 +1,64 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
}: {
|
||||
dconf.settings = {
|
||||
"org/gnome/desktop/interface".color-scheme = lib.mkForce "prefer-dark";
|
||||
"org/gnome/mutter".experimental-features = ["variable-refresh-rate" "scale-monitor-framebuffer"];
|
||||
|
||||
{
|
||||
gtk = {
|
||||
enable = true;
|
||||
iconTheme = {
|
||||
name = "elementary-Xfce-dark";
|
||||
package = pkgs.elementary-xfce-icon-theme;
|
||||
"org/gnome/shell" = {
|
||||
disable-user-extensions = false;
|
||||
|
||||
# `gnome-extensions list` for a list
|
||||
enabled-extensions = [
|
||||
#"gjsosk@vishram1123.com"
|
||||
"gsconnect@andyholmes.github.io"
|
||||
"screen-rotate@shyzus.github.io"
|
||||
"dash-to-dock@micxgx.gmail.com"
|
||||
"launch-new-instance@gnome-shell-extensions.gcampax.github.com"
|
||||
#"power-profile-switcher@eliapasquali.github.io"
|
||||
#"tilingshell@ferrarodomenico.com"
|
||||
#"pop-shell@system76.com"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Extensions
|
||||
home.packages = with pkgs; [
|
||||
gnomeExtensions.gsconnect
|
||||
#gnomeExtensions.screen-rotate
|
||||
gnomeExtensions.dash-to-dock
|
||||
gnomeExtensions.launch-new-instance
|
||||
#gnomeExtensions.pop-shell
|
||||
#gnomeExtensions.power-profile-switcher
|
||||
#gnomeExtensions.gjs-osk -- Disabled due to issue with read only file system
|
||||
|
||||
apostrophe
|
||||
collision
|
||||
contrast
|
||||
curtail
|
||||
drawing
|
||||
eyedropper
|
||||
fragments
|
||||
gnome-decoder
|
||||
gnome-extension-manager
|
||||
gnome-graphs
|
||||
gnome-obfuscate
|
||||
identity
|
||||
impression
|
||||
lorem
|
||||
metadata-cleaner
|
||||
mission-center
|
||||
paper-clip
|
||||
parabolic
|
||||
pika-backup
|
||||
#pitivi
|
||||
pods
|
||||
ptyxis
|
||||
tangram
|
||||
textpieces
|
||||
video-trimmer
|
||||
alpaca
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,462 @@
|
||||
{
|
||||
inputs,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
# Import caelestia-shell home manager module
|
||||
imports = [
|
||||
inputs.caelestia-shell.homeManagerModules.default
|
||||
];
|
||||
|
||||
# Add packages required for Caelestia Shell functionality
|
||||
home.packages = with pkgs; [
|
||||
# Required for network functionality
|
||||
networkmanager
|
||||
# For brightness control
|
||||
brightnessctl
|
||||
# For audio visualization
|
||||
cava
|
||||
# For calculations in launcher
|
||||
libqalculate
|
||||
# For screenshot functionality
|
||||
swappy
|
||||
# For clipboard
|
||||
wl-clipboard
|
||||
# For authentication dialogs (WiFi passwords, etc.)
|
||||
kdePackages.polkit-kde-agent-1
|
||||
# For storing WiFi passwords securely
|
||||
gnome-keyring
|
||||
libsecret
|
||||
];
|
||||
|
||||
# Set up wallpapers directory and sync with Stylix
|
||||
home.file."Pictures/Wallpapers/stylix-wallpaper" = {
|
||||
source = config.stylix.image;
|
||||
enable = config.stylix.image != null;
|
||||
};
|
||||
|
||||
# Caelestia Shell configuration based on https://github.com/caelestia-dots/shell
|
||||
# Integrated with Stylix theming system
|
||||
programs.caelestia = {
|
||||
enable = true;
|
||||
systemd = {
|
||||
enable = true; # if you prefer starting from your compositor
|
||||
target = "graphical-session.target";
|
||||
environment = [];
|
||||
};
|
||||
settings = let
|
||||
# Access Stylix fonts
|
||||
fonts = config.stylix.fonts;
|
||||
in {
|
||||
# ===== APPEARANCE SETTINGS =====
|
||||
appearance = {
|
||||
# Font configuration using Stylix fonts
|
||||
font = {
|
||||
family = {
|
||||
material = "Material Symbols Rounded";
|
||||
mono = fonts.monospace.name;
|
||||
sans = fonts.sansSerif.name;
|
||||
};
|
||||
size = {
|
||||
scale = 1; # Keep default scaling, adjust if needed
|
||||
};
|
||||
};
|
||||
|
||||
# Transparency settings
|
||||
transparency = {
|
||||
enabled = true;
|
||||
base = 0.90; # Adjust based on preference
|
||||
layers = 0.3;
|
||||
};
|
||||
|
||||
# Spacing and layout
|
||||
padding.scale = 1;
|
||||
rounding.scale = 1;
|
||||
spacing.scale = 1;
|
||||
|
||||
# Animation settings
|
||||
anim.durations.scale = 1;
|
||||
};
|
||||
|
||||
# ===== BAR CONFIGURATION =====
|
||||
bar = {
|
||||
persistent = true;
|
||||
showOnHover = false;
|
||||
|
||||
# Ensure bar entries are explicitly defined
|
||||
entries = [
|
||||
{
|
||||
id = "logo";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "workspaces";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "spacer";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "activeWindow";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "spacer";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "tray";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "clock";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "statusIcons";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "power";
|
||||
enabled = true;
|
||||
}
|
||||
{
|
||||
id = "idleInhibitor";
|
||||
enabled = false;
|
||||
}
|
||||
];
|
||||
|
||||
# Status indicators
|
||||
status = {
|
||||
showAudio = true;
|
||||
showBattery = true;
|
||||
showBluetooth = true;
|
||||
showKbLayout = false;
|
||||
showMicrophone = false;
|
||||
showNetwork = true;
|
||||
showLockStatus = true;
|
||||
};
|
||||
|
||||
# Clock settings
|
||||
clock = {
|
||||
showIcon = true;
|
||||
};
|
||||
|
||||
# Workspace configuration
|
||||
workspaces = {
|
||||
activeIndicator = true;
|
||||
activeLabel = "";
|
||||
activeTrail = false;
|
||||
label = " ";
|
||||
occupiedBg = true;
|
||||
occupiedLabel = "";
|
||||
perMonitorWorkspaces = true;
|
||||
showWindows = true;
|
||||
shown = 5;
|
||||
};
|
||||
|
||||
# Tray configuration
|
||||
tray = {
|
||||
background = false;
|
||||
iconSubs = [];
|
||||
recolour = true; # Recolor tray icons to match theme
|
||||
};
|
||||
|
||||
# Scroll actions
|
||||
scrollActions = {
|
||||
brightness = true;
|
||||
workspaces = true;
|
||||
volume = true;
|
||||
};
|
||||
|
||||
dragThreshold = 20;
|
||||
};
|
||||
|
||||
# ===== DASHBOARD =====
|
||||
dashboard = {
|
||||
enabled = true;
|
||||
dragThreshold = 50;
|
||||
mediaUpdateInterval = 500;
|
||||
showOnHover = true;
|
||||
};
|
||||
|
||||
# ===== LAUNCHER =====
|
||||
launcher = {
|
||||
actionPrefix = ">";
|
||||
specialPrefix = "@";
|
||||
dragThreshold = 50;
|
||||
vimKeybinds = false;
|
||||
enableDangerousActions = true;
|
||||
maxShown = 8;
|
||||
maxWallpapers = 9;
|
||||
showOnHover = false;
|
||||
hiddenApps = [];
|
||||
|
||||
# Enable more powerful fuzzy search for better UX
|
||||
useFuzzy = {
|
||||
apps = true;
|
||||
actions = true;
|
||||
schemes = false;
|
||||
variants = false;
|
||||
wallpapers = false;
|
||||
};
|
||||
|
||||
# Add useful launcher actions
|
||||
actions = [
|
||||
{
|
||||
name = "Calculator";
|
||||
icon = "calculate";
|
||||
description = "Do simple math equations (powered by Qalc)";
|
||||
command = ["autocomplete" "calc"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Scheme";
|
||||
icon = "palette";
|
||||
description = "Change the current colour scheme";
|
||||
command = ["autocomplete" "scheme"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Wallpaper";
|
||||
icon = "image";
|
||||
description = "Change the current wallpaper";
|
||||
command = ["autocomplete" "wallpaper"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Variant";
|
||||
icon = "colors";
|
||||
description = "Change the current scheme variant";
|
||||
command = ["autocomplete" "variant"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Random";
|
||||
icon = "casino";
|
||||
description = "Switch to a random wallpaper";
|
||||
command = ["caelestia" "wallpaper" "-r"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Light";
|
||||
icon = "light_mode";
|
||||
description = "Change the scheme to light mode";
|
||||
command = ["setMode" "light"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Dark";
|
||||
icon = "dark_mode";
|
||||
description = "Change the scheme to dark mode";
|
||||
command = ["setMode" "dark"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Shutdown";
|
||||
icon = "power_settings_new";
|
||||
description = "Shutdown the system";
|
||||
command = ["systemctl" "poweroff"];
|
||||
enabled = true;
|
||||
dangerous = true;
|
||||
}
|
||||
{
|
||||
name = "Reboot";
|
||||
icon = "cached";
|
||||
description = "Reboot the system";
|
||||
command = ["systemctl" "reboot"];
|
||||
enabled = true;
|
||||
dangerous = true;
|
||||
}
|
||||
{
|
||||
name = "Logout";
|
||||
icon = "exit_to_app";
|
||||
description = "Log out of the current session";
|
||||
command = ["loginctl" "terminate-user" ""];
|
||||
enabled = true;
|
||||
dangerous = true;
|
||||
}
|
||||
{
|
||||
name = "Lock";
|
||||
icon = "lock";
|
||||
description = "Lock the current session";
|
||||
command = ["loginctl" "lock-session"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
{
|
||||
name = "Sleep";
|
||||
icon = "bedtime";
|
||||
description = "Suspend then hibernate";
|
||||
command = ["systemctl" "suspend-then-hibernate"];
|
||||
enabled = true;
|
||||
dangerous = false;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# ===== NOTIFICATIONS =====
|
||||
notifs = {
|
||||
actionOnClick = false;
|
||||
clearThreshold = 0.3;
|
||||
defaultExpireTimeout = 5000;
|
||||
expandThreshold = 20;
|
||||
expire = false;
|
||||
};
|
||||
|
||||
# ===== OSD (On-Screen Display) =====
|
||||
osd = {
|
||||
enabled = true;
|
||||
enableBrightness = true;
|
||||
enableMicrophone = false;
|
||||
hideDelay = 2000;
|
||||
};
|
||||
|
||||
# ===== PATHS =====
|
||||
paths = {
|
||||
mediaGif = "root:/assets/bongocat.gif";
|
||||
sessionGif = "root:/assets/kurukuru.gif";
|
||||
wallpaperDir = "~/Pictures/Wallpapers";
|
||||
};
|
||||
|
||||
# ===== SERVICES =====
|
||||
services = {
|
||||
audioIncrement = 0.1;
|
||||
defaultPlayer = "Spotify";
|
||||
gpuType = ""; # Auto-detect
|
||||
playerAliases = [
|
||||
{
|
||||
from = "com.github.th-ch.youtube_music";
|
||||
to = "YT Music";
|
||||
}
|
||||
];
|
||||
weatherLocation = ""; # Set your location for weather
|
||||
useFahrenheit = false;
|
||||
useTwelveHourClock = false;
|
||||
smartScheme = true; # Enable dynamic color schemes based on wallpaper
|
||||
visualiserBars = 45;
|
||||
};
|
||||
|
||||
# ===== LOCK SCREEN =====
|
||||
lock = {
|
||||
recolourLogo = true; # Recolor logo to match theme
|
||||
};
|
||||
|
||||
# ===== BORDER =====
|
||||
border = {
|
||||
rounding = 20;
|
||||
thickness = 8;
|
||||
};
|
||||
|
||||
# ===== BACKGROUND =====
|
||||
background = {
|
||||
enabled = true;
|
||||
desktopClock = {
|
||||
enabled = false;
|
||||
};
|
||||
visualiser = {
|
||||
enabled = true;
|
||||
autoHide = true;
|
||||
rounding = 1;
|
||||
spacing = 1;
|
||||
};
|
||||
};
|
||||
|
||||
# ===== SESSION =====
|
||||
session = {
|
||||
dragThreshold = 30;
|
||||
vimKeybinds = false;
|
||||
commands = {
|
||||
logout = ["loginctl" "terminate-user" ""];
|
||||
shutdown = ["systemctl" "poweroff"];
|
||||
hibernate = ["systemctl" "hibernate"];
|
||||
reboot = ["systemctl" "reboot"];
|
||||
};
|
||||
};
|
||||
|
||||
# ===== GENERAL =====
|
||||
general = {
|
||||
apps = {
|
||||
terminal = ["ghostty"]; # Using your terminal preference
|
||||
audio = ["pavucontrol"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cli = {
|
||||
enable = true; # Also add caelestia-cli to path
|
||||
settings = {
|
||||
theme.enableGtk = false; # Let Stylix handle GTK theming
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Add launcher keybind for caelestia
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
bind = [
|
||||
# Launch caelestia launcher with just Super key
|
||||
"SUPER,space,global,caelestia:launcher"
|
||||
];
|
||||
};
|
||||
|
||||
# Set the Stylix wallpaper in Caelestia on startup
|
||||
systemd.user.services.caelestia-set-wallpaper = {
|
||||
Unit = {
|
||||
Description = "Set Stylix wallpaper in Caelestia Shell";
|
||||
After = ["caelestia.service"];
|
||||
Wants = ["caelestia.service"];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = let
|
||||
setWallpaperScript = pkgs.writeShellScript "set-caelestia-wallpaper" ''
|
||||
# Wait a moment for Caelestia to be ready
|
||||
sleep 2
|
||||
|
||||
# Check if Stylix wallpaper exists and set it via shell IPC
|
||||
if [ -f "$HOME/Pictures/Wallpapers/stylix-wallpaper" ]; then
|
||||
${inputs.caelestia-shell.packages.${pkgs.system}.with-cli}/bin/caelestia shell wallpaper set "$HOME/Pictures/Wallpapers/stylix-wallpaper" || true
|
||||
fi
|
||||
'';
|
||||
in "${setWallpaperScript}";
|
||||
RemainAfterExit = false;
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# Authentication agent for NetworkManager and other system operations
|
||||
systemd.user.services.polkit-kde-authentication-agent-1 = {
|
||||
Unit = {
|
||||
Description = "polkit-kde-authentication-agent-1";
|
||||
After = ["graphical-session-pre.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.kdePackages.polkit-kde-agent-1}/libexec/polkit-kde-authentication-agent-1";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
TimeoutStopSec = 10;
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# GNOME Keyring daemon for secure password storage
|
||||
services.gnome-keyring = {
|
||||
enable = true;
|
||||
components = ["pkcs11" "secrets" "ssh"];
|
||||
};
|
||||
}
|
||||
151
home/panotaka/common/optional/desktops/hyprland/default.nix
Normal file
151
home/panotaka/common/optional/desktops/hyprland/default.nix
Normal file
@@ -0,0 +1,151 @@
|
||||
{pkgs, ...}: {
|
||||
imports = [
|
||||
./caelestia-shell.nix
|
||||
./hyprlock.nix
|
||||
./hypridle.nix
|
||||
./keyring.nix
|
||||
];
|
||||
|
||||
# Add essential packages
|
||||
home.packages = [
|
||||
# Essential packages will be provided by caelestia-shell
|
||||
];
|
||||
|
||||
# Configure Hyprland session management
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
# Set mod key
|
||||
"$mod" = "SUPER";
|
||||
# Enable inverted (natural) scrolling on touchpad
|
||||
"input:touchpad:natural_scroll" = true;
|
||||
# Disable middle click on touchpad
|
||||
"input:touchpad:clickfinger_behavior" = false;
|
||||
"input:touchpad:middle_button_emulation" = false;
|
||||
# Disable middle-click paste
|
||||
"misc:middle_click_paste" = false;
|
||||
|
||||
# Built-in touchpad gesture configuration
|
||||
"gestures" = {
|
||||
# Enable workspace swipe gesture on touchpad (vertical for workspaces)
|
||||
workspace_swipe = true;
|
||||
# Use 3 fingers for workspace switching
|
||||
workspace_swipe_fingers = 3;
|
||||
# Distance for gesture recognition
|
||||
workspace_swipe_distance = 300;
|
||||
# Invert direction to match natural scrolling
|
||||
workspace_swipe_invert = true;
|
||||
# Enable workspace swiping from touchscreen edge
|
||||
workspace_swipe_touch = true;
|
||||
# Touchscreen invert direction
|
||||
workspace_swipe_touch_invert = true;
|
||||
# Create new workspace when swiping right on last workspace
|
||||
workspace_swipe_create_new = true;
|
||||
# Lock direction once threshold is reached
|
||||
workspace_swipe_direction_lock = true;
|
||||
# Direction lock threshold in pixels
|
||||
workspace_swipe_direction_lock_threshold = 10;
|
||||
};
|
||||
|
||||
# Essential startup services
|
||||
exec-once = [
|
||||
# Start polkit authentication agent for secure authentication
|
||||
"${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"
|
||||
];
|
||||
|
||||
# Layer rules for proper panel/bar integration
|
||||
layerrule = [
|
||||
# Waybar should be on top and reserve space
|
||||
"blur,waybar"
|
||||
"ignorezero,waybar"
|
||||
];
|
||||
|
||||
# Keybinds
|
||||
bind = [
|
||||
# Launch terminal (kitty)
|
||||
"$mod,T,exec,kitty"
|
||||
# Launch browser (zen)
|
||||
"$mod,B,exec,zen"
|
||||
# Close window
|
||||
"$mod,Q,killactive"
|
||||
# Logout
|
||||
"$mod SHIFT,E,exit"
|
||||
|
||||
# Secrets manager (Seahorse - GNOME keyring GUI)
|
||||
"$mod,K,exec,seahorse"
|
||||
|
||||
# Standard window navigation
|
||||
"$mod,Right,movefocus,r"
|
||||
"$mod,Left,movefocus,l"
|
||||
"$mod,Up,movefocus,u"
|
||||
"$mod,Down,movefocus,d"
|
||||
|
||||
# Move windows
|
||||
"$mod SHIFT,Right,movewindow,r"
|
||||
"$mod SHIFT,Left,movewindow,l"
|
||||
"$mod SHIFT,Up,movewindow,u"
|
||||
"$mod SHIFT,Down,movewindow,d"
|
||||
|
||||
# Resize windows
|
||||
"$mod,equal,resizeactive,10 0"
|
||||
"$mod,minus,resizeactive,-10 0"
|
||||
"$mod SHIFT,equal,resizeactive,0 10"
|
||||
"$mod SHIFT,minus,resizeactive,0 -10"
|
||||
|
||||
# Toggle split direction
|
||||
"$mod,V,togglesplit"
|
||||
|
||||
# Focus controls with vim keys
|
||||
"$mod,H,movefocus,l"
|
||||
"$mod,L,movefocus,r"
|
||||
"$mod,K,movefocus,u"
|
||||
"$mod,J,movefocus,d"
|
||||
|
||||
# Move active window to workspace
|
||||
"$mod SHIFT,1,movetoworkspace,1"
|
||||
"$mod SHIFT,2,movetoworkspace,2"
|
||||
"$mod SHIFT,3,movetoworkspace,3"
|
||||
"$mod SHIFT,4,movetoworkspace,4"
|
||||
"$mod SHIFT,5,movetoworkspace,5"
|
||||
"$mod SHIFT,6,movetoworkspace,6"
|
||||
"$mod SHIFT,7,movetoworkspace,7"
|
||||
"$mod SHIFT,8,movetoworkspace,8"
|
||||
"$mod SHIFT,9,movetoworkspace,9"
|
||||
"$mod SHIFT,0,movetoworkspace,10"
|
||||
|
||||
# Workspace switching with Meta+PageUp/PageDown
|
||||
"META,Prior,workspace,e-1" # Meta+PageUp = previous workspace
|
||||
"META,Next,workspace,e+1" # Meta+PageDown = next workspace
|
||||
|
||||
# Workspace switching with Super+Tab/Shift+Tab
|
||||
"$mod,Tab,workspace,e+1" # Super+Tab = next workspace
|
||||
"$mod SHIFT,Tab,workspace,e-1" # Super+Shift+Tab = previous workspace
|
||||
];
|
||||
|
||||
# Mouse binds for window management
|
||||
bindm = [
|
||||
# Mod + left click to move windows
|
||||
"$mod,mouse:272,movewindow"
|
||||
# Mod + right click to resize windows
|
||||
"$mod,mouse:273,resizewindow"
|
||||
];
|
||||
|
||||
# Scroll binds - super+shift for workspaces
|
||||
binde = [
|
||||
# Super+Shift+Scroll: workspace switching
|
||||
"$mod SHIFT,mouse_down,workspace,e+1"
|
||||
"$mod SHIFT,mouse_up,workspace,e-1"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Session variables for proper Wayland integration
|
||||
home.sessionVariables = {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
MOZ_ENABLE_WAYLAND = "1";
|
||||
QT_QPA_PLATFORM = "wayland";
|
||||
SDL_VIDEODRIVER = "wayland";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
};
|
||||
}
|
||||
37
home/panotaka/common/optional/desktops/hyprland/hypridle.nix
Normal file
37
home/panotaka/common/optional/desktops/hyprland/hypridle.nix
Normal file
@@ -0,0 +1,37 @@
|
||||
{pkgs, ...}: {
|
||||
services.hypridle = {
|
||||
enable = true;
|
||||
settings = {
|
||||
general = {
|
||||
lock_cmd = "pidof hyprlock || hyprlock";
|
||||
before_sleep_cmd = "loginctl lock-session";
|
||||
after_sleep_cmd = "hyprctl dispatch dpms on";
|
||||
};
|
||||
|
||||
listener = [
|
||||
{
|
||||
timeout = 150;
|
||||
on-timeout = "brightnessctl -s set 10";
|
||||
on-resume = "brightnessctl -r";
|
||||
}
|
||||
{
|
||||
timeout = 300;
|
||||
on-timeout = "loginctl lock-session";
|
||||
}
|
||||
{
|
||||
timeout = 330;
|
||||
on-timeout = "hyprctl dispatch dpms off";
|
||||
on-resume = "hyprctl dispatch dpms on";
|
||||
}
|
||||
{
|
||||
timeout = 1800;
|
||||
on-timeout = "systemctl suspend";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
hypridle
|
||||
];
|
||||
}
|
||||
14
home/panotaka/common/optional/desktops/hyprland/hyprlock.nix
Normal file
14
home/panotaka/common/optional/desktops/hyprland/hyprlock.nix
Normal file
@@ -0,0 +1,14 @@
|
||||
{pkgs, ...}: {
|
||||
programs.hyprlock = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Launch hyprlock
|
||||
wayland.windowManager.hyprland.settings.bind = [
|
||||
"$mod,L,exec,hyprlock"
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
hyprlock
|
||||
];
|
||||
}
|
||||
44
home/panotaka/common/optional/desktops/hyprland/keyring.nix
Normal file
44
home/panotaka/common/optional/desktops/hyprland/keyring.nix
Normal file
@@ -0,0 +1,44 @@
|
||||
{pkgs, ...}: {
|
||||
# Additional keyring packages for user interaction
|
||||
home.packages = with pkgs; [
|
||||
seahorse # GUI for managing keyrings and passwords
|
||||
libsecret # Secret service API library
|
||||
gnome-keyring # GNOME keyring daemon
|
||||
polkit_gnome # Polkit authentication agent for GNOME
|
||||
networkmanager # Ensure NetworkManager is available for password integration
|
||||
];
|
||||
|
||||
# Session variables for proper keyring integration
|
||||
home.sessionVariables = {
|
||||
# SSH agent socket for SSH key management
|
||||
SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/keyring/ssh";
|
||||
# Control socket for GNOME Keyring daemon
|
||||
GNOME_KEYRING_CONTROL = "$XDG_RUNTIME_DIR/keyring";
|
||||
# Enable secret service D-Bus API
|
||||
SECRET_SERVICE_API = "1";
|
||||
# Ensure proper D-Bus session bus integration
|
||||
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
|
||||
# Set keyring backend for applications that support it
|
||||
KEYRING_BACKEND = "gnome-keyring";
|
||||
# Ensure XDG runtime directory is available
|
||||
XDG_RUNTIME_DIR = "/run/user/1000";
|
||||
# Enable keyring unlock via PAM
|
||||
GNOME_KEYRING_UNLOCK_PASSWORD = "1";
|
||||
};
|
||||
|
||||
# Enable GNOME keyring service
|
||||
services.gnome-keyring = {
|
||||
enable = true;
|
||||
components = ["pkcs11" "secrets" "ssh"];
|
||||
};
|
||||
|
||||
# Enable additional Wayland session variables for Hyprland
|
||||
wayland.windowManager.hyprland.settings.env = [
|
||||
# Ensure all keyring environment variables are available to Hyprland
|
||||
"SSH_AUTH_SOCK,$XDG_RUNTIME_DIR/keyring/ssh"
|
||||
"GNOME_KEYRING_CONTROL,$XDG_RUNTIME_DIR/keyring"
|
||||
"SECRET_SERVICE_API,1"
|
||||
"KEYRING_BACKEND,gnome-keyring"
|
||||
"GNOME_KEYRING_UNLOCK_PASSWORD,1"
|
||||
];
|
||||
}
|
||||
137
home/panotaka/common/optional/desktops/hyprland/waybar.nix
Normal file
137
home/panotaka/common/optional/desktops/hyprland/waybar.nix
Normal file
@@ -0,0 +1,137 @@
|
||||
{pkgs, ...}: {
|
||||
programs.waybar = {
|
||||
enable = true;
|
||||
settings = {
|
||||
mainBar = {
|
||||
layer = "top";
|
||||
position = "top";
|
||||
height = 30;
|
||||
|
||||
modules-left = ["hyprland/workspaces" "hyprland/mode" "hyprland/window"];
|
||||
modules-center = ["clock"];
|
||||
modules-right = ["network" "bluetooth" "pulseaudio" "battery" "tray" "custom/notification"];
|
||||
|
||||
"hyprland/workspaces" = {
|
||||
disable-scroll = true;
|
||||
all-outputs = true;
|
||||
format = "{icon}";
|
||||
format-icons = {
|
||||
"1" = "1";
|
||||
"2" = "2";
|
||||
"3" = "3";
|
||||
"4" = "4";
|
||||
"5" = "5";
|
||||
"6" = "6";
|
||||
"7" = "7";
|
||||
"8" = "8";
|
||||
"9" = "9";
|
||||
"10" = "10";
|
||||
};
|
||||
};
|
||||
|
||||
"hyprland/mode" = {
|
||||
format = "<span style=\"italic\">{}</span>";
|
||||
};
|
||||
|
||||
"hyprland/window" = {
|
||||
format = "{}";
|
||||
max-length = 50;
|
||||
separate-outputs = true;
|
||||
};
|
||||
|
||||
"clock" = {
|
||||
tooltip-format = "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>";
|
||||
format-alt = "{:%Y-%m-%d}";
|
||||
format = "{:%H:%M}";
|
||||
};
|
||||
|
||||
"network" = {
|
||||
format-wifi = " {essid} ({signalStrength}%)";
|
||||
format-ethernet = " {ipaddr}/{cidr}";
|
||||
tooltip-format = " {ifname} via {gwaddr}";
|
||||
format-linked = " {ifname} (No IP)";
|
||||
format-disconnected = "⚠ Disconnected";
|
||||
format-alt = "{ifname}: {ipaddr}/{cidr}";
|
||||
};
|
||||
|
||||
"bluetooth" = {
|
||||
format = " {status}";
|
||||
format-disabled = "";
|
||||
format-connected = " {device_alias}";
|
||||
format-connected-battery = " {device_alias} {device_battery_percentage}%";
|
||||
tooltip-format = "{controller_alias}\t{controller_address}\n\n{num_connections} connected";
|
||||
tooltip-format-connected = "{controller_alias}\t{controller_address}\n\n{num_connections} connected\n\n{device_enumerate}";
|
||||
tooltip-format-enumerate-connected = "{device_alias}\t{device_address}";
|
||||
tooltip-format-enumerate-connected-battery = "{device_alias}\t{device_address}\t{device_battery_percentage}%";
|
||||
};
|
||||
|
||||
"pulseaudio" = {
|
||||
scroll-step = 5;
|
||||
format = "{icon} {volume}%";
|
||||
format-bluetooth = "{icon} {volume}% ";
|
||||
format-bluetooth-muted = " {icon}";
|
||||
format-muted = " {format_source}";
|
||||
format-source = "{volume}% ";
|
||||
format-source-muted = "";
|
||||
format-icons = {
|
||||
headphone = "";
|
||||
hands-free = "";
|
||||
headset = "";
|
||||
phone = "";
|
||||
portable = "";
|
||||
car = "";
|
||||
default = ["" "" ""];
|
||||
};
|
||||
on-click = "pavucontrol";
|
||||
};
|
||||
|
||||
"battery" = {
|
||||
states = {
|
||||
good = 95;
|
||||
warning = 30;
|
||||
critical = 15;
|
||||
};
|
||||
format = "{icon} {capacity}%";
|
||||
format-charging = " {capacity}%";
|
||||
format-plugged = " {capacity}%";
|
||||
format-alt = "{icon} {time}";
|
||||
format-icons = ["" "" "" "" ""];
|
||||
};
|
||||
|
||||
"tray" = {
|
||||
icon-size = 21;
|
||||
spacing = 10;
|
||||
show-passive-items = true;
|
||||
};
|
||||
|
||||
"custom/notification" = {
|
||||
tooltip = false;
|
||||
format = "{icon}";
|
||||
format-icons = {
|
||||
notification = "<span foreground='red'><sup></sup></span>";
|
||||
none = "";
|
||||
dnd-notification = "<span foreground='red'><sup></sup></span>";
|
||||
dnd-none = "";
|
||||
};
|
||||
return-type = "json";
|
||||
exec-if = "which swaync-client";
|
||||
exec = "swaync-client -swb";
|
||||
on-click = "swaync-client -t -sw";
|
||||
on-click-right = "swaync-client -d -sw";
|
||||
escape = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Auto-start waybar with Hyprland
|
||||
wayland.windowManager.hyprland.settings.exec-once = [
|
||||
"waybar"
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
waybar
|
||||
libappindicator-gtk3
|
||||
swaynotificationcenter
|
||||
];
|
||||
}
|
||||
43
home/panotaka/common/optional/desktops/hyprland/wofi.nix
Normal file
43
home/panotaka/common/optional/desktops/hyprland/wofi.nix
Normal file
@@ -0,0 +1,43 @@
|
||||
{pkgs, ...}: {
|
||||
programs.wofi = {
|
||||
enable = true;
|
||||
settings = {
|
||||
width = 600;
|
||||
height = 400;
|
||||
location = "center";
|
||||
show = "drun";
|
||||
prompt = "Search...";
|
||||
filter_rate = 100;
|
||||
allow_markup = true;
|
||||
no_actions = true;
|
||||
halign = "fill";
|
||||
orientation = "vertical";
|
||||
content_halign = "fill";
|
||||
insensitive = true;
|
||||
allow_images = true;
|
||||
image_size = 40;
|
||||
gtk_dark = true;
|
||||
dynamic_lines = false;
|
||||
matching = "contains";
|
||||
hide_scroll = true;
|
||||
print_command = true;
|
||||
layer = "overlay";
|
||||
sort_order = "default";
|
||||
term = "kitty";
|
||||
exec_search = false;
|
||||
};
|
||||
};
|
||||
|
||||
# Add wofi keybind to Hyprland: just $mod for drun (toggle behavior)
|
||||
wayland.windowManager.hyprland.settings.bindr = [
|
||||
"$mod, SUPER_L, exec, pkill wofi || wofi --show drun"
|
||||
];
|
||||
# Add wofi keybind to Hyprland: $mod+R for run (toggle behavior)
|
||||
wayland.windowManager.hyprland.settings.bind = [
|
||||
"$mod,R,exec, pkill wofi || wofi --show run"
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
wofi
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
# Configuration variables from your script
|
||||
preferred_resolution = "2880x1800";
|
||||
refresh_rate = "120";
|
||||
ui_scale = "1.5";
|
||||
y_offset = "1200";
|
||||
vrr_mode = "1"; # 0 = off, 1 = on, 2 = fullscreen only
|
||||
|
||||
# Inline scripts adapted from your bash script
|
||||
zenbook-top = pkgs.writeShellScriptBin "zenbook-top" ''
|
||||
echo "Setting to top screen only"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,disable"
|
||||
'';
|
||||
|
||||
zenbook-bottom = pkgs.writeShellScriptBin "zenbook-bottom" ''
|
||||
echo "Setting to bottom screen only"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,disable"
|
||||
'';
|
||||
|
||||
zenbook-both = pkgs.writeShellScriptBin "zenbook-both" ''
|
||||
echo "Setting to both screens"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,${preferred_resolution}@${refresh_rate},0x${y_offset},${ui_scale},vrr,${vrr_mode}"
|
||||
'';
|
||||
|
||||
zenbook-left-up = pkgs.writeShellScriptBin "zenbook-left-up" ''
|
||||
echo "Setting to left-right layout"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,${preferred_resolution}@${refresh_rate},${y_offset}x0,${ui_scale},vrr,${vrr_mode}"
|
||||
'';
|
||||
|
||||
zenbook-right-up = pkgs.writeShellScriptBin "zenbook-right-up" ''
|
||||
echo "Setting to right-left layout"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,${preferred_resolution}@${refresh_rate},${y_offset}x0,${ui_scale},vrr,${vrr_mode}"
|
||||
'';
|
||||
|
||||
zenbook-normal = pkgs.writeShellScriptBin "zenbook-normal" ''
|
||||
# Check if lid is closed
|
||||
lid_closed=false
|
||||
if grep -q closed /proc/acpi/button/lid/*/state 2>/dev/null; then
|
||||
lid_closed=true
|
||||
fi
|
||||
|
||||
# Check if keyboard is attached (USB dock detection)
|
||||
keyboard_attached=false
|
||||
if ${pkgs.usbutils}/bin/lsusb | grep 0b05:1b2c; then
|
||||
keyboard_attached=true
|
||||
fi
|
||||
|
||||
if [ "$lid_closed" = true ] && [ "$keyboard_attached" = true ]; then
|
||||
echo "Lid closed and keyboard attached — disabling both screens"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,disable"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,disable"
|
||||
elif [ "$lid_closed" = true ]; then
|
||||
echo "Lid closed — disabling top screen"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,disable"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
elif [ "$keyboard_attached" = true ]; then
|
||||
echo "Keyboard attached — disabling bottom screen"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-1,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
${pkgs.hyprland}/bin/hyprctl keyword monitor "eDP-2,disable"
|
||||
else
|
||||
echo "Normal mode — enabling both screens"
|
||||
${zenbook-both}/bin/zenbook-both
|
||||
fi
|
||||
'';
|
||||
|
||||
zenbook-toggle = pkgs.writeShellScriptBin "zenbook-toggle" ''
|
||||
# Check current state and toggle
|
||||
enabled_count=$(${pkgs.hyprland}/bin/hyprctl monitors | grep -c "eDP.*" || echo "0")
|
||||
if [ "$enabled_count" -eq 1 ]; then
|
||||
${zenbook-both}/bin/zenbook-both
|
||||
else
|
||||
${zenbook-top}/bin/zenbook-top
|
||||
fi
|
||||
'';
|
||||
|
||||
# Event-driven display management (from your original script)
|
||||
zenbook-watch-displays = pkgs.writeShellScriptBin "zenbook-watch-displays" ''
|
||||
${zenbook-normal}/bin/zenbook-normal
|
||||
while ${pkgs.inotify-tools}/bin/inotifywait -e attrib /dev/bus/usb/*/; do
|
||||
${zenbook-normal}/bin/zenbook-normal
|
||||
done
|
||||
'';
|
||||
|
||||
zenbook-set-displays = pkgs.writeShellScriptBin "zenbook-set-displays" ''
|
||||
sleep 1
|
||||
${zenbook-normal}/bin/zenbook-normal
|
||||
'';
|
||||
|
||||
# Enhanced lid monitoring with multiple detection methods
|
||||
zenbook-lid-monitor = pkgs.writeShellScriptBin "zenbook-lid-monitor" ''
|
||||
echo "Starting comprehensive lid monitoring..."
|
||||
|
||||
# Method 1: Monitor ACPI events
|
||||
(${pkgs.acpi}/bin/acpi_listen | while read event; do
|
||||
if echo "$event" | grep -q "button/lid"; then
|
||||
echo "ACPI lid event detected: $event"
|
||||
sleep 0.5 && ${zenbook-set-displays}/bin/zenbook-set-displays
|
||||
fi
|
||||
done) &
|
||||
|
||||
# Method 2: Poll lid state file directly
|
||||
(while true; do
|
||||
if [ -f /proc/acpi/button/lid/LID0/state ] || [ -f /proc/acpi/button/lid/LID/state ]; then
|
||||
current_state=$(cat /proc/acpi/button/lid/*/state 2>/dev/null | head -1)
|
||||
if [ "$current_state" != "$previous_state" ]; then
|
||||
echo "Lid state changed: $current_state"
|
||||
previous_state="$current_state"
|
||||
sleep 0.5 && ${zenbook-set-displays}/bin/zenbook-set-displays
|
||||
fi
|
||||
fi
|
||||
sleep 2
|
||||
done) &
|
||||
|
||||
# Method 3: Monitor systemd logind events
|
||||
(${pkgs.systemd}/bin/journalctl -f --user -u "*" | while read line; do
|
||||
if echo "$line" | grep -i "lid\|suspend\|resume"; then
|
||||
echo "Systemd event: $line"
|
||||
sleep 1 && ${zenbook-set-displays}/bin/zenbook-set-displays
|
||||
fi
|
||||
done) &
|
||||
|
||||
wait
|
||||
'';
|
||||
|
||||
# Auto-run display setup on startup
|
||||
zenbook-autostart = pkgs.writeShellScriptBin "zenbook-autostart" ''
|
||||
# Initial display setup
|
||||
echo "Running initial display setup"
|
||||
${zenbook-set-displays}/bin/zenbook-set-displays
|
||||
|
||||
# Wait a moment for system to stabilize
|
||||
sleep 2
|
||||
|
||||
# Run display setup again to ensure proper configuration
|
||||
echo "Running secondary display setup"
|
||||
${zenbook-set-displays}/bin/zenbook-set-displays
|
||||
|
||||
# Start USB monitoring in background
|
||||
echo "Starting USB monitoring for display changes"
|
||||
${zenbook-watch-displays}/bin/zenbook-watch-displays &
|
||||
|
||||
# Start enhanced lid monitoring
|
||||
echo "Starting enhanced lid monitoring"
|
||||
${zenbook-lid-monitor}/bin/zenbook-lid-monitor &
|
||||
'';
|
||||
in {
|
||||
# Zenbook dual-screen display configuration
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
# Monitor configuration for Zenbook dual screens
|
||||
monitor = [
|
||||
# Primary display (eDP-1) - top screen
|
||||
"eDP-1,${preferred_resolution}@${refresh_rate},0x0,${ui_scale},vrr,${vrr_mode}"
|
||||
# Secondary display (eDP-2) - bottom screen positioned below primary
|
||||
"eDP-2,${preferred_resolution}@${refresh_rate},0x${y_offset},${ui_scale},vrr,${vrr_mode}"
|
||||
# Fallback for any other monitors
|
||||
",preferred,auto,1"
|
||||
];
|
||||
|
||||
# VRR and performance optimizations
|
||||
misc = {
|
||||
# Enable Variable Frame Rate to save power when screen is static
|
||||
vfr = true;
|
||||
};
|
||||
|
||||
# Auto-start the event-driven display management
|
||||
exec-once = [
|
||||
"${zenbook-autostart}/bin/zenbook-autostart"
|
||||
# Additional trigger after a delay to handle race conditions
|
||||
"sleep 5 && ${zenbook-set-displays}/bin/zenbook-set-displays"
|
||||
# Monitor for display hotplug events (DRM/KMS events)
|
||||
"sh -c 'while ${pkgs.inotify-tools}/bin/inotifywait -e modify /sys/class/drm/*/status 2>/dev/null; do sleep 1 && ${zenbook-set-displays}/bin/zenbook-set-displays; done' &"
|
||||
# Monitor for graphics card state changes
|
||||
"sh -c '${pkgs.udev}/bin/udevadm monitor --udev --subsystem-match=drm | while read line; do if echo \"$line\" | grep -q \"change\"; then sleep 2 && ${zenbook-set-displays}/bin/zenbook-set-displays; fi; done' &"
|
||||
];
|
||||
|
||||
# Keybind to run zenbook-set-displays
|
||||
bind = [
|
||||
"$mod,Z,exec,${zenbook-set-displays}/bin/zenbook-set-displays"
|
||||
];
|
||||
};
|
||||
|
||||
# Hook into hypridle for unlock/resume events
|
||||
services.hypridle.settings.general.after_sleep_cmd = lib.mkForce "hyprctl dispatch dpms on && ${zenbook-set-displays}/bin/zenbook-set-displays";
|
||||
|
||||
# Add the scripts to home packages
|
||||
home.packages = [
|
||||
zenbook-top
|
||||
zenbook-bottom
|
||||
zenbook-both
|
||||
zenbook-left-up
|
||||
zenbook-right-up
|
||||
zenbook-normal
|
||||
zenbook-toggle
|
||||
zenbook-watch-displays
|
||||
zenbook-set-displays
|
||||
zenbook-autostart
|
||||
zenbook-lid-monitor
|
||||
];
|
||||
}
|
||||
10
home/panotaka/common/optional/desktops/kde/default.nix
Normal file
10
home/panotaka/common/optional/desktops/kde/default.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = with pkgs; [
|
||||
kdePackages.kdeconnect-kde
|
||||
kdePackages.konsole
|
||||
kdePackages.dolphin
|
||||
kdePackages.okular
|
||||
kdePackages.gwenview
|
||||
kdePackages.spectacle
|
||||
];
|
||||
}
|
||||
667
home/panotaka/common/optional/desktops/kde/zenbook-screen.nix
Normal file
667
home/panotaka/common/optional/desktops/kde/zenbook-screen.nix
Normal file
@@ -0,0 +1,667 @@
|
||||
{pkgs, ...}: let
|
||||
# Configuration constants for ZenBook Duo
|
||||
duoConfig = {
|
||||
# For 3K model (adjust as needed)
|
||||
prefered_resolution = "2880x1800@120.000";
|
||||
ui_scale = 1.5;
|
||||
y_offset = 1200; # height of resolution / ui_scale (1800/1.5 = 1200)
|
||||
backlight = "card1-eDP-2-backlight";
|
||||
|
||||
# USB ID for ZenBook Duo keyboard dock detection
|
||||
dock_usb_id = "0b05:1b2c";
|
||||
|
||||
# Display device identifiers
|
||||
primary_display = "eDP-1";
|
||||
secondary_display = "eDP-2";
|
||||
|
||||
# Touchscreen/tablet device IDs
|
||||
primary_touch_id = "04f3:425b";
|
||||
secondary_touch_id = "04f3:425a";
|
||||
|
||||
# For 1080p model (uncomment if needed)
|
||||
# prefered_resolution = "1920x1200@60.003";
|
||||
# ui_scale = 1;
|
||||
# y_offset = 1200;
|
||||
};
|
||||
|
||||
# Core display management script adapted for KDE
|
||||
duoScript = pkgs.writeShellScript "duo" ''
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Import configuration
|
||||
PREFERRED_RESOLUTION="${duoConfig.prefered_resolution}"
|
||||
UI_SCALE="${toString duoConfig.ui_scale}"
|
||||
Y_OFFSET="${toString duoConfig.y_offset}"
|
||||
BACKLIGHT="${duoConfig.backlight}"
|
||||
DOCK_USB_ID="${duoConfig.dock_usb_id}"
|
||||
PRIMARY_DISPLAY="${duoConfig.primary_display}"
|
||||
SECONDARY_DISPLAY="${duoConfig.secondary_display}"
|
||||
PRIMARY_TOUCH_ID="${duoConfig.primary_touch_id}"
|
||||
SECONDARY_TOUCH_ID="${duoConfig.secondary_touch_id}"
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
|
||||
}
|
||||
|
||||
# Error handling
|
||||
handle_error() {
|
||||
log "ERROR: $1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Utility functions
|
||||
suenv() {
|
||||
sudo /usr/bin/env "$@"
|
||||
}
|
||||
|
||||
retry_command() {
|
||||
local retries=$1
|
||||
shift
|
||||
local count=0
|
||||
until "$@"; do
|
||||
count=$((count + 1))
|
||||
if [ $count -ge $retries ]; then
|
||||
return 1
|
||||
fi
|
||||
log "Command failed, retrying ($count/$retries)..."
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
# ===== DETECTION LOGIC =====
|
||||
|
||||
# Check if external displays are connected
|
||||
has_external_displays() {
|
||||
local external_count
|
||||
external_count=$(${pkgs.kdePackages.kscreen}/bin/kscreen-doctor -o | \
|
||||
grep -v "eDP-[12]" | grep "enabled" | wc -l)
|
||||
[ "$external_count" -gt 0 ]
|
||||
}
|
||||
|
||||
# Get list of active external displays
|
||||
get_active_external_displays() {
|
||||
${pkgs.kdePackages.kscreen}/bin/kscreen-doctor -o | \
|
||||
grep -vE 'eDP-[12]' | \
|
||||
grep "enabled" | \
|
||||
cut -d: -f1
|
||||
}
|
||||
|
||||
# Check if dock is connected (determines single vs dual screen mode)
|
||||
is_dock_connected() {
|
||||
${pkgs.usbutils}/bin/lsusb 2>/dev/null | grep -q "$DOCK_USB_ID"
|
||||
}
|
||||
|
||||
# Get current internal display status
|
||||
get_internal_display_status() {
|
||||
local primary_on secondary_on
|
||||
primary_on=$(${pkgs.kdePackages.kscreen}/bin/kscreen-doctor -o | grep "$PRIMARY_DISPLAY" | grep -q "enabled" && echo "1" || echo "0")
|
||||
secondary_on=$(${pkgs.kdePackages.kscreen}/bin/kscreen-doctor -o | grep "$SECONDARY_DISPLAY" | grep -q "enabled" && echo "1" || echo "0")
|
||||
|
||||
case "$primary_on$secondary_on" in
|
||||
"00") echo "none" ;;
|
||||
"10") echo "top" ;;
|
||||
"01") echo "bottom" ;;
|
||||
"11") echo "both" ;;
|
||||
*) echo "unknown" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get device orientation from accelerometer
|
||||
get_orientation() {
|
||||
# This would typically come from iio-sensor-proxy
|
||||
# For now, return normal as default
|
||||
echo "normal"
|
||||
}
|
||||
|
||||
# Determine optimal display configuration based on current state
|
||||
determine_optimal_config() {
|
||||
local has_external dock_connected orientation current_status
|
||||
|
||||
has_external=$(has_external_displays && echo "true" || echo "false")
|
||||
dock_connected=$(is_dock_connected && echo "true" || echo "false")
|
||||
orientation=$(get_orientation)
|
||||
current_status=$(get_internal_display_status)
|
||||
|
||||
log "State: external=$has_external, dock=$dock_connected, orientation=$orientation, current=$current_status"
|
||||
|
||||
# Determine internal display configuration based on orientation and dock status
|
||||
# External displays don't affect internal display arrangement
|
||||
case "$orientation" in
|
||||
"normal")
|
||||
if [ "$dock_connected" = "true" ]; then
|
||||
echo "top-only"
|
||||
else
|
||||
echo "both-stacked"
|
||||
fi
|
||||
;;
|
||||
"left-up")
|
||||
echo "both-left"
|
||||
;;
|
||||
"right-up")
|
||||
echo "both-right"
|
||||
;;
|
||||
"bottom-up")
|
||||
echo "bottom-only"
|
||||
;;
|
||||
*)
|
||||
echo "both-stacked" # Safe default
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ===== MONITOR CONFIGURATION LOGIC =====
|
||||
|
||||
# Apply display configuration with error handling
|
||||
apply_display_config() {
|
||||
local config_name="$1"
|
||||
log "Applying KDE display configuration: $config_name"
|
||||
|
||||
case "$config_name" in
|
||||
"top-only")
|
||||
retry_command 3 ${pkgs.kdePackages.kscreen}/bin/kscreen-doctor \
|
||||
output."$PRIMARY_DISPLAY".enable \
|
||||
output."$SECONDARY_DISPLAY".disable
|
||||
;;
|
||||
"bottom-only")
|
||||
retry_command 3 ${pkgs.kdePackages.kscreen}/bin/kscreen-doctor \
|
||||
output."$SECONDARY_DISPLAY".enable \
|
||||
output."$PRIMARY_DISPLAY".disable
|
||||
;;
|
||||
"both-stacked")
|
||||
retry_command 3 ${pkgs.kdePackages.kscreen}/bin/kscreen-doctor \
|
||||
output."$PRIMARY_DISPLAY".enable \
|
||||
output."$SECONDARY_DISPLAY".enable \
|
||||
output."$PRIMARY_DISPLAY".position.0,0 \
|
||||
output."$SECONDARY_DISPLAY".position.0,"$Y_OFFSET"
|
||||
;;
|
||||
"both-left")
|
||||
retry_command 3 ${pkgs.kdePackages.kscreen}/bin/kscreen-doctor \
|
||||
output."$SECONDARY_DISPLAY".enable \
|
||||
output."$PRIMARY_DISPLAY".enable \
|
||||
output."$SECONDARY_DISPLAY".position.0,0 \
|
||||
output."$SECONDARY_DISPLAY".rotation.left \
|
||||
output."$PRIMARY_DISPLAY".position."$Y_OFFSET",0 \
|
||||
output."$PRIMARY_DISPLAY".rotation.left
|
||||
;;
|
||||
"both-right")
|
||||
retry_command 3 ${pkgs.kdePackages.kscreen}/bin/kscreen-doctor \
|
||||
output."$PRIMARY_DISPLAY".enable \
|
||||
output."$SECONDARY_DISPLAY".enable \
|
||||
output."$PRIMARY_DISPLAY".position.0,0 \
|
||||
output."$PRIMARY_DISPLAY".rotation.right \
|
||||
output."$SECONDARY_DISPLAY".position."$Y_OFFSET",0 \
|
||||
output."$SECONDARY_DISPLAY".rotation.right
|
||||
;;
|
||||
*)
|
||||
handle_error "Unknown display configuration: $config_name"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Update tablet/touchscreen mappings after successful display config
|
||||
update_tablet_mappings "$config_name"
|
||||
}
|
||||
|
||||
# Update tablet and touchscreen mappings based on display config
|
||||
update_tablet_mappings() {
|
||||
local config="$1"
|
||||
log "Updating tablet mappings for configuration: $config"
|
||||
|
||||
# Map touchscreens to displays using xinput (works with both X11 and Wayland)
|
||||
for device in $(${pkgs.xorg.xinput}/bin/xinput list --name-only | grep -i touch || true); do
|
||||
if echo "$device" | grep -q "$PRIMARY_TOUCH_ID"; then
|
||||
${pkgs.xorg.xinput}/bin/xinput map-to-output "$device" "$PRIMARY_DISPLAY" 2>/dev/null || true
|
||||
elif echo "$device" | grep -q "$SECONDARY_TOUCH_ID"; then
|
||||
${pkgs.xorg.xinput}/bin/xinput map-to-output "$device" "$SECONDARY_DISPLAY" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# ===== EVENT HANDLING & WATCHERS =====
|
||||
|
||||
# Handle display change events
|
||||
handle_display_change() {
|
||||
log "Display change detected"
|
||||
sleep 1 # Allow hardware to stabilize
|
||||
|
||||
local optimal_config
|
||||
optimal_config=$(determine_optimal_config)
|
||||
apply_display_config "$optimal_config"
|
||||
}
|
||||
|
||||
# Handle orientation change events
|
||||
handle_orientation_change() {
|
||||
local new_orientation="$1"
|
||||
log "Orientation changed to: $new_orientation"
|
||||
|
||||
# Always reconfigure internal displays when orientation changes
|
||||
# External displays don't affect the need to maintain proper internal layout
|
||||
local optimal_config
|
||||
optimal_config=$(determine_optimal_config)
|
||||
apply_display_config "$optimal_config"
|
||||
}
|
||||
|
||||
# Watch for USB device changes (dock connect/disconnect)
|
||||
watch_usb_changes() {
|
||||
log "Starting USB device watcher"
|
||||
while ${pkgs.inotify-tools}/bin/inotifywait -e attrib /dev/bus/usb/*/ 2>/dev/null; do
|
||||
handle_display_change
|
||||
done
|
||||
}
|
||||
|
||||
# Watch for orientation changes
|
||||
watch_orientation_changes() {
|
||||
log "Starting orientation watcher"
|
||||
${pkgs.iio-sensor-proxy}/bin/monitor-sensor --accel 2>/dev/null | \
|
||||
${pkgs.coreutils}/bin/stdbuf -oL grep "orientation" | \
|
||||
${pkgs.coreutils}/bin/stdbuf -oL cut -d: -f2 | \
|
||||
${pkgs.coreutils}/bin/stdbuf -oL sed 's/[ )]//g' | \
|
||||
while read -r orientation; do
|
||||
handle_orientation_change "$orientation"
|
||||
done
|
||||
}
|
||||
|
||||
# ===== BACKLIGHT MANAGEMENT =====
|
||||
|
||||
# Sync backlight between displays
|
||||
sync_backlight() {
|
||||
if [ -r "/sys/class/backlight/intel_backlight/brightness" ] && [ -w "/sys/class/backlight/$BACKLIGHT/brightness" ]; then
|
||||
cat "/sys/class/backlight/intel_backlight/brightness" | \
|
||||
suenv tee "/sys/class/backlight/$BACKLIGHT/brightness" >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Watch backlight changes
|
||||
watch_backlight() {
|
||||
log "Starting backlight watcher"
|
||||
sync_backlight # Initial sync
|
||||
while ${pkgs.inotify-tools}/bin/inotifywait -e modify "/sys/class/backlight/intel_backlight/brightness" 2>/dev/null; do
|
||||
sync_backlight
|
||||
done
|
||||
}
|
||||
|
||||
# ===== MAIN COMMAND INTERFACE =====
|
||||
|
||||
case "''${1:-}" in
|
||||
# Automatic configuration
|
||||
"auto"|"configure")
|
||||
optimal_config=$(determine_optimal_config)
|
||||
apply_display_config "$optimal_config"
|
||||
;;
|
||||
|
||||
# Manual display configurations
|
||||
"top")
|
||||
apply_display_config "top-only"
|
||||
;;
|
||||
"bottom")
|
||||
apply_display_config "bottom-only"
|
||||
;;
|
||||
"both"|"normal")
|
||||
apply_display_config "both-stacked"
|
||||
;;
|
||||
"left-up")
|
||||
apply_display_config "both-left"
|
||||
;;
|
||||
"right-up")
|
||||
apply_display_config "both-right"
|
||||
;;
|
||||
|
||||
# Toggle between configurations
|
||||
"toggle")
|
||||
current_status=$(get_internal_display_status)
|
||||
case "$current_status" in
|
||||
"both") apply_display_config "top-only" ;;
|
||||
"top"|"bottom") apply_display_config "both-stacked" ;;
|
||||
*) apply_display_config "both-stacked" ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
# Status reporting
|
||||
"status")
|
||||
echo "Internal: $(get_internal_display_status)"
|
||||
if has_external_displays; then
|
||||
echo "External: $(get_active_external_displays | tr '\n' '+')"
|
||||
fi
|
||||
echo "Dock: $(is_dock_connected && echo "connected" || echo "disconnected")"
|
||||
;;
|
||||
|
||||
# Event watchers
|
||||
"watch-displays")
|
||||
watch_usb_changes
|
||||
;;
|
||||
"watch-orientation")
|
||||
watch_orientation_changes
|
||||
;;
|
||||
"watch-backlight")
|
||||
watch_backlight
|
||||
;;
|
||||
|
||||
# Utility functions
|
||||
"sync-backlight")
|
||||
sync_backlight
|
||||
;;
|
||||
"set-tablet-mapping")
|
||||
update_tablet_mappings "both-stacked"
|
||||
;;
|
||||
"bat-limit")
|
||||
echo "''${2:-80}" | suenv tee /sys/class/power_supply/BAT0/charge_control_end_threshold
|
||||
;;
|
||||
"set-kb-backlight")
|
||||
suenv ${zenbook-kb-backlight}/bin/zenbook-kb-backlight "''${2:-1}"
|
||||
;;
|
||||
|
||||
# Deprecated aliases for backward compatibility
|
||||
"set-displays")
|
||||
log "DEPRECATED: Use 'auto' instead of 'set-displays'"
|
||||
"$0" auto
|
||||
;;
|
||||
"bottom-up")
|
||||
log "DEPRECATED: Use specific orientation commands"
|
||||
apply_display_config "bottom-only"
|
||||
;;
|
||||
"status-internal")
|
||||
get_internal_display_status
|
||||
;;
|
||||
|
||||
# Help
|
||||
"help"|"-h"|"--help"|"")
|
||||
cat << EOF
|
||||
ZenBook Duo Display Management Tool (KDE)
|
||||
|
||||
USAGE: duo <command> [options]
|
||||
|
||||
AUTOMATIC CONFIGURATION:
|
||||
auto, configure Automatically configure displays based on current state
|
||||
|
||||
MANUAL CONFIGURATION:
|
||||
top Enable only top display
|
||||
bottom Enable only bottom display
|
||||
both, normal Enable both displays in stacked configuration
|
||||
left-up Both displays rotated left
|
||||
right-up Both displays rotated right
|
||||
toggle Toggle between single and dual display modes
|
||||
|
||||
STATUS & MONITORING:
|
||||
status Show current display and device status
|
||||
watch-displays Monitor for display/dock changes
|
||||
watch-orientation Monitor for orientation changes
|
||||
watch-backlight Monitor and sync backlight changes
|
||||
|
||||
UTILITIES:
|
||||
sync-backlight Manually sync backlight between displays
|
||||
set-tablet-mapping Update tablet/touchscreen mappings
|
||||
bat-limit [0-100] Set battery charge limit (default: 80)
|
||||
set-kb-backlight [0-3] Set keyboard backlight level
|
||||
|
||||
help Show this help message
|
||||
EOF
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown command: $1"
|
||||
echo "Use 'duo help' for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
|
||||
# Keyboard backlight control script (same as GNOME version)
|
||||
zenbook-kb-backlight = pkgs.python3Packages.buildPythonApplication {
|
||||
pname = "zenbook-kb-backlight";
|
||||
version = "1.0.0";
|
||||
format = "other";
|
||||
|
||||
src = pkgs.writeText "zenbook-kb-backlight.py" ''
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import usb.core
|
||||
import usb.util
|
||||
import sys
|
||||
import time
|
||||
|
||||
# USB vendor and product IDs for ZenBook Duo 2024
|
||||
VENDOR_ID = 0x0b05 # ASUS
|
||||
PRODUCT_ID = 0x19b6 # ZenBook Duo specific
|
||||
|
||||
def find_keyboard_device():
|
||||
"""Find the ZenBook Duo keyboard device"""
|
||||
devices = usb.core.find(find_all=True, idVendor=VENDOR_ID)
|
||||
for device in devices:
|
||||
if device.idProduct == PRODUCT_ID:
|
||||
return device
|
||||
return None
|
||||
|
||||
def set_backlight(brightness):
|
||||
"""Set keyboard backlight brightness (0-3)"""
|
||||
device = find_keyboard_device()
|
||||
if not device:
|
||||
print("ZenBook Duo keyboard device not found")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Detach kernel driver if it's attached
|
||||
if device.is_kernel_driver_active(0):
|
||||
device.detach_kernel_driver(0)
|
||||
|
||||
# Set configuration
|
||||
device.set_configuration()
|
||||
|
||||
# Send backlight control command
|
||||
device.ctrl_transfer(
|
||||
bmRequestType=0x21, # USB_TYPE_CLASS | USB_RECIP_INTERFACE
|
||||
bRequest=0x09, # HID SET_REPORT
|
||||
wValue=0x0301, # Report type and ID
|
||||
wIndex=0, # Interface
|
||||
data_or_wLength=[0x5d, 0xba, brightness, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||||
)
|
||||
return True
|
||||
|
||||
except usb.core.USBError as e:
|
||||
print(f"USB Error: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: zenbook-kb-backlight <brightness>")
|
||||
print("Brightness levels: 0 (off), 1 (low), 2 (medium), 3 (high)")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
brightness = int(sys.argv[1])
|
||||
if brightness < 0 or brightness > 3:
|
||||
raise ValueError("Brightness must be between 0 and 3")
|
||||
|
||||
if set_backlight(brightness):
|
||||
print(f"Keyboard backlight set to level {brightness}")
|
||||
else:
|
||||
print("Failed to set keyboard backlight")
|
||||
sys.exit(1)
|
||||
|
||||
except ValueError as e:
|
||||
print(f"Invalid brightness value: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
'';
|
||||
|
||||
propagatedBuildInputs = with pkgs.python3Packages; [pyusb];
|
||||
|
||||
dontUnpack = true;
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
cp $src $out/bin/zenbook-kb-backlight
|
||||
chmod +x $out/bin/zenbook-kb-backlight
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "ZenBook keyboard backlight control utility";
|
||||
license = pkgs.lib.licenses.mit;
|
||||
};
|
||||
};
|
||||
|
||||
# Combined package with both scripts
|
||||
zenbook-duo-tools = pkgs.stdenv.mkDerivation {
|
||||
pname = "zenbook-duo-tools";
|
||||
version = "1.0.0";
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp ${duoScript} $out/bin/duo
|
||||
cp ${zenbook-kb-backlight}/bin/zenbook-kb-backlight $out/bin/zenbook-kb-backlight
|
||||
chmod +x $out/bin/*
|
||||
'';
|
||||
};
|
||||
in {
|
||||
# Install the ZenBook Duo tools
|
||||
home.packages = with pkgs; [
|
||||
zenbook-duo-tools
|
||||
kdePackages.kscreen # KDE's display management tool
|
||||
kdePackages.powerdevil # Power management
|
||||
inotify-tools
|
||||
usbutils
|
||||
iio-sensor-proxy
|
||||
xorg.xinput # For touchscreen mapping
|
||||
];
|
||||
|
||||
# Systemd user services for automatic display management
|
||||
systemd.user.services = {
|
||||
zenbook-display-startup = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Display Setup on Startup";
|
||||
After = ["graphical-session.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo auto";
|
||||
RemainAfterExit = true;
|
||||
# Add some delay to ensure graphics are ready
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 2";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
|
||||
zenbook-display-watcher = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Display Watcher";
|
||||
After = ["graphical-session.target" "zenbook-display-startup.service"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
Requires = ["zenbook-display-startup.service"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo watch-displays";
|
||||
Restart = "always";
|
||||
RestartSec = "10";
|
||||
# Prevent rapid restarts
|
||||
StartLimitInterval = "60";
|
||||
StartLimitBurst = "3";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
|
||||
zenbook-orientation-watcher = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Orientation Watcher";
|
||||
After = ["graphical-session.target" "zenbook-display-startup.service"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
Requires = ["zenbook-display-startup.service"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo watch-orientation";
|
||||
Restart = "always";
|
||||
RestartSec = "10";
|
||||
StartLimitInterval = "60";
|
||||
StartLimitBurst = "3";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
|
||||
zenbook-backlight-sync = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Backlight Sync";
|
||||
After = ["graphical-session.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-duo-tools}/bin/duo watch-backlight";
|
||||
Restart = "always";
|
||||
RestartSec = "5";
|
||||
# This is less critical, allow more restarts
|
||||
StartLimitInterval = "300";
|
||||
StartLimitBurst = "10";
|
||||
};
|
||||
Install.WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# Shell aliases for convenience (generic across all shells)
|
||||
home.shellAliases = {
|
||||
# Main commands
|
||||
duo = "${zenbook-duo-tools}/bin/duo";
|
||||
duo-auto = "${zenbook-duo-tools}/bin/duo auto";
|
||||
duo-status = "${zenbook-duo-tools}/bin/duo status";
|
||||
duo-help = "${zenbook-duo-tools}/bin/duo help";
|
||||
|
||||
# Display configurations
|
||||
duo-toggle = "${zenbook-duo-tools}/bin/duo toggle";
|
||||
duo-both = "${zenbook-duo-tools}/bin/duo both";
|
||||
duo-top = "${zenbook-duo-tools}/bin/duo top";
|
||||
duo-bottom = "${zenbook-duo-tools}/bin/duo bottom";
|
||||
|
||||
# Utilities
|
||||
duo-sync-backlight = "${zenbook-duo-tools}/bin/duo sync-backlight";
|
||||
zenbook-kb = "${zenbook-duo-tools}/bin/zenbook-kb-backlight";
|
||||
|
||||
# Backward compatibility
|
||||
duo-normal = "${zenbook-duo-tools}/bin/duo both"; # Alias for legacy 'normal' command
|
||||
};
|
||||
|
||||
# KDE-specific configuration via kwriteconfig6
|
||||
home.activation.kdeZenbookConfig = {
|
||||
after = ["writeBoundary"];
|
||||
before = [];
|
||||
data = ''
|
||||
# Configure display scaling for high-DPI Zenbook screens
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kscreenrc --group "Display" --key "ScaleFactor" "${toString duoConfig.ui_scale}"
|
||||
|
||||
# Enable fractional scaling in KWin (Wayland)
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "Wayland" --key "EnableHiDPI" "true"
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "Wayland" --key "UseOutputScaling" "true"
|
||||
|
||||
# Enable fractional scaling in KWin (X11)
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "Xwayland" --key "Scale" "${toString duoConfig.ui_scale}"
|
||||
|
||||
# Enable Variable Refresh Rate (VRR) support
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "Wayland" --key "AllowVariableRefreshRate" "true"
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "Compositing" --key "AllowTearing" "true"
|
||||
|
||||
# Configure tablet mode detection
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "TabletMode" --key "Available" "true"
|
||||
|
||||
# Enable advanced display features
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kwinrc --group "Effect-overview" --key "BorderActivate" "9"
|
||||
|
||||
# Set up custom keyboard shortcut for display configuration
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kglobalshortcutsrc --group "Custom Shortcuts" --key "ZenBook Display Toggle" "Meta+Z,none,${zenbook-duo-tools}/bin/duo auto"
|
||||
|
||||
# Configure KScreen for proper scaling and refresh rates
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kscreenrc --group "General" --key "ScalePolicy" "PerOutputScaling"
|
||||
${pkgs.kdePackages.kconfig}/bin/kwriteconfig6 --file kscreenrc --group "General" --key "EnableVRR" "true"
|
||||
'';
|
||||
};
|
||||
}
|
||||
30
home/panotaka/common/optional/desktops/niri/default.nix
Normal file
30
home/panotaka/common/optional/desktops/niri/default.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
imports = [./waybar.nix ./swayidle.nix ./fuzzel.nix ./swaylock.nix];
|
||||
|
||||
# Import patterns similar to other desktop modules
|
||||
home.packages = [
|
||||
pkgs.wl-clipboard
|
||||
pkgs.grim
|
||||
pkgs.slurp
|
||||
pkgs.polkit_gnome
|
||||
pkgs.xdg-desktop-portal-wlr
|
||||
];
|
||||
|
||||
# Enable Niri and provide baseline settings; other modules merge into programs.niri.settings
|
||||
programs.niri.settings = lib.mkDefault {
|
||||
binds = {};
|
||||
};
|
||||
|
||||
# Session variables for Wayland compatibility
|
||||
home.sessionVariables = {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
MOZ_ENABLE_WAYLAND = "1";
|
||||
QT_QPA_PLATFORM = "wayland";
|
||||
SDL_VIDEODRIVER = "wayland";
|
||||
_JAVA_AWT_WM_NONREPARENTING = "1";
|
||||
};
|
||||
}
|
||||
22
home/panotaka/common/optional/desktops/niri/fuzzel.nix
Normal file
22
home/panotaka/common/optional/desktops/niri/fuzzel.nix
Normal file
@@ -0,0 +1,22 @@
|
||||
{pkgs, ...}: {
|
||||
programs.fuzzel = {
|
||||
enable = true;
|
||||
package = pkgs.fuzzel;
|
||||
|
||||
# Write a minimal fuzzel.ini using settings attribute; users can extend this
|
||||
settings = {
|
||||
main = {
|
||||
terminal = "${pkgs.ghostty}/bin/ghostty";
|
||||
# Use UWSM app launcher wrapper for proper systemd slice management
|
||||
launch-prefix = "uwsm app -- ";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Add a recommended niri keybind to spawn fuzzel (Mod+Return)
|
||||
# Launch fuzzel itself via UWSM for proper session integration
|
||||
programs.niri.settings.binds."Mod+Return".action.spawn = ["uwsm" "app" "--" "${pkgs.fuzzel}/bin/fuzzel"];
|
||||
|
||||
# Add a keybind to launch the power menu (Mod+Shift+P)
|
||||
programs.niri.settings.binds."Mod+Shift+P".action.spawn = ["uwsm" "app" "--" "$HOME/.local/bin/fuzzel-power-menu.sh"];
|
||||
}
|
||||
31
home/panotaka/common/optional/desktops/niri/swayidle.nix
Normal file
31
home/panotaka/common/optional/desktops/niri/swayidle.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{pkgs, ...}: {
|
||||
# Ensure swayidle and swaylock are available for the user
|
||||
home.packages = [pkgs.swayidle pkgs.swaylock pkgs.inotify-tools];
|
||||
|
||||
# Use Home Manager's documented services.swayidle options
|
||||
services.swayidle = {
|
||||
enable = true;
|
||||
package = pkgs.swayidle;
|
||||
# Timeouts:
|
||||
# - lock after 5 minutes
|
||||
# - suspend after 15 minutes
|
||||
# - hibernate after 60 minutes
|
||||
timeouts = [
|
||||
{
|
||||
timeout = 300; # 5 minutes
|
||||
command = "${pkgs.swaylock}/bin/swaylock -f";
|
||||
resumeCommand = "swaymsg resume";
|
||||
}
|
||||
{
|
||||
timeout = 900; # 15 minutes
|
||||
command = "systemctl suspend";
|
||||
resumeCommand = "swaymsg resume";
|
||||
}
|
||||
{
|
||||
timeout = 3600; # 60 minutes
|
||||
command = "systemctl hibernate";
|
||||
resumeCommand = "swaymsg resume";
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
10
home/panotaka/common/optional/desktops/niri/swaylock.nix
Normal file
10
home/panotaka/common/optional/desktops/niri/swaylock.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{pkgs, ...}: {
|
||||
# Enable home-manager swaylock integration
|
||||
programs.swaylock = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Add a keybind to spawn swaylock (Mod+L)
|
||||
# Launch via UWSM for proper systemd integration
|
||||
programs.niri.settings.binds."Mod+L".action.spawn = ["uwsm" "app" "--" "${pkgs.swaylock}/bin/swaylock"];
|
||||
}
|
||||
192
home/panotaka/common/optional/desktops/niri/waybar.nix
Normal file
192
home/panotaka/common/optional/desktops/niri/waybar.nix
Normal file
@@ -0,0 +1,192 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
# Safely access system-level stylix targets (may not always be present during some checks)
|
||||
stylixTargets =
|
||||
if config.stylix != null && config.stylix ? targets
|
||||
then config.stylix.targets
|
||||
else {};
|
||||
waybarOut =
|
||||
if stylixTargets ? waybar && stylixTargets.waybar ? stylixTargets.waybar.outPath
|
||||
then stylixTargets.waybar.outPath
|
||||
else null;
|
||||
colors =
|
||||
if config.lib != null && config.lib.stylix != null && config.lib.stylix.colors != null
|
||||
then config.lib.stylix.colors
|
||||
else {base05 = "ffffff";};
|
||||
in {
|
||||
# Use the programs.waybar home-manager module
|
||||
programs.waybar = {
|
||||
enable = true;
|
||||
package = pkgs.waybar;
|
||||
systemd.enable = true;
|
||||
|
||||
# Waybar settings tailored for sway/hyprland-style setups
|
||||
settings = {
|
||||
mainBar = {
|
||||
layer = "top";
|
||||
position = "top";
|
||||
height = 35;
|
||||
spacing = 4;
|
||||
|
||||
# Add a placeholder for your window manager's workspace module
|
||||
# For Sway/Hyprland: "sway/workspaces" or "hyprland/workspaces"
|
||||
modules-left = ["sway/workspaces" "sway/mode"];
|
||||
modules-center = ["sway/window"];
|
||||
modules-right = [
|
||||
"bluetooth"
|
||||
"network"
|
||||
"pipewire"
|
||||
"tray"
|
||||
"battery"
|
||||
"clock"
|
||||
];
|
||||
|
||||
# --- Module Definitions ---
|
||||
"sway/workspaces" = {
|
||||
disable-scroll = true;
|
||||
all-outputs = true;
|
||||
format = "{name}: {icon}";
|
||||
format-icons = {
|
||||
"1" = "";
|
||||
"2" = "";
|
||||
"3" = "";
|
||||
"focused" = "";
|
||||
"default" = "";
|
||||
};
|
||||
};
|
||||
|
||||
clock = {
|
||||
format = " {:%I:%M %p}";
|
||||
tooltip-format = "<big>{:%A, %B %d, %Y}</big>\n<tt><small>{calendar}</small></tt>";
|
||||
};
|
||||
|
||||
tray = {
|
||||
"icon-size" = 18;
|
||||
spacing = 10;
|
||||
};
|
||||
|
||||
pipewire = {
|
||||
format = "{icon} {volume}%";
|
||||
format-muted = " Muted";
|
||||
format-icons = {
|
||||
"default" = ["" "" ""];
|
||||
};
|
||||
# Native PipeWire control using wpctl
|
||||
on-click = "${pkgs.pavucontrol}/bin/pavucontrol";
|
||||
on-click-right = "wpctl set-mute @DEFAULT_SINK@ toggle";
|
||||
on-scroll-up = "wpctl set-volume @DEFAULT_SINK@ +5%";
|
||||
on-scroll-down = "wpctl set-volume @DEFAULT_SINK@ -5%";
|
||||
scroll-step = 5;
|
||||
};
|
||||
|
||||
network = {
|
||||
format-wifi = " {essid}";
|
||||
format-ethernet = " Wired";
|
||||
format-disconnected = " Off";
|
||||
on-click = "nm-connection-editor";
|
||||
};
|
||||
|
||||
# Battery module (uses sysfs/upower depending on system)
|
||||
battery = {
|
||||
format = "{capacity}% {icon}";
|
||||
tooltip = true;
|
||||
format-icons = {
|
||||
"discharging" = ""; # low battery icon
|
||||
"charging" = ""; # charging icon
|
||||
"full" = "";
|
||||
};
|
||||
};
|
||||
|
||||
bluetooth = {
|
||||
format = " {status}";
|
||||
format-disabled = " Off";
|
||||
format-connected = " {device_alias}";
|
||||
on-click = "blueman-manager";
|
||||
};
|
||||
};
|
||||
};
|
||||
# Use Stylix-generated CSS as a base and override icon/text color to a monochrome value
|
||||
style = let
|
||||
importLine =
|
||||
if waybarOut != null
|
||||
then ''@import "${toString waybarOut}";''
|
||||
else ''/* stylix waybar target not available */'';
|
||||
in
|
||||
with colors; ''
|
||||
/* Import the CSS generated by Stylix for Waybar (if available) */
|
||||
${importLine}
|
||||
|
||||
/* Override the color for common modules to a single monochrome color */
|
||||
#workspaces button label,
|
||||
#taskbar button label,
|
||||
#clock,
|
||||
#tray,
|
||||
#network,
|
||||
#pulseaudio,
|
||||
#battery {
|
||||
color: #${base05};
|
||||
}
|
||||
|
||||
/* Fallback: target all labels */
|
||||
label {
|
||||
color: #${base05};
|
||||
}
|
||||
|
||||
/* Prefer a single icon font for consistent monochrome icons */
|
||||
* {
|
||||
font-family: "JetBrainsMono Nerd Font", sans-serif;
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# The config file is generated automatically by programs.waybar, so we don't need manual file writes
|
||||
# Users can override by setting programs.waybar.settings directly in their config
|
||||
|
||||
# Keep GUI helper packages but don't autostart applets here.
|
||||
# We prefer Waybar modules (network/pipewire/bluetooth/battery) as the primary
|
||||
# UI so users don't get duplicate tray icons. GUI tools are still available
|
||||
# via `home.packages` and the Waybar on-click actions (pavucontrol, nm-connection-editor,
|
||||
# blueman-manager) will launch them when needed.
|
||||
home.packages = with pkgs; [networkmanagerapplet blueman pavucontrol pasystray];
|
||||
|
||||
# Hide the nm-applet and blueman tray icons by overriding their icon entries
|
||||
# in the user's icon theme with a transparent SVG. This lets the applets run
|
||||
# (providing background/autoconnect and secret-service integration) while Waybar
|
||||
# provides the visible UI with nicer icons.
|
||||
home.file."${config.home.homeDirectory}/.local/share/icons/hicolor/scalable/status/nm-applet.svg".text = ''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1" viewBox="0 0 1 1"></svg>
|
||||
'';
|
||||
|
||||
home.file."${config.home.homeDirectory}/.local/share/icons/hicolor/scalable/status/network-wireless.svg".text = ''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1" viewBox="0 0 1 1"></svg>
|
||||
'';
|
||||
|
||||
home.file."${config.home.homeDirectory}/.local/share/icons/hicolor/scalable/status/blueman.svg".text = ''
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1" height="1" viewBox="0 0 1 1"></svg>
|
||||
'';
|
||||
|
||||
# Autostart the applets so they provide background/network/keyring integration
|
||||
# while their icons remain hidden (Waybar shows the label/text UI).
|
||||
home.file."${config.home.homeDirectory}/.config/autostart/nm-applet.desktop".text = ''
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=${pkgs.networkmanagerapplet}/bin/nm-applet
|
||||
Hidden=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
Name=Network Manager Applet
|
||||
Comment=Autostart nm-applet for network management
|
||||
'';
|
||||
|
||||
home.file."${config.home.homeDirectory}/.config/autostart/blueman-manager.desktop".text = ''
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Exec=${pkgs.blueman}/bin/blueman-applet
|
||||
Hidden=false
|
||||
X-GNOME-Autostart-enabled=true
|
||||
Name=Blueman Applet
|
||||
Comment=Autostart blueman for bluetooth management
|
||||
'';
|
||||
}
|
||||
53
home/panotaka/common/optional/desktops/niri/zenbook-debug.sh
Normal file
53
home/panotaka/common/optional/desktops/niri/zenbook-debug.sh
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
# Zenbook Duo Debug Script
|
||||
# Run this to diagnose display/keyboard detection issues
|
||||
|
||||
echo "=== Zenbook Duo Debug Info ==="
|
||||
echo ""
|
||||
|
||||
echo "1. USB Devices:"
|
||||
echo " Looking for keyboard (0b05:1b2c)..."
|
||||
lsusb | grep 0b05:1b2c && echo " ✓ Keyboard USB ID found!" || echo " ✗ Keyboard USB ID NOT found"
|
||||
echo ""
|
||||
echo " All ASUS devices:"
|
||||
lsusb | grep -i asus || echo " (none)"
|
||||
echo ""
|
||||
echo " Full lsusb output:"
|
||||
lsusb
|
||||
echo ""
|
||||
|
||||
echo "2. Niri Outputs:"
|
||||
niri msg outputs || echo " ERROR: Could not get niri outputs"
|
||||
echo ""
|
||||
|
||||
echo "3. Display Check:"
|
||||
echo " eDP-1 status:"
|
||||
niri msg outputs | grep -A5 "eDP-1" || echo " Not found or off"
|
||||
echo ""
|
||||
echo " eDP-2 status:"
|
||||
niri msg outputs | grep -A5 "eDP-2" || echo " Not found or off"
|
||||
echo ""
|
||||
|
||||
echo "4. Systemd Services:"
|
||||
echo " zenbook-autostart:"
|
||||
systemctl --user status zenbook-autostart | grep -E "Active:|Main PID:" || echo " Not running"
|
||||
echo ""
|
||||
echo " zenbook-inotify-monitor:"
|
||||
systemctl --user status zenbook-inotify-monitor | grep -E "Active:|Main PID:" || echo " Not running"
|
||||
echo ""
|
||||
|
||||
echo "5. Log Files:"
|
||||
echo " Recent lsusb log:"
|
||||
[ -f /tmp/zenbook-lsusb.log ] && cat /tmp/zenbook-lsusb.log || echo " (no log file yet)"
|
||||
echo ""
|
||||
|
||||
echo "6. Test Commands:"
|
||||
echo " Try running manually:"
|
||||
echo " - zenbook-normal"
|
||||
echo " - zenbook-top"
|
||||
echo " - zenbook-both"
|
||||
echo " - systemctl --user restart zenbook-inotify-monitor"
|
||||
echo ""
|
||||
echo " View live logs:"
|
||||
echo " - journalctl --user -u zenbook-inotify-monitor -f"
|
||||
echo ""
|
||||
292
home/panotaka/common/optional/desktops/niri/zenbook-screen.nix
Normal file
292
home/panotaka/common/optional/desktops/niri/zenbook-screen.nix
Normal file
@@ -0,0 +1,292 @@
|
||||
{pkgs, ...}: let
|
||||
# Configuration variables from your script
|
||||
preferred_resolution = "2880x1800";
|
||||
refresh_rate = "120";
|
||||
ui_scale = "1.5";
|
||||
y_offset = "1200";
|
||||
|
||||
# Debug script
|
||||
zenbook-debug = pkgs.writeShellScriptBin "zenbook-debug" ''
|
||||
echo "=== Zenbook Duo Debug Info ==="
|
||||
echo ""
|
||||
echo "1. USB Devices:"
|
||||
echo " Looking for keyboard (0b05:1b2c)..."
|
||||
${pkgs.usbutils}/bin/lsusb | grep 0b05:1b2c && echo " ✓ Keyboard USB ID found!" || echo " ✗ Keyboard USB ID NOT found"
|
||||
echo ""
|
||||
echo " All ASUS devices:"
|
||||
${pkgs.usbutils}/bin/lsusb | grep -i asus || echo " (none)"
|
||||
echo ""
|
||||
echo " Full lsusb output:"
|
||||
${pkgs.usbutils}/bin/lsusb
|
||||
echo ""
|
||||
echo "2. Niri Outputs:"
|
||||
${pkgs.niri}/bin/niri msg outputs || echo " ERROR: Could not get niri outputs"
|
||||
echo ""
|
||||
echo "3. Systemd Services:"
|
||||
systemctl --user status zenbook-autostart 2>&1 | head -3 || echo " Not found"
|
||||
systemctl --user status zenbook-inotify-monitor 2>&1 | head -3 || echo " Not found"
|
||||
echo ""
|
||||
echo "4. Log Files:"
|
||||
[ -f /tmp/zenbook-lsusb.log ] && cat /tmp/zenbook-lsusb.log || echo " (no log file yet)"
|
||||
echo ""
|
||||
echo "5. Manual Test Commands:"
|
||||
echo " - zenbook-normal # Run keyboard detection"
|
||||
echo " - zenbook-top # Force top screen only"
|
||||
echo " - zenbook-both # Force both screens"
|
||||
echo " - journalctl --user -u zenbook-inotify-monitor -f # Watch logs"
|
||||
'';
|
||||
|
||||
# Inline scripts adapted for niri
|
||||
# Stage 3: Configuration - applies the display setup
|
||||
zenbook-top = pkgs.writeShellScriptBin "zenbook-top" ''
|
||||
echo "[DEBUG] zenbook-top: Setting to top screen only"
|
||||
echo "[DEBUG] Configuring eDP-1..."
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 on || echo "[ERROR] Failed to turn on eDP-1"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 mode ${preferred_resolution}@${refresh_rate} || echo "[ERROR] Failed to set eDP-1 mode"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 scale ${ui_scale} || echo "[ERROR] Failed to set eDP-1 scale"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 position set 0 0 || echo "[ERROR] Failed to set eDP-1 position"
|
||||
echo "[DEBUG] Disabling eDP-2..."
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 off || echo "[ERROR] Failed to turn off eDP-2"
|
||||
# Force disable by setting power mode off (if supported)
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 disable 2>/dev/null || echo "[DEBUG] disable command not available, using off"
|
||||
echo "[DEBUG] zenbook-top: Complete"
|
||||
'';
|
||||
|
||||
zenbook-bottom = pkgs.writeShellScriptBin "zenbook-bottom" ''
|
||||
echo "Setting to bottom screen only"
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 on
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 mode ${preferred_resolution}@${refresh_rate}
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 scale ${ui_scale}
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 position set 0 0
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 off
|
||||
# Force disable by setting power mode off (if supported)
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 disable 2>/dev/null || echo "[DEBUG] disable command not available, using off"
|
||||
'';
|
||||
|
||||
zenbook-both = pkgs.writeShellScriptBin "zenbook-both" ''
|
||||
echo "[DEBUG] zenbook-both: Setting to both screens"
|
||||
echo "[DEBUG] Configuring eDP-1..."
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 on || echo "[ERROR] Failed to turn on eDP-1"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 mode ${preferred_resolution}@${refresh_rate} || echo "[ERROR] Failed to set eDP-1 mode"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 scale ${ui_scale} || echo "[ERROR] Failed to set eDP-1 scale"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 position set 0 0 || echo "[ERROR] Failed to set eDP-1 position"
|
||||
echo "[DEBUG] Configuring eDP-2..."
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 on || echo "[ERROR] Failed to turn on eDP-2"
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 mode ${preferred_resolution}@${refresh_rate} || echo "[ERROR] Failed to set eDP-2 mode"
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 scale ${ui_scale} || echo "[ERROR] Failed to set eDP-2 scale"
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 position set 0 ${y_offset} || echo "[ERROR] Failed to set eDP-2 position"
|
||||
echo "[DEBUG] zenbook-both: Complete"
|
||||
'';
|
||||
|
||||
zenbook-left-up = pkgs.writeShellScriptBin "zenbook-left-up" ''
|
||||
echo "Setting to left-right layout"
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 on
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 mode ${preferred_resolution}@${refresh_rate}
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 scale ${ui_scale}
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 position set 0 0
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 on
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 mode ${preferred_resolution}@${refresh_rate}
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 scale ${ui_scale}
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 position set ${y_offset} 0
|
||||
'';
|
||||
|
||||
zenbook-right-up = pkgs.writeShellScriptBin "zenbook-right-up" ''
|
||||
echo "Setting to right-left layout"
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 on
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 mode ${preferred_resolution}@${refresh_rate}
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 scale ${ui_scale}
|
||||
${pkgs.niri}/bin/niri msg output eDP-1 position set 0 0
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 on
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 mode ${preferred_resolution}@${refresh_rate}
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 scale ${ui_scale}
|
||||
${pkgs.niri}/bin/niri msg output eDP-2 position set ${y_offset} 0
|
||||
'';
|
||||
|
||||
# Stage 2: Detection - determines which configuration to apply
|
||||
zenbook-detect = pkgs.writeShellScriptBin "zenbook-detect" ''
|
||||
# Simple keyboard detection based on the original duo script
|
||||
echo "[DEBUG] zenbook-detect: Starting detection"
|
||||
echo "[DEBUG] Running lsusb to find keyboard..."
|
||||
${pkgs.usbutils}/bin/lsusb > /tmp/zenbook-lsusb.log
|
||||
echo "[DEBUG] lsusb output saved to /tmp/zenbook-lsusb.log"
|
||||
|
||||
# Check if keyboard is attached (USB device ID 0b05:1b2c)
|
||||
if ${pkgs.usbutils}/bin/lsusb | grep -q 0b05:1b2c; then
|
||||
echo "[DEBUG] Keyboard detected (0b05:1b2c found)"
|
||||
echo "Keyboard attached — top screen only"
|
||||
${zenbook-top}/bin/zenbook-top
|
||||
else
|
||||
echo "[DEBUG] Keyboard NOT detected (0b05:1b2c not found)"
|
||||
echo "[DEBUG] Checking for any ASUS devices..."
|
||||
${pkgs.usbutils}/bin/lsusb | grep -i asus || echo "[DEBUG] No ASUS devices found"
|
||||
echo "Normal mode — both screens"
|
||||
${zenbook-both}/bin/zenbook-both
|
||||
fi
|
||||
'';
|
||||
|
||||
# Legacy alias for compatibility
|
||||
zenbook-normal = pkgs.writeShellScriptBin "zenbook-normal" ''
|
||||
${zenbook-detect}/bin/zenbook-detect
|
||||
'';
|
||||
|
||||
zenbook-toggle = pkgs.writeShellScriptBin "zenbook-toggle" ''
|
||||
# Check current state and toggle
|
||||
enabled_count=$(${pkgs.niri}/bin/niri msg outputs | grep -c "eDP.*" || echo "0")
|
||||
if [ "$enabled_count" -eq 1 ]; then
|
||||
${zenbook-both}/bin/zenbook-both
|
||||
else
|
||||
${zenbook-top}/bin/zenbook-top
|
||||
fi
|
||||
'';
|
||||
|
||||
# Stage 1: Watch service - monitors for changes and triggers detection
|
||||
zenbook-watch-displays = pkgs.writeShellScriptBin "zenbook-watch-displays" ''
|
||||
echo "[DEBUG] zenbook-watch-displays: Starting"
|
||||
echo "[DEBUG] Running initial detection"
|
||||
# Run initial detection
|
||||
${zenbook-detect}/bin/zenbook-detect
|
||||
|
||||
echo "[DEBUG] Starting USB device monitoring on /dev/bus/usb/*/"
|
||||
# Track last run time to debounce rapid-fire events
|
||||
last_run=0
|
||||
debounce_seconds=3
|
||||
|
||||
# Watch for USB device changes (keyboard attach/detach)
|
||||
while ${pkgs.inotify-tools}/bin/inotifywait -e attrib /dev/bus/usb/*/; do
|
||||
current_time=$(date +%s)
|
||||
time_diff=$((current_time - last_run))
|
||||
|
||||
if [ $time_diff -ge $debounce_seconds ]; then
|
||||
echo "[DEBUG] USB device change detected at $(date) (debounced)"
|
||||
sleep 0.5
|
||||
${zenbook-detect}/bin/zenbook-detect
|
||||
last_run=$current_time
|
||||
else
|
||||
echo "[DEBUG] USB device change ignored (debounce: $time_diff < $debounce_seconds seconds)"
|
||||
fi
|
||||
done
|
||||
'';
|
||||
|
||||
# Legacy wrapper - calls detect directly
|
||||
zenbook-set-displays = pkgs.writeShellScriptBin "zenbook-set-displays" ''
|
||||
sleep 0.5
|
||||
${zenbook-detect}/bin/zenbook-detect
|
||||
'';
|
||||
|
||||
# Simplified auto-run display setup on startup (based on original duo approach)
|
||||
zenbook-autostart = pkgs.writeShellScriptBin "zenbook-autostart" ''
|
||||
echo "Running initial display setup"
|
||||
sleep 1
|
||||
${zenbook-detect}/bin/zenbook-detect
|
||||
'';
|
||||
in {
|
||||
# Zenbook dual-screen display configuration for niri
|
||||
# NOTE: We only configure eDP-1 statically and let scripts manage eDP-2 dynamically
|
||||
# This allows the off command to actually work
|
||||
programs.niri.settings = {
|
||||
outputs = {
|
||||
"eDP-1" = {
|
||||
mode = {
|
||||
width = 2880;
|
||||
height = 1800;
|
||||
refresh = 120.0;
|
||||
};
|
||||
scale = 1.5;
|
||||
position = {
|
||||
x = 0;
|
||||
y = 0;
|
||||
};
|
||||
variable-refresh-rate = true;
|
||||
};
|
||||
# eDP-2 is managed dynamically by zenbook-detect scripts
|
||||
};
|
||||
|
||||
# Keybind to run zenbook-detect via UWSM
|
||||
binds."Mod+Z".action.spawn = ["uwsm" "app" "--" "${zenbook-detect}/bin/zenbook-detect"];
|
||||
};
|
||||
|
||||
# Migrate to systemd user services for UWSM integration
|
||||
systemd.user.services = {
|
||||
# Initial display setup
|
||||
zenbook-autostart = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Initial Display Setup";
|
||||
After = ["graphical-session.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${zenbook-autostart}/bin/zenbook-autostart";
|
||||
RemainAfterExit = false;
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# Secondary display setup after delay
|
||||
zenbook-delayed-setup = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo Delayed Display Setup";
|
||||
After = ["graphical-session.target" "zenbook-autostart.service"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "oneshot";
|
||||
ExecStartPre = "${pkgs.coreutils}/bin/sleep 5";
|
||||
ExecStart = "${zenbook-set-displays}/bin/zenbook-set-displays";
|
||||
RemainAfterExit = false;
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# Monitor USB device changes for keyboard attach/detach
|
||||
zenbook-inotify-monitor = {
|
||||
Unit = {
|
||||
Description = "ZenBook Duo USB Device Monitor";
|
||||
After = ["graphical-session.target"];
|
||||
PartOf = ["graphical-session.target"];
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${zenbook-watch-displays}/bin/zenbook-watch-displays";
|
||||
Restart = "always";
|
||||
RestartSec = "5";
|
||||
};
|
||||
Install = {
|
||||
WantedBy = ["graphical-session.target"];
|
||||
};
|
||||
};
|
||||
|
||||
# DISABLED: udev monitor - not needed with inotify approach
|
||||
# zenbook-udev-monitor service removed to prevent conflicts
|
||||
};
|
||||
|
||||
# DISABLED: swayidle hook was running zenbook-detect every second, causing conflicts
|
||||
# The zenbook-inotify-monitor service handles USB detection automatically
|
||||
# services.swayidle.timeouts = lib.mkAfter [
|
||||
# {
|
||||
# timeout = 1;
|
||||
# command = "${zenbook-detect}/bin/zenbook-detect";
|
||||
# resumeCommand = "${zenbook-detect}/bin/zenbook-detect";
|
||||
# }
|
||||
# ];
|
||||
|
||||
# Add the scripts to home packages
|
||||
home.packages = [
|
||||
zenbook-debug
|
||||
zenbook-top
|
||||
zenbook-bottom
|
||||
zenbook-both
|
||||
zenbook-left-up
|
||||
zenbook-right-up
|
||||
zenbook-detect
|
||||
zenbook-normal
|
||||
zenbook-toggle
|
||||
zenbook-watch-displays
|
||||
zenbook-set-displays
|
||||
zenbook-autostart
|
||||
];
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
# FIXME(starter): add/edit any optional, media related pkgs here
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
{pkgs, ...}: {
|
||||
#imports = [ ./foo.nix ];
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
home.packages = with pkgs; [
|
||||
vlc
|
||||
;
|
||||
};
|
||||
# ...other packages
|
||||
];
|
||||
}
|
||||
|
||||
@@ -7,14 +7,10 @@
|
||||
|
||||
#imports = [ ./foo.nix ];
|
||||
|
||||
home.packages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
home.packages = with pkgs; [
|
||||
blender
|
||||
inkscape
|
||||
libreoffice-qt
|
||||
hunspell
|
||||
hunspellDicts
|
||||
;
|
||||
};
|
||||
davinci-resolve
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
{pkgs, ...}: {
|
||||
home.packages = builtins.attrValues {
|
||||
inherit
|
||||
(pkgs)
|
||||
home.packages = with pkgs; [
|
||||
obsidian
|
||||
;
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
|
||||
# TODO add ttf-font-awesome or font-awesome for waybar
|
||||
fontProfiles = {
|
||||
enable = true;
|
||||
monospace = {
|
||||
family = "FiraCode Nerd Font";
|
||||
package = pkgs.nerdfonts.override { fonts = [ "FiraCode" ]; };
|
||||
};
|
||||
regular = {
|
||||
family = "Fira Sans";
|
||||
package = pkgs.fira;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
security.sudo.extraConfig = ''
|
||||
Defaults lecture = never # rollback results in sudo lectures after each reboot, it's somewhat useless anyway
|
||||
Defaults pwfeedback # password input feedback - makes typed password visible as asterisks
|
||||
Defaults timestamp_timeout=120 # only ask for password every 2h
|
||||
Defaults timestamp_timeout=5 # only ask for password every 2h
|
||||
# Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic.
|
||||
Defaults env_keep+=SSH_AUTH_SOCK
|
||||
'';
|
||||
@@ -27,7 +27,7 @@
|
||||
enable = true;
|
||||
clean.enable = true;
|
||||
clean.extraArgs = "--keep-since 20d --keep 20";
|
||||
flake = "/home/user/${config.hostSpec.home}/nix-config";
|
||||
flake = "/home/user/${config.hostSpec.home}/Projects/nix-config";
|
||||
};
|
||||
|
||||
#
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
}: {
|
||||
programs.ssh = lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||
startAgent = true;
|
||||
#startAgent = true;
|
||||
enableAskPassword = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# NOTE(starter): configure your audio needs as required.
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
hardware.pulseaudio.enable = false;
|
||||
{pkgs, ...}: {
|
||||
services.pulseaudio.enable = false;
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
@@ -12,10 +11,8 @@
|
||||
jack.enable = true;
|
||||
};
|
||||
|
||||
environment.systemPackages = builtins.attrValues {
|
||||
inherit (pkgs)
|
||||
environment.systemPackages = with pkgs; [
|
||||
playerctl # cli utility and lib for controlling media players
|
||||
# pamixer # cli pulseaudio sound mixer
|
||||
;
|
||||
};
|
||||
];
|
||||
}
|
||||
|
||||
4
hosts/common/optional/cosmic-greeter.nix
Normal file
4
hosts/common/optional/cosmic-greeter.nix
Normal file
@@ -0,0 +1,4 @@
|
||||
{pkgs, ...}: {
|
||||
# Enable the COSMIC Greeter (Display Manager)
|
||||
services.displayManager.cosmic-greeter.enable = true;
|
||||
}
|
||||
9
hosts/common/optional/cosmic.nix
Normal file
9
hosts/common/optional/cosmic.nix
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
# Enable the COSMIC desktop environment
|
||||
services.desktopManager.cosmic.enable = true;
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
}
|
||||
11
hosts/common/optional/flatpak.nix
Normal file
11
hosts/common/optional/flatpak.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
# NOTE(starter): This is just a basic enabling of the XFCE windows manager for simplicity
|
||||
{pkgs, ...}: {
|
||||
services.flatpak.enable = true;
|
||||
systemd.services.flatpak-repo = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [pkgs.flatpak];
|
||||
script = ''
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
'';
|
||||
};
|
||||
}
|
||||
7
hosts/common/optional/gdm.nix
Normal file
7
hosts/common/optional/gdm.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
# NOTE(starter): This is just a basic enabling of the XFCE windows manager for simplicity
|
||||
{
|
||||
services.xserver.displayManager = {
|
||||
gdm.enable = true;
|
||||
gdm.wayland = true;
|
||||
};
|
||||
}
|
||||
28
hosts/common/optional/gnome.nix
Normal file
28
hosts/common/optional/gnome.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{pkgs, ...}: {
|
||||
services.xserver.desktopManager.gnome.enable = true;
|
||||
#environment.sessionVariables.GTK_USE_PORTAL = "1";
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
|
||||
environment.gnome.excludePackages = with pkgs; [
|
||||
atomix # puzzle game
|
||||
cheese # webcam tool
|
||||
epiphany # web browser
|
||||
evince # document viewer
|
||||
geary # email reader
|
||||
gedit # text editor
|
||||
gnome-characters
|
||||
gnome-shell-extensions
|
||||
gnome-music
|
||||
gnome-photos
|
||||
gnome-terminal
|
||||
gnome-tour
|
||||
hitori # sudoku game
|
||||
iagno # go game
|
||||
tali # poker game
|
||||
totem # video player
|
||||
];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
gsettings-desktop-schemas
|
||||
];
|
||||
}
|
||||
31
hosts/common/optional/greetd.nix
Normal file
31
hosts/common/optional/greetd.nix
Normal file
@@ -0,0 +1,31 @@
|
||||
{pkgs, ...}: {
|
||||
services.greetd = {
|
||||
enable = true;
|
||||
settings = {
|
||||
default_session = {
|
||||
command = "${pkgs.greetd.tuigreet}/bin/tuigreet --time --cmd ${pkgs.niri}/bin/niri-session";
|
||||
user = "greeter";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Enable the GNOME Keyring daemon system-wide
|
||||
services.gnome.gnome-keyring.enable = true;
|
||||
|
||||
# Enable GNOME Keyring support in PAM
|
||||
security.pam.services.greetd.enableGnomeKeyring = true;
|
||||
security.pam.services.login.enableGnomeKeyring = true;
|
||||
|
||||
# Ensure gnome-keyring daemon runs for user sessions
|
||||
systemd.user.services.gnome-keyring = {
|
||||
wantedBy = ["default.target"];
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.gnome-keyring}/bin/gnome-keyring-daemon --start --foreground --components=pkcs11,secrets,ssh";
|
||||
Restart = "on-abort";
|
||||
};
|
||||
};
|
||||
|
||||
# Disable conflicting getty services on tty1
|
||||
systemd.services."getty@tty1".enable = false;
|
||||
systemd.services."autovt@tty1".enable = false;
|
||||
}
|
||||
19
hosts/common/optional/hyprland.nix
Normal file
19
hosts/common/optional/hyprland.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}: {
|
||||
programs.hyprland = {
|
||||
enable = true;
|
||||
withUWSM = false; # Disable UWSM integration
|
||||
# You can add more configuration options here as needed
|
||||
# For example, to set a basic config file:
|
||||
# settings = {
|
||||
# ...
|
||||
# };
|
||||
portalPackage = pkgs.xdg-desktop-portal-hyprland;
|
||||
};
|
||||
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
}
|
||||
@@ -1,4 +1,14 @@
|
||||
# NOTE(starter): This is just a basic enabling of the XFCE windows manager for simplicity
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
environment.sessionVariables.GTK_USE_PORTAL = "1";
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
environment.sessionVariables.KWIN_DRM_PREFER_COLOR_DEPTH = "24";
|
||||
environment.systemPackages = with pkgs.kdePackages; [plasma-thunderbolt sddm-kcm];
|
||||
|
||||
# Fix Qt platform theme configuration for KDE - force override stylix
|
||||
qt.platformTheme = lib.mkForce "kde";
|
||||
}
|
||||
|
||||
90
hosts/common/optional/lxqt-greeter.nix
Normal file
90
hosts/common/optional/lxqt-greeter.nix
Normal file
@@ -0,0 +1,90 @@
|
||||
# LXQt Default Greeter (SDDM with LXQt theme)
|
||||
#
|
||||
# This module configures SDDM as the display manager with LXQt theming
|
||||
# to provide a consistent greeter experience for LXQt desktop environments.
|
||||
#
|
||||
# Features:
|
||||
# - SDDM display manager with Wayland support
|
||||
# - LXQt theme integration for the greeter
|
||||
# - Proper session detection for LXQt-based environments
|
||||
# - Qt theming consistency between greeter and desktop
|
||||
#
|
||||
# Usage:
|
||||
# Add this to your host configuration instead of gdm.nix:
|
||||
# imports = lib.flatten [
|
||||
# # ... other imports ...
|
||||
# "hosts/common/optional/lxqt-greeter.nix"
|
||||
# ];
|
||||
#
|
||||
{pkgs, ...}: {
|
||||
# Enable SDDM as the display manager
|
||||
services.displayManager = {
|
||||
sddm = {
|
||||
enable = true;
|
||||
wayland = {
|
||||
enable = true;
|
||||
compositor = "kwin"; # Use KWin for the greeter compositor
|
||||
};
|
||||
# Use LXQt theme for SDDM
|
||||
theme = "breeze"; # Breeze theme works well with LXQt
|
||||
};
|
||||
};
|
||||
|
||||
# Install SDDM themes and LXQt integration packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
# SDDM themes that work well with LXQt
|
||||
kdePackages.sddm-kcm # SDDM configuration module
|
||||
|
||||
# Additional SDDM themes (optional)
|
||||
where-is-my-sddm-theme
|
||||
];
|
||||
|
||||
# Ensure proper font rendering for the greeter
|
||||
fonts = {
|
||||
packages = with pkgs; [
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-emoji
|
||||
liberation_ttf
|
||||
fira-code
|
||||
fira-code-symbols
|
||||
];
|
||||
|
||||
fontconfig = {
|
||||
defaultFonts = {
|
||||
serif = ["Noto Serif"];
|
||||
sansSerif = ["Noto Sans"];
|
||||
monospace = ["Fira Code"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# SDDM configuration
|
||||
environment.etc."sddm.conf".text = ''
|
||||
[Autologin]
|
||||
Relogin=false
|
||||
Session=
|
||||
User=
|
||||
|
||||
[General]
|
||||
HaltCommand=/run/current-system/systemd/bin/systemctl poweroff
|
||||
RebootCommand=/run/current-system/systemd/bin/systemctl reboot
|
||||
|
||||
[Theme]
|
||||
Current=breeze
|
||||
CursorTheme=breeze_cursors
|
||||
Font=Noto Sans,10,-1,0,50,0,0,0,0,0
|
||||
|
||||
[Users]
|
||||
MaximumUid=60513
|
||||
MinimumUid=1000
|
||||
|
||||
[Wayland]
|
||||
EnableHiDPI=true
|
||||
SessionDir=/run/current-system/sw/share/wayland-sessions
|
||||
|
||||
[X11]
|
||||
EnableHiDPI=true
|
||||
SessionDir=/run/current-system/sw/share/xsessions
|
||||
'';
|
||||
}
|
||||
162
hosts/common/optional/lxqt-niri.nix
Normal file
162
hosts/common/optional/lxqt-niri.nix
Normal file
@@ -0,0 +1,162 @@
|
||||
# LXQt Desktop Environment with Niri Window Manager
|
||||
#
|
||||
# This module provides LXQt desktop environment components running with
|
||||
# Niri as the Wayland compositor instead of the default window manager.
|
||||
#
|
||||
# Features:
|
||||
# - LXQt panel, settings, file manager, and utilities
|
||||
# - Niri as the tiling Wayland compositor
|
||||
# - Proper Qt theming with LXQt themes and Kvantum
|
||||
# - XDG portals for screen sharing and file dialogs
|
||||
# - Audio, network, and power management integration
|
||||
#
|
||||
# Usage:
|
||||
# Add this to your host configuration:
|
||||
# imports = lib.flatten [
|
||||
# # ... other imports ...
|
||||
# "hosts/common/optional/lxqt-niri.nix"
|
||||
# "hosts/common/optional/gdm.nix" # or sddm.nix for display manager
|
||||
# ];
|
||||
#
|
||||
# The session will appear as "LXQt (Niri)" in the session list.
|
||||
#
|
||||
{
|
||||
pkgs,
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
inputs.niri.nixosModules.niri
|
||||
];
|
||||
|
||||
# Enable Niri as the window manager
|
||||
programs.niri.enable = true;
|
||||
|
||||
# Enable LXQt desktop environment components
|
||||
# Note: We don't enable services.xserver.desktopManager.lxqt.enable = true
|
||||
# because it would conflict with our custom display manager configuration
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
# Install additional LXQt components and utilities
|
||||
environment.systemPackages = with pkgs; [
|
||||
# Core LXQt components that work well with other window managers
|
||||
lxqt.lxqt-panel
|
||||
lxqt.lxqt-session
|
||||
lxqt.lxqt-config
|
||||
lxqt.lxqt-themes
|
||||
lxqt.lxqt-notificationd
|
||||
lxqt.lxqt-powermanagement
|
||||
lxqt.lxqt-policykit
|
||||
lxqt.lxqt-archiver
|
||||
lxqt.qterminal
|
||||
lxqt.pcmanfm-qt
|
||||
lxqt.lximage-qt
|
||||
lxqt.qps
|
||||
|
||||
# Theme engines and styling
|
||||
libsForQt5.qtstyleplugins
|
||||
libsForQt5.qt5ct
|
||||
|
||||
# System tools that integrate well with LXQt
|
||||
lxqt.pavucontrol-qt
|
||||
qpwgraph
|
||||
|
||||
# Network management
|
||||
libsForQt5.networkmanager-qt
|
||||
|
||||
# Custom session script
|
||||
(writeScriptBin "niri-session" ''
|
||||
#!/bin/sh
|
||||
|
||||
# Set up environment
|
||||
export XDG_CURRENT_DESKTOP=LXQt
|
||||
export XDG_SESSION_DESKTOP=lxqt-niri
|
||||
export DESKTOP_SESSION=lxqt-niri
|
||||
|
||||
# Start LXQt session components in background
|
||||
${lxqt.lxqt-session}/bin/lxqt-session &
|
||||
|
||||
# Start Niri as the main session
|
||||
exec ${niri}/bin/niri
|
||||
'')
|
||||
];
|
||||
|
||||
# Configure XDG portals for better integration
|
||||
xdg.portal = {
|
||||
enable = true;
|
||||
extraPortals = with pkgs; [
|
||||
xdg-desktop-portal-gtk
|
||||
xdg-desktop-portal-wlr
|
||||
];
|
||||
config = {
|
||||
common = {
|
||||
default = ["gtk"];
|
||||
"org.freedesktop.impl.portal.Screenshot" = ["wlr"];
|
||||
"org.freedesktop.impl.portal.Screencast" = ["wlr"];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Use LXQt's polkit agent
|
||||
security.polkit.enable = true;
|
||||
systemd.user.services.lxqt-policykit-agent = {
|
||||
description = "LXQt PolicyKit Agent";
|
||||
wantedBy = ["graphical-session.target"];
|
||||
wants = ["graphical-session.target"];
|
||||
after = ["graphical-session.target"];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.lxqt.lxqt-policykit}/bin/lxqt-policykit-agent";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
TimeoutStopSec = 10;
|
||||
};
|
||||
};
|
||||
|
||||
# Configure Qt theming (basic settings)
|
||||
# Note: More specific Qt theming may be handled by system-wide theming modules
|
||||
|
||||
# Configure Qt theming to use LXQt
|
||||
qt = {
|
||||
platformTheme = lib.mkForce "lxqt";
|
||||
};
|
||||
|
||||
# Environment variables for proper integration
|
||||
environment.sessionVariables = {
|
||||
NIXOS_OZONE_WL = "1";
|
||||
QT_QPA_PLATFORM = "wayland;xcb";
|
||||
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
|
||||
QT_AUTO_SCREEN_SCALE_FACTOR = "1";
|
||||
QT_QPA_PLATFORMTHEME = lib.mkForce "lxqt";
|
||||
QT_STYLE_OVERRIDE = "kvantum";
|
||||
DESKTOP_SESSION = "lxqt-niri";
|
||||
XDG_CURRENT_DESKTOP = "LXQt";
|
||||
XDG_SESSION_DESKTOP = "lxqt-niri";
|
||||
};
|
||||
|
||||
# Enable necessary services for LXQt functionality
|
||||
services = {
|
||||
# Power management
|
||||
upower.enable = true;
|
||||
};
|
||||
|
||||
# Create a custom session file for LXQt + Niri
|
||||
environment.etc."xdg/lxqt/session.conf".text = ''
|
||||
[General]
|
||||
__userfile__=true
|
||||
window_manager=niri
|
||||
'';
|
||||
|
||||
# Create desktop entry for the session
|
||||
environment.etc."wayland-sessions/lxqt-niri.desktop".text = ''
|
||||
[Desktop Entry]
|
||||
Name=LXQt (Niri)
|
||||
Comment=LXQt Desktop with Niri Window Manager
|
||||
Exec=niri-session
|
||||
Type=Application
|
||||
Keywords=niri;lxqt;wayland;
|
||||
'';
|
||||
}
|
||||
57
hosts/common/optional/niri.nix
Normal file
57
hosts/common/optional/niri.nix
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}: {
|
||||
imports = [
|
||||
inputs.niri.nixosModules.niri
|
||||
];
|
||||
|
||||
programs.niri.enable = true;
|
||||
|
||||
# Enable UWSM (Universal Wayland Session Manager) for better session management
|
||||
# See docs/uwsm-niri-integration.md for usage and migration guide
|
||||
programs.uwsm = {
|
||||
enable = true;
|
||||
waylandCompositors = {
|
||||
niri = {
|
||||
prettyName = "Niri";
|
||||
comment = "Niri scrollable-tiling Wayland compositor managed by UWSM";
|
||||
binPath = "/run/current-system/sw/bin/niri-session";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# UWSM provides better environment variable inheritance and systemd integration
|
||||
# All startup applications are now managed via systemd.user.services with
|
||||
# WantedBy=["graphical-session.target"] in the home-manager configuration
|
||||
|
||||
# Use KDE portal instead of GNOME for better KDE integration
|
||||
xdg.portal = {
|
||||
enable = true;
|
||||
extraPortals = with pkgs; [
|
||||
kdePackages.xdg-desktop-portal-kde
|
||||
];
|
||||
config.common.default = "kde";
|
||||
};
|
||||
|
||||
# Use KDE polkit for authentication instead of GNOME
|
||||
security.polkit.enable = true;
|
||||
systemd = {
|
||||
user.services.polkit-kde-authentication-agent-1 = {
|
||||
description = "polkit-kde-authentication-agent-1";
|
||||
wantedBy = ["graphical-session.target"];
|
||||
wants = ["graphical-session.target"];
|
||||
after = ["graphical-session.target"];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.kdePackages.polkit-kde-agent-1}/libexec/polkit-kde-authentication-agent-1";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 1;
|
||||
TimeoutStopSec = 10;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
# NOTE(starter): This is just a basic enabling of the XFCE windows manager for simplicity
|
||||
{
|
||||
services.displayManager = {
|
||||
services.displayManager = {
|
||||
sddm.enable = true;
|
||||
sddm.wayland = {
|
||||
enable = true;
|
||||
compositor = "kwin";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
5
hosts/common/optional/services/bluetooth.nix
Normal file
5
hosts/common/optional/services/bluetooth.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
# Enable bluetooth
|
||||
{...}: {
|
||||
hardware.bluetooth.enable = true;
|
||||
hardware.bluetooth.powerOnBoot = true;
|
||||
}
|
||||
8
hosts/common/optional/services/docker.nix
Normal file
8
hosts/common/optional/services/docker.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
# Enable bluetooth
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
virtualisation.docker.enable = true;
|
||||
}
|
||||
17
hosts/common/optional/services/ollama.nix
Normal file
17
hosts/common/optional/services/ollama.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
# Enable bluetooth
|
||||
{
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: {
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
environmentVariables = {
|
||||
OLLAMA_INTEL_GPU = "1";
|
||||
OLLAMA_ORIGINS = "moz-extension://*";
|
||||
};
|
||||
loadModels = [
|
||||
];
|
||||
};
|
||||
systemd.services.ollama.serviceConfig.MemoryDenyWriteExecute = lib.mkForce false;
|
||||
}
|
||||
17
hosts/common/optional/services/printing.nix
Normal file
17
hosts/common/optional/services/printing.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
# Enable printing support
|
||||
{pkgs, ...}: {
|
||||
# Autodiscovery of network printers
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
services.printing = {
|
||||
enable = true;
|
||||
drivers = with pkgs; [
|
||||
cups-filters
|
||||
cups-browsed
|
||||
];
|
||||
};
|
||||
}
|
||||
5
hosts/common/optional/services/tailscale.nix
Normal file
5
hosts/common/optional/services/tailscale.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{config, ...}: {
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
};
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user