110 lines
4.9 KiB
Nix
110 lines
4.9 KiB
Nix
# 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;
|
|
# Reuse the desktop's explicit mode instead of keeping a second 180 Hz
|
|
# setting here. The MacBook uses automatic/preferred output configuration.
|
|
gamingMonitor = builtins.head config.home-manager.users.fred.wayland.windowManager.hyprland.settings.monitor;
|
|
greeterClient = pkgs.writeShellScript "fred-greeter-client" ''
|
|
${lib.optionalString (config.networking.hostName == "FredOS-Gaming") ''
|
|
# Run inside Cage, where its Wayland output-management socket exists.
|
|
# A missing connector or unsupported mode must not prevent login.
|
|
if ! ${pkgs.coreutils}/bin/timeout -k 1s 5s ${pkgs.wlr-randr}/bin/wlr-randr \
|
|
--output ${lib.escapeShellArg gamingMonitor.output} \
|
|
--mode ${lib.escapeShellArg gamingMonitor.mode} \
|
|
--scale ${lib.escapeShellArg (toString gamingMonitor.scale)}; then
|
|
echo "Greeter: desktop display mode unavailable; keeping Cage's current mode" >&2
|
|
fi
|
|
''}
|
|
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
|
exec ${pkgs.quickshell}/bin/qs -p ${greeter}
|
|
'';
|
|
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"; }
|
|
{ name = "greeter-client"; path = greeterClient; }
|
|
];
|
|
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 -- ${greeterClient}
|
|
'');
|
|
};
|
|
};
|
|
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"
|
|
'';
|
|
};
|
|
};
|
|
}
|