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