dot
vizie's NixOS desktop: Hyprland, CachyOS kernel and gaming tweaks
586be2a
9 files changed +73 −241
modifiedMIGRATION.md
@@ -86,7 +86,8 @@ | ||
| 86 | 86 | |
| 87 | 87 | |
| 88 | 88 | |
| 89 | -- | |
| 89 | +- | |
| 90 | + | |
| 90 | 91 | - |
| 91 | 92 | |
| 92 | 93 | |
@@ -120,10 +121,6 @@ | ||
| 120 | 121 | installed, so kitty has been showing Noto Sans Mono. That's kept. Add |
| 121 | 122 | `nerd-fonts.jetbrains-mono` to `fonts.packages` in `modules/nixos/desktop.nix` |
| 122 | 123 | to get the font the config names. |
| 123 | -- | |
| 124 | - | |
| 125 | - | |
| 126 | - | |
| 127 | 124 | - |
| 128 | 125 | |
| 129 | 126 | |
modifiedREADME.md
@@ -2,8 +2,8 @@ | ||
| 2 | 2 | |
| 3 | 3 | |
| 4 | 4 | |
| 5 | - | |
| 6 | - | |
| 5 | + | |
| 6 | + | |
| 7 | 7 | |
| 8 | 8 | |
| 9 | 9 | |
@@ -19,7 +19,7 @@ | ||
| 19 | 19 | base.nix Nix, boot, locale, network, firewall, user |
| 20 | 20 | cachyos.nix CachyOS kernel + cachyos-settings, file by file |
| 21 | 21 | nvidia.nix RTX 3080 Ti, open kernel module |
| 22 | - desktop.nix Hyprland, uwsm, greetd, audio, Bluetooth, fonts | |
| 22 | + desktop.nix Hyprland, uwsm, autologin, audio, Bluetooth, fonts | |
| 23 | 23 | gaming.nix Steam, proton-cachyos, gamemode, gamescope, ... |
| 24 | 24 | apps.nix desktop apps, Claude Cowork, OpenDeck udev, Flatpak |
| 25 | 25 | vm.nix the test VM |
deletedconfig/greetd/hyprland.lua
@@ -1,91 +1,0 @@ | ||
| 1 | --- gtkgreet runs as a full-screen layer (-l); blur the wallpaper behind it so the | |
| 2 | --- login screen looks like hyprlock (blur 5/2 + dim from style.css). | |
| 3 | -hl.layer_rule({ | |
| 4 | - match = { | |
| 5 | - namespace = "gtk-layer-shell", | |
| 6 | - }, | |
| 7 | - blur = true, | |
| 8 | - ignore_alpha = 0, | |
| 9 | -}) | |
| 10 | - | |
| 11 | -hl.monitor({ | |
| 12 | - output = "HDMI-A-2", | |
| 13 | - mode = "2560x1440@280", | |
| 14 | - position = "0x0", | |
| 15 | - scale = 1, | |
| 16 | - vrr = 0, | |
| 17 | -}) | |
| 18 | - | |
| 19 | -hl.monitor({ | |
| 20 | - output = "DP-1", | |
| 21 | - disabled = true, | |
| 22 | -}) | |
| 23 | - | |
| 24 | --- Same cursor as the desktop session. The greeter user has no settings of its | |
| 25 | --- own, so without this Hyprland falls back to the default (Adwaita) cursor. | |
| 26 | --- gtkgreet's own window reads GNOME's cursor setting instead; that default comes | |
| 27 | --- from greetd/99_greeter-cursor.gschema.override in /usr/share/glib-2.0/schemas. | |
| 28 | -hl.env("XCURSOR_THEME", "BreezeX-Black") | |
| 29 | -hl.env("XCURSOR_SIZE", "28") | |
| 30 | - | |
| 31 | -hl.config({ | |
| 32 | - misc = { | |
| 33 | - disable_hyprland_logo = true, | |
| 34 | - disable_splash_rendering = true, | |
| 35 | - -- Wallpaper's average colour (dimmed like style.css) instead of black, | |
| 36 | - -- shown for the moment before hyprpaper has drawn the wallpaper. | |
| 37 | - background_color = "rgb(0d1513)", | |
| 38 | - }, | |
| 39 | - general = { | |
| 40 | - border_size = 2, | |
| 41 | - gaps_in = 5, | |
| 42 | - gaps_out = 17, | |
| 43 | - layout = "dwindle", | |
| 44 | - col = { | |
| 45 | - active_border = "rgb(aaffff)", | |
| 46 | - inactive_border = "rgba(00000000)", | |
| 47 | - }, | |
| 48 | - }, | |
| 49 | - decoration = { | |
| 50 | - rounding = 10, | |
| 51 | - blur = { | |
| 52 | - enabled = true, | |
| 53 | - size = 5, | |
| 54 | - passes = 2, | |
| 55 | - new_optimizations = true, | |
| 56 | - }, | |
| 57 | - shadow = { | |
| 58 | - enabled = false, | |
| 59 | - render_power = 3, | |
| 60 | - range = 4, | |
| 61 | - color = "rgba(1a1a1aee)", | |
| 62 | - }, | |
| 63 | - }, | |
| 64 | - input = { | |
| 65 | - kb_layout = "no", | |
| 66 | - follow_mouse = 1, | |
| 67 | - sensitivity = 0, | |
| 68 | - accel_profile = "flat", | |
| 69 | - }, | |
| 70 | - debug = { | |
| 71 | - disable_logs = false, | |
| 72 | - }, | |
| 73 | -}) | |
| 74 | - | |
| 75 | --- Login screen fades in over the wallpaper and out again when you log in. | |
| 76 | -hl.curve("easeOutQuint", { type = "bezier", points = { {0.23, 1}, {0.32, 1} } }) | |
| 77 | -hl.curve("almostLinear", { type = "bezier", points = { {0.5, 0.5}, {0.75, 1} } }) | |
| 78 | -hl.animation({ leaf = "layersIn", enabled = true, speed = 5, bezier = "easeOutQuint", style = "fade" }) | |
| 79 | -hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 5, bezier = "almostLinear" }) | |
| 80 | -hl.animation({ leaf = "layersOut", enabled = true, speed = 3, bezier = "almostLinear", style = "fade" }) | |
| 81 | -hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 3, bezier = "almostLinear" }) | |
| 82 | - | |
| 83 | -hl.on("hyprland.start", function() | |
| 84 | - hl.exec_cmd("hyprpaper -c /etc/greetd/hyprpaper.conf") | |
| 85 | - -- gtkgreet exits once the login succeeds: let its fade-out finish, stop | |
| 86 | - -- hyprpaper (it segfaults if the compositor disappears under it), then quit | |
| 87 | - -- this Hyprland cleanly so greetd starts the session right away. Without this | |
| 88 | - -- the greeter got killed and Hyprland/hyprpaper/portals crashed on the way out. | |
| 89 | - hl.exec_cmd("gtkgreet -l -c /etc/greetd/session.sh -s /etc/greetd/style.css; sleep 0.35; pkill -xf 'hyprpaper -c /etc/greetd/hyprpaper.conf'; sleep 0.1; hyprctl dispatch 'hl.dsp.exit()'") | |
| 90 | - hl.exec_cmd("kitty") | |
| 91 | -end) |
deletedconfig/greetd/hyprpaper.conf
@@ -1,7 +1,0 @@ | ||
| 1 | -wallpaper { | |
| 2 | - monitor = | |
| 3 | - path = /etc/greetd/wallpapers | |
| 4 | - timeout = 30 | |
| 5 | -} | |
| 6 | - | |
| 7 | -splash = false |
deletedconfig/greetd/session.sh
@@ -1,11 +1,0 @@ | ||
| 1 | -#!/bin/sh | |
| 2 | -# Session started by the login screen (gtkgreet -c /etc/greetd/session.sh). | |
| 3 | -# The VT is briefly visible between the greeter quitting and Hyprland taking | |
| 4 | -# over the screen, so clear it, hide the text cursor, and keep uwsm's startup | |
| 5 | -# report off it. Hyprland itself runs as a systemd unit and logs to the journal. | |
| 6 | -# | |
| 7 | -# greetd starts this with a bare environment, so it goes through a login shell | |
| 8 | -# first: that loads NixOS's /etc/profile and Home Manager's session variables, | |
| 9 | -# which uwsm then hands to the systemd user session (and so to every service). | |
| 10 | - | |
| 11 | - |
deletedconfig/greetd/style.css
@@ -1,64 +1,0 @@ | ||
| 1 | -/* greetd login screen (gtkgreet -l), styled like hyprlock (modules/home/desktop.nix): | |
| 2 | - full-screen layer, Hyprland blurs the wallpaper behind it (layer rule in | |
| 3 | - hyprland.lua), translucent black boxes, #eee text, rounding 10. */ | |
| 4 | - | |
| 5 | - | |
| 6 | - | |
| 7 | - | |
| 8 | - | |
| 9 | -} | |
| 10 | - | |
| 11 | - | |
| 12 | - | |
| 13 | -} | |
| 14 | - | |
| 15 | - | |
| 16 | - | |
| 17 | - | |
| 18 | -} | |
| 19 | - | |
| 20 | -/* The "Username:" / "Password:" prompt sits left of the box and can't be | |
| 21 | - moved above it, so hide it; the red "Login failed" label is not a first | |
| 22 | - child and stays visible. */ | |
| 23 | - | |
| 24 | - | |
| 25 | - | |
| 26 | - | |
| 27 | - | |
| 28 | - | |
| 29 | -} | |
| 30 | - | |
| 31 | -/* Content fades in just after Hyprland's layer fade (see hyprland.lua). */ | |
| 32 | -{ | |
| 33 | - from } | |
| 34 | - to } | |
| 35 | -} | |
| 36 | - | |
| 37 | - | |
| 38 | - | |
| 39 | -} | |
| 40 | - | |
| 41 | -/* "Login failed" */ | |
| 42 | - | |
| 43 | - | |
| 44 | -} | |
| 45 | - | |
| 46 | - | |
| 47 | - | |
| 48 | - | |
| 49 | - | |
| 50 | - | |
| 51 | - | |
| 52 | - | |
| 53 | - | |
| 54 | - | |
| 55 | -} | |
| 56 | - | |
| 57 | - | |
| 58 | - | |
| 59 | -} | |
| 60 | - | |
| 61 | -/* Session command and buttons: Enter logs in, like the lock screen. */ | |
| 62 | - | |
| 63 | - | |
| 64 | -} |
modifiedmodules/home/desktop.nix
@@ -250,9 +250,9 @@ | ||
| 250 | 250 | misc = { |
| 251 | 251 | disable_hyprland_logo = true; |
| 252 | 252 | disable_splash_rendering = true; |
| 253 | - # The wallpaper's average colour instead of black, so the moment | |
| 254 | - # between the login screen and hyprpaper drawing the wallpaper doesn't | |
| 255 | - # flash black. | |
| 253 | + # The wallpaper's average colour instead of black, so the moments | |
| 254 | + # before hyprlock and after unlocking, before hyprpaper has drawn the | |
| 255 | + # wallpaper, don't flash black. | |
| 256 | 256 | background_color = "rgb(121d1a)"; |
| 257 | 257 | }; |
| 258 | 258 | ecosystem.no_donation_nag = true; |
@@ -280,8 +280,8 @@ | ||
| 280 | 280 | |
| 281 | 281 | # --- Lock screen, idle, wallpaper ----------------------------------------------- |
| 282 | 282 | |
| 283 | - # Styled to match the greetd login screen (config/greetd/style.css): same | |
| 284 | - # bamboo wallpaper, translucent black boxes, #eee text, rounding 10. | |
| 283 | + # Also the login screen (login-lock below): the bamboo wallpaper, translucent | |
| 284 | + # black boxes, #eee text, rounding 10. | |
| 285 | 285 | programs.hyprlock = { |
| 286 | 286 | enable = true; |
| 287 | 287 | # From the NixOS module (programs.hyprlock), which also sets up its PAM. |
@@ -382,6 +382,44 @@ | ||
| 382 | 382 | }; |
| 383 | 383 | }; |
| 384 | 384 | |
| 385 | + # The login screen. tty1 logs in by itself (modules/nixos/desktop.nix), so the | |
| 386 | + # session starts locked: once Hyprland is up, hyprlock runs before | |
| 387 | + # graphical-session.target, which requires it to exit successfully (unlocked), | |
| 388 | + # so the bar, wallpaper, autostart apps and everything else in services.nix | |
| 389 | + # only start after you unlock. | |
| 390 | + # | |
| 391 | + # If hyprlock fails (it couldn't lock, or crashed), the session ends rather | |
| 392 | + # than carry on unlocked, and tty1 logs in again, locked. It only runs at | |
| 393 | + # login: started on its own (a rebuild, systemctl) it does nothing. | |
| 394 | + systemd.user.services.login-lock = { | |
| 395 | + Unit = { | |
| 396 | + Description = "Lock screen at login"; | |
| 397 | + # uwsm's waitenv finishes once Hyprland has put WAYLAND_DISPLAY in the | |
| 398 | + # environment that this unit starts with. | |
| 399 | + After = [ | |
| 400 | + "graphical-session-pre.target" | |
| 401 | + "wayland-session-waitenv.service" | |
| 402 | + ]; | |
| 403 | + Before = [ "graphical-session.target" ]; | |
| 404 | + OnFailure = [ "wayland-session-shutdown.target" ]; | |
| 405 | + OnFailureJobMode = "replace-irreversibly"; | |
| 406 | + X-RestartIfChanged = false; | |
| 407 | + }; | |
| 408 | + Service = { | |
| 409 | + Type = "oneshot"; | |
| 410 | + ExecCondition = "/bin/bash -c '! /bin/systemctl --user -q is-active graphical-session.target'"; | |
| 411 | + # Lock first and draw the wallpaper once it has loaded: Hyprland takes | |
| 412 | + # input until the session is locked, and waiting for the wallpaper | |
| 413 | + # roughly quadruples that time. | |
| 414 | + ExecStart = " --immediate-render"; | |
| 415 | + TimeoutStartSec = "infinity"; | |
| 416 | + # With the compositor: session-graphical.slice only starts after | |
| 417 | + # graphical-session.target. | |
| 418 | + Slice = "session.slice"; | |
| 419 | + }; | |
| 420 | + Install.RequiredBy = [ "graphical-session.target" ]; | |
| 421 | + }; | |
| 422 | + | |
| 385 | 423 | services.hypridle = { |
| 386 | 424 | enable = true; |
| 387 | 425 | settings = { |
modifiedmodules/nixos/desktop.nix
@@ -1,14 +1,9 @@ | ||
| 1 | -# Hyprland under uwsm, the greetd login screen, audio, Bluetooth, fonts and the | |
| 1 | +# Hyprland under uwsm, logging in on tty1, audio, Bluetooth, fonts and the | |
| 2 | 2 | # system side of theming. |
| 3 | 3 | { |
| 4 | - config, | |
| 5 | - lib, | |
| 6 | 4 | pkgs, |
| 7 | 5 | ... |
| 8 | 6 | }: |
| 9 | -let | |
| 10 | - greetdFiles = ../../config/greetd; | |
| 11 | -in | |
| 12 | 7 | { |
| 13 | 8 | programs.hyprland = { |
| 14 | 9 | enable = true; |
@@ -26,43 +21,28 @@ | ||
| 26 | 21 | extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; |
| 27 | 22 | }; |
| 28 | 23 | |
| 29 | - # --- Login screen ------------------------------------------------------------- | |
| 24 | + # --- Login -------------------------------------------------------------------- | |
| 30 | 25 | |
| 31 | - # gtkgreet in a small Hyprland of its own, blurred over the wallpaper. Same | |
| 32 | - # files as /etc/greetd on CachyOS; see config/greetd. | |
| 33 | - services.greetd = { | |
| 34 | - enable = true; | |
| 35 | - settings = { | |
| 36 | - terminal.vt = 1; | |
| 37 | - default_session = { | |
| 38 | - command = "/bin/start-hyprland -- --config /etc/greetd/hyprland.lua"; | |
| 39 | - user = "greeter"; | |
| 40 | - }; | |
| 41 | - }; | |
| 42 | - }; | |
| 43 | - environment.etc = { | |
| 44 | - "greetd/hyprland.lua".source = "/hyprland.lua"; | |
| 45 | - "greetd/hyprpaper.conf".source = "/hyprpaper.conf"; | |
| 46 | - "greetd/style.css".source = "/style.css"; | |
| 47 | - "greetd/session.sh".source = "/session.sh"; | |
| 48 | - "greetd/wallpapers/wallpaper.jpg".source = ../../config/hypr/wallpaper.jpg; | |
| 49 | - }; | |
| 26 | + # No display manager: tty1 logs you in automatically and its login shell starts | |
| 27 | + # Hyprland. The session comes up locked, though: hyprlock runs first and the | |
| 28 | + # rest of the desktop (graphical-session.target) waits until it is unlocked; | |
| 29 | + # see login-lock in modules/home/desktop.nix. | |
| 30 | + services.getty.autologinUser = "vizie"; | |
| 31 | + | |
| 32 | + # In /etc/profile and /etc/zprofile, after the session variables. The tty test | |
| 33 | + # comes first so that uwsm's environment preloader, which reads the profile | |
| 34 | + # too, skips this without running uwsm. The VT is briefly visible before | |
| 35 | + # Hyprland takes over the screen, so clear it, hide the text cursor, and keep | |
| 36 | + # uwsm's startup report off it; Hyprland logs to the journal. | |
| 37 | + environment.loginShellInit = '' | |
| 38 | + if [ "$(tty)" = /dev/tty1 ] && uwsm check may-start -q; then | |
| 39 | + printf '\033[2J\033[3J\033[H\033[?25l' | |
| 40 | + exec uwsm start hyprland-uwsm.desktop >/dev/null 2>&1 | |
| 41 | + fi | |
| 42 | + ''; | |
| 50 | 43 | |
| 51 | - # The greeter user has no settings of its own; these system-wide GSettings | |
| 52 | - # defaults give gtkgreet the desktop's cursor. They replace | |
| 53 | - # 99_greeter-cursor.gschema.override from CachyOS. | |
| 54 | - programs.dconf = { | |
| 55 | - enable = true; | |
| 56 | - profiles.user.databases = [ | |
| 57 | - { | |
| 58 | - settings."org/gnome/desktop/interface" = { | |
| 59 | - cursor-theme = "BreezeX-Black"; | |
| 60 | - cursor-size = lib.gvariant.mkInt32 28; | |
| 61 | - color-scheme = "prefer-dark"; | |
| 62 | - }; | |
| 63 | - } | |
| 64 | - ]; | |
| 65 | - }; | |
| 44 | + # Home Manager's dconf.settings (theming.nix, services.nix) need it. | |
| 45 | + programs.dconf.enable = true; | |
| 66 | 46 | |
| 67 | 47 | # --- Audio, Bluetooth, devices -------------------------------------------------- |
| 68 | 48 | |
@@ -125,12 +105,6 @@ | ||
| 125 | 105 | }; |
| 126 | 106 | |
| 127 | 107 | environment.systemPackages = with pkgs; [ |
| 128 | - # The greeter runs these from /etc/greetd/hyprland.lua. | |
| 129 | - gtkgreet | |
| 130 | - hyprpaper | |
| 131 | - kitty | |
| 132 | - procps | |
| 133 | - | |
| 134 | 108 | breezex-cursor |
| 135 | 109 | papirus-icon-theme |
| 136 | 110 | kdePackages.breeze-icons |
modifiedmodules/nixos/vm.nix
@@ -2,8 +2,8 @@ | ||
| 2 | 2 | # nixos-rebuild build-vm --flake .#desktop (or ./vm.sh) |
| 3 | 3 | # It shares the host's /nix/store, so it builds in seconds once the real |
| 4 | 4 | # system has. Only what can't work in a VM is changed: no NVIDIA, a virtual GPU, |
| 5 | -# the configs copied in rather than linked to your checkout, and an automatic | |
| 6 | -# first login (log out, Super+Delete, to see the real login screen). | |
| 5 | +# the configs copied in rather than linked to your checkout, and a password to | |
| 6 | +# get past the lock screen at login. | |
| 7 | 7 | { lib, ... }: |
| 8 | 8 | { |
| 9 | 9 | virtualisation.vmVariant = { |
@@ -50,11 +50,7 @@ | ||
| 50 | 50 | dot.nvidia.enable = false; |
| 51 | 51 | home-manager.users.vizie.dot.liveConfig = lib.mkForce false; |
| 52 | 52 | |
| 53 | - # greetd's one-time initial session: straight into the desktop on boot; the | |
| 54 | - # login screen comes up after you log out. | |
| 55 | - services.greetd.settings.initial_session = { | |
| 56 | - command = "/etc/greetd/session.sh"; | |
| 57 | - user = "vizie"; | |
| 58 | - }; | |
| 53 | + # The VM's user has no password of its own to unlock the session with. | |
| 54 | + users.users.vizie.initialPassword = "vizie"; | |
| 59 | 55 | }; |
| 60 | 56 | } |