{ flake, flakeInputs, userName, pkgs, customUtils, lib, config, sources, ... }@inputs:

with lib;

let
  cfg = config.home-manager.users.${userName};
  emacsScratch = pkgs.stdenv.mkDerivation (sources.emacs-scratch_el // rec {
    phases = [ "installPhase" ];

    installPhase = ''
      mkdir -p $out/share/emacs/site-lisp
      cp $src/scratch.el $out/share/emacs/site-lisp/default.el
    '';
  });
  muteScript = pkgs.stdenv.mkDerivation {
    name = "mute";
    src = ./scripts/mute.zsh;

    buildInputs = with pkgs; [ makeWrapper ];

    phases = [ "installPhase" ];

    installPhase = ''
      mkdir -p $out/bin
      install -m 0755 $src $out/bin/mute
      wrapProgram $out/bin/mute \
        --prefix PATH : ${pkgs.zsh}/bin \
        --prefix PATH : ${pkgs.findutils}/bin \
        --prefix PATH : ${pkgs.util-linux}/bin \
        --prefix PATH : ${pkgs.coreutils}/bin \
        --prefix PATH : ${pkgs.pulseaudio}/bin
    '';
  };
  wrapElectron = { package, bin ? package.meta.mainProgram or package.pname or (pkgs.lib.strings.nameFromURL package.name "-"), outBin ? bin, sandbox ? true }: pkgs.symlinkJoin {
    name = "${package.name}-wrapped";
    buildInputs = with pkgs; [ makeWrapper ];
    paths = [ package ];
    inherit bin outBin;
    postBuild = ''
      hidden=$out/bin/."$(basename "$bin")"-wrapped
      while [ -e "$hidden" ]; do
        hidden="''${hidden}_"
      done
      mv "$out/bin/$bin" "$hidden"
      makeWrapper "$hidden" "$out/bin/$outBin" \
        ${optionalString (!sandbox) "--add-flags '--no-sandbox'"}
    '';
  };

  wrappedChrome = wrapElectron { package = pkgs.google-chrome; outBin = "google-chrome"; };
  wrappedZulip = wrapElectron { package = pkgs.zulip; bin = "zulip"; outBin = "zulip"; };
  wrappedElementDesktop = wrapElectron { package = pkgs.element-desktop; bin = "element-desktop"; };
  wrappedRocketChatDesktop = wrapElectron { package = pkgs.rocketchat-desktop; bin = "rocketchat-desktop"; outBin = "rocketchat"; };
  wrappedYTMDesktop = wrapElectron { package = pkgs.ytmdesktop; sandbox = false; };

  wrappedKeepassxc = pkgs.symlinkJoin {
    inherit (pkgs.keepassxc) name;
    paths = with pkgs; [
      keepassxc
      (pkgs.writeTextFile {
        name = "org.keepassxc.KeePassXC";
        destination = "/share/dbus-1/services/org.keepassxc.KeePassXC.MainWindow.service";
        text = ''
          [D-BUS Service]
          Name=org.keepassxc.KeePassXC.MainWindow
          Exec=${pkgs.coreutils}/bin/false
          SystemdService=keepassxc.service
        '';
      })
      (pkgs.writeTextFile {
        name = "org.freedesktop.secrets";
        destination = "/share/dbus-1/services/org.freedesktop.secrets.service";
        text = ''
          [D-BUS Service]
          Name=org.freedesktop.secrets
          Exec=${pkgs.coreutils}/bin/false
          SystemdService=keepassxc.service
        '';
      })
    ];
  };

  lockCommand = "${config.systemd.package}/bin/systemctl --user start gtklock.service";
in {
  imports = with flake.nixosModules.userProfiles.${userName}; [
    mpv yt-dlp (args: import ./xcompose.nix (inputs // args))
  ];

  config = {
    services.displayManager.defaultSession = "Hyprland"; # "none+xmonad";

    home-manager.users.${userName} = {
      imports = [
        ./libvirt
        flakeInputs.nix-index-database.hmModules.nix-index
        flakeInputs.impermanence.nixosModules.home-manager.impermanence
      ];

      home.stateVersion = "20.09";

      nixpkgs.config = {
        allowUnfree = true;
        zathura.useMupdf = false;
      };

      nix.registry = {
        "flk" = {
          from = {
            type = "indirect";
            id = "flk";
          };
          to = {
            type = "git";
            url = "file:///home/gkleen/config/nixos-flakes";
          };
        };
      };

      programs = {
        ssh = {
          matchBlocks = import ./ssh-hosts.nix { inherit pkgs; }; # customUtils.nixImport { dir = ./ssh-hosts; };
          extraConfig = ''
            Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uniworx5.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
              ProxyJump remote.cip.ifi.lmu.de

            Match host *.mathinst.loc,*.cipmath.loc,*.math.lmu.de
              IdentityFile ~/.ssh/gkleen@mathinst.loc
              HostKeyAlgorithms +ssh-rsa
              PubkeyAcceptedAlgorithms +ssh-rsa
              ConnectTimeout 30
              PasswordAuthentication yes
              KbdInteractiveAuthentication yes
              UpdateHostKeys yes
              GlobalKnownHostsFile ${pkgs.writeText "ssh_known_hosts" ''
                @cert-authority *.mathinst.loc,*.math.lmu.de,*.cipmath.loc ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBUTFpVCdETCXiDSDl7YGbR1J4BLTsoBzjDtflHJGO/z ssh-pki@mgmt01
              ''}

            Match host *.mathinst.loc,*.math.lmu.de !host ssh.math.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
              # ProxyCommand ${pkgs.socat}/bin/socat - SOCKS4A:127.0.0.1:%h:%p,socksport=8118
              ProxyJump ssh.math.lmu.de

            Match host *.cipmath.loc !host cip04.cipmath.loc,mgmt-cls01.cipmath.loc !exec "nc -z -w 1 %h %p &>/dev/null"
              ProxyJump cip04

            Match host *.ifi.lmu.de,*.math.lmu.de
              AddressFamily inet

            Match host *.mgmt.yggdrasil
              ProxyJump vidhar

            Host *
          '';
        };

        emacs = {
          enable = true;
	        package = pkgs.emacs29-pgtk;
          extraPackages = epkgs: with epkgs; [
            evil evil-dvorak undo-tree magit haskell-tng-mode nix-mode
            yaml-mode json-mode shakespeare-mode smart-mode-line
            highlight-parentheses highlight-symbol ag sass-mode lua-mode
            fira-code-mode use-package wanderlust # notmuch
            git-gutter emacsScratch
            edit-server mediawiki editorconfig typescript-mode
            markdown-mode nftables-mode rustic lsp-mode lsp-ui
            direnv company projectile tomorrow-night-paradise-theme
            treesit-grammars.with-all-grammars magit-delta scad-mode
          ];
          overrides = self: super: {
            tomorrow-night-paradise-theme = super.trivialBuild {
              inherit (sources.tomorrow-night-paradise-theme) pname version src;
            };
          };
        };
        firefox = {
          enable = true;
          profiles.default = {
            settings = {
              # "layout.css.devPixelsPerPx" = "0.5833";
              "browser.tabs.drawInTitlebar" = false;
              "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
              "dom.security.https_only_mode" = true;
            };
          };
        };

        zathura.enable = true;
        imv.enable = true;

        mpv.config = {
          demuxer-max-bytes = 1073741824;
          demuxer-max-back-bytes = 268435456;
          gpu-api = "vulkan";
        };

        zsh.initExtra = ''
          source ${./zshrc}
        '';
        zsh.dirHashes = let
          flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs;
          inputNames = {
            "nixpkgs" = "nixos";
          };
        in flakeHashes // {
          u2w = "$HOME/projects/uni2work";
          docs = "$HOME/documents";
          dl = "$HOME/Downloads";
          scrot = "$HOME/screenshots";
          flk = "$HOME/projects/machines";
          rz = "$HOME/projects/rz";
          pro = "$HOME/projects/pro";
          media = "$HOME/media";
        };

        obs-studio = {
          enable = true;
          plugins = with pkgs; [];
        };

        gh = {
          enable = true;
          settings = {
            editor = "${config.home-manager.users.${userName}.programs.emacs.package}/bin/emacsclient";
            gitProtocol = "ssh";
          };
        };

        kitty = {
          enable = true;
          font = {
            package = pkgs.nerd-fonts.fira-mono;
            name = "Fira Mono";
            size = 10;
          };
          settings = {
            scrollback_pager_history_size = 50;
            # background_opacity = "0.9";
            enable_audio_bell = false;
            update_check_interval = 0;
            strip_trailing_spaces = "smart";
            focus_follows_mouse = true;
            visual_bell_duration = "0.1";
            visual_bell_color = "#26240d";
            tab_bar_style = "powerline";
            tab_powerline_style = "slanted";
            # notify_on_cmd_finish = "invisible 120";
          };
          keybindings = {
            "kitty_mod+n" = "detach_window";
            "kitty_mod+m" = "detach_window ask";
          };
        };
        waybar = {
	        enable = true;
          systemd = {
	          enable = true;
            target = "hyprland-session.target";
          };
	        settings = let
            windowRewrites = {
              "(.*) — Mozilla Firefox" = "$1";
              "(.*) - Mozilla Thunderbird" = "$1";
              "(.*) - mpv" = "$1";
            };
            iconSize = 11;
          in [
            {
              layer = "top";
              position = "top";
              height = 14;
              output = [ "eDP-1" "DP-2" "DP-3" ];
              modules-left = [ "hyprland/workspaces" ];
              modules-center = [ "hyprland/window" ];
              modules-right = [ # "custom/worktime" "custom/worktime-today"
                "custom/weather" "custom/keymap" "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "clock" ];

              "custom/weather" = {
                format = "{}";
                tooltip = true;
                interval = 3600;
                exec = "${lib.getExe pkgs.wttrbar} --hide-conditions --nerd --custom-indicator \"<span font=\\\"Symbols Nerd Font Mono\\\" size=\\\"120%\\\">{ICON}</span> {FeelsLikeC}°\"";
                return-type = "json";
              };
              "custom/keymap" = {
                format = "{}";
                tooltip = true;
                return-type = "json";
                exec = pkgs.writers.writePython3 "keymap" {} ''
                  import os
                  import socket
                  import re
                  import subprocess
                  import json


                  def output(keymap):
                      short = keymap
                      if keymap == "English (programmer Dvorak)":
                          short = "dvp"
                      elif keymap == "English (US)":
                          short = "<span color=\"#ffffff\">us</span>"
                      print(json.dumps({'text': short, 'tooltip': keymap}, separators=(',', ':')), flush=True)  # noqa: E501


                  r = subprocess.run(["hyprctl", "devices", "-j"], check=True, stdout=subprocess.PIPE, text=True)  # noqa: E501
                  for keyboard in json.loads(r.stdout)['keyboards']:
                      if keyboard['name'] != "at-translated-set-2-keyboard":
                          continue
                      output(keyboard['active_keymap'])

                  sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
                  sock.connect(os.environ["XDG_RUNTIME_DIR"] + "/hypr/" + os.environ["HYPRLAND_INSTANCE_SIGNATURE"] + "/.socket2.sock")  # noqa: E501
                  expected = re.compile(r'^activelayout>>at-translated-set-2-keyboard,(?P<keymap>.+)$')  # noqa: E501
                  for line in sock.makefile(buffering=1, encoding='utf-8'):
                      if match := expected.match(line):
                          output(match.group("keymap"))
                '';
                on-click = "hyprctl switchxkblayout at-translated-set-2-keyboard next";
              };
              "custom/worktime" = {
                interval = 60;
                exec = getExe pkgs.worktime;
                tooltip = false;
              };
              "custom/worktime-today" = {
                interval = 60;
                exec = "${getExe pkgs.worktime} today";
                tooltip = false;
              };
              "hyprland/workspaces" = {
                all-outputs = true;
              };
              "hyprland/window" = {
                separate-outputs = true;
                icon = true;
                icon-size = 14;
                rewrite = windowRewrites;
              };
              clock = {
                  interval = 1;
                  # timezone = "Europe/Berlin";
                  format = "W{:%V-%u %F %H:%M:%S%Ez}";
                  tooltip-format = "<tt><small>{calendar}</small></tt>";
                  calendar = {
                    mode = "year";
                    mode-mon-col = 3;
                    weeks-pos = "left";
                    on-scroll = 1;
                    format = {
                      months = "<span color='#ffead3'><b>{}</b></span>";
                      days = "{}";
                      weeks = "<span color='#99ffdd'><b>{}</b></span>";
                      weekdays = "<span color='#ffcc66'><b>{}</b></span>";
                      today = "<span color='#ff6699'><b>{}</b></span>";
                    };
                  };
              };
              battery = {
                format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
                icon-size = iconSize - 2;
                states = { warning = 30; critical = 15; };
                format-icons = ["&#xf008e;" "&#xf007a;" "&#xf007b;" "&#xf007c;" "&#xf007d;" "&#xf007e;" "&#xf007f;" "&#xf0080;" "&#xf0081;" "&#xf0082;" "&#xf0079;" ];
                format-charging = "&#xf0084;";
                format-plugged = "&#xf06a5;";
                tooltip-format = "{capacity}% {timeTo}";
                interval = 20;
              };
              tray = {
                icon-size = 16;
                # show-passive-items = true;
                spacing = 1;
              };
              privacy = {
                icon-spacing = 7;
                icon-size = iconSize;
                modules = [
                  { type = "screenshare"; }
                  { type = "audio-in"; }
                ];
              };
              idle_inhibitor = {
                format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
                icon-size = iconSize;
                format-icons = { activated = "&#xf0208;"; deactivated = "&#xf0209;"; };
                timeout = 120;
              };
              backlight = {
                format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
                icon-size = iconSize;
                tooltip-format = "{percent}%";
                format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"];
                on-scroll-up = "lightctl -d -e4 -n1 up";
                on-scroll-down = "lightctl -d -e4 -n1 down";
              };
              wireplumber = {
                format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
                icon-size = iconSize;
                tooltip-format = "{volume}% {node_name}";
                format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"];
                format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>";
                # ignored-sinks = ["Easy Effects Sink"];
                on-scroll-up = "volumectl -d -u up";
                on-scroll-down = "volumectl -d -u down";
                on-click = "volumectl -d toggle-mute";
              };
            }
            {
              layer = "top";
              position = "top";
              height = 14;
              output = [ "!eDP-1" "!DP-2" "!DP-3" ];
              modules-left = [ "hyprland/workspaces" ];
              modules-center = [ "hyprland/window" ];
              modules-right = [ "clock" ];

              "hyprland/workspaces" = {
                all-outputs = false;
              };
              "hyprland/window" = {
                separate-outputs = true;
                icon = true;
                icon-size = 14;
                rewrite = windowRewrites;
              };
              clock = {
                  interval = 1;
                  # timezone = "Europe/Berlin";
                  format = "{:%H:%M}";
                  tooltip-format = "W{:%V-%u %F %H:%M:%S%Ez}";
              };
            }
          ];
          style = ''
            @define-color white #ffffff;
            @define-color grey #555555;
            @define-color blue #1a8fff;
            @define-color green #23fd00;
            @define-color orange #f28a21;
            @define-color red #f2201f;

            * {
              border: none;
              font-family: "Fira Sans Nerd Font";
              font-size: 10pt;
              min-height: 0;
            }

            window#waybar {
              background-color: rgba(0, 0, 0, 0.66);
              color: @white;
            }

            .modules-left {
              margin-left: 9px;
            }
            .modules-right {
              margin-right: 9px;
            }

            .module {
              margin: 0 5px;
            }

            #workspaces button {
              color: @grey;
            }
            #workspaces button.hosting-monitor {
              color: @white;
            }
            #workspaces button.visible {
              color: @blue;
            }
            #workspaces button.active {
              color: @green;
            }
            #workspaces button.urgent {
              color: @red;
            }

            #custom-weather, #custom-keymap, #custom-worktime, #custom-worktime-today {
              color: @grey;
              margin: 0 5px;
            }
            #custom-weather, #custom-worktime-today {
              margin-right: 3px;
            }
            #custom-keymap, #custom-weather {
              margin-left: 3px;
            }

            #tray {
              margin: 0;
            }
            #battery, #idle_inhibitor, #backlight, #wireplumber {
              color: @grey;
              margin: 0 5px 0 2px;
            }
            #idle_inhibitor {
              margin-right: 2px;
              margin-left: 3px;
            }
            #battery {
              margin-right: 3px;
            }
            #battery.discharging {
              color: @white;
            }
            #battery.warning {
              color: @orange;
            }
            #battery.critical {
              color: @red;
            }
            #battery.charging {
              color: @white;
            }
            #idle_inhibitor.activated {
              color: @white;
            }

            #idle_inhibitor {
              padding-top: 1px;
            }

            #privacy {
              color: @red;
              margin: -1px 2px 0px 5px;
            }
            #clock {
              /* margin-right: 5px; */
            }
          '';
	      };
        wpaperd = {
          enable = true;
          settings.default = {
            path = "~/.wallpapers";
            duration = "8h";
            mode = "center";
          };
        };
        fuzzel = {
          enable = true;
          settings = {
            main = {
              terminal = lib.getExe pkgs.kitty;
              layer = "overlay";
              icon-theme = "Paper";
              font = "Fira Sans";
            };
            colors = {
              background = "000000aa";
              text = "cdd6f4ff";
              match = "94e2d5ff";
              selection = "585b70ff";
              selection-match = "94e2d5ff";
              selection-text = "cdd6f4ff";
              border = "b4befeff";
            };
            dmenu = {
              exit-immediately-if-empty = true;
            };
          };
        };
      };

      services = {
        dunst = {
          settings = import ./dunst-settings.nix inputs;
          iconTheme = {
            package = pkgs.paper-icon-theme;
            name = "Paper";
          };
          enable = true;
        };
        emacs = {
          enable = true;
          socketActivation.enable = true;
          client = {
            enable = true;
            arguments = mkForce ["--reuse-frame" "--alternate-editor" "\"\""];
          };
        };
        gpg-agent = {
          enable = true;
          enableSshSupport = true;
          extraConfig = ''
            pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry
            grab
          '';
        };
        xembed-sni-proxy.enable = true;
        udiskie = {
          enable = true;
          automount = false;
          settings = {
            program_options = {
              file_manager = "";
            };
            notification_actions = {
              device_mounted = [];
            };
          };
        };
        network-manager-applet.enable = true;
        blueman-applet.enable = true;

        unison = {
          enable = true;
          pairs = {
            documents = {
              roots = ["${cfg.home.homeDirectory}/documents" "ssh://unison.vidhar/documents"];
              stateDirectory = "${cfg.xdg.dataHome}/documents.unison";
              commandOptions = {
                auto = "true";
                batch = "true";
                log = "false";
                repeat = "watch";
                sshcmd = "${pkgs.openssh}/bin/ssh";
                ui = "text";
              };
            };
          };
        };

        easyeffects = {
          enable = true;
        };

        etesync-dav = {
          enable = true;
          serverUrl = "https://etesync.yggdrasil.li";
        };

        swayidle = {
          enable = true;
          events = [
            { event = "before-sleep"; command = lockCommand; }
            { event = "after-resume"; command = "${cfg.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms on"; }
            { event = "lock"; command = lockCommand; }
          ];
          timeouts = [
            { timeout = 300;
              command = "${cfg.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms off";
            }
            { timeout = 330; command = lockCommand; }
          ];
          extraArgs = [
            "idlehint" "30"
          ];
        };
        poweralertd.enable = true;
        avizo = {
          enable = true;
          settings.default = {
            time = "1.0";
            background = "rgba(0, 0, 0, 0.8)";
            border-color = "rgba(0, 0, 0, 1)";
            bar-fg-color = "rgba(160, 160, 160, 1)";
            bar-bg-color = "rgba(32, 32, 32, 0.96)";
            # y-offset = "0.25";
          };
        };
      };

      home.pointerCursor = {
        package = pkgs.vanilla-dmz;
        name = "Vanilla-DMZ-AA";
        size = 16;

        x11 = {
          enable = true;
          defaultCursor = "left_ptr";
        };
        gtk.enable = true;
      };

      gtk = {
        enable = true;
        font = {
          package = pkgs.fira;
          name = "Fira Sans";
          size = 10;
        };
        theme = {
          package = pkgs.equilux-theme;
          name = "Equilux-compact";
        };
        iconTheme = {
          package = pkgs.paper-icon-theme;
          name = "Paper-Mono-Dark";
        };
      };

      xsession.preferStatusNotifierItems = true;

      xresources.properties = import ./xresources.nix;

      home = {
        packages = with pkgs; [
          fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs
          mumble pulseaudio-ctl pamixer libnotify screen-message
          wrappedYTMDesktop libsForQt5.qt5ct playerctl evince
          thunderbird zoom-us steam steam-run wireshark virt-manager
          rclone cached-nix-shell worktime fira-code-symbols
          libreoffice xournalpp google-chrome nixos-shell virt-viewer
          freerdp gnome-icon-theme paper-icon-theme sshpassSecret
          weechat element-desktop matrix-synapse-tools.synadm
          flakeInputs.deploy-rs.packages.${config.nixpkgs.system}.deploy-rs
          sieve-connect gimp inkscape udiskie glab nitrokey-app
          pynitrokey gtklock wlrctl remmina openscad spice-record
          libguestfs-with-appliance nerd-fonts.fira-mono
          nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts
        ];

        file = {
          ".backup-munin".source = ./backup-patterns;
          ".mozilla/firefox/default/chrome/userChrome.css".source = ./firefox-chrome.css;
          ".mozilla/firefox/default/chrome/userContent.css".source = ./firefox-content.css;
          ".local/share/etesync-dav/CACHEDIR.TAG".text = ''
            Signature: 8a477f597d28d172789f06886806bc55
          '';
          ".cups/client.conf".text = ''
            ServerName cups.mathinst.loc
          '';
        };

        sessionVariables = {
          # GDK_SCALE = 96.0 / 282.0;
          # QT_AUTO_SCREEN_SCALE_FACTOR = 1;
          QT_QPA_PLATFORMTHEME = "qt5ct";
          LIBVIRT_DEFAULT_URI = "qemu:///system";
          STACK_XDG = 1;
          EDITOR = pkgs.writeShellScript "editor" ''
            args=("--reuse-frame" "--alternate-editor" "")
            args+=("$@")
            exec -a emacsclient ${cfg.services.emacs.package}/bin/emacsclient "''${args[@]}"
          '';
          RCLONE_PASSWORD_COMMAND = "${pkgs.libsecret}/bin/secret-tool lookup service rclone";
        };

        extraProfileCommands = ''
          export XDG_DATA_DIRS="${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}''${XDG_DATA_DIRS:+:''${XDG_DATA_DIRS}}"
        '';
      };

      xdg.configFile = {
        "dunst/dunstrc.d" = {
          source = ./dunstrc.d;
          recursive = true;
          onChange = ''
            ${pkgs.systemd}/bin/systemctl --user try-restart dunst
          '';
        };
        "wireplumber" = {
          source = ./wireplumber;
          recursive = true;
          onChange = ''
            ${pkgs.systemd}/bin/systemctl --user try-restart wireplumber
          '';
        };
        "stack/config.yaml" = {
          source = (pkgs.formats.yaml {}).generate "config.yaml" {
            recommend-stack-upgrade = false;
          };
        };
        "gtklock/config.ini" = {
          source = (pkgs.formats.ini {}).generate "config.ini" {
            main = {
              idle-hide = true;
              follow-focus = true;
              start-hidden = true;
              time-format = "%H:%M:%S";
              date-format = "%Y-%m-%d";
            };
          };
        };
        "qalculate/qalc.cfg" = {
          source = (pkgs.formats.ini {}).generate "qalc.cfg" {
            General = {
              dot_as_separator = 0;
            };
          };
        };
        "emacs/init.el".source = ./emacs.el;
      };

      xdg.dataFile = {
        "pandoc/abbreviations" = {
          source = pkgs.runCommand "pandoc-abbreviations" {
            buildInputs = [ pkgs.pandoc pkgs.coreutils ];
          } (let
            germanAbbrevs = pkgs.fetchFromGitHub {
              owner = "jfilter";
              repo = "german-abbreviations";
              rev = "8eb9dae93b6f05d7c53374cd217ab2dc89558e0c";
              sha256 = "SaD3tSqzen6Y3SPICe6/9vhe4iMHlArZ3kFQaEk7Hps=";
            };
          in ''
            cat \
              <(pandoc --print-default-data-file=abbreviations) \
              <(grep -E '^[^ ]+\.$' ${germanAbbrevs}/german_abbreviations.txt) \
              ${pkgs.writeText "abbrevs.txt" ''
                i.A.
                d.h.
                D.h.
                gdw.
              ''} \
              | sort | uniq >$out
          '');
        };
        "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service";
        "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service";
        "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation {
          inherit (sources.emoji-data) pname src;
          version = lib.removePrefix "v" sources.emoji-data.version;
          buildInputs = with pkgs; [ jq (ruby.withPackages (ps: with ps; [ nokogiri rspec racc rubocop rubocop-performance rspec-core rspec-expectations rspec-mocks diff-lcs parallel parser rainbow regexp_parser rubocop-ast ruby-progressbar unicode-display_width rspec-support optimist ast ])) ];
          LC_ALL = "C.UTF-8";
          patches = [
            (pkgs.writeText "nix.patch" ''
              diff --git a/Makefile b/Makefile
              index 896cb50..c7b6db8 100644
              --- a/Makefile
              +++ b/Makefile
              @@ -21,10 +21,10 @@ data:
               cldr:
               	@[ ! -d cldr/.git ] && git submodule update --init cldr

              -data/all.json: compile.rb $(wildcard lib/*.rb) $(INPUT_FILES) | cldr data check-ruby gems
              +data/all.json: compile.rb $(wildcard lib/*.rb) $(INPUT_FILES) | data
               	@ruby compile.rb > "$@"

              -data/%.txt: views/%.txt.jq data/all.json | data check-jq
              +data/%.txt: views/%.txt.jq data/all.json | data
               	@jq -r -f "$<" < data/all.json > "$@"

               data/%.json: views/%.json.jq data/all.json | data check-jq
            '')
          ];
          postPatch = ''
            cp ${pkgs.writeText "list.txt.jq" ''
              .categories[] |

              # Collect category + subcategory combos
              .name as $cat |
              reduce .subcategories[] as $sub (
                [];
                # Build an array of all emojis in this subcategory
                . + (
                  $sub.emojis | map(
                    # emoji: name (keyword, keyword, keyword)
                    "\(.characters): \(.name // .tts_descriptions.en // "") (\(.keywords.en // [] | join(", ")))"
                  )
                )
              ) |

              # Merge into a single string
              join("\n")
            ''} views/list.txt.jq
          '';
          buildFlagsArray = ["data/list.txt"];
          installPhase = ''
            cp data/list.txt $out
          '';
        };
      };

      xdg.mimeApps = {
        enable = true;
        defaultApplications = let
          filters = {
          };
          doFilter = n: v: (filters.${n} or id) (filter (d: d != "emacs.desktop") v);
        in mapAttrs doFilter (cfg.lib.xdg.mimeAssociations [
          cfg.programs.zathura.package
          cfg.programs.imv.package
          cfg.programs.emacs.package
          cfg.programs.firefox.package
        ]) // {
          "x-scheme-handler/mailto" = "thunderbird.desktop";
        };
      };

      xdg.desktopEntries = {
        element-lmu = {
          name = "Element (LMU)";
          exec = "element-desktop --profile=lmu %u";
          icon = "element";
          genericName = "Matrix Client";
          categories = [ "Network" "InstantMessaging" "Chat" ];
          settings = {
            StartupWMClass = "Element";
          };
        };
        rainbow = {
          name = "Rainbow";
          exec = toString (pkgs.writeShellScript "rainbow" ''
            exec -- \
              ${config.systemd.package}/bin/systemd-run --wait --user --slice-inherit \
              --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \
              --property 'Environment=DSCP=46' \
              -- ${pkgs.dscp}/bin/dscp ${pkgs.google-chrome}/bin/google-chrome-stable \
              --force-device-scale-factor=1.5 \
              --class=Rainbow \
              --kiosk "https://web.openrainbow.com" \
              --user-data-dir=''${HOME}/.config/google-chrome-rainbow
          '');
          icon = pkgs.fetchurl {
            url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg";
            hash = "sha256-5fmo8rDqVDpzkGaPjk4Y+SsSZpAsY7VUQSFW6WdHwuU=";
          };
        };
      };

      fonts = {
        fontconfig.enable = true;
        lmu-hausschrift.enable = true;
      };

      systemd.user = import ./systemd.nix inputs;

      dconf.settings = {
        "org/gnome/desktop/interface" = {
          color-scheme = "prefer-dark";
        };
      };

      wayland.windowManager.hyprland = {
        enable = true;
        settings = import ./hyprland.nix inputs;
      };

      xdg.portal = {
        enable = true;
        xdgOpenUsePortal = true;
        config = {
          common.default = [ "gtk" ];
          hyprland.default = [ "gtk" "kde" "hyprland" ];
        };
        extraPortals = with pkgs; [
          xdg-desktop-portal-kde xdg-desktop-portal-gtk xdg-desktop-portal-wlr xdg-desktop-portal-hyprland
        ];
      };
    };
  };
}