This repository has no description
14 kB
447 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 # Split bindings removed to avoid accidental sub-containers.
245 # Use $mod+w to flatten into tabs, $mod+e to toggle split direction.
246 bindsym $mod+n split none
247
248 # Switch the current container between different layout styles
249 bindsym $mod+s layout stacking
250 bindsym $mod+w layout tabbed
251 bindsym $mod+e layout toggle split
252
253 # Make the current focus fullscreen
254 bindsym $mod+f fullscreen
255
256 # Toggle the current focus between tiling and floating mode
257 bindsym $mod+Shift+space floating toggle
258
259 # Swap focus between the tiling area and the floating area
260 bindsym $mod+a focus mode_toggle
261
262 # Workspace manager menu
263 bindsym $mod+space exec ${lib.getExe self.packages.${pkgs.system}.workspace-menu}
264
265 # Move focus to the parent container
266 bindsym $mod+Shift+a focus parent
267 #
268 # Scratchpad:
269 #
270 # Sway has a "scratchpad", which is a bag of holding for windows.
271 # You can send windows there and get them back later.
272
273 # Move the currently focused window to the scratchpad
274 bindsym $mod+Shift+minus move scratchpad
275
276 # Show the next scratchpad window or hide the focused scratchpad window.
277 # If there are multiple scratchpad windows, this command cycles through them.
278 bindsym $mod+minus scratchpad show
279 #
280 # Resizing containers:
281 #
282 mode "resize" {
283 # left will shrink the containers width
284 # right will grow the containers width
285 # up will shrink the containers height
286 # down will grow the containers height
287 bindsym $left resize shrink width 10px
288 bindsym $down resize grow height 10px
289 bindsym $up resize shrink height 10px
290 bindsym $right resize grow width 10px
291
292 # Ditto, with arrow keys
293 bindsym Left resize shrink width 10px
294 bindsym Down resize grow height 10px
295 bindsym Up resize shrink height 10px
296 bindsym Right resize grow width 10px
297
298 # Return to default mode
299 bindsym Return mode "default"
300 bindsym Escape mode "default"
301 }
302 bindsym $mod+r mode "resize"
303
304 default_border pixel 1
305 default_floating_border none
306 smart_borders on
307
308 bindsym $mod+q exec ${pkgs.writers.writeDash "goto_workspace" ''
309 set -efux
310 WS=$(swaymsg -r -t get_workspaces |
311 jq -r '.[].name' |
312 menu -p 'Workspace name: '
313 )
314 if [ -n "$WS" ]; then
315 ${lib.getExe gotoWorkspace} "$WS"
316 fi
317 ''}
318
319 bindsym $mod+Shift+q exec ${pkgs.writers.writeDash "moveto_workspace" ''
320 set -efux
321 WS=$(swaymsg -r -t get_workspaces |
322 jq -r '.[].name' |
323 menu -p 'Workspace name: '
324 )
325 if [ -n "$WS" ]; then
326 swaymsg move container to workspace "$WS"
327 fi
328 ''}
329
330 bindsym $mod+y exec /run/current-system/sw/bin/switch-theme toggle
331
332 bindsym $mod+Tab exec ${pkgs.sway-overfocus}/bin/sway-overfocus split-rw group-rw split-dw group-dw
333 bindsym $mod+Escape workspace back_and_forth
334
335 # Focus primary output
336 bindsym $mod+F1 exec ${
337 lib.getExe (
338 pkgs.writeShellApplication {
339 name = "focus-primary-output";
340 runtimeInputs = [
341 pkgs.sway
342 pkgs.jq
343 ];
344 text = ''
345 PRIMARY=$(swaymsg -r -t get_outputs | jq -r 'sort_by(.x, .y) | .[0].name')
346 swaymsg focus output "$PRIMARY"
347 '';
348 }
349 )
350 }
351
352 # Cycle through secondary outputs
353 bindsym $mod+F2 exec ${
354 lib.getExe (
355 pkgs.writeShellApplication {
356 name = "cycle-secondary-outputs";
357 runtimeInputs = [
358 pkgs.sway
359 pkgs.jq
360 pkgs.gnugrep
361 pkgs.coreutils
362 ];
363 text = ''
364 OUTPUTS=$(swaymsg -r -t get_outputs | jq -r 'sort_by(.x, .y)')
365 PRIMARY=$(echo "$OUTPUTS" | jq -r '.[0].name')
366 CURRENT=$(echo "$OUTPUTS" | jq -r '.[] | select(.focused == true).name')
367 SECONDARIES=$(echo "$OUTPUTS" | jq -r '.[1:] | .[].name')
368
369 if [ -z "$SECONDARIES" ]; then
370 exit 0
371 fi
372
373 if [ "$CURRENT" = "$PRIMARY" ]; then
374 # Focus first secondary
375 NEXT=$(echo "$SECONDARIES" | head -n1)
376 else
377 # Find next secondary in the list
378 NEXT=$(echo "$SECONDARIES" | grep -A1 "^$CURRENT$" | tail -n1)
379 # If we're at the end, wrap to first secondary
380 if [ "$NEXT" = "$CURRENT" ]; then
381 NEXT=$(echo "$SECONDARIES" | head -n1)
382 fi
383 fi
384
385 swaymsg focus output "$NEXT"
386 '';
387 }
388 )
389 }
390
391 # screenlock
392 bindsym $mod+F11 exec ${lib.getExe' pkgs.systemd "systemctl"} --user start lock.target
393
394 # kill window (xkill-like)
395 mode "kill" {
396 bindsym --whole-window button1 kill, mode "default"
397 bindsym --whole-window button2 mode "default"
398 bindsym --whole-window button3 mode "default"
399 bindsym Escape mode "default"
400 }
401 bindsym $mod+x mode "kill"
402
403 # media buttons
404 bindsym XF86AudioMute exec ${pkgs.pulseaudio.out}/bin/pactl -- set-sink-mute @DEFAULT_SINK@ toggle
405 bindsym XF86AudioRaiseVolume exec ${pkgs.pulseaudio.out}/bin/pactl -- set-sink-volume @DEFAULT_SINK@ +4%
406 bindsym XF86AudioLowerVolume exec ${pkgs.pulseaudio.out}/bin/pactl -- set-sink-volume @DEFAULT_SINK@ -4%
407
408 # brightness keys
409 bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
410 bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
411
412 # background programs
413 exec ${pkgs.copyq}/bin/copyq --start-server
414 exec ydotoold
415 exec_always pkill kanshi; exec ${pkgs.kanshi}/bin/kanshi
416
417
418 # theme and env specific stuff
419 exec_always ${pkgs.writers.writeDash "dbus-sway-environment" ''
420 set -efux
421 dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP=sway
422 systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP
423 systemctl --user start --no-block sway-session.target
424 systemctl --user stop xdg-desktop-portal xdg-desktop-portal-wlr
425 systemctl --user start xdg-desktop-portal xdg-desktop-portal-wlr
426 ''}
427
428 exec_always ${pkgs.writers.writeDash "gsettings" ''
429 set -efux
430 export XDG_DATA_DIRS=${pkgs.gsettings-desktop-schemas}:$XDG_DATA_DIRS
431 gnome_schema=org.gnome.desktop.interface
432 gsettings set $gnome_schema gtk-theme 'Dracula'
433 ''}
434
435 # keyboard
436 input type:keyboard {
437 xkb_layout us
438 xkb_variant altgr-intl
439 xkb_options caps:hyper
440 }
441
442 # flameshot
443 for_window [app_id="flameshot"] border pixel 0, floating enable, fullscreen disable, move absolute position 0 0
444 exec ${pkgs.flameshot}/bin/flameshot
445 '';
446
447}