commit - 4cd15b53068761f7ea875c81f706a11b42d1620b
commit + cbbc749ce296ab9dc4e0020a6faa95d6c4959016
blob - 28c92d6ad03327f70c9edfa43a2b76184c0da98d
blob + b19c762c63942d472a4416a5f12c401687b3d73c
--- home/ale/home.nix
+++ home/ale/home.nix
# README, sin necesitar ningún mkOrder manual).
syntaxHighlighting.enable = true;
initContent = lib.mkMerge [
+ ''
+ # Secrets locales (API keys, tokens): archivo fuera de /nixdots para
+ # no versionar ni exponer credenciales en el Nix store.
+ [ -f "$HOME/.config/zsh/secrets.zsh" ] && source "$HOME/.config/zsh/secrets.zsh"
+ ''
# zsh-autosuggestions -- sourceado a mano (NO con la opción nativa
# programs.zsh.autosuggestion.enable) porque esa opción fija su propio
# mkOrder en 700, es decir ANTES del compinit de oh-my-zsh (800) y
zed-editor # editor -- paquete directo de nixpkgs (el binario se llama
# `zeditor`, no `zed`; el .desktop instalado sí queda como "Zed" en el
# launcher)
+ tor-browser # paquete directo de nixpkgs -- sin módulo declarativo
+ # propio como zen-browser (programs.zen-browser)
];
# --- LibrePods: autostart en segundo plano ---
blob - /dev/null
blob + 1ee66264286f65a298ad85527e80247978f20e7d (mode 644)
--- /dev/null
+++ modules/dms-greeter-fixed.nix
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+let
+ inherit (lib)
+ types
+ mkEnableOption
+ mkOption
+ mkIf
+ mkDefault
+ literalExpression
+ getExe
+ makeBinPath
+ optionalString
+ escapeShellArgs
+ ;
+
+ cfg = config.services.displayManager.dms-greeter;
+ cfgDms = config.programs.dms-shell;
+ cfgAutoLogin = config.services.displayManager.autoLogin;
+ sessionData = config.services.displayManager.sessionData;
+
+ # Miracle WM is nested under `programs.wayland.miracle-wm` unlike the rest
+ compositorOption =
+ if cfg.compositor.name == "miracle-wm" then "wayland.miracle-wm" else "${cfg.compositor.name}";
+ cacheDir = "/var/lib/dms-greeter";
+
+ # Not all compositor packages match the name they use and Miracle does not have a package option
+ compositorPkg =
+ if cfg.compositor.name == "miracle-wm" then
+ pkgs.miracle-wm
+ else
+ lib.attrByPath [
+ "programs"
+ cfg.compositor.name
+ "package"
+ ] null config;
+
+ # PARCHE (ale, 2026-09-15, ver NOTES.md): el módulo upstream
+ # (nixos/modules/services/display-managers/dms-greeter.nix) invoca
+ # "${cfg.package}/bin/dms-greeter", asumiendo el layout de dms-shell >=1.6
+ # (donde el CLI Go `dms` embebe los assets de quickshell y ya no expone un
+ # bin/dms-greeter suelto -- confirmado: ni siquiera pkgs.dms-shell 1.6.1 de
+ # nixpkgs lo genera, ver `cmd/` upstream: solo dms y dankinstall). Este repo
+ # pinea dank-material-shell a v1.5.3 a propósito (flake.nix), cuyo layout
+ # SÍ instala el launcher como archivo suelto en
+ # share/quickshell/dms/Modules/Greetd/assets/dms-greeter, junto con el flag
+ # -p que le indica qué config de quickshell cargar (sin esto, busca la
+ # config nombrada "dms-greeter" en las rutas de búsqueda de quickshell en
+ # vez de la ruta absoluta del paquete). greetd fallaba en boot-loop
+ # ("No existe el fichero o el directorio") en cuanto nixpkgs actualizó el
+ # módulo (nix flake update, sep-2026) sin que este repo hubiera cambiado de
+ # versión de dms-shell. Bug real de nixpkgs, no arreglado río arriba a esta
+ # fecha (nixpkgs#546897 es uno distinto, sobre configHome). Todo lo demás
+ # de este archivo es una copia literal del módulo upstream -- si algún día
+ # se actualiza dank-material-shell a >=1.6 con un launcher equivalente,
+ # basta con quitar este archivo + el disabledModules en desktop.nix.
+ greeterScript = pkgs.writeShellScriptBin "dms-greeter-start" ''
+ export PATH=$PATH:${
+ makeBinPath [
+ cfg.quickshell.package
+ compositorPkg
+ pkgs.glib # provides gdbus, used by the fprintd hardware probe and portal reads
+ ]
+ }
+ ${
+ escapeShellArgs (
+ [
+ "${cfg.package}/share/quickshell/dms/Modules/Greetd/assets/dms-greeter"
+ "--cache-dir"
+ cacheDir
+ "--command"
+ cfg.compositor.name
+ "-p"
+ "${cfg.package}/share/quickshell/dms"
+ ]
+ ++ lib.optionals (cfg.compositor.customConfig != "") [
+ "-C"
+ "${pkgs.writeText "dmsgreeter-compositor-config" cfg.compositor.customConfig}"
+ ]
+ )
+ } ${optionalString cfg.logs.save "> ${cfg.logs.path} 2>&1"}
+ '';
+
+ autoLoginCommand =
+ pkgs.runCommand "dms-greeter-autologin-command"
+ {
+ nativeBuildInputs = [
+ pkgs.gnugrep
+ pkgs.coreutils
+ ];
+ }
+ ''
+ set -euo pipefail
+
+ session="${sessionData.autologinSession}"
+ desktops="${sessionData.desktops}"
+
+ for sessionFile in \
+ "$desktops/share/wayland-sessions/$session.desktop" \
+ "$desktops/share/xsessions/$session.desktop"
+ do
+ if [ -f "$sessionFile" ]; then
+ command="$(grep -m1 '^Exec=' "$sessionFile" | cut -d= -f2- || true)"
+
+ if [ -n "$command" ]; then
+ printf '%s\n' "$command" > "$out"
+ exit 0
+ fi
+ fi
+ done
+
+ echo "dms-greeter autologin: could not resolve Exec for session '$session'" >&2
+ exit 1
+ '';
+
+ jq = getExe pkgs.jq;
+
+ configFilesFromHome =
+ if cfg.configHome != null then
+ [
+ "${cfg.configHome}/.config/DankMaterialShell/settings.json"
+ "${cfg.configHome}/.local/state/DankMaterialShell/session.json"
+ "${cfg.configHome}/.cache/DankMaterialShell/dms-colors.json"
+ ]
+ else
+ [ ];
+in
+{
+ options.services.displayManager.dms-greeter = {
+ enable = mkEnableOption "DankMaterialShell greeter";
+
+ package = lib.mkPackageOption pkgs "dms-greeter" { };
+
+ compositor = {
+ name = mkOption {
+ type = types.enum [
+ "niri"
+ "hyprland"
+ "sway"
+ "mangowc"
+ "miracle-wm"
+ "labwc"
+ ];
+ example = "niri";
+ description = ''
+ The Wayland compositor to run the greeter in.
+
+ The specified compositor must be enabled via its corresponding
+ `programs.<compositor>.enable` option.
+
+ Supported compositors:
+ - niri: A scrollable-tiling Wayland compositor
+ - hyprland: A dynamic tiling Wayland compositor
+ - sway: An i3-compatible Wayland compositor
+ - mango: A dwm-inspired Wayland compositor with modern config options and multiple layouts
+ - miracle-wm: A keyboard-driven Wayland compositor with smooth animations and extensibility
+ - labwc: Lightweight stacking Wayland compositor inspired by Openbox
+ '';
+ };
+
+ customConfig = mkOption {
+ type = types.lines;
+ default = "";
+ example = ''
+ # Niri example
+ input {
+ keyboard {
+ xkb {
+ layout "us"
+ }
+ }
+ }
+ '';
+ description = ''
+ Custom compositor configuration to use for the greeter session.
+
+ This configuration is written to a file and passed to the compositor
+ when launching the greeter. The format and available options depend
+ on the selected compositor.
+
+ Leave empty to use the system's default compositor configuration.
+ '';
+ };
+ };
+
+ configFiles = mkOption {
+ type = types.listOf types.path;
+ default = [ ];
+ example = literalExpression ''
+ [
+ "/home/user/.config/DankMaterialShell/settings.json"
+ "/home/user/.local/state/DankMaterialShell/session.json"
+ ]
+ '';
+ description = ''
+ List of DankMaterialShell configuration files to copy into the greeter
+ data directory at `/var/lib/dms-greeter`.
+
+ This is useful for preserving user preferences like wallpapers, themes,
+ and other settings in the greeter screen.
+
+ ::: {.tip}
+ Use {option}`configHome` instead if your configuration files are in
+ standard XDG locations.
+ :::
+ '';
+ };
+
+ configHome = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "/home/alice";
+ description = ''
+ Path to a user's home directory from which to copy DankMaterialShell
+ configuration files.
+
+ When set, the following files will be automatically copied to the greeter:
+ - `~/.config/DankMaterialShell/settings.json`
+ - `~/.local/state/DankMaterialShell/session.json`
+ - `~/.cache/DankMaterialShell/dms-colors.json`
+
+ If your configuration files are in non-standard locations, use the
+ {option}`configFiles` option instead.
+ '';
+ };
+
+ quickshell = {
+ package = mkOption {
+ type = types.package;
+ default = if cfgDms.enable then cfgDms.quickshell.package else pkgs.quickshell;
+ defaultText = literalExpression ''
+ if config.programs.dms-shell.enable
+ then config.programs.dms-shell.quickshell.package
+ else pkgs.quickshell;
+ '';
+ description = ''
+ The Quickshell package to use for the greeter.
+
+ Defaults to the quickshell package from `programs.dms-shell` if it is enabled,
+ otherwise defaults to `pkgs.quickshell`.
+ '';
+ };
+ };
+
+ logs = {
+ save = mkEnableOption "saving logs from the DMS greeter to a file";
+
+ path = mkOption {
+ type = types.path;
+ default = "/tmp/dms-greeter.log";
+ example = "/var/log/dms-greeter.log";
+ description = ''
+ File path where DMS greeter logs will be saved.
+
+ This is useful for debugging greeter issues. Logs will include
+ output from both the greeter and the compositor.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion =
+ # Assemble the full attribute structure because miracle-wm is not nested in the same location as the others
+ lib.attrByPath (
+ [ "programs" ] ++ lib.splitString "." compositorOption ++ [ "enable" ]
+ ) false config;
+ message = ''
+ DankMaterialShell greeter: The compositor "${cfg.compositor.name}" is not enabled.
+
+ Please enable the compositor via:
+ programs.${compositorOption}.enable = true;
+ '';
+ }
+ {
+ assertion = cfgAutoLogin.enable -> sessionData.autologinSession != null;
+ message = ''
+ dms-greeter auto-login requires services.displayManager.defaultSession to be set,
+ or at least one session in services.displayManager.sessionPackages.
+ '';
+ }
+ ];
+
+ services.greetd = {
+ enable = mkDefault true;
+ settings = {
+ default_session = {
+ user = "dms-greeter";
+ command = getExe greeterScript;
+ };
+ initial_session = mkIf (cfgAutoLogin.enable && (cfgAutoLogin.user != null)) {
+ inherit (cfgAutoLogin) user;
+ command = ''${getExe pkgs.bash} -lc "${config.systemd.package}/bin/systemd-cat $(<${autoLoginCommand})"'';
+ };
+ };
+ };
+
+ environment.systemPackages = [ cfg.package ];
+
+ fonts.packages = with pkgs; [
+ fira-code
+ inter
+ material-symbols
+ ];
+
+ systemd.tmpfiles.settings."10-dms-greeter".${cacheDir}.d = {
+ user = "dms-greeter";
+ group = "dms-greeter";
+ mode = "0750";
+ };
+
+ systemd.services.greetd.preStart =
+ let
+ allConfigFiles = cfg.configFiles ++ configFilesFromHome;
+ in
+ ''
+ cd ${cacheDir}
+ ${lib.concatStringsSep "\n" (
+ lib.map (f: ''
+ if [ -f "${f}" ]; then
+ cp "${f}" .
+ fi
+ '') allConfigFiles
+ )}
+
+ if [ -f session.json ]; then
+ copy_wallpaper() {
+ local path=$(${jq} -r ".$1 // empty" session.json)
+ if [ -f "$path" ]; then
+ cp "$path" "$2"
+ ${jq} ".$1 = \"${cacheDir}/$2\"" session.json > session.tmp
+ mv session.tmp session.json
+ fi
+ }
+
+ copy_monitor_wallpapers() {
+ ${jq} -r ".$1 // {} | to_entries[] | .key + \":\" + .value" session.json 2>/dev/null | while IFS=: read monitor path; do
+ local dest="$2-$(echo "$monitor" | tr -c '[:alnum:]' '-')"
+ if [ -f "$path" ]; then
+ cp "$path" "$dest"
+ ${jq} --arg m "$monitor" --arg p "${cacheDir}/$dest" ".$1[\$m] = \$p" session.json > session.tmp
+ mv session.tmp session.json
+ fi
+ done
+ }
+
+ copy_wallpaper "wallpaperPath" "wallpaper"
+ copy_wallpaper "wallpaperPathLight" "wallpaper-light"
+ copy_wallpaper "wallpaperPathDark" "wallpaper-dark"
+ copy_monitor_wallpapers "monitorWallpapers" "wallpaper-monitor"
+ copy_monitor_wallpapers "monitorWallpapersLight" "wallpaper-monitor-light"
+ copy_monitor_wallpapers "monitorWallpapersDark" "wallpaper-monitor-dark"
+ fi
+
+ if [ -f settings.json ]; then
+ theme_file="$(${jq} -r '.customThemeFile // empty' settings.json)"
+ if [ -f "$theme_file" ] && [ -r "$theme_file" ]; then
+ cp "$theme_file" custom-theme.json
+ mv settings.json settings.orig.json
+ ${jq} '.customThemeFile = "${cacheDir}/custom-theme.json"' settings.orig.json > settings.json
+ fi
+ fi
+
+ mv dms-colors.json colors.json || :
+ chown dms-greeter:dms-greeter * || :
+ '';
+
+ services.displayManager.dms-greeter.configFiles = lib.mkIf (
+ cfg.configHome != null
+ ) configFilesFromHome;
+
+ users.groups.dms-greeter = { };
+ users.users.dms-greeter = {
+ description = "DankMaterialShell greeter user";
+ isSystemUser = true;
+ home = cacheDir;
+ homeMode = "0750";
+ createHome = true;
+ group = "dms-greeter";
+ extraGroups = [ "video" ];
+ };
+
+ security.pam.services.dms-greeter = { };
+
+ hardware.graphics.enable = mkDefault true;
+ services.libinput.enable = mkDefault true;
+ };
+
+ meta.teams = [ lib.teams.danklinux ];
+}