dot
vizie's NixOS desktop: Hyprland, CachyOS kernel and gaming tweaks
| 1 | # The desktop's background programs, as systemd user services. On CachyOS most |
| 2 | # of these were started by hyprland.lua (hl.exec_cmd at hyprland.start). |
| 3 | # |
| 4 | # uwsm starts Hyprland and then graphical-session.target; every service here is |
| 5 | # wanted by that target and stopped with it, so they come up after the |
| 6 | # compositor is ready and go away at logout. They are restarted if they crash. |
| 7 | # |
| 8 | # systemctl --user status waybar is it running, and its last log lines |
| 9 | # journalctl --user -u waybar -f follow its log |
| 10 | # systemctl --user restart waybar e.g. after changing its config |
| 11 | # |
| 12 | # Slices are uwsm's: session-graphical for the shell itself (bar, idle, wallpaper, |
| 13 | # notifications), background-graphical for helpers. |
| 14 | { |
| 15 | config, |
| 16 | lib, |
| 17 | pkgs, |
| 18 | ... |
| 19 | }: |
| 20 | let |
| 21 | graphical = |
| 22 | { |
| 23 | description, |
| 24 | exec, |
| 25 | slice ? "background-graphical.slice", |
| 26 | after ? [ ], |
| 27 | unit ? { }, |
| 28 | service ? { }, |
| 29 | }: |
| 30 | { |
| 31 | Unit = { |
| 32 | Description = description; |
| 33 | PartOf = [ "graphical-session.target" ]; |
| 34 | After = [ "graphical-session.target" ] ++ after; |
| 35 | Requisite = [ "graphical-session.target" ]; |
| 36 | } |
| 37 | // unit; |
| 38 | Service = { |
| 39 | ExecStart = exec; |
| 40 | Restart = "on-failure"; |
| 41 | RestartSec = 2; |
| 42 | Slice = slice; |
| 43 | } |
| 44 | // service; |
| 45 | Install.WantedBy = [ "graphical-session.target" ]; |
| 46 | }; |
| 47 | |
| 48 | configDir = ""; |
| 49 | in |
| 50 | { |
| 51 | systemd.user.services = { |
| 52 | # Waybar, hypridle, hyprpaper and dunst come from their Home Manager modules |
| 53 | # (desktop.nix); these put them with the rest of the shell. |
| 54 | waybar.Service.Slice = "session-graphical.slice"; |
| 55 | hypridle.Service.Slice = "session-graphical.slice"; |
| 56 | hyprpaper.Service.Slice = "session-graphical.slice"; |
| 57 | dunst = { |
| 58 | Service.Slice = "session-graphical.slice"; |
| 59 | # The module only starts dunst on the first notification (D-Bus |
| 60 | # activation); start it with the session, as before. |
| 61 | Install.WantedBy = [ "graphical-session.target" ]; |
| 62 | }; |
| 63 | |
| 64 | # The Waybar flyouts (control centre, notifications). Started with the |
| 65 | # session so the first click on the Waybar button opens instantly. |
| 66 | eww = graphical { |
| 67 | description = "Eww daemon for the Waybar flyouts"; |
| 68 | exec = " --config /waybar/eww daemon --no-daemonize"; |
| 69 | }; |
| 70 | |
| 71 | hyprpolkitagent = graphical { |
| 72 | description = "Hyprland polkit agent"; |
| 73 | exec = "/libexec/hyprpolkitagent"; |
| 74 | slice = "session-graphical.slice"; |
| 75 | }; |
| 76 | |
| 77 | # Puts Wine/Proton tray icons (Battle.net) into Waybar's tray, so it needs |
| 78 | # the tray to be there first. |
| 79 | xembedsniproxy = graphical { |
| 80 | description = "XEmbed to StatusNotifierItem tray bridge"; |
| 81 | exec = lib.getExe pkgs.xembedsniproxy; |
| 82 | after = [ "waybar.service" ]; |
| 83 | # Restarting it while a Wine app is open breaks that app's tray icon until |
| 84 | # the app is restarted, so a rebuild leaves the running one alone. |
| 85 | unit.X-RestartIfChanged = false; |
| 86 | }; |
| 87 | |
| 88 | # Forwards the X11 clipboard (Wine/Proton games) to Wayland whatever has |
| 89 | # focus. Waits for Xwayland by itself. |
| 90 | xwl-clipbridge = graphical { |
| 91 | description = "X11 to Wayland clipboard bridge"; |
| 92 | exec = "/bin/python3 /hypr/scripts/xwl-clipbridge"; |
| 93 | service.Environment = [ "PATH=" ]; |
| 94 | }; |
| 95 | |
| 96 | # The apps opened at login (Signal, Discord, Faugus, OpenDeck, WowUp); see |
| 97 | # config/hypr/scripts/autostart-apps. It starts each one as its own unit and |
| 98 | # exits; the window placement rules for them are in config/hypr/startup.lua. |
| 99 | autostart-apps = graphical { |
| 100 | description = "Open the apps that start at login"; |
| 101 | exec = "/hypr/scripts/autostart-apps"; |
| 102 | after = [ "waybar.service" ]; |
| 103 | service = { |
| 104 | Type = "oneshot"; |
| 105 | Restart = "no"; |
| 106 | # The script finds the apps (and pgrep, uwsm, hyprctl, ...) on the |
| 107 | # system and user profiles, whatever environment the session imported. |
| 108 | Environment = [ |
| 109 | "PATH= |
| 110 | |
| 111 | :/etc/profiles/per-user//bin:/run/current-system/sw/bin" |
| 112 | ]; |
| 113 | # It waits for the tray and for Signal and Discord to open, up to about |
| 114 | # two minutes; more than the 15 s default the CachyOS settings set. |
| 115 | TimeoutStartSec = "3min"; |
| 116 | }; |
| 117 | unit.X-RestartIfChanged = false; |
| 118 | }; |
| 119 | }; |
| 120 | |
| 121 | # Network and Bluetooth live in the control centre, not the tray. blueman-applet |
| 122 | # still runs, from the autostart entry services.blueman installs (uwsm runs it |
| 123 | # as app-blueman@autostart.service), for pairing prompts and notifications; |
| 124 | # only its tray icon is turned off (ShowConnected needs that icon). |
| 125 | dconf.settings."org/blueman/general".plugin-list = [ |
| 126 | "!StatusIcon" |
| 127 | "!ShowConnected" |
| 128 | ]; |
| 129 | |
| 130 | # Bitwarden at login. This one stays an XDG autostart entry, as on CachyOS |
| 131 | # (uwsm runs those as systemd units too: app-bitwarden@autostart.service); the |
| 132 | # entry just needs NixOS's name for the program. |
| 133 | xdg.configFile."autostart/bitwarden.desktop".text = '' |
| 134 | [Desktop Entry] |
| 135 | Type=Application |
| 136 | Name=Bitwarden |
| 137 | Comment=Bitwarden startup script |
| 138 | Exec= |
| 139 | StartupNotify=false |
| 140 | Terminal=false |
| 141 | ''; |
| 142 | } |