{ config, lib, pkgs, ... }: # greetd greeter: a throwaway Hyprland running quickshell's greeter.qml as the # `greeter` user. Hyprland must exit after the login so greetd can start the # real session, hence the exit dispatch once qs returns. let cfg = config.homelab.greeter; hyprland = config.programs.hyprland.package; toLua = lib.generators.toLua { }; shellDir = ../../dotfiles/quickshell; session = pkgs.writeShellScript "greeter-session" '' ${lib.getExe pkgs.quickshell} -p ${shellDir}/greeter.qml ${hyprland}/bin/hyprctl dispatch 'hl.dsp.exit()' ''; hyprConfig = pkgs.writeText "greeter-hyprland.lua" '' ${lib.concatMapStrings (m: "hl.monitor(${toLua m})\n") cfg.monitors} hl.config(${toLua { input = { kb_layout = cfg.keyboardLayout; numlock_by_default = true; }; animations.enabled = false; misc = { disable_hyprland_logo = true; disable_splash_rendering = true; background_color = "rgb(0a0a0a)"; }; ecosystem = { no_update_news = true; no_donation_nag = true; }; }}) hl.env("QS_GREETER_OUTPUT", ${toLua cfg.primaryOutput}) hl.env("QS_GREETER_USER", ${toLua cfg.defaultUser}) hl.env("QS_GREETER_HOST", ${toLua config.networking.hostName}) hl.env("QS_GREETER_SESSION", "start-hyprland") hl.on("hyprland.start", function() hl.exec_cmd("${session}") end) ''; in { options.homelab.greeter = { monitors = lib.mkOption { type = lib.types.listOf lib.types.attrs; default = [ ]; description = "hl.monitor() tables; reuse the user's so outputs line up."; }; primaryOutput = lib.mkOption { type = lib.types.str; default = ""; description = "Output that gets the login panel (others get the backdrop only)."; }; defaultUser = lib.mkOption { type = lib.types.str; default = ""; }; keyboardLayout = lib.mkOption { type = lib.types.str; default = "us"; }; }; config = { services.greetd = { enable = true; settings.default_session.command = "${hyprland}/bin/start-hyprland -- --config ${hyprConfig}"; }; # Hyprland and quickshell want a writable $HOME for cache/state. users.users.greeter = { home = "/var/lib/greeter"; createHome = true; }; }; }