1 { config, lib, pkgs, ... }:
4 cfg = config.programs.dconf;
6 # Compile keyfiles to dconf DB
7 compileDconfDb = dir: pkgs.runCommand "dconf-db"
9 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
10 } "dconf compile $out ${dir}";
12 # Check if dconf keyfiles are valid
13 checkDconfKeyfiles = dir: pkgs.runCommand "check-dconf-keyfiles"
15 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
17 if [[ -f ${dir} ]]; then
18 echo "dconf keyfiles should be a directory but a file is provided: ${dir}"
22 dconf compile db ${dir} || (
23 echo "The dconf keyfiles are invalid: ${dir}"
29 mkAllLocks = settings: lib.flatten (
30 lib.mapAttrsToList (k: v: lib.mapAttrsToList (k': _: "/${k}/${k'}") v) settings);
32 # Generate dconf DB from dconfDatabase and keyfiles
33 mkDconfDb = val: compileDconfDb (pkgs.symlinkJoin {
34 name = "nixos-generated-dconf-keyfiles";
36 (pkgs.writeTextDir "nixos-generated-dconf-keyfiles" (lib.generators.toDconfINI val.settings))
37 (pkgs.writeTextDir "locks/nixos-generated-dconf-locks" (lib.concatStringsSep "\n"
38 (if val.lockAll then mkAllLocks val.settings else val.locks)
40 ] ++ (map checkDconfKeyfiles val.keyfiles);
43 # Check if a dconf DB file is valid. The dconf cli doesn't return 1 when it can't
44 # open the database file so we have to check if the output is empty.
45 checkDconfDb = file: pkgs.runCommand "check-dconf-db"
47 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
49 if [[ -d ${file} ]]; then
50 echo "dconf DB should be a file but a directory is provided: ${file}"
54 echo "file-db:${file}" > profile
55 DCONF_PROFILE=$(pwd)/profile dconf dump / > output 2> error
56 if [[ ! -s output ]] && [[ -s error ]]; then
58 echo "The dconf DB file is invalid: ${file}"
65 # Generate dconf profile
66 mkDconfProfile = name: value:
67 if lib.isDerivation value || lib.isPath value then
68 pkgs.runCommand "dconf-profile" { } ''
69 if [[ -d ${value} ]]; then
70 echo "Dconf profile should be a file but a directory is provided."
73 mkdir -p $out/etc/dconf/profile/
74 cp ${value} $out/etc/dconf/profile/${name}
77 pkgs.writeTextDir "etc/dconf/profile/${name}" (
78 lib.concatMapStrings (x: "${x}\n") ((
79 lib.optional value.enableUserDb "user-db:user"
84 db = if lib.isAttrs value && !lib.isDerivation value then mkDconfDb value else checkDconfDb value;
91 dconfDatabase = with lib.types; submodule {
93 keyfiles = lib.mkOption {
94 type = listOf (oneOf [ path package ]);
96 description = "A list of dconf keyfile directories.";
98 settings = lib.mkOption {
101 description = "An attrset used to generate dconf keyfile.";
102 example = literalExpression ''
105 "com/raggesilver/BlackBox" = {
106 scrollback-lines = mkUint32 10000;
107 theme-dark = "Tommorow Night";
112 locks = lib.mkOption {
113 type = with lib.types; listOf str;
116 A list of dconf keys to be lockdown. This doesn't take effect if `lockAll`
119 example = literalExpression ''
120 [ "/org/gnome/desktop/background/picture-uri" ]
123 lockAll = lib.mkOption {
124 type = lib.types.bool;
126 description = "Lockdown all dconf keys in `settings`.";
131 dconfProfile = with lib.types; submodule {
133 enableUserDb = lib.mkOption {
136 description = "Add `user-db:user` at the beginning of the profile.";
139 databases = lib.mkOption {
140 type = with lib.types; listOf (oneOf [
147 List of data sources for the profile. An element can be an attrset,
148 or the path of an already compiled database. Each element is converted
151 A key is searched from up to down and the first result takes the
152 priority. If a lock for a particular key is installed then the value from
153 the last database in the profile where the key is locked will be used.
154 This can be used to enforce mandatory settings.
164 enable = lib.mkEnableOption "dconf";
166 profiles = lib.mkOption {
167 type = with lib.types; attrsOf (oneOf [
174 Attrset of dconf profiles. By default the `user` profile is used which
175 ends up in `/etc/dconf/profile/user`.
177 example = lib.literalExpression ''
179 # A "user" profile with a database
185 # A "bar" profile from a package
186 bar = pkgs.bar-dconf-profile;
187 # A "foo" profile from a path
193 packages = lib.mkOption {
194 type = lib.types.listOf lib.types.package;
196 description = "A list of packages which provide dconf profiles and databases in {file}`/etc/dconf`.";
201 config = lib.mkIf (cfg.profiles != { } || cfg.enable) {
202 programs.dconf.packages = lib.mapAttrsToList mkDconfProfile cfg.profiles;
204 environment.etc.dconf = lib.mkIf (cfg.packages != [ ]) {
205 source = pkgs.symlinkJoin {
206 name = "dconf-system-config";
207 paths = map (x: "${x}/etc/dconf") cfg.packages;
208 nativeBuildInputs = [ (lib.getBin pkgs.dconf) ];
210 if test -d $out/db; then
217 services.dbus.packages = [ pkgs.dconf ];
219 systemd.packages = [ pkgs.dconf ];
221 # For dconf executable
222 environment.systemPackages = [ pkgs.dconf ];
224 environment.sessionVariables = lib.mkIf cfg.enable {
225 # Needed for unwrapped applications
226 GIO_EXTRA_MODULES = [ "${pkgs.dconf.lib}/lib/gio/modules" ];