Unverified Commit 1c46efec authored by Marcus Ramberg's avatar Marcus Ramberg Committed by GitHub
Browse files

dms-shell, dsearch, dgop, dms-greeter: init packages and NixOS modules (#467407)

parents 3a53249b b744e5ab
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -15295,6 +15295,12 @@
    githubId = 1104419;
    name = "Lucas Hoffmann";
  };
  luckshiba = {
    email = "luckshiba@protonmail.com";
    github = "luckshiba";
    githubId = 43530291;
    name = "LuckShiba";
  };
  lucperkins = {
    email = "lucperkins@gmail.com";
    github = "lucperkins";
+3 −0
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@
  ./programs/direnv.nix
  ./programs/dmrconfig.nix
  ./programs/droidcam.nix
  ./programs/dsearch.nix
  ./programs/dublin-traceroute.nix
  ./programs/ecryptfs.nix
  ./programs/environment.nix
@@ -340,6 +341,7 @@
  ./programs/vivid.nix
  ./programs/vscode.nix
  ./programs/wavemon.nix
  ./programs/wayland/dms-shell.nix
  ./programs/wayland/dwl.nix
  ./programs/wayland/gtklock.nix
  ./programs/wayland/hyprland.nix
@@ -605,6 +607,7 @@
  ./services/development/zammad.nix
  ./services/display-managers/cosmic-greeter.nix
  ./services/display-managers/default.nix
  ./services/display-managers/dms-greeter.nix
  ./services/display-managers/gdm.nix
  ./services/display-managers/greetd.nix
  ./services/display-managers/lemurs.nix
+53 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  inherit (lib)
    mkEnableOption
    mkOption
    mkIf
    mkPackageOption
    types
    ;

  cfg = config.programs.dsearch;
in
{
  options.programs.dsearch = {
    enable = mkEnableOption "dsearch, a fast filesystem search service with fuzzy matching";

    package = mkPackageOption pkgs "dsearch" { };

    systemd = {
      enable = mkEnableOption "systemd user service for dsearch" // {
        default = true;
      };

      target = mkOption {
        type = types.str;
        default = "default.target";
        description = ''
          The systemd target that will automatically start the dsearch service.

          By default, dsearch starts with the user session (`default.target`).
          You can change this to `graphical-session.target` if you only want
          it to run in graphical sessions.
        '';
      };
    };
  };

  config = mkIf cfg.enable {
    environment.systemPackages = [ cfg.package ];

    systemd.packages = [ cfg.package ];

    systemd.user.services.dsearch.wantedBy = mkIf cfg.systemd.enable [ cfg.systemd.target ];
  };

  meta.maintainers = with lib.maintainers; [ luckshiba ];
}
+202 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  inherit (lib)
    mkEnableOption
    mkOption
    mkIf
    mkPackageOption
    types
    optional
    optionals
    ;

  cfg = config.programs.dms-shell;

  optionalPackages =
    optionals cfg.enableSystemMonitoring [ pkgs.dgop ]
    ++ optionals cfg.enableClipboard [
      pkgs.cliphist
      pkgs.wl-clipboard
    ]
    ++ optionals cfg.enableVPN [
      pkgs.glib
      pkgs.networkmanager
    ]
    ++ optional cfg.enableBrightnessControl pkgs.brightnessctl
    ++ optional cfg.enableColorPicker pkgs.hyprpicker
    ++ optional cfg.enableDynamicTheming pkgs.matugen
    ++ optional cfg.enableAudioWavelength pkgs.cava
    ++ optional cfg.enableCalendarEvents pkgs.khal
    ++ optional cfg.enableSystemSound pkgs.kdePackages.qtmultimedia;
in
{
  options.programs.dms-shell = {
    enable = mkEnableOption "DankMaterialShell, a complete desktop shell for Wayland compositors";

    package = mkPackageOption pkgs "dms-shell" { };

    systemd = {
      target = mkOption {
        type = types.str;
        default = "graphical-session.target";
        description = ''
          The systemd target that will automatically start the DankMaterialShell service.

          Common targets include:
          - `graphical-session.target` for most desktop environments
          - `wayland-session.target` for Wayland-specific sessions
        '';
      };

      restartIfChanged = mkOption {
        type = types.bool;
        default = true;
        description = ''
          Whether to restart the dms.service when the DankMaterialShell package or
          configuration changes. This ensures the latest version is always running
          after a system rebuild.
        '';
      };
    };

    enableSystemMonitoring = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for system monitoring widgets.
        This includes process list viewers and system resource monitors.

        Requires: dgop
      '';
    };

    enableClipboard = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for clipboard management widgets.
        This enables clipboard history and clipboard manager functionality.

        Requires: cliphist, wl-clipboard
      '';
    };

    enableVPN = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for VPN widgets.
        This enables VPN status monitoring and management through NetworkManager.

        Requires: glib, networkmanager
      '';
    };

    enableBrightnessControl = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for brightness and backlight control.
        This enables screen brightness adjustment widgets.

        Requires: brightnessctl
      '';
    };

    enableColorPicker = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for color picking functionality.
        This enables on-screen color picker tools.

        Requires: hyprpicker
      '';
    };

    enableDynamicTheming = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for dynamic theming support.
        This enables automatic theme generation based on wallpapers and other sources.

        Requires: matugen
      '';
    };

    enableAudioWavelength = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for audio wavelength visualization.
        This enables audio spectrum and waveform visualizer widgets.

        Requires: cava
      '';
    };

    enableCalendarEvents = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for calendar events support.
        This enables calendar widgets that display events and reminders via khal.

        Requires: khal
      '';
    };

    enableSystemSound = mkOption {
      type = types.bool;
      default = true;
      description = ''
        Whether to install dependencies required for system sound support.
        This enables audio playback for system notifications and events.

        Requires: qtmultimedia
      '';
    };

    quickshell = {
      package = mkPackageOption pkgs "quickshell" { };
    };
  };

  config = mkIf cfg.enable {
    environment.etc."xdg/quickshell/dms".source = "${cfg.package}/share/quickshell/dms";

    systemd.packages = [ cfg.package ];

    systemd.user.services.dms = {
      wantedBy = [ cfg.systemd.target ];
      restartTriggers = optional cfg.systemd.restartIfChanged "${cfg.package}/share/quickshell/dms";
      path = lib.mkForce [ ];
    };

    environment.systemPackages = [
      cfg.package
      cfg.quickshell.package
      pkgs.ddcutil
      pkgs.libsForQt5.qt5ct
      pkgs.kdePackages.qt6ct
    ]
    ++ optionalPackages;

    fonts.packages = with pkgs; [
      fira-code
      inter
      material-symbols
    ];

    hardware.graphics.enable = lib.mkDefault true;
  };

  meta.maintainers = with lib.maintainers; [ luckshiba ];
}
+261 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  inherit (lib)
    types
    mkEnableOption
    mkOption
    mkIf
    mkDefault
    mkPackageOption
    literalExpression
    getExe
    makeBinPath
    optionalString
    concatMapStringsSep
    ;

  cfg = config.services.displayManager.dms-greeter;
  cfgAutoLogin = config.services.displayManager.autoLogin;

  greeterScript = pkgs.writeShellScriptBin "dms-greeter-start" ''
    export PATH=$PATH:${
      makeBinPath [
        cfg.quickshell.package
        config.programs.${cfg.compositor.name}.package
      ]
    }
    exec ${cfg.package}/share/quickshell/dms/Modules/Greetd/assets/dms-greeter \
      --command ${cfg.compositor.name} \
      -p ${cfg.package}/share/quickshell/dms \
      --cache-dir /var/lib/dms-greeter \
      ${
        optionalString (
          cfg.compositor.customConfig != ""
        ) "-C ${pkgs.writeText "dms-greeter-compositor-config" cfg.compositor.customConfig}"
      } \
      ${optionalString cfg.logs.save ">> ${cfg.logs.path} 2>&1"}
  '';

  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 = mkPackageOption pkgs "dms-shell" { };

    compositor = {
      name = mkOption {
        type = types.enum [
          "niri"
          "hyprland"
          "sway"
        ];
        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
        '';
      };

      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 = mkPackageOption 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 = config.programs.${cfg.compositor.name}.enable or false;
        message = ''
          DankMaterialShell greeter: The compositor "${cfg.compositor.name}" is not enabled.

          Please enable the compositor via:
            programs.${cfg.compositor.name}.enable = true;
        '';
      }
    ];

    services.greetd = {
      enable = true;
      settings = {
        default_session = {
          user = "dms-greeter";
          command = getExe greeterScript;
        };
        initial_session = mkIf (cfgAutoLogin.enable && (cfgAutoLogin.user != null)) {
          inherit (cfgAutoLogin) user command;
        };
      };
    };

    environment.systemPackages = [ cfg.package ];

    fonts.packages = with pkgs; [
      fira-code
      inter
      material-symbols
    ];

    systemd.tmpfiles.settings."10-dms-greeter"."/var/lib/dms-greeter".d = {
      user = "dms-greeter";
      group = "dms-greeter";
      mode = "0750";
    };

    systemd.services.greetd.preStart =
      let
        allConfigFiles = cfg.configFiles ++ configFilesFromHome;
      in
      ''
        set -euo pipefail

        cd /var/lib/dms-greeter || exit 1

        ${concatMapStringsSep "\n" (f: ''
          if [[ -f "${f}" ]]; then
            cp "${f}" . || true
          fi
        '') allConfigFiles}

        # Handle session.json wallpaper path
        if [[ -f session.json ]]; then
          if wallpaper=$(${getExe pkgs.jq} -r '.wallpaperPath' session.json 2>/dev/null); then
            if [[ -f "$wallpaper" ]]; then
              cp "$wallpaper" wallpaper.jpg || true
              mv session.json session.orig.json
              ${getExe pkgs.jq} '.wallpaperPath = "/var/lib/dms-greeter/wallpaper.jpg"' \
                session.orig.json > session.json || true
            fi
          fi
        fi

        # Rename colors file if it exists
        [[ -f dms-colors.json ]] && mv dms-colors.json colors.json || true

        # Fix ownership of all files
        chown -R "dms-greeter:dms-greeter" . || true
      '';

    users.groups.dms-greeter = { };
    users.users.dms-greeter = {
      description = "DankMaterialShell greeter user";
      isSystemUser = true;
      home = "/var/lib/dms-greeter";
      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.maintainers = with lib.maintainers; [ luckshiba ];
}
Loading