This repository has no description
14 kB
442 lines
1{
2 pkgs,
3 lib,
4 self,
5 ...
6}:
7let
8
9 term = "/run/current-system/sw/bin/kitty";
10
11 # Unified script: switch to workspace and move it to current output
12 gotoWorkspace = pkgs.writeShellApplication {
13 name = "goto-workspace";
14 runtimeInputs = [
15 pkgs.sway
16 pkgs.jq
17 ];
18 text = ''
19 WS="$1"
20 CURRENT_OUTPUT=$(swaymsg -r -t get_outputs | jq -r '.[] | select(.focused == true).name')
21 swaymsg workspace "$WS"
22 swaymsg move workspace to output "$CURRENT_OUTPUT"
23 '';
24 };
25
26in
27{
28 # Make goto-workspace available system-wide for workspace switching
29 environment.systemPackages = [ gotoWorkspace ];
30
31 # Firefox as a systemd user service, started on login
32 systemd.user.services.firefox = {
33 description = "Firefox Web Browser";
34 partOf = [ "sway-session.target" ];
35 wantedBy = [ "sway-session.target" ];
36 after = [ "sway-session.target" ];
37 serviceConfig = {
38 Type = "simple";
39 ExecStart = lib.getExe self.packages.${pkgs.system}.firefox;
40 };
41 };
42 imports = [
43 ../lib/wayland.nix
44 ./noctalia.nix
45 ];
46 programs.sway = {
47 enable = true;
48 wrapperFeatures.gtk = true;
49 extraSessionCommands = ''
50 export SWAYSOCK=/run/user/$(id -u)/sway-ipc.sock
51 '';
52 };
53
54 # Enable realtime scheduling for sway
55 security.pam.loginLimits = [
56 {
57 domain = "@users";
58 item = "rtprio";
59 type = "-";
60 value = 1;
61 }
62 ];
63
64 systemd.user.services.swayidle = {
65 description = "Idle manager for Wayland";
66 documentation = [ "man:swayidle(1)" ];
67 partOf = [ "sway-session.target" ];
68 wantedBy = [ "sway-session.target" ];
69 serviceConfig = {
70 Type = "simple";
71 ExecStart = ''
72 ${pkgs.swayidle}/bin/swayidle -w \
73 timeout 120 '${lib.getExe' pkgs.systemd "systemctl"} --user start lock.target' \
74 timeout 300 '${lib.getExe' pkgs.systemd "systemctl"} suspend-then-hibernate' \
75 before-sleep '${lib.getExe' pkgs.systemd "systemctl"} --user start lock.target'
76 '';
77 Restart = "on-failure";
78 RestartSec = 1;
79 };
80 };
81
82 # Inhibit idle when audio is playing (prevents suspend during calls/music)
83 systemd.user.services.sway-audio-idle-inhibit = {
84 description = "Inhibit idle when audio is playing";
85 partOf = [ "sway-session.target" ];
86 wantedBy = [ "sway-session.target" ];
87 serviceConfig = {
88 Type = "simple";
89 ExecStart = "${pkgs.sway-audio-idle-inhibit}/bin/sway-audio-idle-inhibit";
90 Restart = "on-failure";
91 RestartSec = 1;
92 };
93 };
94
95 systemd.user.services.sway-urgent-rumble = {
96 description = "Trigger rumble on urgent windows";
97 partOf = [ "sway-session.target" ];
98 wantedBy = [ "sway-session.target" ];
99 serviceConfig = {
100 Type = "simple";
101 ExecStart = lib.getExe (
102 pkgs.writeShellApplication {
103 name = "sway-urgent-rumble";
104 runtimeInputs = [
105 pkgs.sway
106 pkgs.jq
107 self.packages.${pkgs.system}.gpd-rumble
108 ];
109 text = ''
110 # Find first force-feedback capable device
111 FF_DEVICE=""
112 for ev in /sys/class/input/event*; do
113 if [ -f "$ev/device/capabilities/ff" ] && [ "$(cat "$ev/device/capabilities/ff")" != "0" ]; then
114 FF_DEVICE="/dev/input/''${ev##*/}"
115 break
116 fi
117 done
118
119 if [ -z "$FF_DEVICE" ]; then
120 echo "No force-feedback device found, exiting"
121 exit 0
122 fi
123
124 echo "Using force-feedback device: $FF_DEVICE"
125
126 swaymsg -t subscribe -m '["window"]' | \
127 jq --unbuffered -r 'select(.change == "urgent" and .container.urgent == true) | "urgent"' | \
128 while read -r _; do
129 gpd-rumble 200 100 "$FF_DEVICE" &
130 done
131 '';
132 }
133 );
134 Restart = "on-failure";
135 RestartSec = 1;
136 };
137 };
138
139 environment.etc."sway/config".text = ''
140 # Default config for sway
141 #
142 # Copy this to ~/.config/sway/config and edit it to your liking.
143 #
144 # Read `man 5 sway` for a complete reference.
145
146 ### Variables
147 #
148 # Logo key. Use Mod1 for Alt.
149 set $mod Mod4
150 # Home row direction keys, like vim
151 set $left h
152 set $down j
153 set $up k
154 set $right l
155 # Your preferred terminal emulator
156 set $term ${term}
157 # Your preferred application launcher
158 # Note: pass the final command to swaymsg so that the resulting window can be opened
159 # on the original workspace that the command was run on.
160 set $menu ${pkgs.dmenu}/bin/dmenu_path | menu | xargs swaymsg exec --
161
162 ### Output configuration
163 #
164 # Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/)
165 # output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
166 #
167 # Example configuration:
168 #
169 # output HDMI-A-1 resolution 1920x1080 position 1920,0
170 #
171 # You can get the names of your outputs by running: swaymsg -t get_outputs
172
173 ### Idle configuration
174 #
175 # Example configuration:
176 #
177 # exec swayidle -w \
178 # timeout 300 'swaylock -f -c 000000' \
179 # timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
180 # before-sleep 'swaylock -f -c 000000'
181 #
182 # This will lock your screen after 300 seconds of inactivity, then turn off
183 # your displays after another 300 seconds, and turn your screens back on when
184 # resumed. It will also lock your screen before your computer goes to sleep.
185
186 ### Input configuration
187 #
188 # Example configuration:
189 #
190 input "2321:21128:HTIX5288:00_0911:5288_Touchpad" {
191 tap enabled
192 }
193 #
194 # You can get the names of your inputs by running: swaymsg -t get_inputs
195 # Read `man 5 sway-input` for more information about this section.
196
197 ### Key bindings
198 #
199 # Basics:
200 #
201 # Start a terminal
202 bindsym $mod+Shift+Return exec $term
203
204 # Kill focused window
205 bindsym $mod+Shift+c kill
206
207 # Start your launcher
208 bindsym $mod+d exec $menu
209
210 # Drag floating windows by holding down $mod and left mouse button.
211 # Resize them with right mouse button + $mod.
212 # Despite the name, also works for non-floating windows.
213 # Change normal to inverse to use left mouse button for resizing and right
214 # mouse button for dragging.
215 floating_modifier $mod normal
216
217 # Reload the configuration file
218 bindsym $mod+Shift+r reload
219
220 # Exit sway (logs you out of your Wayland session)
221 bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -B 'Yes, exit sway' 'swaymsg exit'
222 #
223 # Moving around:
224 #
225 # Move your focus around
226 bindsym $mod+Left focus left
227 bindsym $mod+Down focus down
228 bindsym $mod+Up focus up
229 bindsym $mod+Right focus right
230
231 # Move the focused window with the same, but add Shift
232 bindsym $mod+Shift+Left move left
233 bindsym $mod+Shift+Down move down
234 bindsym $mod+Shift+Up move up
235 bindsym $mod+Shift+Right move right
236 # Layout stuff:
237 #
238 # You can "split" the current object of your focus with
239 # $mod+b or $mod+v, for horizontal and vertical splits
240 # respectively.
241 bindsym $mod+b splith
242 bindsym $mod+v splitv
243
244 # Switch the current container between different layout styles
245 bindsym $mod+s layout stacking
246 bindsym $mod+w layout tabbed
247 bindsym $mod+e layout toggle split
248
249 # Make the current focus fullscreen
250 bindsym $mod+f fullscreen
251
252 # Toggle the current focus between tiling and floating mode
253 bindsym $mod+Shift+space floating toggle
254
255 # Swap focus between the tiling area and the floating area
256 bindsym $mod+a focus mode_toggle
257
258 # Workspace manager menu
259 bindsym $mod+space exec ${lib.getExe self.packages.${pkgs.system}.workspace-menu}
260
261 # Move focus to the parent container
262 bindsym $mod+Shift+a focus parent
263 #
264 # Scratchpad:
265 #
266 # Sway has a "scratchpad", which is a bag of holding for windows.
267 # You can send windows there and get them back later.
268
269 # Move the currently focused window to the scratchpad
270 bindsym $mod+Shift+minus move scratchpad
271
272 # Show the next scratchpad window or hide the focused scratchpad window.
273 # If there are multiple scratchpad windows, this command cycles through them.
274 bindsym $mod+minus scratchpad show
275 #
276 # Resizing containers:
277 #
278 mode "resize" {
279 # left will shrink the containers width
280 # right will grow the containers width
281 # up will shrink the containers height
282 # down will grow the containers height
283 bindsym $left resize shrink width 10px
284 bindsym $down resize grow height 10px
285 bindsym $up resize shrink height 10px
286 bindsym $right resize grow width 10px
287
288 # Ditto, with arrow keys
289 bindsym Left resize shrink width 10px
290 bindsym Down resize grow height 10px
291 bindsym Up resize shrink height 10px
292 bindsym Right resize grow width 10px
293
294 # Return to default mode
295 bindsym Return mode "default"
296 bindsym Escape mode "default"
297 }
298 bindsym $mod+r mode "resize"
299
300 default_border pixel 1
301 default_floating_border none
302 smart_borders on
303
304 bindsym $mod+q exec ${pkgs.writers.writeDash "goto_workspace" ''
305 set -efux
306 WS=$(swaymsg -r -t get_workspaces |
307 jq -r '.[].name' |
308 menu -p 'Workspace name: '
309 )
310 if [ -n "$WS" ]; then
311 ${lib.getExe gotoWorkspace} "$WS"
312 fi
313 ''}
314
315 bindsym $mod+Shift+q exec ${pkgs.writers.writeDash "moveto_workspace" ''
316 set -efux
317 WS=$(swaymsg -r -t get_workspaces |
318 jq -r '.[].name' |
319 menu -p 'Workspace name: '
320 )
321 if [ -n "$WS" ]; then
322 swaymsg move container to workspace "$WS"
323 fi
324 ''}
325
326 bindsym $mod+y exec /run/current-system/sw/bin/switch-theme toggle
327
328 bindsym $mod+Tab focus next
329 bindsym $mod+Escape workspace back_and_forth
330
331 # Focus primary output
332 bindsym $mod+F1 exec ${
333 lib.getExe (
334 pkgs.writeShellApplication {
335 name = "focus-primary-output";
336 runtimeInputs = [
337 pkgs.sway
338 pkgs.jq
339 ];
340 text = ''
341 PRIMARY=$(swaymsg -r -t get_outputs | jq -r 'sort_by(.x, .y) | .[0].name')
342 swaymsg focus output "$PRIMARY"
343 '';
344 }
345 )
346 }
347
348 # Cycle through secondary outputs
349 bindsym $mod+F2 exec ${
350 lib.getExe (
351 pkgs.writeShellApplication {
352 name = "cycle-secondary-outputs";
353 runtimeInputs = [
354 pkgs.sway
355 pkgs.jq
356 pkgs.gnugrep
357 pkgs.coreutils
358 ];
359 text = ''
360 OUTPUTS=$(swaymsg -r -t get_outputs | jq -r 'sort_by(.x, .y)')
361 PRIMARY=$(echo "$OUTPUTS" | jq -r '.[0].name')
362 CURRENT=$(echo "$OUTPUTS" | jq -r '.[] | select(.focused == true).name')
363 SECONDARIES=$(echo "$OUTPUTS" | jq -r '.[1:] | .[].name')
364
365 if [ -z "$SECONDARIES" ]; then
366 exit 0
367 fi
368
369 if [ "$CURRENT" = "$PRIMARY" ]; then
370 # Focus first secondary
371 NEXT=$(echo "$SECONDARIES" | head -n1)
372 else
373 # Find next secondary in the list
374 NEXT=$(echo "$SECONDARIES" | grep -A1 "^$CURRENT$" | tail -n1)
375 # If we're at the end, wrap to first secondary
376 if [ "$NEXT" = "$CURRENT" ]; then
377 NEXT=$(echo "$SECONDARIES" | head -n1)
378 fi
379 fi
380
381 swaymsg focus output "$NEXT"
382 '';
383 }
384 )
385 }
386
387 # screenlock
388 bindsym $mod+F11 exec ${lib.getExe' pkgs.systemd "systemctl"} --user start lock.target
389
390 # kill window (xkill-like)
391 mode "kill" {
392 bindsym --whole-window button1 kill, mode "default"
393 bindsym --whole-window button2 mode "default"
394 bindsym --whole-window button3 mode "default"
395 bindsym Escape mode "default"
396 }
397 bindsym $mod+x mode "kill"
398
399 # media buttons
400 bindsym XF86AudioMute exec ${pkgs.pulseaudio.out}/bin/pactl -- set-sink-mute @DEFAULT_SINK@ toggle
401 bindsym XF86AudioRaiseVolume exec ${pkgs.pulseaudio.out}/bin/pactl -- set-sink-volume @DEFAULT_SINK@ +4%
402 bindsym XF86AudioLowerVolume exec ${pkgs.pulseaudio.out}/bin/pactl -- set-sink-volume @DEFAULT_SINK@ -4%
403
404 # brightness keys
405 bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
406 bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
407
408 # background programs
409 exec ${pkgs.copyq}/bin/copyq --start-server
410 exec ydotoold
411 exec_always pkill kanshi; exec ${pkgs.kanshi}/bin/kanshi
412
413 # theme and env specific stuff
414 exec_always ${pkgs.writers.writeDash "dbus-sway-environment" ''
415 set -efux
416 dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP=sway
417 systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP
418 systemctl --user restart --no-block sway-session.target
419 systemctl --user stop xdg-desktop-portal xdg-desktop-portal-wlr
420 systemctl --user start xdg-desktop-portal xdg-desktop-portal-wlr
421 ''}
422
423 exec_always ${pkgs.writers.writeDash "gsettings" ''
424 set -efux
425 export XDG_DATA_DIRS=${pkgs.gsettings-desktop-schemas}:$XDG_DATA_DIRS
426 gnome_schema=org.gnome.desktop.interface
427 gsettings set $gnome_schema gtk-theme 'Dracula'
428 ''}
429
430 # keyboard
431 input type:keyboard {
432 xkb_layout us
433 xkb_variant altgr-intl
434 xkb_options caps:hyper
435 }
436
437 # flameshot
438 for_window [app_id="flameshot"] border pixel 0, floating enable, fullscreen disable, move absolute position 0 0
439 exec ${pkgs.flameshot}/bin/flameshot
440 '';
441
442}