This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

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