Updated everything

This commit is contained in:
2025-09-22 09:06:50 -03:00
parent 20c8ecb0bd
commit 438296b01b
51 changed files with 1778 additions and 1090 deletions

17
.vscode/tasks.json vendored
View File

@@ -1,17 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Hyprland Configuration",
"type": "shell",
"command": "nix",
"args": [
"build",
".#homeConfigurations.panotaka@Bellerophon.activationPackage"
],
"group": "build",
"isBackground": false,
"problemMatcher": []
}
]
}

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

253
flake.lock generated
View File

@@ -8,11 +8,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1755729720, "lastModified": 1757330146,
"narHash": "sha256-F6NKjTnVe5we9N7HAux1LEibshcTOndmm18TePGWQ68=", "narHash": "sha256-ujlZerjj0ouA63nftpoHF/tA+xE5gDJZVBuuZP6YS+Q=",
"owner": "aylur", "owner": "aylur",
"repo": "ags", "repo": "ags",
"rev": "c674fe0e4130cec4f16e620c1fe30183cdb055f4", "rev": "5347d21c2289df157e91e297daa37572e0d277b5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -29,11 +29,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1752404970, "lastModified": 1756474652,
"narHash": "sha256-XULTToDUkIshNXEO+YP2mAHdQv8bxWDvKjbamBfOC8E=", "narHash": "sha256-iiBU6itpEqE0spXeNJ3uJTfioSyKYjt5bNepykpDXTE=",
"owner": "aylur", "owner": "aylur",
"repo": "astal", "repo": "astal",
"rev": "2c5eb54f39e1710c6e2c80915a240978beb3269a", "rev": "20bd8318e4136fbd3d4eb2d64dbabc3acbc915dd",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -47,11 +47,11 @@
"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": {
@@ -141,20 +141,67 @@
"type": "github" "type": "github"
} }
}, },
"caelestia-cli": {
"inputs": {
"caelestia-shell": [
"caelestia-shell"
],
"nixpkgs": [
"caelestia-shell",
"nixpkgs"
]
},
"locked": {
"lastModified": 1757772762,
"narHash": "sha256-7m4hqYSgRe68lkzHFLb1GN5gQac4X4akKfKgFvhj/34=",
"owner": "caelestia-dots",
"repo": "cli",
"rev": "62e7911864ce6ec8a0b371735cf640d81821100e",
"type": "github"
},
"original": {
"owner": "caelestia-dots",
"repo": "cli",
"type": "github"
}
},
"caelestia-shell": {
"inputs": {
"caelestia-cli": "caelestia-cli",
"nixpkgs": [
"nixpkgs"
],
"quickshell": "quickshell"
},
"locked": {
"lastModified": 1758031737,
"narHash": "sha256-D9e9R64xox8swabXvu0DEf8goazQGypjuLe6u7ejZ/k=",
"owner": "caelestia-dots",
"repo": "shell",
"rev": "542495c74faff1285fa7371d2e5cbb2e5294ef9d",
"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": 1755784454, "lastModified": 1757928168,
"narHash": "sha256-5LJOcUS2LoSg7qrNCPdOlBHA9YL3cMJVAqXu26DJNjw=", "narHash": "sha256-smFckXZeYHoS6330QBZf0K7JrmN+1hsHmIesKqTzU6U=",
"owner": "cachix", "owner": "cachix",
"repo": "devenv", "repo": "devenv",
"rev": "6edd3ff0206feedfd50a9e3295e0d9302131eaed", "rev": "d9019631e0e965b78f94a63246863fa7d8315d17",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -170,11 +217,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1755519972, "lastModified": 1757508292,
"narHash": "sha256-bU4nqi3IpsUZJeyS8Jk85ytlX61i4b0KCxXX9YcOgVc=", "narHash": "sha256-7lVWL5bC6xBIMWWDal41LlGAG+9u2zUorqo3QCUL4p4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "4073ff2f481f9ef3501678ff479ed81402caae6d", "rev": "146f45bee02b8bd88812cfce6ffc0f933788875a",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -186,11 +233,11 @@
"firefox-gnome-theme": { "firefox-gnome-theme": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1748383148, "lastModified": 1756083905,
"narHash": "sha256-pGvD/RGuuPf/4oogsfeRaeMm6ipUIznI2QSILKjKzeA=", "narHash": "sha256-UqYGTBgI5ypGh0Kf6zZjom/vABg7HQocB4gmxzl12uo=",
"owner": "rafaelmardojai", "owner": "rafaelmardojai",
"repo": "firefox-gnome-theme", "repo": "firefox-gnome-theme",
"rev": "4eb2714fbed2b80e234312611a947d6cb7d70caf", "rev": "b655eaf16d4cbec9c3472f62eee285d4b419a808",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -235,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": {
@@ -261,11 +307,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1751413152, "lastModified": 1756770412,
"narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=", "narHash": "sha256-+uWLQZccFHwqpGqr2Yt5VsW/PbeJVTn9Dk6SHWhNRPw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "77826244401ea9de6e3bac47c2db46005e1f30b5", "rev": "4524271976b625a4a605beefd893f270620fd751",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -378,11 +424,11 @@
}, },
"hardware": { "hardware": {
"locked": { "locked": {
"lastModified": 1755330281, "lastModified": 1757943327,
"narHash": "sha256-aJHFJWP9AuI8jUGzI77LYcSlkA9wJnOIg4ZqftwNGXA=", "narHash": "sha256-w6cDExPBqbq7fTLo4dZ1ozDGeq3yV6dSN4n/sAaS6OM=",
"owner": "nixos", "owner": "nixos",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "3dac8a872557e0ca8c083cdcfc2f218d18e113b0", "rev": "67a709cfe5d0643dafd798b0b613ed579de8be05",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -398,11 +444,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1755755322, "lastModified": 1757997814,
"narHash": "sha256-spCxkNihCk3uT3LUrUwzdEAjLA/E0EtEgF3KVI05nlM=", "narHash": "sha256-F+1aoG+3NH4jDDEmhnDUReISyq6kQBBuktTUqCUWSiw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "282b4c98de97da6667cb03de4f427371734bc39c", "rev": "5820376beb804de9acf07debaaff1ac84728b708",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -444,11 +490,11 @@
"xwayland-satellite-unstable": "xwayland-satellite-unstable" "xwayland-satellite-unstable": "xwayland-satellite-unstable"
}, },
"locked": { "locked": {
"lastModified": 1755424351, "lastModified": 1758006511,
"narHash": "sha256-xcorYLNdtLpb0wH5CPlUcpmYQUxeK95j1X855xQw+DY=", "narHash": "sha256-YmZX6Wydog4Q9p7dRZDFOFkUfCtQfoXRobmJdg3F1dg=",
"owner": "sodiboo", "owner": "sodiboo",
"repo": "niri-flake", "repo": "niri-flake",
"rev": "9aa137af01f05386e5bb5050e983750017007a66", "rev": "0be585b11314ac02804b4fe03196116c4f747d6d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -460,16 +506,16 @@
"niri-stable": { "niri-stable": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1748151941, "lastModified": 1756556321,
"narHash": "sha256-z4viQZLgC2bIJ3VrzQnR+q2F3gAOEQpU1H5xHtX/2fs=", "narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=",
"owner": "YaLTeR", "owner": "YaLTeR",
"repo": "niri", "repo": "niri",
"rev": "8ba57fcf25d2fc9565131684a839d58703f1dae7", "rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "YaLTeR", "owner": "YaLTeR",
"ref": "v25.05.1", "ref": "v25.08",
"repo": "niri", "repo": "niri",
"type": "github" "type": "github"
} }
@@ -477,11 +523,11 @@
"niri-unstable": { "niri-unstable": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1755419373, "lastModified": 1758000903,
"narHash": "sha256-EFH3zbpyLYjEboNV2Lmkxf9joEuFCmeYX+MMLRPStpg=", "narHash": "sha256-FyfB40rl2mbRGIvF2/6Iwv9xHDxOmhaE1MhlV6Efsg4=",
"owner": "YaLTeR", "owner": "YaLTeR",
"repo": "niri", "repo": "niri",
"rev": "a6febb86aa5af0df7bf2792ca027ef95a503d599", "rev": "c30e5c91851d77d48ff2120f0e710501b19d61b4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -496,7 +542,10 @@
"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"
@@ -534,11 +583,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1755751773, "lastModified": 1757430124,
"narHash": "sha256-d1H34kko9J5fWrxCVgfa1TkIwdkGt/eDSVopAWenw24=", "narHash": "sha256-MhDltfXesGH8VkGv3hmJ1QEKl1ChTIj9wmGAFfWj/Wk=",
"owner": "lnl7", "owner": "lnl7",
"repo": "nix-darwin", "repo": "nix-darwin",
"rev": "3a0a38a1e7ac2c4b4150ea37a491fdffdc9c92e1", "rev": "830b3f0b50045cf0bcfd4dab65fad05bf882e196",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -555,11 +604,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1755741555, "lastModified": 1757987447,
"narHash": "sha256-95N5X0MHiGkCSudjPqA/Grvnhlz+XEzjnnLruG37iog=", "narHash": "sha256-VbCSJEbiNtt8VTGkhCbSLwIs45013DHCXw2s8O27Xxs=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nix4vscode", "repo": "nix4vscode",
"rev": "69b1b5ad001042ce730ca5c2ecc0f693ccadc94b", "rev": "ac15473ac105ddb22395639470ad338e3c4fc7c9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -570,11 +619,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1755330281, "lastModified": 1757943327,
"narHash": "sha256-aJHFJWP9AuI8jUGzI77LYcSlkA9wJnOIg4ZqftwNGXA=", "narHash": "sha256-w6cDExPBqbq7fTLo4dZ1ozDGeq3yV6dSN4n/sAaS6OM=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "3dac8a872557e0ca8c083cdcfc2f218d18e113b0", "rev": "67a709cfe5d0643dafd798b0b613ed579de8be05",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -617,11 +666,11 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1755274400, "lastModified": 1757810152,
"narHash": "sha256-rTInmnp/xYrfcMZyFMH3kc8oko5zYfxsowaLv1LVobY=", "narHash": "sha256-Vp9K5ol6h0J90jG7Rm4RWZsCB3x7v5VPx588TQ1dkfs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "ad7196ae55c295f53a7d1ec39e4a06d922f3b899", "rev": "9a094440e02a699be5c57453a092a8baf569bdad",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -633,11 +682,11 @@
}, },
"nixpkgs-stable_2": { "nixpkgs-stable_2": {
"locked": { "locked": {
"lastModified": 1755704039, "lastModified": 1757810152,
"narHash": "sha256-gKlP0LbyJ3qX0KObfIWcp5nbuHSb5EHwIvU6UcNBg2A=", "narHash": "sha256-Vp9K5ol6h0J90jG7Rm4RWZsCB3x7v5VPx588TQ1dkfs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9cb344e96d5b6918e94e1bca2d9f3ea1e9615545", "rev": "9a094440e02a699be5c57453a092a8baf569bdad",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -649,11 +698,11 @@
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1755615617, "lastModified": 1757745802,
"narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=", "narHash": "sha256-hLEO2TPj55KcUFUU1vgtHE9UEIOjRcH/4QbmfHNF820=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "20075955deac2583bb12f07151c2df830ef346b4", "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -665,11 +714,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1755615617, "lastModified": 1757745802,
"narHash": "sha256-HMwfAJBdrr8wXAkbGhtcby1zGFvs+StOp19xNsbqdOg=", "narHash": "sha256-hLEO2TPj55KcUFUU1vgtHE9UEIOjRcH/4QbmfHNF820=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "20075955deac2583bb12f07151c2df830ef346b4", "rev": "c23193b943c6c689d70ee98ce3128239ed9e32d1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -691,11 +740,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1751906969, "lastModified": 1756961635,
"narHash": "sha256-BSQAOdPnzdpOuCdAGSJmefSDlqmStFNScEnrWzSqKPw=", "narHash": "sha256-hETvQcILTg5kChjYNns1fD5ELdsYB/VVgVmBtqKQj9A=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "ddb679f4131e819efe3bbc6457ba19d7ad116f25", "rev": "6ca27b2654ac55e3f6e0ca434c1b4589ae22b370",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -713,11 +762,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1755446520, "lastModified": 1757974173,
"narHash": "sha256-I0Ok1OGDwc1jPd8cs2VvAYZsHriUVFGIUqW+7uSsOUM=", "narHash": "sha256-4DpXmct/2rcLgScT1CXOLr0TUeIlrBB1rnFqCOf5MUw=",
"owner": "cachix", "owner": "cachix",
"repo": "git-hooks.nix", "repo": "git-hooks.nix",
"rev": "4b04db83821b819bbbe32ed0a025b31e7971f22e", "rev": "302af509428169db34f268324162712d10559f74",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -726,9 +775,31 @@
"type": "github" "type": "github"
} }
}, },
"quickshell": {
"inputs": {
"nixpkgs": [
"caelestia-shell",
"nixpkgs"
]
},
"locked": {
"lastModified": 1756981260,
"narHash": "sha256-GhuD9QVimjynHI0OOyZsqJsnlXr2orowh9H+HYz4YMs=",
"ref": "refs/heads/master",
"rev": "6eb12551baf924f8fdecdd04113863a754259c34",
"revCount": 672,
"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", "ags": "ags",
"caelestia-shell": "caelestia-shell",
"devenv": "devenv", "devenv": "devenv",
"disko": "disko", "disko": "disko",
"hardware": "hardware", "hardware": "hardware",
@@ -767,11 +838,11 @@
"tinted-zed": "tinted-zed" "tinted-zed": "tinted-zed"
}, },
"locked": { "locked": {
"lastModified": 1755708361, "lastModified": 1757956156,
"narHash": "sha256-RmqBx2EamhIk0WVhQSNb8iehaVhilO7D0YAnMoFPqJQ=", "narHash": "sha256-f0W7qbsCqpi6swQ5w8H+0YrAbNwsHgCFDkNRMTJjqrE=",
"owner": "danth", "owner": "danth",
"repo": "stylix", "repo": "stylix",
"rev": "2355da455d7188228aaf20ac16ea9386e5aa6f0c", "rev": "0ce0103b498bb22f899ed8862d8d7f9503ed9cdb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -847,11 +918,11 @@
"tinted-schemes": { "tinted-schemes": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1750770351, "lastModified": 1754779259,
"narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=", "narHash": "sha256-8KG2lXGaXLUE0F/JVwLQe7kOVm21IDfNEo0gfga5P4M=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "schemes", "repo": "schemes",
"rev": "5a775c6ffd6e6125947b393872cde95867d85a2a", "rev": "097d751b9e3c8b97ce158e7d141e5a292545b502",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -863,11 +934,11 @@
"tinted-tmux": { "tinted-tmux": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1751159871, "lastModified": 1754788770,
"narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=", "narHash": "sha256-LAu5nBr7pM/jD9jwFc6/kyFY4h7Us4bZz7dvVvehuwo=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "tinted-tmux", "repo": "tinted-tmux",
"rev": "bded5e24407cec9d01bd47a317d15b9223a1546c", "rev": "fb2175accef8935f6955503ec9dd3c973eec385c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -879,11 +950,11 @@
"tinted-zed": { "tinted-zed": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1751158968, "lastModified": 1755613540,
"narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=", "narHash": "sha256-zBFrrTxHLDMDX/OYxkCwGGbAhPXLi8FrnLhYLsSOKeY=",
"owner": "tinted-theming", "owner": "tinted-theming",
"repo": "base16-zed", "repo": "base16-zed",
"rev": "86a470d94204f7652b906ab0d378e4231a5b3384", "rev": "937bada16cd3200bdbd3a2f5776fc3b686d5cba0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -895,16 +966,16 @@
"xwayland-satellite-stable": { "xwayland-satellite-stable": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1748488455, "lastModified": 1755491097,
"narHash": "sha256-IiLr1alzKFIy5tGGpDlabQbe6LV1c9ABvkH6T5WmyRI=", "narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=",
"owner": "Supreeeme", "owner": "Supreeeme",
"repo": "xwayland-satellite", "repo": "xwayland-satellite",
"rev": "3ba30b149f9eb2bbf42cf4758d2158ca8cceef73", "rev": "388d291e82ffbc73be18169d39470f340707edaa",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "Supreeeme", "owner": "Supreeeme",
"ref": "v0.6", "ref": "v0.7",
"repo": "xwayland-satellite", "repo": "xwayland-satellite",
"type": "github" "type": "github"
} }
@@ -912,11 +983,11 @@
"xwayland-satellite-unstable": { "xwayland-satellite-unstable": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1755219541, "lastModified": 1757179758,
"narHash": "sha256-yKV6xHaPbEbh5RPxAJnb9yTs1wypr7do86hFFGQm1w8=", "narHash": "sha256-TIvyWzRt1miQj6Cf5Wy8Qz43XIZX7c4vTVwRLAT5S4Y=",
"owner": "Supreeeme", "owner": "Supreeeme",
"repo": "xwayland-satellite", "repo": "xwayland-satellite",
"rev": "5a184d435927c3423f0ad189ea2b490578450fb7", "rev": "970728d0d9d1eada342bb8860af214b601139e58",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -933,11 +1004,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1755745641, "lastModified": 1757999874,
"narHash": "sha256-dk5XmelXuuIPr7twSyVlxcORlRKr7ch68wXd1Bz+T4c=", "narHash": "sha256-kgV3ms4hR86tIxaNAYJI8NNgkmEygN+JwkXCPAx2P2U=",
"owner": "0xc000022070", "owner": "0xc000022070",
"repo": "zen-browser-flake", "repo": "zen-browser-flake",
"rev": "e00337af97e646e0ecb94097983f33bda767fb41", "rev": "7dcbd22ca3943e4cfb3122f96cf515f028b3236a",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -182,6 +182,11 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
caelestia-shell = {
url = "github:caelestia-dots/shell";
inputs.nixpkgs.follows = "nixpkgs";
};
# #
# ========= Personal Repositories ========= # ========= Personal Repositories =========
# #

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

@@ -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

@@ -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

@@ -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,7 +35,7 @@
"ms-python.python" "ms-python.python"
"jock.svg" "jock.svg"
"redhat.vscode-yaml" "redhat.vscode-yaml"
"arrterian.nix-env-selector" "mkhl.direnv"
]; ];
userSettings = { userSettings = {
# --- Privacy & Telemetry --- # --- Privacy & Telemetry ---
@@ -59,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;

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

@@ -1,6 +1,7 @@
{ {
pkgs, pkgs,
lib, lib,
inputs,
... ...
}: { }: {
# GNOME desktop packages # GNOME desktop packages
@@ -12,6 +13,8 @@
# It's usually part of mutter/gnome-shell, we'll use gdbus calls instead # It's usually part of mutter/gnome-shell, we'll use gdbus calls instead
inotify-tools # for watching USB changes inotify-tools # for watching USB changes
iio-sensor-proxy # for rotation detection (includes monitor-sensor) iio-sensor-proxy # for rotation detection (includes monitor-sensor)
xdotool # for monitor focus detection
papers
# GNOME Extensions # GNOME Extensions
gnomeExtensions.dash-to-dock gnomeExtensions.dash-to-dock
@@ -25,6 +28,7 @@
gnomeExtensions.launch-new-instance gnomeExtensions.launch-new-instance
gnomeExtensions.paperwm gnomeExtensions.paperwm
gnomeExtensions.just-perfection gnomeExtensions.just-perfection
gnomeExtensions.touchpad-gesture-customization
]; ];
# GNOME desktop settings via dconf # GNOME desktop settings via dconf
@@ -52,6 +56,7 @@
"launch-new-instance@gnome-shell-extensions.gcampax.github.com" "launch-new-instance@gnome-shell-extensions.gcampax.github.com"
"paperwm@paperwm.github.com" "paperwm@paperwm.github.com"
"just-perfection@just-perfection" "just-perfection@just-perfection"
"touchpad-gesture-customization@rexhsu"
]; ];
}; };
@@ -72,6 +77,21 @@
experimental-features = ["scale-monitor-framebuffer" "variable-refresh-rate"]; 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 # PaperWM extension settings placeholder
"org/gnome/shell/extensions/paperwm" = { "org/gnome/shell/extensions/paperwm" = {
# Add any PaperWM-specific dconf keys here if needed # Add any PaperWM-specific dconf keys here if needed
@@ -87,4 +107,7 @@
close = ["<Super>q"]; 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,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

@@ -1,20 +1,14 @@
{ {pkgs, ...}: {
config,
lib,
pkgs,
...
}: {
imports = [ imports = [
./caelestia-shell.nix
./hyprlock.nix ./hyprlock.nix
./hypridle.nix ./hypridle.nix
./wofi.nix
./waybar.nix
./keyring.nix ./keyring.nix
]; ];
# Add essential packages # Add essential packages
home.packages = with pkgs; [ home.packages = [
networkmanagerapplet # NetworkManager system tray applet # Essential packages will be provided by caelestia-shell
]; ];
# Configure Hyprland session management # Configure Hyprland session management
@@ -58,8 +52,6 @@
exec-once = [ exec-once = [
# Start polkit authentication agent for secure authentication # Start polkit authentication agent for secure authentication
"${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1" "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"
# Start NetworkManager applet for network management
"nm-applet --indicator"
]; ];
# Layer rules for proper panel/bar integration # Layer rules for proper panel/bar integration
@@ -72,7 +64,7 @@
# Keybinds # Keybinds
bind = [ bind = [
# Launch terminal (kitty) # Launch terminal (kitty)
"$mod,RETURN,exec,kitty" "$mod,T,exec,kitty"
# Launch browser (zen) # Launch browser (zen)
"$mod,B,exec,zen" "$mod,B,exec,zen"
# Close window # Close window
@@ -80,8 +72,6 @@
# Logout # Logout
"$mod SHIFT,E,exit" "$mod SHIFT,E,exit"
# Network utility (NetworkManager applet)
"$mod,N,exec,nm-applet"
# Secrets manager (Seahorse - GNOME keyring GUI) # Secrets manager (Seahorse - GNOME keyring GUI)
"$mod,K,exec,seahorse" "$mod,K,exec,seahorse"
@@ -158,13 +148,4 @@
SDL_VIDEODRIVER = "wayland"; SDL_VIDEODRIVER = "wayland";
_JAVA_AWT_WM_NONREPARENTING = "1"; _JAVA_AWT_WM_NONREPARENTING = "1";
}; };
# Shell aliases for NetworkManager integration
home.shellAliases = {
# NetworkManager aliases for easier network management
nmcli-wifi-list = "nmcli dev wifi list";
nmcli-connect = "nmcli dev wifi connect";
nmcli-status = "nmcli general status";
nmcli-connections = "nmcli connection show";
};
} }

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

@@ -1,103 +0,0 @@
# AGS Bar Configuration for Niri
This AGS configuration provides a comprehensive status bar for the Niri Wayland compositor with the following features:
## Features
### 🕒 Clock Widget
- Displays current time and date
- Updates every second
- Format: `HH:MM Mon DD`
### 🔊 Volume Control
- Shows current volume level and mute status
- **Left click**: Toggle mute
- Visual feedback with icons:
- 🔇 Muted
- 🔈 Low volume (0-33%)
- 🔉 Medium volume (34-66%)
- 🔊 High volume (67-100%)
### 🔋 Battery Indicator
- Shows battery percentage
- Charging status indicator
- Icons:
- 🔌 Charging
- 🔋 Battery levels
- 🪫 Low battery
### 🔵 Bluetooth Widget
- Shows Bluetooth power status
- **Left click**: Toggle Bluetooth on/off
- **Right click**: Auto-connect to paired devices
- Shows number of connected devices
- Icons:
- 🔵 Bluetooth enabled
- ⚫ Bluetooth disabled
- 📱 Connected devices counter
### 🌐 Network Widget
- Shows network connection status
- **Left click**: Toggle WiFi / show connection info
- Auto-connects to known networks
- Icons:
- 🌐 Wired connection
- 📶 WiFi strength indicator
- ❌ No connection
- Displays current WiFi SSID when connected
## Multi-Monitor Support
The bar automatically appears on all connected monitors using AGS's reactive monitor binding system. When monitors are added or removed, the bar will automatically adjust.
## Styling
The bar uses a modern dark theme with:
- Semi-transparent background
- Catppuccin-inspired color scheme
- Hover effects and smooth transitions
- Color-coded widget borders:
- 🟢 Volume (Green)
- 🟡 Battery (Yellow)
- 🔵 Bluetooth (Blue)
- 🔴 Network (Pink)
## Files
- `app.tsx` - Main application entry point
- `Bar.tsx` - Bar component with all widgets
- `style.css` - Styling and theme
- `package.json` - Project configuration
- `tsconfig.json` - TypeScript configuration
## Usage
The bar starts automatically with Niri via the `spawn-at-startup` configuration in the main Niri config. To manually restart:
```bash
pkill ags && ags run
```
## Customization
To customize the bar:
1. **Add new widgets**: Create functions in `Bar.tsx` and add them to the left/center/right sections
2. **Modify styling**: Edit `style.css` to change colors, spacing, and animations
3. **Change layout**: Modify the `centerbox` structure in the main Bar component
4. **Add keybindings**: Use Niri's keybinding system to interact with AGS widgets
## Dependencies
All required Astal libraries are automatically provided via the Nix configuration:
- `astal.battery` - Battery information
- `astal.bluetooth` - Bluetooth control
- `astal.network` - Network management
- `astal.wireplumber` - Audio control
## Notes
- The configuration uses modern AGS v2 syntax with JSX
- TypeScript errors in the editor are expected (AGS handles compilation)
- Network auto-connection relies on NetworkManager's saved connections
- Bluetooth auto-connection attempts to connect to paired devices

View File

@@ -1,226 +0,0 @@
import { Astal, Gtk, Gdk } from "ags/gtk4"
import { bind, Variable } from "ags"
import Wp from "gi://AstalWp"
import Battery from "gi://AstalBattery"
import Bluetooth from "gi://AstalBluetooth"
import Network from "gi://AstalNetwork"
import App from "ags/gtk4/app"
type BarProps = {
gdkmonitor: Gdk.Monitor
}
function Clock() {
const time = Variable("").poll(1000, 'date "+%H:%M %b %e"')
return (
<label
className="clock"
label={bind(time)}
/>
)
}
function VolumeWidget() {
const speaker = Wp.get_default()?.audio.defaultSpeaker!
function getVolumeIcon(volume: number, muted: boolean) {
if (muted) return "🔇"
if (volume > 66) return "🔊"
if (volume > 33) return "🔉"
if (volume > 0) return "🔈"
return "🔇"
}
return (
<box className="volume" spacing={8}>
<label
label={bind(speaker, "volume").as(v =>
getVolumeIcon(Math.floor(v * 100), speaker.mute)
)}
/>
<label
label={bind(speaker, "volume").as(v => `${Math.floor(v * 100)}%`)}
/>
<eventbox
onButtonPressEvent={(self, event) => {
if (event.button === 1) { // Left click
speaker.mute = !speaker.mute
}
}}
>
<label label="🎵" />
</eventbox>
</box>
)
}
function BatteryWidget() {
const bat = Battery.get_default()
function getBatteryIcon(percentage: number, charging: boolean) {
if (charging) return "🔌"
if (percentage > 80) return "🔋"
if (percentage > 60) return "🔋"
if (percentage > 40) return "🔋"
if (percentage > 20) return "🪫"
return "🪫"
}
return (
<box className="battery" spacing={8}>
<label
label={bind(bat, "percentage").as(p =>
getBatteryIcon(p, bat.charging)
)}
/>
<label
label={bind(bat, "percentage").as(p => `${Math.floor(p)}%`)}
/>
</box>
)
}
function BluetoothWidget() {
const bluetooth = Bluetooth.get_default()
return (
<box className="bluetooth" spacing={8}>
<label
label={bind(bluetooth, "isPowered").as(powered =>
powered ? "🔵" : "⚫"
)}
/>
<eventbox
onButtonPressEvent={async (self, event) => {
if (event.button === 1) { // Left click to toggle
bluetooth.isPowered = !bluetooth.isPowered
} else if (event.button === 3) { // Right click to connect to known devices
const devices = bluetooth.devices.filter(d => d.paired && !d.connected)
if (devices.length > 0) {
try {
await devices[0].connectDevice()
} catch (error) {
// Failed to connect to Bluetooth device
}
}
}
}}
>
<label
label={bind(bluetooth, "devices").as(devices => {
const connected = devices.filter(d => d.connected).length
return connected > 0 ? `📱${connected}` : "📱"
})}
/>
</eventbox>
</box>
)
}
function NetworkWidget() {
const network = Network.get_default()
function getNetworkIcon(wifi: any, wired: any) {
if (wired?.state === Network.DeviceState.ACTIVATED) {
return "🌐"
}
if (wifi?.state === Network.DeviceState.ACTIVATED) {
const strength = wifi.activeAccessPoint?.strength || 0
if (strength > 80) return "📶"
if (strength > 60) return "📶"
if (strength > 40) return "📶"
if (strength > 20) return "📶"
return "📶"
}
return "❌"
}
return (
<box className="network" spacing={8}>
<label
label={bind(network, "wifi").as(() =>
getNetworkIcon(network.wifi, network.wired)
)}
/>
<eventbox
onButtonPressEvent={async (self, event) => {
if (event.button === 1 && network.wifi) { // Left click
if (network.wifi.state === Network.DeviceState.ACTIVATED) {
// Already connected, show current connection
const ap = network.wifi.activeAccessPoint
if (ap) {
// Connected to network
}
} else {
// Try to connect to a known network
network.wifi.enabled = true
const accessPoints = network.wifi.accessPoints
const knownAPs = accessPoints.filter(ap => ap.ssid && ap.ssid.length > 0)
if (knownAPs.length > 0) {
try {
// This would typically require network manager secrets
// For auto-connection, NetworkManager should handle this
await network.wifi.connectToAccessPoint(knownAPs[0])
} catch (error) {
// Failed to connect to WiFi
}
}
}
}
}}
>
<label
label={bind(network, "wifi").as(() => {
if (network.wifi?.activeAccessPoint?.ssid) {
return network.wifi.activeAccessPoint.ssid
}
return "WiFi"
})}
/>
</eventbox>
</box>
)
}
function WorkspaceWidget() {
// Simple workspace widget showing current workspace
// Note: Niri doesn't have built-in workspace API, so this is a placeholder
return (
<box className="workspaces" spacing={8}>
<label label="󰍹 Workspaces" />
</box>
)
}
export default function Bar({ gdkmonitor }: BarProps) {
const { TOP, LEFT, RIGHT } = Astal.WindowAnchor
return (
<window
className="bar"
gdkmonitor={gdkmonitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE}
anchor={TOP | LEFT | RIGHT}
application={App}
>
<centerbox className="bar-content">
<box className="left" spacing={16} halign={Gtk.Align.START}>
<Clock />
</box>
<box className="center" spacing={16} halign={Gtk.Align.CENTER}>
<WorkspaceWidget />
</box>
<box className="right" spacing={16} halign={Gtk.Align.END}>
<NetworkWidget />
<BluetoothWidget />
<VolumeWidget />
<BatteryWidget />
</box>
</centerbox>
</window>
)
}

View File

@@ -1,19 +0,0 @@
import Gtk from "gi://Gtk"
import Bar from "./Bar"
import { For, createBinding } from "ags"
import app from "ags/gtk4/app"
function main() {
const monitors = createBinding(app, "monitors")
return (
<For each={monitors} cleanup={(win) => (win as Gtk.Window).destroy()}>
{(monitor) => <Bar gdkmonitor={monitor} />}
</For>
)
}
app.start({
main,
css: "./style.css"
})

View File

@@ -1,14 +0,0 @@
{
"name": "ags-config",
"version": "1.0.0",
"description": "AGS configuration for niri desktop",
"type": "module",
"main": "app.tsx",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
},
"dependencies": {
"ags": "*"
}
}

View File

@@ -1,71 +0,0 @@
/* Bar styling for Niri */
.bar {
background-color: rgba(30, 30, 46, 0.9);
color: #cdd6f4;
border-bottom: 2px solid #89b4fa;
padding: 0;
margin: 0;
}
.bar-content {
padding: 8px 16px;
}
.left, .center, .right {
padding: 4px 8px;
}
.clock {
font-weight: bold;
font-size: 14px;
color: #89b4fa;
}
.volume, .battery, .bluetooth, .network, .workspaces {
padding: 4px 8px;
border-radius: 8px;
background-color: rgba(69, 71, 90, 0.8);
transition: all 0.3s ease;
}
.volume:hover, .battery:hover, .bluetooth:hover, .network:hover, .workspaces:hover {
background-color: rgba(89, 91, 110, 0.9);
transform: scale(1.05);
}
.volume label, .battery label, .bluetooth label, .network label, .workspaces label {
font-size: 12px;
font-weight: 500;
}
/* Widget specific colors */
.volume {
border-left: 3px solid #a6e3a1;
}
.battery {
border-left: 3px solid #f9e2af;
}
.bluetooth {
border-left: 3px solid #89b4fa;
}
.network {
border-left: 3px solid #f38ba8;
}
.workspaces {
border-left: 3px solid #cba6f7;
}
/* Responsive design */
@media (max-width: 1200px) {
.bar-content {
padding: 6px 12px;
}
.volume, .battery, .bluetooth, .network, .workspaces {
padding: 3px 6px;
}
}

View File

@@ -1,23 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"lib": ["ES2022"],
"allowJs": true,
"checkJs": true,
"declaration": false,
"strict": true,
"noImplicitAny": false,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"noEmit": true,
"skipLibCheck": true
},
"include": [
"**/*.ts",
"**/*.tsx",
"**/*.js"
]
}

View File

@@ -1,33 +0,0 @@
{
inputs,
pkgs,
...
}: {
# Add the AGS home manager module
imports = [inputs.ags.homeManagerModules.default];
programs.ags = {
enable = true;
# Symlink to ~/.config/ags
configDir = ./config;
# Additional packages and executables to add to GJS runtime
extraPackages = with pkgs; [
gtk3
glib
# Add Astal packages for enhanced functionality
astal.astal4
astal.io
astal.apps
astal.battery
astal.bluetooth
astal.network
astal.tray
astal.wireplumber
];
};
# Note: ags package is provided automatically by programs.ags.enable = true
# No need to add it to home.packages separately
}

View File

@@ -1,12 +1,7 @@
{pkgs, ...}: { {pkgs, ...}: {
imports = [ imports = [
# ./waybar.nix # Disabled in favor of AGS
./wofi.nix
./swaylock.nix
./swayidle.nix
./keyring.nix ./keyring.nix
./mako.nix ./custom-shell.nix # Our custom shell components
./ags
]; ];
# Add network utility packages # Add network utility packages
@@ -169,7 +164,7 @@
# Window resizing # Window resizing
"Mod+R".action.switch-preset-column-width = {}; "Mod+R".action.switch-preset-column-width = {};
"Mod+Shift+R".action.reset-window-height = {}; "Mod+Shift+R".action.reset-window-height = {};
"Mod+F".action.set-window-width = "100%"; "Mod+F".action.maximize-column = {};
# Screenshots # Screenshots
"Print".action.spawn = ["grim"]; "Print".action.spawn = ["grim"];

View File

@@ -1,7 +1,8 @@
{pkgs, ...}: { {pkgs, ...}: {
# Additional keyring packages for user interaction # Additional keyring packages for user interaction
home.packages = with pkgs; [ home.packages = with pkgs; [
seahorse # GUI for managing keyrings and passwords kdePackages.kwalletmanager # KDE wallet manager GUI (Qt 6)
kdePackages.kwallet # KDE wallet library (Qt 6)
libsecret # Secret service API library libsecret # Secret service API library
]; ];
@@ -9,19 +10,17 @@
home.sessionVariables = { home.sessionVariables = {
# SSH agent socket for SSH key management # SSH agent socket for SSH key management
SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/keyring/ssh"; 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 # Enable secret service D-Bus API
SECRET_SERVICE_API = "1"; SECRET_SERVICE_API = "1";
# Ensure proper D-Bus session bus integration # Ensure proper D-Bus session bus integration
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus"; DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
# Enable password store integration # Enable password store integration
PASSWORD_STORE_ENABLE_EXTENSIONS = "true"; PASSWORD_STORE_ENABLE_EXTENSIONS = "true";
# Set keyring backend for applications that support it # Set keyring backend for KDE wallet
KEYRING_BACKEND = "gnome-keyring"; KEYRING_BACKEND = "kwallet";
# Ensure XDG runtime directory is available # Ensure XDG runtime directory is available
XDG_RUNTIME_DIR = "/run/user/1000"; XDG_RUNTIME_DIR = "/run/user/1000";
# Enable keyring unlock via PAM # KWallet integration
GNOME_KEYRING_UNLOCK_PASSWORD = "1"; KWALLET_ENABLED = "1";
}; };
} }

View File

@@ -1,38 +0,0 @@
{pkgs, ...}: {
services.mako = {
enable = true;
settings = {
# Basic appearance
border-radius = 8;
border-size = 2;
width = 400;
height = 100;
padding = "10";
margin = "5";
default-timeout = 5000;
group-by = "app-name";
sort = "+time";
layer = "overlay";
anchor = "top-right";
# Action configuration
actions = true;
# Icon configuration
icon-path = "${pkgs.adwaita-icon-theme}/share/icons/Adwaita";
max-icon-size = 48;
# History configuration
max-history = 10;
# Markup configuration
markup = true;
format = "<b>%s</b>\\n%b";
};
};
home.packages = with pkgs; [
mako
libnotify # for notify-send command
];
}

View File

@@ -1,39 +0,0 @@
{pkgs, ...}: {
services.swayidle = {
enable = true;
events = [
{
event = "before-sleep";
command = "${pkgs.swaylock}/bin/swaylock -f";
}
{
event = "lock";
command = "${pkgs.swaylock}/bin/swaylock -f";
}
];
timeouts = [
{
timeout = 150;
command = "${pkgs.brightnessctl}/bin/brightnessctl -s set 10";
resumeCommand = "${pkgs.brightnessctl}/bin/brightnessctl -r";
}
{
timeout = 300;
command = "${pkgs.systemd}/bin/loginctl lock-session";
}
{
timeout = 330;
command = "${pkgs.niri}/bin/niri msg action power-off-monitors";
resumeCommand = "${pkgs.niri}/bin/niri msg action power-on-monitors";
}
{
timeout = 1800;
command = "${pkgs.systemd}/bin/systemctl suspend";
}
];
};
home.packages = with pkgs; [
swayidle
];
}

View File

@@ -1,15 +0,0 @@
{pkgs, ...}: {
programs.swaylock = {
enable = true;
settings = {
font-size = 24;
indicator-idle-visible = false;
indicator-radius = 100;
show-failed-attempts = true;
};
};
home.packages = with pkgs; [
swaylock
];
}

View File

@@ -1,282 +0,0 @@
{
config,
pkgs,
...
}: {
# Configure Stylix to target Waybar
stylix.targets.waybar.enable = true;
programs.waybar = {
enable = true;
settings = {
mainBar = {
layer = "top";
position = "top";
height = 30;
modules-left = ["niri/workspaces" "niri/mode" "niri/window"];
modules-center = ["clock"];
modules-right = ["network" "bluetooth" "pulseaudio" "battery" "tray" "custom/notification"];
"niri/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";
};
};
"niri/mode" = {
format = "<span style=\"italic\">{}</span>";
};
"niri/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;
};
"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 = "";
inhibited-notification = "<span foreground='red'><sup></sup></span>";
inhibited-none = "";
dnd-inhibited-notification = "<span foreground='red'><sup></sup></span>";
dnd-inhibited-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;
};
};
};
# Define the stylesheet using Adwaita-inspired design with Stylix variables
style = ''
* {
border: none;
border-radius: 0;
min-height: 0;
font-family: "Cantarell", sans-serif;
font-size: 13px;
font-weight: 500;
}
window#waybar {
background: linear-gradient(180deg, rgba(255,255,255,0.1) 0%, rgba(0,0,0,0.1) 100%);
background-color: #${config.lib.stylix.colors.base00};
color: #${config.lib.stylix.colors.base05};
border-bottom: 1px solid rgba(0,0,0,0.1);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition-property: background-color;
transition-duration: 200ms;
}
#workspaces {
margin: 0 8px;
}
#workspaces button {
padding: 4px 12px;
margin: 6px 2px;
color: #${config.lib.stylix.colors.base04};
background-color: transparent;
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.1);
transition: all 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
min-width: 24px;
}
#workspaces button.active,
#workspaces button.focused {
background: linear-gradient(135deg, #${config.lib.stylix.colors.base0D} 0%, #${config.lib.stylix.colors.base0E} 100%);
color: #${config.lib.stylix.colors.base00};
border: 1px solid #${config.lib.stylix.colors.base0D};
box-shadow: 0 2px 8px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.2);
transform: translateY(-1px);
}
#workspaces button:hover {
background-color: rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.2);
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
#clock,
#network,
#bluetooth,
#pulseaudio,
#battery,
#tray,
#custom-notification {
padding: 6px 12px;
margin: 6px 2px;
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%);
background-color: #${config.lib.stylix.colors.base01};
border: 1px solid rgba(255,255,255,0.1);
border-radius: 12px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.1);
transition: all 200ms ease;
}
#clock:hover,
#network:hover,
#bluetooth:hover,
#pulseaudio:hover,
#battery:hover,
#tray:hover,
#custom-notification:hover {
background-color: #${config.lib.stylix.colors.base02};
border: 1px solid rgba(255,255,255,0.2);
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.15), inset 0 1px 0 rgba(255,255,255,0.2);
}
#mode {
background: linear-gradient(135deg, #${config.lib.stylix.colors.base08} 0%, #${config.lib.stylix.colors.base09} 100%);
color: #${config.lib.stylix.colors.base00};
padding: 6px 12px;
margin: 6px 2px;
border-radius: 12px;
border: 1px solid #${config.lib.stylix.colors.base08};
box-shadow: 0 2px 8px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.3);
font-weight: 600;
}
#window {
color: #${config.lib.stylix.colors.base05};
padding: 6px 12px;
margin: 6px 4px;
font-weight: 400;
opacity: 0.8;
}
#battery.warning {
color: #${config.lib.stylix.colors.base09};
background: linear-gradient(135deg, rgba(255,193,7,0.1) 0%, rgba(255,193,7,0.05) 100%);
border: 1px solid rgba(255,193,7,0.3);
}
#battery.critical {
color: #${config.lib.stylix.colors.base08};
background: linear-gradient(135deg, rgba(220,53,69,0.1) 0%, rgba(220,53,69,0.05) 100%);
border: 1px solid rgba(220,53,69,0.3);
animation: blink 1s ease-in-out infinite alternate;
}
@keyframes blink {
to {
background-color: rgba(220,53,69,0.2);
}
}
#network.disconnected {
color: #${config.lib.stylix.colors.base08};
background: linear-gradient(135deg, rgba(220,53,69,0.1) 0%, rgba(220,53,69,0.05) 100%);
border: 1px solid rgba(220,53,69,0.3);
}
#pulseaudio.muted {
color: #${config.lib.stylix.colors.base03};
opacity: 0.6;
}
#tray > .passive {
opacity: 0.7;
}
#tray > .needs-attention {
background-color: #${config.lib.stylix.colors.base08};
border: 1px solid #${config.lib.stylix.colors.base08};
animation: blink 1s ease-in-out infinite alternate;
}
'';
};
home.packages = with pkgs; [
waybar
];
}

View File

@@ -1,37 +0,0 @@
{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;
};
};
# Keybind: Mod+Return launches wofi only if not already running
programs.niri.settings.binds."Mod+Return".action.spawn = ["sh" "-c" "pgrep -x wofi || wofi --show drun"];
home.packages = with pkgs; [
wofi
];
}

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

@@ -9,12 +9,31 @@
programs.niri.enable = true; programs.niri.enable = true;
# XDG Desktop Portal for niri # Use KDE portal instead of GNOME for better KDE integration
xdg.portal = { xdg.portal = {
enable = true; enable = true;
extraPortals = with pkgs; [ extraPortals = with pkgs; [
xdg-desktop-portal-gnome 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"; environment.sessionVariables.NIXOS_OZONE_WL = "1";

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

@@ -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

@@ -26,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;
@@ -49,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

@@ -20,13 +20,14 @@
# This is your main performance tuning knob. 'performance' tells the CPU # This is your main performance tuning knob. 'performance' tells the CPU
# to aggressively ramp up to high clock speeds when it detects a load. # to aggressively ramp up to high clock speeds when it detects a load.
# 'balance_power' is a good choice for extending battery life. # 'balance_performance' provides good performance while being more thermal-aware.
CPU_ENERGY_PERF_POLICY_ON_AC = "performance"; CPU_ENERGY_PERF_POLICY_ON_AC = "balance_performance";
CPU_ENERGY_PERF_POLICY_ON_BAT = "balance_power"; CPU_ENERGY_PERF_POLICY_ON_BAT = "balance_power";
# Allow the CPU to use its full performance range when plugged in. # Allow the CPU to use its performance range when plugged in, but cap it
# slightly to reduce heat generation while maintaining good responsiveness.
CPU_MIN_PERF_ON_AC = 0; CPU_MIN_PERF_ON_AC = 0;
CPU_MAX_PERF_ON_AC = 100; CPU_MAX_PERF_ON_AC = 85; # Reduced from 100% to help with thermal management
CPU_MIN_PERF_ON_BAT = 0; CPU_MIN_PERF_ON_BAT = 0;
CPU_MAX_PERF_ON_BAT = 60; # Slightly higher than before for better battery responsiveness. CPU_MAX_PERF_ON_BAT = 60; # Slightly higher than before for better battery responsiveness.
@@ -42,9 +43,9 @@
# --- Intel Arc GPU & System Settings --- # --- Intel Arc GPU & System Settings ---
# Set the platform profile. 'balanced' is a much safer bet than 'performance' # Set the platform profile. 'low-power' is more conservative than 'balanced'
# to avoid overwhelming the chassis's cooling solution. # to help with thermal management while still providing reasonable performance.
PLATFORM_PROFILE_ON_AC = "balanced"; PLATFORM_PROFILE_ON_AC = "low-power";
PLATFORM_PROFILE_ON_BAT = "low-power"; PLATFORM_PROFILE_ON_BAT = "low-power";
# Use 'powersupersave' for PCIe ASPM. This allows the components, # Use 'powersupersave' for PCIe ASPM. This allows the components,

View File

@@ -69,10 +69,10 @@
# 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/gnome.nix" "hosts/common/optional/gnome.nix"
"hosts/common/optional/gdm.nix" "hosts/common/optional/gdm.nix"

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:
(prev.lib.packagesFromDirectoryRecursive {
callPackage = prev.lib.callPackageWith final; callPackage = prev.lib.callPackageWith final;
directory = ../pkgs/common; 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 {};