{ inputs, pkgs, lib, getFlakePkg, ... }: let jay = pkgs.jay.overrideAttrs (prev: { version = "unstable-slay-${toString inputs.jay-src.lastModified}"; src = inputs.jay-src; cargoDeps = pkgs.rustPlatform.importCargoLock { lockFile = "${inputs.jay-src}/Cargo.lock"; }; patches = [ ./patches/0001-add-configurable-gap-between-tiled-windows.patch ./patches/0002-add-position-and-size-animations-for-tiled-windows.patch ./patches/0003-add-window-border-frames-when-gaps-are-enabled.patch ./patches/0004-add-sequential-animation-mode-for-tiled-windows.patch ./patches/0005-add-cursor-follows-focus-setting.patch ./patches/0006-add-toggle-focus-between-floating-and-tiled-layers.patch ./patches/0007-add-open-close-animations-for-tiled-windows.patch ./patches/0008-add-directional-focus-navigation-for-floating-window.patch ]; }); jay-session = pkgs.writeShellScript "jay-session" '' systemctl --user import-environment dbus-update-activation-environment --all systemctl --user start jay-session-bridge.service & exec ${lib.getExe jay} run ''; in { environment.systemPackages = [ jay ]; services.greetd = { enable = true; settings.default_session.command = "${lib.getExe (getFlakePkg inputs.tuigreet)} --sessions /etc/greetd/wayland-sessions --remember-session"; }; environment.etc."greetd/wayland-sessions/jay.desktop".text = '' [Desktop Entry] Name=Jay Comment=A Wayland compositor written in Rust Exec=${jay-session} Type=Application DesktopNames=jay ''; # bridge service to activate graphical-session.target for direct-launched jay. # waits for jay IPC readiness before pulling in the target. systemd.user.services.jay-session-bridge = { unitConfig = { Description = "Activate graphical-session.target for direct-launched jay"; BindsTo = [ "graphical-session.target" ]; Before = [ "graphical-session.target" ]; Wants = [ "graphical-session-pre.target" ]; After = [ "graphical-session-pre.target" ]; }; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; # Jay's IPC goes through the Wayland socket (unlike niri's separate IPC socket), # so we can't use a jay subcommand without WAYLAND_DISPLAY already set. # Wait for Jay to create its wayland socket in XDG_RUNTIME_DIR instead. ExecStart = pkgs.writeShellScript "jay-ready" '' until find "$XDG_RUNTIME_DIR" -maxdepth 1 -name "wayland-*" ! -name "*.lock" -type s | grep -q .; do sleep 0.1 done ''; }; }; }