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