Compare commits

..

14 Commits

Author SHA1 Message Date
e38480e320 feat: enhance Waybar configuration for Sway/Hyprland with improved module settings and autostart functionality 2025-10-06 12:08:32 -03:00
86d27b80d8 feat: refactor Niri configuration by removing deprecated services and scripts, and updating display management to use niri-native scripts 2025-10-02 18:37:39 -03:00
ca62a6bd19 Add Niri desktop configuration with integrated utilities
- Introduced a new power menu script using fuzzel for session management.
- Updated Bellerophon configuration to include Niri desktop and its components.
- Removed obsolete README for Niri and consolidated its configuration files.
- Added swayidle and swaylock integration for idle management and screen locking.
- Implemented waybar for status bar functionality with basic configuration.
- Created fuzzel integration for application launching and menu access.
- Added zenbook debugging scripts for display and keyboard diagnostics.
- Migrated keyring and other configurations to streamline Niri setup.
- Enhanced display management with systemd services for better integration.
2025-10-02 13:16:27 -03:00
66e65b91ea feat: update desktop environment configuration from COSMIC to GNOME and add kernel patches for Zenbook 2025-09-26 10:20:39 -03:00
642ff1820e feat: add COSMIC desktop environment and greeter configuration 2025-09-25 15:12:48 -03:00
438296b01b Updated everything 2025-09-22 09:07:03 -03:00
20c8ecb0bd feat: enable Git LFS and configure credential helper 2025-08-26 09:38:45 -03:00
c784df06fd Updated configuration 2025-08-26 09:21:24 -03:00
3b2ccc8417 Updated Configuration 2025-08-19 09:23:21 -03:00
d9966d8f38 Updated lockfiles 2025-08-12 10:15:49 -03:00
eb58a62168 feat: transition from Hyprland to GNOME desktop environment
- Updated Bellerophon configuration to include GNOME desktop settings and packages.
- Added GNOME-specific packages and extensions for enhanced user experience.
- Introduced scripts for display management tailored for ZenBook Duo under GNOME.
- Implemented systemd services for automatic display management and backlight control.
- Integrated UWSM for improved session management in Hyprland.
- Enhanced lid monitoring and USB display management scripts for ZenBook Duo.
- Configured keyring support for GNOME and integrated it with PAM.
- Updated display manager settings to enable GDM for GNOME sessions.
2025-08-11 13:51:24 -03:00
c74f623232 Update Hyprlock configuration to correct keybinds setting 2025-08-10 22:39:50 -03:00
8224513e07 Add Hyprland and Greetd configurations; update desktop settings and user examples 2025-08-10 22:39:39 -03:00
87a2314170 Enhance Copilot instructions with detailed project overview and directory roles; clarify developer workflows and integration points. 2025-08-08 10:08:27 -03:00
78 changed files with 5020 additions and 327 deletions

View File

@@ -1,43 +1,48 @@
# Copilot Instructions for EmergentMind's Nix-Config # Copilot Instructions for EmergentMind's Nix-Config
## Project Overview ## Project Overview
- This is a modular, flake-based NixOS configuration system, designed for multi-host, multi-user, and reproducible setups. - This is a modular, flake-based NixOS configuration system for managing multiple hosts, users, and environments (NixOS, Darwin, Home Manager).
- Major directories: - 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.
- `hosts/`: Per-host NixOS configs (e.g., `hosts/nixos/Bellerophon/`). - Secrets are managed via a private `nix-secrets` repo and sops-nix, integrated as a flake input (see docs/secretsmgmt.md).
- `home/`: Per-user Home Manager configs.
- `modules/`: Reusable NixOS and Home Manager modules, auto-imported via `lib.custom.scanPaths`.
- `overlays/`, `pkgs/`: Custom packages and overlays.
- `nixos-installer/`: Standalone flake for bootstrapping new hosts, with its own README and workflows.
- `docs/`: Project documentation, including secrets management.
- `scripts/`: Helper scripts for bootstrap, rebuild, sops, etc.
## Key Patterns & Conventions ## Key Architectural Patterns
- **Imports**: Use `lib.custom.relativeToRoot` and `lib.custom.scanPaths` for DRY, recursive module imports. - **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.
- **Host/Module Structure**: Each host and user has a directory with a `default.nix` as entrypoint. Common/optional configs are split for clarity. - **User configs**: User-level Home Manager configs live in `home/<user>/<host>.nix` and are imported by host configs.
- **Disk Layout**: Disk setup is handled by `disko` modules, with per-host overrides for device and swap. - **Common logic**: Shared modules for users and hosts are in `hosts/common/` and `home/exampleSecondUser/common/` etc.
- **Secrets**: Secrets are managed via a private `nix-secrets` repo and sops-nix. See `docs/secretsmgmt.md` and `nixos-installer/README.md` for details. - **Optional features**: Features like desktops, shells, and services are split into `common/optional/` submodules and imported as needed.
- **VSCode/Language Support**: Language-specific VSCode configs live in `home/panotaka/common/optional/coding/vscode/languages/` and are imported via the main VSCode module. - **Installer**: The `nixos-installer/` flake provides a minimal environment and scripts for bootstrapping new machines.
## Developer Workflows ## Developer Workflows
- **Build & Rebuild**: Use `just rebuild` (runs pre/post hooks, see `justfile`). For full checks: `just rebuild-full` or `just check`. - **Build & switch**: Use `just` commands (see `justfile`) for common workflows, e.g. `just switch`, `just iso`, or run `nixos-rebuild switch --flake .#<hostname>`.
- **ISO Generation**: `just iso` builds a custom NixOS installer ISO. - **Testing**: Tests are in `tests/` and use `bats` for shell scripts. Run with `just test`.
- **Secrets**: Use `just rekey`, `just sops-add-creation-rules`, and related commands for sops/age key management. - **Secrets**: To update secrets, edit the `nix-secrets` repo and re-pull as a flake input.
- **Sync/Deploy**: Use `just sync` and `just build-host` for remote deployment. - **Installer**: See `nixos-installer/README.md` for remote install and ISO generation.
- **Testing**: Tests live in `tests/` and use `bats`.
## 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 ## Integration Points
- **External**: Relies on `nix-secrets` (private), sops-nix, disko, stylix, nix4vscode, and nixos-hardware modules. - **Secrets**: sops-nix, private flake input, see `docs/secretsmgmt.md`.
- **Cross-Component**: Host configs import common modules and optional features via mapped imports. Home Manager and NixOS modules are kept separate but coordinated. - **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 ## Examples
- To add a new host: copy an existing host dir in `hosts/nixos/`, update disk and user settings, and add secrets as per `nixos-installer/README.md`. - 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 language to VSCode: add a `.nix` file to `vscode/languages/` and import it in the main VSCode module. - To add a new shell, create a module in `common/core/shell/` and import it in the user config.
- To update secrets: run `just rekey` and follow the documented workflow. - To add a new host, create a directory in `hosts/nixos/` and a matching user config in `home/<user>/`.
## References ## Key Files & Directories
- See `README.md`, `nixos-installer/README.md`, and `docs/secretsmgmt.md` for deep dives on architecture and workflows. - `flake.nix`, `flake.lock`: Flake entrypoints
- For module patterns, see `modules/` and `hosts/common/core/`. - `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.
If you are unsure about a workflow or pattern, check the referenced docs or ask for clarification in your PR.

43
docs/lxqt-niri-setup.md Normal file
View 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

View 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)

View 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

437
flake.lock generated
View File

@@ -1,15 +1,57 @@
{ {
"nodes": { "nodes": {
"ags": {
"inputs": {
"astal": "astal",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1759227262,
"narHash": "sha256-ibKJckw+KWH6n+pscOA7DWImanr988zKB7R2Z6ZEMLM=",
"owner": "aylur",
"repo": "ags",
"rev": "f68a0d03fbb94f4beacedd922ffaa0bf0f10397a",
"type": "github"
},
"original": {
"owner": "aylur",
"repo": "ags",
"type": "github"
}
},
"astal": {
"inputs": {
"nixpkgs": [
"ags",
"nixpkgs"
]
},
"locked": {
"lastModified": 1756474652,
"narHash": "sha256-iiBU6itpEqE0spXeNJ3uJTfioSyKYjt5bNepykpDXTE=",
"owner": "aylur",
"repo": "astal",
"rev": "20bd8318e4136fbd3d4eb2d64dbabc3acbc915dd",
"type": "github"
},
"original": {
"owner": "aylur",
"repo": "astal",
"type": "github"
}
},
"base16": { "base16": {
"inputs": { "inputs": {
"fromYaml": "fromYaml" "fromYaml": "fromYaml"
}, },
"locked": { "locked": {
"lastModified": 1746562888, "lastModified": 1755819240,
"narHash": "sha256-YgNJQyB5dQiwavdDFBMNKk1wyS77AtdgDk/VtU6wEaI=", "narHash": "sha256-qcMhnL7aGAuFuutH4rq9fvAhCpJWVHLcHVZLtPctPlo=",
"owner": "SenchoPens", "owner": "SenchoPens",
"repo": "base16.nix", "repo": "base16.nix",
"rev": "806a1777a5db2a1ef9d5d6f493ef2381047f2b89", "rev": "75ed5e5e3fce37df22e49125181fa37899c3ccd6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -37,11 +79,11 @@
"base16-helix": { "base16-helix": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1748408240, "lastModified": 1752979451,
"narHash": "sha256-9M2b1rMyMzJK0eusea0x3lyh3mu5nMeEDSc4RZkGm+g=", "narHash": "sha256-0CQM+FkYy0fOO/sMGhOoNL80ftsAzYCg9VhIrodqusM=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "base16-helix", "repo": "base16-helix",
"rev": "6c711ab1a9db6f51e2f6887cc3345530b33e152e", "rev": "27cf1e66e50abc622fb76a3019012dc07c678fac",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -85,11 +127,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1748883665, "lastModified": 1752264895,
"narHash": "sha256-R0W7uAg+BLoHjMRMQ8+oiSbTq8nkGz5RDpQ+ZfxxP3A=", "narHash": "sha256-1zBPE/PNAkPNUsOWFET4J0cjlvziH8DOekesDmjND+w=",
"owner": "cachix", "owner": "cachix",
"repo": "cachix", "repo": "cachix",
"rev": "f707778d902af4d62d8dd92c269f8e70de09acbe", "rev": "47053aef762f452e816e44eb9a23fbc3827b241a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -99,20 +141,67 @@
"type": "github" "type": "github"
} }
}, },
"caelestia-cli": {
"inputs": {
"caelestia-shell": [
"caelestia-shell"
],
"nixpkgs": [
"caelestia-shell",
"nixpkgs"
]
},
"locked": {
"lastModified": 1758937572,
"narHash": "sha256-9kz/tV6Mc53rSYBvsh6jw1kBBlhAYZdj0yovFE5sFaw=",
"owner": "caelestia-dots",
"repo": "cli",
"rev": "1de7da5f2ba366a7dab54f6f4315e5bc4ff5d823",
"type": "github"
},
"original": {
"owner": "caelestia-dots",
"repo": "cli",
"type": "github"
}
},
"caelestia-shell": {
"inputs": {
"caelestia-cli": "caelestia-cli",
"nixpkgs": [
"nixpkgs"
],
"quickshell": "quickshell"
},
"locked": {
"lastModified": 1759322152,
"narHash": "sha256-WiQnLQL4yJBs6C1JVDAvTuU2gft/QEVeu4DGfK55lwY=",
"owner": "caelestia-dots",
"repo": "shell",
"rev": "11dc993f4b54631c88c655f1fe5f3caea0e96605",
"type": "github"
},
"original": {
"owner": "caelestia-dots",
"repo": "shell",
"type": "github"
}
},
"devenv": { "devenv": {
"inputs": { "inputs": {
"cachix": "cachix", "cachix": "cachix",
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"git-hooks": "git-hooks", "git-hooks": "git-hooks",
"nix": "nix", "nix": "nix",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1754418859, "lastModified": 1759359709,
"narHash": "sha256-6fnM9o5RIG3OtuBF0yhQMECtqzc5pXAc1uSkVaffy58=", "narHash": "sha256-A+vFSdQuzZfTpShWsUjQ+DBYYlh3Ta+vVI4qJzO1GqI=",
"owner": "cachix", "owner": "cachix",
"repo": "devenv", "repo": "devenv",
"rev": "e13cd53579f6a0f441ac09230178dccb3008dd36", "rev": "f0ea46e67b4fc24e91b4f52cb74721fbd68abe1d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -128,11 +217,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1753140376, "lastModified": 1758287904,
"narHash": "sha256-7lrVrE0jSvZHrxEzvnfHFE/Wkk9DDqb+mYCodI5uuB8=", "narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "545aba02960caa78a31bd9a8709a0ad4b6320a5c", "rev": "67ff9807dd148e704baadbd4fd783b54282ca627",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -144,11 +233,11 @@
"firefox-gnome-theme": { "firefox-gnome-theme": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1748383148, "lastModified": 1758112371,
"narHash": "sha256-pGvD/RGuuPf/4oogsfeRaeMm6ipUIznI2QSILKjKzeA=", "narHash": "sha256-lizRM2pj6PHrR25yimjyFn04OS4wcdbc38DCdBVa2rk=",
"owner": "rafaelmardojai", "owner": "rafaelmardojai",
"repo": "firefox-gnome-theme", "repo": "firefox-gnome-theme",
"rev": "4eb2714fbed2b80e234312611a947d6cb7d70caf", "rev": "0909cfe4a2af8d358ad13b20246a350e14c2473d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -193,16 +282,15 @@
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"devenv", "devenv",
"nix",
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1733312601, "lastModified": 1756770412,
"narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=", "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9", "rev": "4524271976b625a4a605beefd893f270620fd751",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -219,11 +307,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1749398372, "lastModified": 1756770412,
"narHash": "sha256-tYBdgS56eXYaWVW3fsnPQ/nFlgWi/Z2Ymhyu21zVM98=", "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "9305fe4e5c2a6fcf5ba6a3ff155720fbe4076569", "rev": "4524271976b625a4a605beefd893f270620fd751",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -261,11 +349,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1750779888, "lastModified": 1758108966,
"narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=", "narHash": "sha256-ytw7ROXaWZ7OfwHrQ9xvjpUWeGVm86pwnEd1QhzawIo=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d", "rev": "54df955a695a84cd47d4a43e08e1feaf90b1fd9b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -320,27 +408,27 @@
"gnome-shell": { "gnome-shell": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1744584021, "lastModified": 1748186689,
"narHash": "sha256-0RJ4mJzf+klKF4Fuoc8VN8dpQQtZnKksFmR2jhWE1Ew=", "narHash": "sha256-UaD7Y9f8iuLBMGHXeJlRu6U1Ggw5B9JnkFs3enZlap0=",
"owner": "GNOME", "owner": "GNOME",
"repo": "gnome-shell", "repo": "gnome-shell",
"rev": "52c517c8f6c199a1d6f5118fae500ef69ea845ae", "rev": "8c88f917db0f1f0d80fa55206c863d3746fa18d0",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "GNOME", "owner": "GNOME",
"ref": "48.1", "ref": "48.2",
"repo": "gnome-shell", "repo": "gnome-shell",
"type": "github" "type": "github"
} }
}, },
"hardware": { "hardware": {
"locked": { "locked": {
"lastModified": 1754316476, "lastModified": 1759261527,
"narHash": "sha256-Ry1gd1BQrNVJJfT11cpVP0FY8XFMx4DJV2IDp01CH9w=", "narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=",
"owner": "nixos", "owner": "nixos",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "9368056b73efb46eb14fd4667b99e0f81b805f28", "rev": "e087756cf4abbe1a34f3544c480fc1034d68742f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -356,27 +444,108 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1753592768, "lastModified": 1759337100,
"narHash": "sha256-oV695RvbAE4+R9pcsT9shmp6zE/+IZe6evHWX63f2Qg=", "narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "fc3add429f21450359369af74c2375cb34a2d204", "rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-community", "owner": "nix-community",
"ref": "release-25.05",
"repo": "home-manager", "repo": "home-manager",
"type": "github" "type": "github"
} }
}, },
"home-manager_2": {
"inputs": {
"nixpkgs": [
"zen-browser",
"nixpkgs"
]
},
"locked": {
"lastModified": 1752603129,
"narHash": "sha256-S+wmHhwNQ5Ru689L2Gu8n1OD6s9eU9n9mD827JNR+kw=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "e8c19a3cec2814c754f031ab3ae7316b64da085b",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"niri": {
"inputs": {
"niri-stable": "niri-stable",
"niri-unstable": "niri-unstable",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable",
"xwayland-satellite-stable": "xwayland-satellite-stable",
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
},
"locked": {
"lastModified": 1759402670,
"narHash": "sha256-xmUTws/OKlj4sM6Z+tsIAWPA37CBtkMWQqiQ8OZFSo8=",
"owner": "sodiboo",
"repo": "niri-flake",
"rev": "c7008abf4b9df7f65991176835628949acb426cd",
"type": "github"
},
"original": {
"owner": "sodiboo",
"repo": "niri-flake",
"type": "github"
}
},
"niri-stable": {
"flake": false,
"locked": {
"lastModified": 1756556321,
"narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294",
"type": "github"
},
"original": {
"owner": "YaLTeR",
"ref": "v25.08",
"repo": "niri",
"type": "github"
}
},
"niri-unstable": {
"flake": false,
"locked": {
"lastModified": 1759395653,
"narHash": "sha256-sv9J1z6CrTPf9lRJLyCN90fZVdQz7LFeX7pIlInH8BQ=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "ba6e5e082a79901dc89b0d49c5da1b769d652aec",
"type": "github"
},
"original": {
"owner": "YaLTeR",
"repo": "niri",
"type": "github"
}
},
"nix": { "nix": {
"inputs": { "inputs": {
"flake-compat": [ "flake-compat": [
"devenv", "devenv",
"flake-compat" "flake-compat"
], ],
"flake-parts": "flake-parts", "flake-parts": [
"devenv",
"flake-parts"
],
"git-hooks-nix": [ "git-hooks-nix": [
"devenv", "devenv",
"git-hooks" "git-hooks"
@@ -393,16 +562,16 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1752773918, "lastModified": 1758763079,
"narHash": "sha256-dOi/M6yNeuJlj88exI+7k154z+hAhFcuB8tZktiW7rg=", "narHash": "sha256-Bx1A+lShhOWwMuy3uDzZQvYiBKBFcKwy6G6NEohhv6A=",
"owner": "cachix", "owner": "cachix",
"repo": "nix", "repo": "nix",
"rev": "031c3cf42d2e9391eee373507d8c12e0f9606779", "rev": "6f0140527c2b0346df4afad7497baa08decb929f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "cachix", "owner": "cachix",
"ref": "devenv-2.30", "ref": "devenv-2.30.5",
"repo": "nix", "repo": "nix",
"type": "github" "type": "github"
} }
@@ -414,11 +583,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1751313918, "lastModified": 1758805352,
"narHash": "sha256-HsJM3XLa43WpG+665aGEh8iS8AfEwOIQWk3Mke3e7nk=", "narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=",
"owner": "lnl7", "owner": "lnl7",
"repo": "nix-darwin", "repo": "nix-darwin",
"rev": "e04a388232d9a6ba56967ce5b53a8a6f713cdfcf", "rev": "c48e963a5558eb1c3827d59d21c5193622a1477c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -435,11 +604,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1754446571, "lastModified": 1759369869,
"narHash": "sha256-f+Shs8gU0AhN3Q0N1dycqossDqUGQWVaR65ILFo9hNY=", "narHash": "sha256-4X76RvMmzngRshwTDFsloxjHYdKtQoMY5Ob8+qwS+Dc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix4vscode", "repo": "nix4vscode",
"rev": "b6ee5ce110217325d059222e87e471577effbc3c", "rev": "c90d1d398e9db998b0852a339dc3dc10efbdb2ce",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -450,27 +619,26 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1754316476, "lastModified": 1759261527,
"narHash": "sha256-Ry1gd1BQrNVJJfT11cpVP0FY8XFMx4DJV2IDp01CH9w=", "narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "9368056b73efb46eb14fd4667b99e0f81b805f28", "rev": "e087756cf4abbe1a34f3544c480fc1034d68742f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "master",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"type": "github" "type": "github"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1750441195, "lastModified": 1758532697,
"narHash": "sha256-yke+pm+MdgRb6c0dPt8MgDhv7fcBbdjmv1ZceNTyzKg=", "narHash": "sha256-bhop0bR3u7DCw9/PtLCwr7GwEWDlBSxHp+eVQhCW9t4=",
"owner": "cachix", "owner": "cachix",
"repo": "devenv-nixpkgs", "repo": "devenv-nixpkgs",
"rev": "0ceffe312871b443929ff3006960d29b120dc627", "rev": "207a4cb0e1253c7658c6736becc6eb9cace1f25f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -498,27 +666,43 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1751274312, "lastModified": 1759281824,
"narHash": "sha256-/bVBlRpECLVzjV19t5KMdMFWSwKLtb5RyXdjz3LJT+g=", "narHash": "sha256-FIBE1qXv9TKvSNwst6FumyHwCRH3BlWDpfsnqRDCll0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "50ab793786d9de88ee30ec4e4c24fb4236fc2674", "rev": "5b5be50345d4113d04ba58c444348849f5585b4a",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-24.11", "ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1759281824,
"narHash": "sha256-FIBE1qXv9TKvSNwst6FumyHwCRH3BlWDpfsnqRDCll0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5b5be50345d4113d04ba58c444348849f5585b4a",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1754214453, "lastModified": 1759036355,
"narHash": "sha256-Q/I2xJn/j1wpkGhWkQnm20nShYnG7TI99foDBpXm1SY=", "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "5b09dc45f24cf32316283e62aec81ffee3c3e376", "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -530,16 +714,16 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1754292888, "lastModified": 1759036355,
"narHash": "sha256-1ziydHSiDuSnaiPzCQh1mRFBsM2d2yRX9I+5OPGEmIE=", "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ce01daebf8489ba97bd1609d185ea276efdeb121", "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-25.05", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@@ -553,15 +737,14 @@
"nixpkgs": [ "nixpkgs": [
"stylix", "stylix",
"nixpkgs" "nixpkgs"
], ]
"treefmt-nix": "treefmt-nix"
}, },
"locked": { "locked": {
"lastModified": 1751320053, "lastModified": 1758998580,
"narHash": "sha256-3m6RMw0FbbaUUa01PNaMLoO7D99aBClmY5ed9V3vz+0=", "narHash": "sha256-VLx0z396gDCGSiowLMFz5XRO/XuNV+4EnDYjdJhHvUk=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "cbde1735782f9c2bb2c63d5e05fba171a14a4670", "rev": "ba8d9c98f5f4630bcb0e815ab456afd90c930728",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -579,11 +762,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1754416808, "lastModified": 1758108966,
"narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=", "narHash": "sha256-ytw7ROXaWZ7OfwHrQ9xvjpUWeGVm86pwnEd1QhzawIo=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864", "rev": "54df955a695a84cd47d4a43e08e1feaf90b1fd9b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -592,18 +775,42 @@
"type": "github" "type": "github"
} }
}, },
"quickshell": {
"inputs": {
"nixpkgs": [
"caelestia-shell",
"nixpkgs"
]
},
"locked": {
"lastModified": 1758273351,
"narHash": "sha256-wOv1guIi9THD1NjOtBU2Xh/Avg9xv7nIjsfFSkr1NeQ=",
"ref": "refs/heads/master",
"rev": "e9a574d919a89602d2868621576b2ccae54a5cb0",
"revCount": 675,
"type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
},
"original": {
"type": "git",
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
}
},
"root": { "root": {
"inputs": { "inputs": {
"ags": "ags",
"caelestia-shell": "caelestia-shell",
"devenv": "devenv", "devenv": "devenv",
"disko": "disko", "disko": "disko",
"hardware": "hardware", "hardware": "hardware",
"home-manager": "home-manager", "home-manager": "home-manager",
"niri": "niri",
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nix4vscode": "nix4vscode", "nix4vscode": "nix4vscode",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"nixpkgs-darwin": "nixpkgs-darwin", "nixpkgs-darwin": "nixpkgs-darwin",
"nixpkgs-stable": "nixpkgs-stable", "nixpkgs-stable": "nixpkgs-stable_2",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
"pre-commit-hooks": "pre-commit-hooks", "pre-commit-hooks": "pre-commit-hooks",
"stylix": "stylix", "stylix": "stylix",
@@ -631,16 +838,15 @@
"tinted-zed": "tinted-zed" "tinted-zed": "tinted-zed"
}, },
"locked": { "locked": {
"lastModified": 1753979771, "lastModified": 1759404594,
"narHash": "sha256-MdMdQymbivEWWkC5HqeLYtP8FYu0SqiSpiRlyw9Fm3Y=", "narHash": "sha256-k9hd15rLqG7x3OCUPrcQtpleDlOyQjy16ZEseruypNQ=",
"owner": "danth", "owner": "danth",
"repo": "stylix", "repo": "stylix",
"rev": "5b81b0c4fbab3517b39d63f493760d33287150ad", "rev": "3f70c5855572004f9c630ed4a92aa186755361be",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "danth", "owner": "danth",
"ref": "release-25.05",
"repo": "stylix", "repo": "stylix",
"type": "github" "type": "github"
} }
@@ -712,11 +918,11 @@
"tinted-schemes": { "tinted-schemes": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1750770351, "lastModified": 1757716333,
"narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=", "narHash": "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "schemes", "repo": "schemes",
"rev": "5a775c6ffd6e6125947b393872cde95867d85a2a", "rev": "317a5e10c35825a6c905d912e480dfe8e71c7559",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -728,11 +934,11 @@
"tinted-tmux": { "tinted-tmux": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1751159871, "lastModified": 1757811970,
"narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=", "narHash": "sha256-n5ZJgmzGZXOD9pZdAl1OnBu3PIqD+X3vEBUGbTi4JiI=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "tinted-tmux", "repo": "tinted-tmux",
"rev": "bded5e24407cec9d01bd47a317d15b9223a1546c", "rev": "d217ba31c846006e9e0ae70775b0ee0f00aa6b1e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -744,11 +950,11 @@
"tinted-zed": { "tinted-zed": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1751158968, "lastModified": 1757811247,
"narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=", "narHash": "sha256-4EFOUyLj85NRL3OacHoLGEo0wjiRJzfsXtR4CZWAn6w=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "base16-zed", "repo": "base16-zed",
"rev": "86a470d94204f7652b906ab0d378e4231a5b3384", "rev": "824fe0aacf82b3c26690d14e8d2cedd56e18404e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -757,43 +963,52 @@
"type": "github" "type": "github"
} }
}, },
"treefmt-nix": { "xwayland-satellite-stable": {
"inputs": { "flake": false,
"nixpkgs": [
"stylix",
"nur",
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1733222881, "lastModified": 1755491097,
"narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=", "narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=",
"owner": "numtide", "owner": "Supreeeme",
"repo": "treefmt-nix", "repo": "xwayland-satellite",
"rev": "49717b5af6f80172275d47a418c9719a31a78b53", "rev": "388d291e82ffbc73be18169d39470f340707edaa",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "numtide", "owner": "Supreeeme",
"repo": "treefmt-nix", "ref": "v0.7",
"repo": "xwayland-satellite",
"type": "github"
}
},
"xwayland-satellite-unstable": {
"flake": false,
"locked": {
"lastModified": 1758577423,
"narHash": "sha256-sB2GAOjhjoWnjU6A/uHNJiY6O3UeztV5pJAN2g1FkXU=",
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"rev": "03368548ba745e17a85bd631613a59cb2d8469a4",
"type": "github"
},
"original": {
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"type": "github" "type": "github"
} }
}, },
"zen-browser": { "zen-browser": {
"inputs": { "inputs": {
"home-manager": [ "home-manager": "home-manager_2",
"home-manager"
],
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1754458246, "lastModified": 1759378939,
"narHash": "sha256-6fvYurXcdg+AC7IBoLEgRIU3GXMaAaVwnteKk9OKBBM=", "narHash": "sha256-MWCIUqkxoMnvNYjooFiFHzlcZDBOp4DTXERe8xdEWoU=",
"owner": "0xc000022070", "owner": "0xc000022070",
"repo": "zen-browser-flake", "repo": "zen-browser-flake",
"rev": "f806c5bfd831b8f9333b31f45b85b711025ba3de", "rev": "3ac78827a82614c394e6f8fcc84c5cea9c3847f4",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -114,18 +114,18 @@
# #
# NOTE(starter): As with typical flake-based configs, you'll need to update the nixOS, hm, # 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. # and darwin version numbers below when new releases are available.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; 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. # 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 # 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 # keep 'nixpkgs-stable' set to stable for critical packages while setting 'nixpkgs' to the beta branch to
# get a jump start on deprecation changes. # get a jump start on deprecation changes.
# See also 'stable-packages' and 'unstable-packages' overlays at 'overlays/default.nix" # 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"; nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
hardware.url = "github:nixos/nixos-hardware"; hardware.url = "github:nixos/nixos-hardware";
home-manager = { home-manager = {
url = "github:nix-community/home-manager/release-25.05"; url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
@@ -144,7 +144,7 @@
}; };
nixos-hardware = { nixos-hardware = {
url = "github:NixOS/nixos-hardware/master"; url = "github:NixOS/nixos-hardware";
}; };
nix4vscode = { nix4vscode = {
@@ -160,7 +160,7 @@
devenv.url = "github:cachix/devenv"; devenv.url = "github:cachix/devenv";
stylix = { stylix = {
url = "github:danth/stylix/release-25.05"; url = "github:danth/stylix";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
@@ -169,10 +169,22 @@
# #
zen-browser = { zen-browser = {
url = "github:0xc000022070/zen-browser-flake"; url = "github:0xc000022070/zen-browser-flake";
inputs = { inputs.nixpkgs.follows = "nixpkgs";
home-manager.follows = "home-manager"; };
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";
}; };
# #

View 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

View File

@@ -10,7 +10,8 @@
# #
# FIXME(starter): add or remove any optional config directories or files ehre # FIXME(starter): add or remove any optional config directories or files ehre
common/optional/browsers common/optional/browsers
common/optional/desktops common/optional/desktops/niri
common/optional/desktops/niri/zenbook-screen.nix
common/optional/comms common/optional/comms
common/optional/media common/optional/media
common/optional/coding common/optional/coding

View File

@@ -21,6 +21,7 @@ in {
# FIXME(starter): add/edit as desired # FIXME(starter): add/edit as desired
./fonts.nix ./fonts.nix
./kitty.nix ./kitty.nix
./ghostty.nix
./git.nix ./git.nix
./ssh.nix ./ssh.nix
./shell ./shell
@@ -28,7 +29,7 @@ in {
inherit hostSpec; inherit hostSpec;
services.ssh-agent.enable = true; #services.ssh-agent.enable = true;
home = { home = {
username = lib.mkDefault config.hostSpec.username; username = lib.mkDefault config.hostSpec.username;
@@ -37,10 +38,6 @@ in {
sessionPath = [ sessionPath = [
"$HOME/.local/bin" "$HOME/.local/bin"
]; ];
sessionVariables = {
FLAKE = "$HOME/src/nix/nix-config";
SHELL = "bash";
};
}; };
home.packages = with pkgs; [ home.packages = with pkgs; [

View File

@@ -1,7 +1,41 @@
{ pkgs, ... }: {pkgs, ...}: {
{
fonts.fontconfig.enable = true; fonts.fontconfig.enable = true;
home.packages = [ home.packages = with pkgs; [
pkgs.noto-fonts 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
]; ];
} }

View 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"; };
};
}

View File

@@ -10,6 +10,12 @@
package = pkgs.gitAndTools.gitFull; package = pkgs.gitAndTools.gitFull;
userName = "Thomas Syms"; userName = "Thomas Syms";
userEmail = "thomassyms@gmail.com"; userEmail = "thomassyms@gmail.com";
lfs.enable = true;
extraConfig = {
credential.helper = "${
pkgs.git.override {withLibsecret = true;}
}/bin/git-credential-libsecret";
};
ignores = [ ignores = [
".csvignore" ".csvignore"

View File

@@ -1,5 +1,5 @@
{ {
programs.kitty = { programs.kitty = {
enable = true; enable = true;
}; };
} }

View File

@@ -1,5 +1,5 @@
{pkgs, ...}: { {pkgs, ...}: {
home.packages = with pkgs; [ home.packages = with pkgs; [
oterm # oterm removed
]; ];
} }

View File

@@ -8,6 +8,7 @@
./btop.nix ./btop.nix
./carapace.nix ./carapace.nix
./common.nix ./common.nix
./devenv.nix
./direnv.nix ./direnv.nix
./eza.nix ./eza.nix
./fish.nix ./fish.nix

View File

@@ -0,0 +1,3 @@
{pkgs, ...}: {
home.packages = [pkgs.devenv];
}

View File

@@ -0,0 +1,6 @@
{pkgs, ...}: {
programs.nushell = {
enable = true;
configFile.source = null; # Use default config, or set to a custom file if desired
};
}

View 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
];
};
}

View File

@@ -3,14 +3,17 @@
programs.ssh = { programs.ssh = {
enable = true; enable = true;
# Global SSH settings
addKeysToAgent = "yes";
controlMaster = "auto"; controlMaster = "auto";
controlPath = "${config.home.homeDirectory}/.ssh/sockets/S.%r@%h:%p"; controlPath = "${config.home.homeDirectory}/.ssh/sockets/S.%r@%h:%p";
controlPersist = "20m"; controlPersist = "20m";
# Avoids infinite hang if control socket connection interrupted. ex: vpn goes down/up
serverAliveCountMax = 3; serverAliveCountMax = 3;
serverAliveInterval = 5; # 3 * 5s serverAliveInterval = 5; # 3 * 5s
hashKnownHosts = true; hashKnownHosts = true;
addKeysToAgent = "yes";
# Set default values for all hosts
matchBlocks."*" = {};
}; };
home.file = { home.file = {
".ssh/config.d/.keep".text = "# Managed by Home Manager"; ".ssh/config.d/.keep".text = "# Managed by Home Manager";

View File

@@ -5,7 +5,7 @@
}: { }: {
# home.nix # home.nix
imports = [ imports = [
inputs.zen-browser.homeModules.beta inputs.zen-browser.homeModules.default
# inputs.zen-browser.homeModules.twilight # inputs.zen-browser.homeModules.twilight
# inputs.zen-browser.homeModules.twilight-official # inputs.zen-browser.homeModules.twilight-official
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
"GitHub.copilot" "GitHub.copilot"
"GitHub.copilot-chat" "GitHub.copilot-chat"
]; ];

View File

@@ -13,7 +13,7 @@
enableUpdateCheck = false; # Let Home Manager manage VSCode versions enableUpdateCheck = false; # Let Home Manager manage VSCode versions
enableExtensionUpdateCheck = false; # Let nix4vscode manage extensions enableExtensionUpdateCheck = false; # Let nix4vscode manage extensions
mutableExtensionsDir = false; mutableExtensionsDir = false;
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# --- General --- # --- General ---
"britesnow.vscode-toggle-quotes" "britesnow.vscode-toggle-quotes"
"mrmlnc.vscode-duplicate" "mrmlnc.vscode-duplicate"
@@ -35,6 +35,7 @@
"ms-python.python" "ms-python.python"
"jock.svg" "jock.svg"
"redhat.vscode-yaml" "redhat.vscode-yaml"
"mkhl.direnv"
]; ];
userSettings = { userSettings = {
# --- Privacy & Telemetry --- # --- Privacy & Telemetry ---
@@ -58,6 +59,7 @@
"window.titleBarStyle" = "native"; "window.titleBarStyle" = "native";
"workbench.navigationControl.enabled" = false; "workbench.navigationControl.enabled" = false;
"workbench.layoutControl.enabled" = false; "workbench.layoutControl.enabled" = false;
# --- Extension-specific telemetry opt-outs --- # --- Extension-specific telemetry opt-outs ---
"code-runner.enableAppInsights" = false; "code-runner.enableAppInsights" = false;
"docker-explorer.enableTelemetry" = false; "docker-explorer.enableTelemetry" = false;
@@ -73,6 +75,7 @@
"terraform.telemetry.enabled" = false; "terraform.telemetry.enabled" = false;
"vsicons.dontShowNewVersionMessage" = true; "vsicons.dontShowNewVersionMessage" = true;
"workbench.welcomePage.walkthroughs.openOnInstall" = false; "workbench.welcomePage.walkthroughs.openOnInstall" = false;
"nixEnvSelector.useFlakes" = true;
}; };
}; };
} }

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# CSV language support # CSV language support
"mechatroner.rainbow-csv" "mechatroner.rainbow-csv"
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# Godot language support # Godot language support
"geequlim.godot-tools" "geequlim.godot-tools"
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# Go language support # Go language support
"golang.go" "golang.go"
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# General # General
"christian-kohler.npm-intellisense" "christian-kohler.npm-intellisense"
"dbaeumer.vscode-eslint" "dbaeumer.vscode-eslint"

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# General # General
"james-yu.latex-workshop" "james-yu.latex-workshop"
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# General # General
"bpruitt-goddard.mermaid-markdown-syntax-highlighting" "bpruitt-goddard.mermaid-markdown-syntax-highlighting"
"davidanson.vscode-markdownlint" "davidanson.vscode-markdownlint"

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# Nix language support # Nix language support
"jnoortheen.nix-ide" "jnoortheen.nix-ide"
"kamadorueda.alejandra" "kamadorueda.alejandra"

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# Python language support # Python language support
"ms-python.python" "ms-python.python"
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# Rust language support # Rust language support
"barbosshack.crates-io" "barbosshack.crates-io"
"tamasfe.even-better-toml" "tamasfe.even-better-toml"

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# SVG language support # SVG language support
"jock.svg" "jock.svg"
]; ];

View File

@@ -1,6 +1,6 @@
{pkgs, ...}: { {pkgs, ...}: {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
# YAML language support # YAML language support
"redhat.vscode-yaml" "redhat.vscode-yaml"
]; ];

View 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.
}

View 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
}

View 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/"
];
};
};
}

View File

@@ -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"];
};
}

View 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";
};
}

View 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
];
}

View 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
];
}

View 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"
];
}

View 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
];
}

View 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
];
}

View File

@@ -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
];
}

View File

@@ -0,0 +1,10 @@
{pkgs, ...}: {
home.packages = with pkgs; [
kdePackages.kdeconnect-kde
kdePackages.konsole
kdePackages.dolphin
kdePackages.okular
kdePackages.gwenview
kdePackages.spectacle
];
}

View 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"
'';
};
}

View 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";
};
}

View 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"];
}

View 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";
}
];
};
}

View 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"];
}

View 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
'';
}

View 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 ""

View 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
];
}

View File

@@ -1,6 +1,5 @@
{pkgs, ...}: { {pkgs, ...}: {
imports = [ imports = [
./lmstudio.nix
./obsidian.nix ./obsidian.nix
]; ];
@@ -12,5 +11,6 @@
blender blender
inkscape inkscape
libreoffice-qt libreoffice-qt
davinci-resolve
]; ];
} }

View File

@@ -1,5 +0,0 @@
{pkgs, ...}: {
home.packages = with pkgs; [
lmstudio
];
}

View File

@@ -4,7 +4,7 @@
... ...
}: { }: {
programs.ssh = lib.optionalAttrs pkgs.stdenv.isLinux { programs.ssh = lib.optionalAttrs pkgs.stdenv.isLinux {
startAgent = true; #startAgent = true;
enableAskPassword = true; enableAskPassword = true;
}; };
} }

View File

@@ -0,0 +1,4 @@
{pkgs, ...}: {
# Enable the COSMIC Greeter (Display Manager)
services.displayManager.cosmic-greeter.enable = true;
}

View File

@@ -0,0 +1,9 @@
{
pkgs,
lib,
...
}: {
# Enable the COSMIC desktop environment
services.desktopManager.cosmic.enable = true;
environment.sessionVariables.NIXOS_OZONE_WL = "1";
}

View File

@@ -23,7 +23,6 @@
]; ];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
gnomeExtensions.appindicator
gsettings-desktop-schemas gsettings-desktop-schemas
]; ];
} }

View 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;
}

View 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";
}

View File

@@ -1,7 +1,14 @@
{pkgs, ...}: { {
pkgs,
lib,
...
}: {
services.desktopManager.plasma6.enable = true; services.desktopManager.plasma6.enable = true;
environment.sessionVariables.GTK_USE_PORTAL = "1"; environment.sessionVariables.GTK_USE_PORTAL = "1";
environment.sessionVariables.NIXOS_OZONE_WL = "1"; environment.sessionVariables.NIXOS_OZONE_WL = "1";
environment.sessionVariables.KWIN_DRM_PREFER_COLOR_DEPTH = "24"; environment.sessionVariables.KWIN_DRM_PREFER_COLOR_DEPTH = "24";
environment.systemPackages = with pkgs.kdePackages; [plasma-thunderbolt sddm-kcm]; environment.systemPackages = with pkgs.kdePackages; [plasma-thunderbolt sddm-kcm];
# Fix Qt platform theme configuration for KDE - force override stylix
qt.platformTheme = lib.mkForce "kde";
} }

View 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
'';
}

View 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;
'';
}

View 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";
}

View File

@@ -1,10 +1,10 @@
# NOTE(starter): This is just a basic enabling of the XFCE windows manager for simplicity # NOTE(starter): This is just a basic enabling of the XFCE windows manager for simplicity
{ {
services.displayManager = { services.displayManager = {
sddm.enable = true; sddm.enable = true;
sddm.wayland = { sddm.wayland = {
enable = true; enable = true;
compositor = "kwin"; compositor = "kwin";
}; };
}; };
} }

View 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
];
};
}

View File

@@ -0,0 +1,3 @@
{
services.system76-scheduler.enable = true;
}

View File

@@ -6,7 +6,7 @@
home-manager.sharedModules = [ home-manager.sharedModules = [
{ {
stylix.autoEnable = true; stylix.autoEnable = true;
stylix.targets.vscode.enable = false; stylix.targets.vscode.enable = true;
} }
]; ];
} }

View File

@@ -13,6 +13,12 @@ in {
stylix.base16Scheme = "${tinted-schemes}/base16/tokyo-city-dark.yaml"; stylix.base16Scheme = "${tinted-schemes}/base16/tokyo-city-dark.yaml";
stylix.cursor = {
package = pkgs.qogir-icon-theme;
name = "Qogir";
size = 24;
};
stylix.fonts = { stylix.fonts = {
serif = { serif = {
package = pkgs.noto-fonts; package = pkgs.noto-fonts;
@@ -20,20 +26,22 @@ in {
}; };
sansSerif = { sansSerif = {
package = pkgs.noto-fonts; package = pkgs.inter;
name = "Noto Sans"; name = "Inter";
}; };
monospace = { monospace = {
package = pkgs.nerd-fonts.fira-code; package = pkgs.nerd-fonts.jetbrains-mono;
name = "Fira Code Nerd Font"; name = "JetBrainsMono Nerd Font Mono";
}; };
emoji = { emoji = {
package = pkgs.noto-fonts-emoji; package = pkgs.noto-fonts-emoji;
name = "Noto Color Emoji"; name = "Noto Color Emoji";
}; };
sizes = { sizes = {
applications = 10; applications = 10; # whole-number size
desktop = 10; desktop = 10;
popups = 10; popups = 10;
terminal = 10; terminal = 10;
@@ -43,12 +51,12 @@ in {
home-manager.sharedModules = [ home-manager.sharedModules = [
{ {
programs.vscode = { programs.vscode = {
extensions = pkgs.nix4vscode.forVscode [ extensions = pkgs.nix4vscode.forVscodeVersion pkgs.vscode.version [
"huytd.tokyo-city" "huytd.tokyo-city"
"vscode-icons-team.vscode-icons" "vscode-icons-team.vscode-icons"
]; ];
userSettings = { userSettings = {
"workbench.colorTheme" = "Tokyo City Darker"; #"workbench.colorTheme" = "Tokyo City Darker";
"workbench.iconTheme" = "vscode-icons"; "workbench.iconTheme" = "vscode-icons";
}; };
}; };

View File

@@ -3,61 +3,78 @@
services.tlp = { services.tlp = {
enable = true; enable = true;
settings = { settings =
# Set CPU driver operation mode to 'active' to allow the CPU to manage its own frequency scaling # In services.tlp.settings
CPU_DRIVER_OPMODE_ON_AC = "active"; {
CPU_DRIVER_OPMODE_ON_BAT = "active"; # --- CPU Settings for Core Ultra 9 185H ---
# Use 'performance' governor for max performance on AC # Use the modern 'intel_pstate' driver in active mode. This is correct.
CPU_SCALING_GOVERNOR_ON_AC = "performance"; CPU_DRIVER_OPMODE_ON_AC = "active";
CPU_SCALING_GOVERNOR_ON_BAT = "powersave"; CPU_DRIVER_OPMODE_ON_BAT = "active";
# Set Energy Performance Preference (EPP) to balance performance on AC and favor power savings on battery # CRITICAL: Use 'powersave' for both. On modern Intel chips, this enables
CPU_ENERGY_PERF_POLICY_ON_AC = "balance_performance"; # dynamic scaling from idle up to max boost. It is the best-performing
CPU_ENERGY_PERF_POLICY_ON_BAT = "balance_power"; # and most efficient setting.
CPU_SCALING_GOVERNOR_ON_AC = "powersave";
CPU_SCALING_GOVERNOR_ON_BAT = "powersave";
# Define CPU performance limits: full performance on AC, limited to 50% on battery to save power # This is your main performance tuning knob. 'performance' tells the CPU
CPU_MIN_PERF_ON_AC = 0; # to aggressively ramp up to high clock speeds when it detects a load.
CPU_MAX_PERF_ON_AC = 100; # 'balance_performance' provides good performance while being more thermal-aware.
CPU_MIN_PERF_ON_BAT = 0; CPU_ENERGY_PERF_POLICY_ON_AC = "balance_performance";
CPU_MAX_PERF_ON_BAT = 50; CPU_ENERGY_PERF_POLICY_ON_BAT = "balance_power";
# Enable Turbo Boost on AC for maximum performance; disable on battery to conserve energy # Allow the CPU to use its performance range when plugged in, but cap it
CPU_BOOST_ON_AC = 1; # slightly to reduce heat generation while maintaining good responsiveness.
CPU_BOOST_ON_BAT = 0; CPU_MIN_PERF_ON_AC = 0;
CPU_MAX_PERF_ON_AC = 85; # Reduced from 100% to help with thermal management
CPU_MIN_PERF_ON_BAT = 0;
CPU_MAX_PERF_ON_BAT = 60; # Slightly higher than before for better battery responsiveness.
# Enable Intel's Hardware P-States (HWP) dynamic boost on AC; disable on battery # ESSENTIAL: Enable Turbo Boost on AC. This is how you get peak performance.
CPU_HWP_DYN_BOOST_ON_AC = 1; # The 'powersave' governor will use boost intelligently when needed.
CPU_HWP_DYN_BOOST_ON_BAT = 1; # Disabling on battery is key for thermal control and battery life.
CPU_BOOST_ON_AC = 1;
CPU_BOOST_ON_BAT = 0;
# Set platform profile to 'performance' on AC and 'low-power' on battery, if supported by the system # HWP Dynamic Boost is a good feature to keep enabled.
PLATFORM_PROFILE_ON_AC = "performance"; CPU_HWP_DYN_BOOST_ON_AC = 1;
PLATFORM_PROFILE_ON_BAT = "low-power"; CPU_HWP_DYN_BOOST_ON_BAT = 1;
# Enable Wi-Fi power saving on both AC and battery # --- Intel Arc GPU & System Settings ---
WIFI_PWR_ON_AC = "on";
WIFI_PWR_ON_BAT = "on";
# Configure PCIe Active State Power Management: 'performance' on AC, aggressive power saving on battery # Set the platform profile. 'low-power' is more conservative than 'balanced'
PCIE_ASPM_ON_AC = "performance"; # to help with thermal management while still providing reasonable performance.
PCIE_ASPM_ON_BAT = "powersupersave"; PLATFORM_PROFILE_ON_AC = "low-power";
PLATFORM_PROFILE_ON_BAT = "low-power";
# Enable runtime power management for PCIe devices: 'on' for AC, 'auto' for battery # Use 'powersupersave' for PCIe ASPM. This allows the components,
RUNTIME_PM_ON_AC = "on"; # including the GPU, to enter deeper sleep states, reducing idle heat.
RUNTIME_PM_ON_BAT = "auto"; PCIE_ASPM_ON_AC = "powersupersave";
PCIE_ASPM_ON_BAT = "powersupersave";
# Enable sound power saving on both AC and battery; '1' sets a 1-second timeout # Runtime Power Management is crucial for the integrated GPU to power down
SOUND_POWER_SAVE_ON_AC = 1; # when not in heavy use. 'auto' is the recommended setting for modern hardware.
SOUND_POWER_SAVE_ON_BAT = 1; RUNTIME_PM_ON_AC = "auto";
SOUND_POWER_SAVE_CONTROLLER = "Y"; RUNTIME_PM_ON_BAT = "auto";
# Whitelist everything except devices known to cause issues (like some audio codecs).
# The default blacklist is usually sufficient.
RUNTIME_PM_DRIVER_BLACKLIST = "amdgpu nouveau nvidia pcieport";
# Enable USB autosuspend to save power when devices are idle # --- Other Power Saving ---
USB_AUTOSUSPEND = 1;
#Optional helps save long term battery health # Keep Wi-Fi power saving on; it's generally fine.
#START_CHARGE_THRESH_BAT0 = 40; # 40 and below it starts to charge WIFI_PWR_ON_AC = "on";
#STOP_CHARGE_THRESH_BAT0 = 80; # 80 and above it stops charging WIFI_PWR_ON_BAT = "on";
};
# Sound power saving is fine.
SOUND_POWER_SAVE_ON_AC = 1;
SOUND_POWER_SAVE_ON_BAT = 1;
SOUND_POWER_SAVE_CONTROLLER = "Y";
# USB autosuspend is fine.
USB_AUTOSUSPEND = 1;
};
}; };
#powerManagement.powertop.enable = true; #powerManagement.powertop.enable = true;

View File

@@ -7,61 +7,58 @@
# . # .
# If you have no need for secondary users, simple delete this file and its parent directory, and ensure that # If you have no need for secondary users, simple delete this file and its parent directory, and ensure that
# your `nix-confitg/hosts/[platform]/[hostname]/default.nix` files do not import this file. # your `nix-confitg/hosts/[platform]/[hostname]/default.nix` files do not import this file.
# #
# Basic user for viewing exampleSecondUser # Basic user for viewing exampleSecondUser
# #
{ {
inputs, inputs,
lib, lib,
pkgs, pkgs,
config, config,
... ...
}: }: let
let
hostSpec = config.hostSpec; hostSpec = config.hostSpec;
secretsSubPath = "passwords/exampleSecondUser"; secretsSubPath = "passwords/exampleSecondUser";
in in
{ {
# Decrypt passwords/exampleSecondUser to /run/secrets-for-users/ so it can be used to create the user # Decrypt passwords/exampleSecondUser to /run/secrets-for-users/ so it can be used to create the user
sops.secrets.${secretsSubPath}.neededForUsers = true; sops.secrets.${secretsSubPath}.neededForUsers = true;
users.mutableUsers = false; # Required for password to be set via sops during system activation! users.mutableUsers = false; # Required for password to be set via sops during system activation!
users.users.exampleSecondUser = { users.users.exampleSecondUser = {
isNormalUser = true; isNormalUser = true;
hashedPasswordFile = config.sops.secrets.${secretsSubPath}.path; hashedPasswordFile = config.sops.secrets.${secretsSubPath}.path;
shell = pkgs.zsh; # default shell shell = pkgs.zsh; # default shell
extraGroups = [ extraGroups = [
"audio" "audio"
"video" "video"
]; ];
packages = [ pkgs.home-manager ]; packages = [pkgs.home-manager];
};
}
# Import this user's personal/home configurations
// lib.optionalAttrs (inputs ? "home-manager") {
home-manager = {
extraSpecialArgs = {
inherit pkgs inputs;
hostSpec = config.hostSpec;
}; };
users.exampleSecondUser.imports = lib.flatten ( }
lib.optional (!hostSpec.isMinimal) [ # Import this user's personal/home configurations
( // lib.optionalAttrs (inputs ? "home-manager") {
{ config, ... }: home-manager = {
import (lib.custom.relativeToRoot "home/exampleSecondUser/${hostSpec.hostName}.nix") { extraSpecialArgs = {
inherit inherit pkgs inputs;
pkgs hostSpec = config.hostSpec;
inputs };
config users.exampleSecondUser.imports = lib.flatten (
lib lib.optional (!hostSpec.isMinimal) [
hostSpec (
; {config, ...}:
} import (lib.custom.relativeToRoot "home/exampleSecondUser/${hostSpec.hostName}.nix") {
) inherit
] pkgs
); inputs
}; config
} lib
hostSpec
;
}
)
]
);
};
}

View File

@@ -69,15 +69,16 @@
# The following are for example sake only and are not necessarily required. # The following are for example sake only and are not necessarily required.
#"hosts/common/optional/services/openssh.nix" # allow remote SSH access #"hosts/common/optional/services/openssh.nix" # allow remote SSH access
"hosts/common/optional/services/bluetooth.nix" "hosts/common/optional/services/bluetooth.nix"
"hosts/common/optional/services/printing.nix"
"hosts/common/optional/thunderbolt.nix" "hosts/common/optional/thunderbolt.nix"
"hosts/common/optional/services/ollama.nix" "hosts/common/optional/services/ollama.nix"
"hosts/common/optional/services/docker.nix" "hosts/common/optional/services/docker.nix"
"hosts/common/optional/services/tailscale.nix"
"hosts/common/optional/audio.nix" # pipewire and cli controls "hosts/common/optional/audio.nix" # pipewire and cli controls
"hosts/common/optional/kde.nix" "hosts/common/optional/niri.nix"
"hosts/common/optional/sddm.nix" "hosts/common/optional/gdm.nix"
"hosts/common/optional/flatpak.nix" "hosts/common/optional/flatpak.nix"
"hosts/common/optional/thermal-management.nix" "hosts/common/optional/thermal-management.nix"
"hosts/common/optional/system76-scheduler.nix"
# Theming # Theming
"hosts/common/optional/theming/targets/all-except-vscode.nix" "hosts/common/optional/theming/targets/all-except-vscode.nix"

View File

@@ -33,29 +33,31 @@ in {
}; };
}; };
systemd.user.services.watchDisplays = { # DISABLED: Old gnome-monitor-config approach - now using niri-native zenbook-screen.nix
description = "set screens on keyboard event"; # systemd.user.services.watchDisplays = {
wantedBy = ["default.target"]; # description = "set screens on keyboard event";
after = ["graphical-session.target"]; # wantedBy = ["default.target"];
# after = ["graphical-session.target"];
path = [pkgs.gnome-monitor-config pkgs.usbutils pkgs.inotify-tools]; # path = [pkgs.gnome-monitor-config pkgs.usbutils pkgs.inotify-tools];
serviceConfig = { # serviceConfig = {
preStart = "${patchedDuoScript} normal"; # preStart = "${patchedDuoScript} normal";
ExecStart = "${patchedDuoScript} watch-displays"; # ExecStart = "${patchedDuoScript} watch-displays";
Restart = "always"; # Restart = "always";
RestartSec = 5; # RestartSec = 5;
}; # };
}; # };
systemd.user.services.watchRotation = { # DISABLED: Old rotation script - conflicts with niri
description = "rotate screens"; # systemd.user.services.watchRotation = {
wantedBy = ["default.target"]; # description = "rotate screens";
after = ["graphical-session.target"]; # wantedBy = ["default.target"];
path = [pkgs.gnome-monitor-config pkgs.iio-sensor-proxy]; # after = ["graphical-session.target"];
serviceConfig = { # path = [pkgs.gnome-monitor-config pkgs.iio-sensor-proxy];
ExecStart = "${patchedDuoScript} watch-rotation"; # serviceConfig = {
Restart = "always"; # ExecStart = "${patchedDuoScript} watch-rotation";
RestartSec = 5; # Restart = "always";
}; # RestartSec = 5;
}; # };
# };
} }

View File

@@ -14,16 +14,33 @@
boot.initrd.availableKernelModules = ["xhci_pci" "thunderbolt" "vmd" "nvme" "usbhid"]; boot.initrd.availableKernelModules = ["xhci_pci" "thunderbolt" "vmd" "nvme" "usbhid"];
boot.initrd.kernelModules = []; boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-intel" "evdi"]; boot.kernelPackages = pkgs.linuxPackages_latest;
boot.kernelParams = ["i915.enable_psr=0"]; boot.kernelModules = ["kvm-intel" "evdi" "intel_vpu"];
boot.kernelPatches = [ boot.kernelParams = [
/* "i915.enable_guc=3"
{ #"i915.enable_psr=0"
name = "zenbook-asus-wmi"; # Suppress rfkill/WLAN toggle events from asus-wmi
patch = ./zenbook-asus-wmi.patch; "asus_nb_wmi.wapf=4"
}
*/
]; ];
boot.kernelPatches = [
# Both patches are malformed/outdated and don't apply to current kernel versions
# Using alternative approach with extraModprobeConfig below
];
# Suppress rfkill events from keyboard attach/detach
services.udev.extraRules = ''
# Zenbook Duo - suppress rfkill/airplane mode key events on keyboard connect/disconnect
SUBSYSTEM=="input", ATTRS{name}=="Asus WMI hotkeys", ENV{KEY_RFKILL}="0", ENV{KEY_WLAN}="0"
'';
# Hardware database override to disable rfkill key on ASUS WMI hotkeys
services.udev.extraHwdb = ''
evdev:name:Asus WMI hotkeys:dmi:*
KEYBOARD_KEY_88=unknown
KEYBOARD_KEY_5d=unknown
KEYBOARD_KEY_5e=unknown
KEYBOARD_KEY_5f=unknown
'';
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's # (the default) this is the recommended approach. When using systemd-networkd it's
@@ -40,9 +57,7 @@
sof-firmware sof-firmware
#rotation stuff #rotation stuff
gnome-monitor-config intel-gpu-tools # For debugging and monitoring the iGPU
usbutils intel-media-driver # VA-API driver for modern Intel GPUs
inotify-tools
kdePackages.libkscreen
]; ];
} }

View File

@@ -0,0 +1,189 @@
From 2f8f8e6bb2da47c677a07f76f141c527ddd5d51c Mon Sep 17 00:00:00 2001
From: hacker1024 <hacker1024@users.sourceforge.net>
Date: Fri, 12 Apr 2024 13:59:24 +1000
Subject: [PATCH] asus-wmi: Add additional DEVID_THROTTLE_THERMAL_POLICY
---
drivers/platform/x86/asus-wmi.c | 102 +++++++++++++++------
include/linux/platform_data/x86/asus-wmi.h | 1 +
2 files changed, 76 insertions(+), 27 deletions(-)
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 18be35fdb381..c7958b31dae0 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -93,9 +93,13 @@ module_param(fnlock_default, bool, 0444);
#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02
#define ASUS_FAN_BOOST_MODES_MASK 0x03
+#define ASUS_THROTTLE_THERMAL_POLICY_COUNT 3
#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0
#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2
+#define ASUS_THROTTLE_THERMAL_POLICY_LITE_DEFAULT 0
+#define ASUS_THROTTLE_THERMAL_POLICY_LITE_OVERBOOST 2
+#define ASUS_THROTTLE_THERMAL_POLICY_LITE_SILENT 1
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
@@ -282,6 +286,7 @@ struct asus_wmi {
bool kbd_rgb_state_available;
bool throttle_thermal_policy_available;
+ bool throttle_thermal_policy_lite;
u8 throttle_thermal_policy_mode;
bool cpu_fan_curve_available;
@@ -3404,6 +3409,14 @@ static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
&result);
+ if (err == -ENODEV) {
+ err = asus_wmi_get_devstate(asus,
+ ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_LITE,
+ &result);
+ asus->throttle_thermal_policy_lite = true;
+ } else {
+ asus->throttle_thermal_policy_lite = false;
+ }
if (err) {
if (err == -ENODEV)
return 0;
@@ -3424,7 +3437,10 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
value = asus->throttle_thermal_policy_mode;
- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
+ err = asus_wmi_set_devstate(
+ asus->throttle_thermal_policy_lite
+ ? ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_LITE
+ : ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
value, &retval);
sysfs_notify(&asus->platform_device->dev.kobj, NULL,
@@ -3466,7 +3482,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
u8 new_mode = asus->throttle_thermal_policy_mode + 1;
int err;
- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
+ if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_COUNT - 1)
new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
asus->throttle_thermal_policy_mode = new_mode;
@@ -3505,7 +3521,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
if (result < 0)
return result;
- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
+ if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_COUNT - 1)
return -EINVAL;
asus->throttle_thermal_policy_mode = new_mode;
@@ -3536,18 +3552,34 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
tp = asus->throttle_thermal_policy_mode;
- switch (tp) {
- case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
- *profile = PLATFORM_PROFILE_BALANCED;
- break;
- case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
- *profile = PLATFORM_PROFILE_PERFORMANCE;
- break;
- case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
- *profile = PLATFORM_PROFILE_QUIET;
- break;
- default:
- return -EINVAL;
+ if (!asus->throttle_thermal_policy_lite) {
+ switch (tp) {
+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
+ *profile = PLATFORM_PROFILE_BALANCED;
+ break;
+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
+ *profile = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
+ *profile = PLATFORM_PROFILE_QUIET;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (tp) {
+ case ASUS_THROTTLE_THERMAL_POLICY_LITE_DEFAULT:
+ *profile = PLATFORM_PROFILE_BALANCED;
+ break;
+ case ASUS_THROTTLE_THERMAL_POLICY_LITE_OVERBOOST:
+ *profile = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ case ASUS_THROTTLE_THERMAL_POLICY_LITE_SILENT:
+ *profile = PLATFORM_PROFILE_QUIET;
+ break;
+ default:
+ return -EINVAL;
+ }
}
return 0;
@@ -3561,18 +3593,34 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof,
asus = container_of(pprof, struct asus_wmi, platform_profile_handler);
- switch (profile) {
- case PLATFORM_PROFILE_PERFORMANCE:
- tp = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
- break;
- case PLATFORM_PROFILE_BALANCED:
- tp = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
- break;
- case PLATFORM_PROFILE_QUIET:
- tp = ASUS_THROTTLE_THERMAL_POLICY_SILENT;
- break;
- default:
- return -EOPNOTSUPP;
+ if (!asus->throttle_thermal_policy_lite) {
+ switch (profile) {
+ case PLATFORM_PROFILE_PERFORMANCE:
+ tp = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
+ break;
+ case PLATFORM_PROFILE_BALANCED:
+ tp = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+ break;
+ case PLATFORM_PROFILE_QUIET:
+ tp = ASUS_THROTTLE_THERMAL_POLICY_SILENT;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ } else {
+ switch (profile) {
+ case PLATFORM_PROFILE_PERFORMANCE:
+ tp = ASUS_THROTTLE_THERMAL_POLICY_LITE_OVERBOOST;
+ break;
+ case PLATFORM_PROFILE_BALANCED:
+ tp = ASUS_THROTTLE_THERMAL_POLICY_LITE_DEFAULT;
+ break;
+ case PLATFORM_PROFILE_QUIET:
+ tp = ASUS_THROTTLE_THERMAL_POLICY_LITE_SILENT;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
}
asus->throttle_thermal_policy_mode = tp;
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index ab1c7deff118..ddf5b3766cd2 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -64,6 +64,7 @@
#define ASUS_WMI_DEVID_SCREENPAD_LIGHT 0x00050032
#define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
+#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_LITE 0x00110019
/* Misc */
#define ASUS_WMI_DEVID_PANEL_OD 0x00050019
--
2.44.0

View File

@@ -0,0 +1,48 @@
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index fceffe2082ec..ed3633c5955d 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -145,6 +145,10 @@ static
struct quirk_entry quirk_asus_ignore_fan = {
.wmi_ignore_fan = true,
};
+static
+struct quirk_entry quirk_asus_zenbook_duo_kbd = {
+ .ignore_key_wlan = true,
+};
+
static int dmi_matched(const struct dmi_system_id *dmi)
{
pr_info("Identified laptop model '%s'\n", dmi->ident);
@@ -516,6 +520,15 @@ static const struct
dmi_system_id asus_quirks[] = {
...
@@ -630,7 +643,12 @@ static void
asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
...
case 0x32: /* Volume Mute */
if (atkbd_reports_vol_keys)
*code = ASUS_WMI_KEY_IGNORE;
-
+ break;
+ case 0x5D: /* Wireless console Toggle */
+ case 0x5E: /* Wireless console Enable */
+ case 0x5F: /* Wireless console Disable */
+ if (quirks->ignore_key_wlan)
+ *code = ASUS_WMI_KEY_IGNORE;
break;
}
}
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index cc30f1853847..a6ee9440d932 100644
@@ -50,6 +50,7 @@ struct quirk_entry {
*/
int no_display_toggle;
u32 xusb2pr;
+ bool ignore_key_wlan;
};
struct asus_wmi_driver {

View File

@@ -7,10 +7,19 @@
... ...
}: let }: let
# Adds my custom packages # Adds my custom packages
additions = final: prev: (prev.lib.packagesFromDirectoryRecursive { additions = final: prev:
callPackage = prev.lib.callPackageWith final; (prev.lib.packagesFromDirectoryRecursive {
directory = ../pkgs/common; callPackage = prev.lib.callPackageWith final;
}); directory = ../pkgs/common;
})
// {
# Custom GNOME extensions
gnomeExtensions =
prev.gnomeExtensions
// {
monitor-workspace-manager = final.monitor-workspace-manager;
};
};
linuxModifications = final: prev: prev.lib.mkIf final.stdenv.isLinux {}; linuxModifications = final: prev: prev.lib.mkIf final.stdenv.isLinux {};