dot

vizie's NixOS desktop: Hyprland, CachyOS kernel and gaming tweaks

160 lines5671 bytesNix
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}:
20let
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 = "${config.xdg.configHome}";
49in
50{
51 systemd.user.services = {
52 waybar = graphical {
53 description = "Waybar";
54 exec = lib.getExe pkgs.waybar;
55 slice = "session-graphical.slice";
56 service.ExecReload = "${pkgs.coreutils}/bin/kill -SIGUSR2 $MAINPID";
57 };
58
59 hypridle = graphical {
60 description = "Hyprland's idle daemon";
61 exec = lib.getExe pkgs.hypridle;
62 slice = "session-graphical.slice";
63 unit.ConditionEnvironment = "WAYLAND_DISPLAY";
64 };
65
66 hyprpaper = graphical {
67 description = "Hyprland wallpaper daemon";
68 exec = lib.getExe pkgs.hyprpaper;
69 slice = "session-graphical.slice";
70 };
71
72 dunst = graphical {
73 description = "Dunst notification daemon";
74 exec = lib.getExe pkgs.dunst;
75 slice = "session-graphical.slice";
76 service = {
77 Type = "dbus";
78 BusName = "org.freedesktop.Notifications";
79 };
80 };
81
82 # The Waybar flyouts (control centre, notifications). Started with the
83 # session so the first click on the Waybar button opens instantly.
84 eww = graphical {
85 description = "Eww daemon for the Waybar flyouts";
86 exec = "${lib.getExe pkgs.eww} --config ${configDir}/waybar/eww daemon --no-daemonize";
87 };
88
89 hyprpolkitagent = graphical {
90 description = "Hyprland polkit agent";
91 exec = "${pkgs.hyprpolkitagent}/libexec/hyprpolkitagent";
92 slice = "session-graphical.slice";
93 };
94
95 # Puts Wine/Proton tray icons (Battle.net) into Waybar's tray, so it needs
96 # the tray to be there first.
97 xembedsniproxy = graphical {
98 description = "XEmbed to StatusNotifierItem tray bridge";
99 exec = lib.getExe pkgs.xembedsniproxy;
100 after = [ "waybar.service" ];
101 # Restarting it while a Wine app is open breaks that app's tray icon until
102 # the app is restarted, so a rebuild leaves the running one alone.
103 unit.X-RestartIfChanged = false;
104 };
105
106 # Forwards the X11 clipboard (Wine/Proton games) to Wayland whatever has
107 # focus. Waits for Xwayland by itself.
108 xwl-clipbridge = graphical {
109 description = "X11 to Wayland clipboard bridge";
110 exec = "${pkgs.python3-desktop}/bin/python3 ${configDir}/hypr/scripts/xwl-clipbridge";
111 service.Environment = [ "PATH=${lib.makeBinPath [ pkgs.wl-clipboard ]}" ];
112 };
113
114 # The apps opened at login (Signal, Discord, Faugus, OpenDeck, WowUp); see
115 # config/hypr/scripts/autostart-apps. It starts each one as its own unit and
116 # exits; the window placement rules for them are in hyprland.lua.
117 autostart-apps = graphical {
118 description = "Open the apps that start at login";
119 exec = "${configDir}/hypr/scripts/autostart-apps";
120 after = [ "waybar.service" ];
121 service = {
122 Type = "oneshot";
123 Restart = "no";
124 # The script finds the apps (and pgrep, uwsm, hyprctl, ...) on the
125 # system and user profiles, whatever environment the session imported.
126 Environment = [
127 "PATH=${
128 lib.makeBinPath [ pkgs.python3-desktop ]
129 }:/etc/profiles/per-user/${config.home.username}/bin:/run/current-system/sw/bin"
130 ];
131 # It waits for the tray and for Signal and Discord to open, up to about
132 # two minutes; more than the 15 s default the CachyOS settings set.
133 TimeoutStartSec = "3min";
134 };
135 unit.X-RestartIfChanged = false;
136 };
137 };
138
139 # Network and Bluetooth live in the control centre, not the tray. blueman-applet
140 # still runs, from the autostart entry services.blueman installs (uwsm runs it
141 # as app-blueman@autostart.service), for pairing prompts and notifications;
142 # only its tray icon is turned off (ShowConnected needs that icon).
143 dconf.settings."org/blueman/general".plugin-list = [
144 "!StatusIcon"
145 "!ShowConnected"
146 ];
147
148 # Bitwarden at login. This one stays an XDG autostart entry, as on CachyOS
149 # (uwsm runs those as systemd units too: app-bitwarden@autostart.service); the
150 # entry just needs NixOS's name for the program.
151 xdg.configFile."autostart/bitwarden.desktop".text = ''
152 [Desktop Entry]
153 Type=Application
154 Name=Bitwarden
155 Comment=Bitwarden startup script
156 Exec=${lib.getExe pkgs.bitwarden-desktop}
157 StartupNotify=false
158 Terminal=false
159 '';
160}