Files
nixos-config/modules/desktop/default.nix
T

555 lines
17 KiB
Nix

#
# Desktop module — import this instead of manual WM/virtualisation imports.
#
# Usage in hosts/<hostname>/default.nix:
#
# imports = [
# ./hardware-configuration.nix
# ../../modules/desktop
# ];
#
# myDesktop.windowManager = "niri"; # niri (default) | sway | kde
# myDesktop.cpu = "amd"; # amd | intel | none (default)
#
# myDesktop.virtualisation.enable = true;
#
# myDesktop.syncthing.enable = true;
# myDesktop.syncthing.devices = { "jupiter.home.example.de" = { id = "XXXXX-..."; }; };
# myDesktop.syncthing.folders = { "Sync" = { path = "/home/user/Sync"; devices = [...]; }; };
#
# myDesktop.openrgb.enable = true;
# myDesktop.openrgb.motherboard = "amd"; # or "intel"
#
# myDesktop.laptop.enable = true;
# myDesktop.laptop.lidSwitch = "suspend-then-hibernate";
# myDesktop.laptop.hibernateDelaySec = "1h";
#
# myDesktop.nitrokey.enable = true;
#
# myDesktop.extraSystemPackages = with pkgs; [ some-tool ];
#
{
config,
lib,
pkgs,
inputs,
user,
...
}: let
cfg = config.myDesktop;
in {
# Hardware modules that are always useful on desktops (bluetooth, …)
imports = import ../hardware;
# ── Options ──────────────────────────────────────────────────────────────
options.myDesktop = with lib; {
windowManager = mkOption {
type = types.enum ["niri" "sway" "kde"];
default = "niri";
description = "Window manager / desktop environment for this host.";
};
cpu = mkOption {
type = types.enum ["amd" "intel" "none"];
default = "none";
description = "CPU type selects the matching KVM kernel parameters.";
};
virtualisation.enable =
mkEnableOption "virtualisation stack (podman/docker-compat, qemu/libvirt, virt-manager)";
syncthing = {
enable = mkEnableOption "syncthing continuous file synchronisation";
devices = mkOption {
type = types.attrs;
default = {};
example =
literalExpression
''{ "jupiter.home.example.de" = { id = "XXXXX-XXXXX-XXXXX-..."; }; }'';
description = "Syncthing peer devices.";
};
folders = mkOption {
type = types.attrs;
default = {};
example =
literalExpression
''{ "Sync" = { path = "/home/user/Sync"; devices = [ "jupiter" ]; ignorePerms = false; }; }'';
description = "Syncthing shared folders.";
};
};
openrgb = {
enable = mkEnableOption "OpenRGB RGB motherboard control";
motherboard = mkOption {
type = types.str;
default = "amd";
description = "Motherboard vendor string passed to OpenRGB (amd or intel).";
};
};
laptop = {
enable = mkEnableOption "laptop-specific settings (lid-switch, hibernate delay)";
lidSwitch = mkOption {
type = types.str;
default = "suspend-then-hibernate";
description = "systemd-logind action on lid close.";
};
hibernateDelaySec = mkOption {
type = types.str;
default = "1h";
description = "Delay before transitioning from suspend to hibernate.";
};
};
nitrokey.enable = mkEnableOption "Nitrokey hardware security key support";
niri.hotkeyVariant = mkOption {
type = types.enum ["default" "lifebook"];
default = "default";
description = "Niri hotkey variant to deploy selects binds/<variant>.kdl.";
};
git.signingKey = mkOption {
type = types.str;
default = "/home/${user}/.ssh/id_ed25519_sk_rk_red";
description = "SSH key used for git commit signing on this host.";
};
extraSystemPackages = mkOption {
type = types.listOf types.package;
default = [];
description = "Additional system packages specific to this host.";
};
};
# ── Configuration ────────────────────────────────────────────────────────
config = lib.mkMerge [
# ── Base desktop config (replaces configuration_desktop.nix) ───────────
{
users.users.${user} = {
isNormalUser = true;
uid = 2000;
extraGroups = [
"wheel"
"video"
"audio"
"camera"
"networkmanager"
"lp"
"kvm"
"libvirtd"
"adb"
"dialout"
"tss"
];
};
security = {
pam.services.login.enableGnomeKeyring = true;
# swaylock PAM is harmless on non-sway WMs
pam.services.swaylock = {};
rtkit.enable = true;
};
environment.systemPackages = with pkgs;
[
file
powertop
cpufrequtils
lm_sensors
libva-utils
at-spi2-core
qmk-udev-rules
gptfdisk
age-plugin-yubikey
pwgen
sbctl
ausweisapp
e2fsprogs
orca-slicer
]
++ cfg.extraSystemPackages;
nixpkgs.config.permittedInsecurePackages = ["mbedtls-2.28.10"];
services = {
pipewire = {
enable = true;
alsa.enable = true;
pulse.enable = true;
wireplumber.enable = true;
};
pcscd.enable = true;
yubikey-agent.enable = true;
udev.packages = with pkgs; [yubikey-personalization nitrokey-udev-rules];
flatpak.enable = true;
gvfs.enable = true;
fwupd.enable = true;
blueman.enable = true;
avahi = {
enable = true;
nssmdns4 = true;
publish = {
enable = true;
addresses = true;
userServices = true;
};
};
};
programs.dconf.enable = true;
system.autoUpgrade.enable = false;
home-manager.users.${user}.programs.git.signing.key =
cfg.git.signingKey;
}
# ── Niri ───────────────────────────────────────────────────────────────
(lib.mkIf (cfg.windowManager == "niri") {
environment = {
systemPackages = with pkgs; [
alacritty
xdg-desktop-portal-gnome
xdg-desktop-portal-gtk
swaylock
swayidle
slurp
grim
lxqt.lxqt-openssh-askpass
clinfo
glib
brightnessctl
playerctl
xwayland-satellite
breeze-hacked-cursor-theme
pwvucontrol
satty
wl-clipboard
];
loginShellInit = ''
export GTK_IM_MODULE="simple"
export ELECTRON_OZONE_PLATFORM_HINT="auto"
export NIXOS_OZONE_WL="1"
export WLR_RENDERER="vulkan"
export _JAVA_AWT_WM_NONREPARENTING="1"
'';
};
services = {
iio-niri.enable = false;
greetd = {
enable = true;
useTextGreeter = true;
settings.default_session.command = "${pkgs.tuigreet}/bin/tuigreet --time --cmd niri-session";
};
tuned.enable = true;
upower.enable = true;
};
programs = {
niri.enable = true;
ssh.enableAskPassword = true;
ssh.askPassword = "${pkgs.lxqt.lxqt-openssh-askpass}/bin/lxqt-openssh-askpass";
};
# Noctalia shell + niri home config via home-manager
home-manager.users.${user} = {
imports = [
inputs.noctalia.homeModules.default
../wm/niri/home.nix
];
xdg.configFile."niri/binds.kdl".source =
../wm/niri/binds/${cfg.niri.hotkeyVariant}.kdl;
services = {
mako.enable = true;
polkit-gnome.enable = true;
};
programs = {
fuzzel.enable = true;
noctalia-shell = {
enable = true;
settings = {
appLauncher.terminalCommand = "alacritty -e";
bar = {
density = "compact";
position = "top";
showCapsule = false;
widgets = {
left = [
{
id = "ControlCenter";
useDistroLogo = true;
}
{
hideUnoccupied = false;
id = "Workspace";
labelMode = "index";
showApplications = true;
}
{id = "ActiveWindow";}
];
center = [
{
formatHorizontal = "HH:mm\\ndd-MM-yy";
formatVertical = "HH mm";
id = "Clock";
useMonospacedFont = true;
usePrimaryColor = true;
}
];
right = [
{id = "MediaMini";}
{
id = "SystemMonitor";
showNetworkStats = true;
compactMode = false;
}
{id = "WiFi";}
{id = "Bluetooth";}
{
id = "Battery";
displayMode = "icon-always";
hideIfNotDetected = true;
}
{
id = "Volume";
displayMode = "alwaysShow";
}
{
id = "NotificationHistory";
hideWhenZero = true;
}
{id = "Tray";}
];
};
};
colorSchemes.predefinedScheme = "Catppuccin";
general = {
avatarImage = "/home/${user}/.face";
radiusRatio = 0.2;
lockOnSusepnd = true;
};
location = {
monthBeforeDay = true;
name = "Munich, Germany";
showWeekNumberInCalendar = true;
firstDayOfWeek = 0;
};
wallpaper = {
enabled = true;
overviewEnabled = false;
directory = "/home/${user}/.setup/modules/themes/";
};
brightness = {
enforceMinimum = true;
brightnessStep = 5;
};
controlCenter.shortcuts.left = [
{id = "WiFi";}
{id = "Bluetooth";}
{id = "ScreenRecorder";}
{id = "PowerProfile";}
{id = "KeepAwake";}
];
dock.enabled = false;
sessionMenu.enableCountdown = false;
templates = {
fuzzel = true;
alacritty = true;
qt = true;
gtk = true;
discord = true;
code = true;
telegram = true;
niri = true;
firefox = true;
};
};
};
};
home.file.".cache/noctalia/wallpapers.json".text = builtins.toJSON {
defaultWallpaper = "/home/${user}/.setup/modules/themes/wall.jpg";
};
};
})
# ── Sway ───────────────────────────────────────────────────────────────
(lib.mkIf (cfg.windowManager == "sway") {
environment = {
loginShellInit = ''
if [ -z $DISPLAY ] && [ $UID != 0 ] && [ "$(tty)" = "/dev/tty1" ]; then
exec sway
fi
'';
systemPackages = with pkgs; [
xdg-desktop-portal-wlr
sway
swaylock
swayidle
slurp
grim
bemenu
lxqt.lxqt-openssh-askpass
clinfo
waybar
glib
];
};
programs = {
sway = {
enable = true;
extraSessionCommands = ''
export MOZ_ENABLE_WAYLAND="1"
export MOZ_WEBRENDER="1"
export WLR_RENDERER="vulkan"
export XDG_SESSION_TYPE="wayland"
export GTK_THEME="Arc"
export _JAVA_AWT_WM_NONREPARENTING="1"
'';
};
ssh.enableAskPassword = true;
ssh.askPassword = "${pkgs.lxqt.lxqt-openssh-askpass}/bin/lxqt-openssh-askpass";
};
xdg.portal = {
enable = true;
wlr.enable = true;
extraPortals = [pkgs.xdg-desktop-portal-gtk];
};
home-manager.users.${user}.imports = [
../wm/sway/home.nix
../wm/waybar.nix # sway uses waybar for the bar
];
})
# ── KDE Plasma ─────────────────────────────────────────────────────────
(lib.mkIf (cfg.windowManager == "kde") {
environment.systemPackages = with pkgs; [
kdePackages.discover
maliit-keyboard
maliit-framework
kdePackages.ksshaskpass
];
programs.ssh = {
enableAskPassword = true;
askPassword = lib.mkDefault "${pkgs.kdePackages.ksshaskpass}/bin/ksshaskpass";
};
services = {
packagekit.enable = true;
desktopManager.plasma6.enable = true;
udev.packages = with pkgs; [gnome-settings-daemon];
};
qt.platformTheme = "kde";
home-manager.users.${user}.imports = [../wm/kde/home.nix];
})
# ── Virtualisation (podman/docker-compat + qemu/libvirt) ───────────────
(lib.mkIf cfg.virtualisation.enable {
users.groups = {
docker.members = [user];
libvirtd.members = ["root" user];
};
virtualisation = {
podman = {
enable = true;
autoPrune.enable = true;
dockerCompat = true;
};
libvirtd = {
enable = true;
onShutdown = "shutdown";
qemu.runAsRoot = false;
};
spiceUSBRedirection.enable = true;
};
environment.systemPackages = with pkgs; [
virt-manager
virt-viewer
qemu
OVMF
OVMF-cloud-hypervisor
gvfs
cloud-hypervisor
];
})
# ── KVM – AMD ──────────────────────────────────────────────────────────
(lib.mkIf (cfg.virtualisation.enable && cfg.cpu == "amd") {
boot.extraModprobeConfig = ''
options kvm_amd nested=0 avic=1 npt=1
'';
})
# ── KVM – Intel ────────────────────────────────────────────────────────
(lib.mkIf (cfg.virtualisation.enable && cfg.cpu == "intel") {
boot.extraModprobeConfig = ''
options kvm_intel nested=1
options kvm_intel emulate_invalid_guest_state=0
options kvm ignore_nsrs=1
'';
})
# ── Syncthing ──────────────────────────────────────────────────────────
(lib.mkIf cfg.syncthing.enable {
services.syncthing = {
enable = true;
group = "users";
user = user;
dataDir = "/home/${user}/Sync";
configDir = "/home/${user}/.config/syncthing";
overrideDevices = true;
overrideFolders = true;
openDefaultPorts = true;
settings = {
devices = cfg.syncthing.devices;
folders = cfg.syncthing.folders;
};
};
})
# ── OpenRGB ────────────────────────────────────────────────────────────
(lib.mkIf cfg.openrgb.enable {
services.hardware.openrgb = {
enable = true;
motherboard = cfg.openrgb.motherboard;
};
})
# ── Laptop ─────────────────────────────────────────────────────────────
(lib.mkIf cfg.laptop.enable {
systemd.sleep.extraConfig = "HibernateDelaySec=${cfg.laptop.hibernateDelaySec}";
services.logind.settings.Login.HandleLidSwitch =
cfg.laptop.lidSwitch;
})
# ── Nitrokey ───────────────────────────────────────────────────────────
(lib.mkIf cfg.nitrokey.enable {
hardware.nitrokey.enable = true;
})
];
}