# Authenticate before creating the desktop; keep its lock separate from the bar. { config, lib, pkgs, ... }: let enabled = lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]; theme = config.home-manager.users.fred.xdg.configFile."quickshell/Theme.qml".text; bundle = name: shell: pkgs.linkFarm name [ { name = "shell.qml"; path = shell; } { name = "AuthView.qml"; path = ./quickshell/AuthView.qml; } { name = "Theme.qml"; path = pkgs.writeText "Theme.qml" theme; } { name = "qmldir"; path = pkgs.writeText "qmldir" "singleton Theme 1.0 Theme.qml\nAuthView 1.0 AuthView.qml\n"; } ]; greeter = bundle "fred-greeter" ./quickshell/Greeter.qml; locker = bundle "fred-lock" ./quickshell/SessionLock.qml; session = pkgs.writeShellScript "hyprland-session" '' exec ${config.programs.hyprland.package}/bin/start-hyprland >/dev/null 2>&1 ''; lockCommand = pkgs.writeShellApplication { name = "fred-lock"; runtimeInputs = [ pkgs.systemd pkgs.coreutils pkgs.quickshell ]; text = builtins.readFile ../scripts/lock-session.sh; }; in { config = lib.mkIf enabled { system.build.auth = pkgs.linkFarm "fred-auth" [ { name = "greeter"; path = greeter; } { name = "lock"; path = locker; } { name = "bin"; path = "${lockCommand}/bin"; } ]; services.greetd = { enable = true; greeterManagesPlymouth = true; settings.default_session = { user = "greeter"; command = toString (pkgs.writeShellScript "fred-greeter" '' export FRED_SESSION_COMMAND=${session} export FRED_GREETER=1 export QML2_IMPORT_PATH=${pkgs.qt6.qt5compat}/lib/qt-6/qml export XKB_DEFAULT_LAYOUT=gb,no export XKB_DEFAULT_OPTIONS=${lib.escapeShellArg ("grp:win_space_toggle" + lib.optionalString (config.networking.hostName == "FredOS-Gaming") ",altwin:swap_lalt_lwin")} exec ${pkgs.dbus}/bin/dbus-run-session -- ${pkgs.cage}/bin/cage -s -- ${pkgs.quickshell}/bin/qs -p ${greeter} ''); }; }; security.pam.services.greetd.allowNullPassword = lib.mkForce false; security.pam.services.fred-lock = { allowNullPassword = false; }; environment.systemPackages = [ lockCommand ]; home-manager.users.fred.systemd.user.services.quickshell-lock = { Unit = { Description = "Independent Quickshell session lock"; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" ]; StartLimitIntervalSec = 0; }; Service = { ExecStart = "${pkgs.quickshell}/bin/qs -p ${locker}"; Environment = [ "QML2_IMPORT_PATH=${pkgs.qt6.qt5compat}/lib/qt-6/qml" ]; Restart = "always"; RestartSec = 1; TimeoutStartSec = 5; }; # No WantedBy: greetd already authenticated the new desktop session. }; systemd.services.lock-before-sleep = { description = "Require a confirmed session lock before sleep"; before = [ "sleep.target" ]; requiredBy = [ "sleep.target" ]; serviceConfig = { Type = "oneshot"; User = "fred"; TimeoutStartSec = "20s"; }; script = '' set -euo pipefail export HOME=/home/fred export XDG_RUNTIME_DIR=/run/user/$(${pkgs.coreutils}/bin/id -u) # A greeter has no desktop to lock. Query logind, not a potentially # stale user target, and fail closed if querying logind fails. sessions=$(${pkgs.systemd}/bin/loginctl list-sessions --no-legend --no-pager) fred_uid=$(${pkgs.coreutils}/bin/id -u) while read -r session uid _; do [ "$uid" = "$fred_uid" ] || continue type=$(${pkgs.systemd}/bin/loginctl show-session "$session" -p Type --value) if [ "$type" = wayland ] || [ "$type" = x11 ]; then exec ${lockCommand}/bin/fred-lock fi done <<< "$sessions" ''; }; }; }