diff --git a/lib/dconf.nix b/lib/dconf.nix
new file mode 100644
index 0000000000000..8dd5e3ee26e78
--- /dev/null
+++ b/lib/dconf.nix
@@ -0,0 +1,15 @@
+{ lib }:
+
+# This module contains helpers for the `programs.dconf` NixOS module
+
+rec {
+ types = {
+ tuple = "_tuple";
+ };
+
+ mkTuple = _elements: {
+ inherit _elements;
+
+ _type = types.tuple;
+ };
+}
diff --git a/lib/default.nix b/lib/default.nix
index 8bb06954518b9..4791dbd628975 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -42,6 +42,7 @@ let
# serialization
cli = callLibs ./cli.nix;
+ dconf = callLibs ./dconf.nix;
generators = callLibs ./generators.nix;
# misc
diff --git a/lib/generators.nix b/lib/generators.nix
index b77cca75010f9..6f51d686647dc 100644
--- a/lib/generators.nix
+++ b/lib/generators.nix
@@ -175,6 +175,18 @@ rec {
+ "\n")
+ (toINI { inherit mkSectionName mkKeyValue listsAsDuplicateKeys; } sections);
+ # converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI
+ flattenAttrs = with builtins; extraIsLeafPredicate: sep: let
+ recurse = path: value:
+ if isAttrs value && !lib.isDerivation value && !extraIsLeafPredicate value then
+ lib.mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
+ else if length path > 1 then {
+ ${concatStringsSep sep (lib.reverseList (tail path))}.${head path} = value;
+ } else {
+ ${head path} = value;
+ };
+ in attrs: lib.foldl lib.recursiveUpdate { } (lib.flatten (recurse [ ] attrs));
+
/* Generate a git-config file from an attrset.
*
* It has two major differences from the regular INI format:
@@ -213,21 +225,27 @@ rec {
let mkKeyValue = mkKeyValueDefault { } " = " k;
in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (lib.toList v));
- # converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI
- gitFlattenAttrs = let
- recurse = path: value:
- if isAttrs value && !lib.isDerivation value then
- lib.mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
- else if length path > 1 then {
- ${concatStringsSep "." (lib.reverseList (tail path))}.${head path} = value;
- } else {
- ${head path} = value;
- };
- in attrs: lib.foldl lib.recursiveUpdate { } (lib.flatten (recurse [ ] attrs));
-
toINI_ = toINI { inherit mkKeyValue mkSectionName; };
in
- toINI_ (gitFlattenAttrs attrs);
+ toINI_ (flattenAttrs (_: false) "." attrs);
+
+ /* mkValueStringDefault wrapper that handles dconf INI quirks. */
+ mkValueStringDconf = v:
+ if builtins.isList v then
+ "[${lib.concatMapStringsSep ", " mkValueStringDconf v}]"
+ else if lib.types.isType lib.dconf.types.tuple v then
+ "(${lib.concatMapStringsSep ", " mkValueStringDconf v._elements})"
+ else if builtins.isString v then
+ "'${v}'"
+ else mkValueStringDefault {} v;
+
+ /* mkKeyValueDefault wrapper that handles dconf INI quirks. */
+ mkKeyValueDconf = mkKeyValueDefault { mkValueString = mkValueStringDconf; } "=";
+
+ /* Generates INI in dconf keyfile style.
+ * The main differences of the format is that it requires strings to be quoted and has a tuple type (`lib.dconf.mkTuple`).
+ */
+ toDconfINI = attrs: toINI { mkKeyValue = mkKeyValueDconf; } (flattenAttrs (x: lib.types.isType lib.dconf.types.tuple x) "/" attrs);
/* Generates JSON from an arbitrary (non-function) value.
* For more information see the documentation of the builtin.
diff --git a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
index c53474144d270..bfc7d405f25cb 100644
--- a/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
+++ b/nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
@@ -125,6 +125,18 @@
would in NixOS 22.05 and earlier.
+
+
+ The programs.dconf module now supports
+ configuration using the Nix language. This allows you to
+ configure settings of apps and DEs (if they use
+ dconf) declaratively without having to use
+ extraGSettingsOverrides which has some
+ problems noted in
+ this
+ issue.
+
+
PHP now defaults to PHP 8.1, updated from 8.0.
@@ -651,6 +663,14 @@
emacs-gtk.
+
+
+ The option programs.dconf.packages has been
+ removed, use
+ programs.dconf.profiles.user.databases
+ instead.
+
+
riak package removed along with
diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md
index 863bf95b55f3d..1c202fd8f9682 100644
--- a/nixos/doc/manual/release-notes/rl-2211.section.md
+++ b/nixos/doc/manual/release-notes/rl-2211.section.md
@@ -51,6 +51,11 @@ In addition to numerous new and upgraded packages, this release has the followin
Alternatively, you can remove the `hostPlatform` line and use NixOS like you
would in NixOS 22.05 and earlier.
+- The `programs.dconf` module now supports configuration using the Nix language.
+ This allows you to configure settings of apps and DEs (if they use `dconf`)
+ declaratively without having to use `extraGSettingsOverrides` which has some
+ problems noted in [this issue](https://github.com/NixOS/nixpkgs/issues/54150).
+
- PHP now defaults to PHP 8.1, updated from 8.0.
- `protonup` has been aliased to and replaced by `protonup-ng` due to upstream not maintaining it.
@@ -212,6 +217,8 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).
- Emacs now uses the Lucid toolkit by default instead of GTK because of stability and compatibility issues.
Users who still wish to remain using GTK can do so by using `emacs-gtk`.
+- The option `programs.dconf.packages` has been removed, use `programs.dconf.profiles.user.databases` instead.
+
- riak package removed along with `services.riak` module, due to lack of maintainer to update the package.
- ppd files in `pkgs.cups-drv-rastertosag-gdi` are now gzipped. If you refer to such a ppd file with its path (e.g. via [hardware.printers.ensurePrinters](options.html#opt-hardware.printers.ensurePrinters)) you will need to append `.gz` to the path.
diff --git a/nixos/modules/i18n/input-method/ibus.nix b/nixos/modules/i18n/input-method/ibus.nix
index 520db128acd9f..2acf27eeb3c04 100644
--- a/nixos/modules/i18n/input-method/ibus.nix
+++ b/nixos/modules/i18n/input-method/ibus.nix
@@ -66,7 +66,7 @@ in
# Without dconf enabled it is impossible to use IBus
programs.dconf.enable = true;
- programs.dconf.packages = [ ibusPackage ];
+ programs.dconf.profiles.ibus.databases = [ (pkgs.dconf-utils.mkDconfDb "${ibusPackage}/etc/dconf/db/ibus.d") ];
services.dbus.packages = [
ibusPackage
diff --git a/nixos/modules/programs/dconf.nix b/nixos/modules/programs/dconf.nix
index 7261a143528ff..802cf82af671b 100644
--- a/nixos/modules/programs/dconf.nix
+++ b/nixos/modules/programs/dconf.nix
@@ -1,56 +1,55 @@
{ config, lib, pkgs, ... }:
-with lib;
-
let
cfg = config.programs.dconf;
- cfgDir = pkgs.symlinkJoin {
- name = "dconf-system-config";
- paths = map (x: "${x}/etc/dconf") cfg.packages;
- postBuild = ''
- mkdir -p $out/profile
- mkdir -p $out/db
- '' + (
- concatStringsSep "\n" (
- mapAttrsToList (
- name: path: ''
- ln -s ${path} $out/profile/${name}
- ''
- ) cfg.profiles
- )
- ) + ''
- ${pkgs.dconf}/bin/dconf update $out/db
- '';
- };
+
+ asFileDb = val:
+ let db =
+ if lib.isAttrs val && !lib.isDerivation val then
+ pkgs.dconf-utils.mkDconfDb "${pkgs.writeTextDir "dconf/db" (lib.generators.toDconfINI val)}/dconf"
+ else val;
+ in "file-db:${db}";
in
{
- ###### interface
+ imports = [
+ (lib.mkRemovedOptionModule [ "programs" "dconf" "packages" ] "This option is not supported anymore, you should use `programs.dconf.profiles..databases` instead.")
+ ];
options = {
programs.dconf = {
- enable = mkEnableOption (lib.mdDoc "dconf");
+ enable = lib.mkEnableOption (lib.mdDoc "dconf");
+
+ profiles = lib.mkOption {
+ type = with lib.types; attrsOf (submodule {
+ options = {
+ enableUserDb = lib.mkOption {
+ type = bool;
+ default = true;
+ description = lib.mdDoc "Add `user-db:user` at the beginning of the profile.";
+ };
- profiles = mkOption {
- type = types.attrsOf types.path;
- default = {};
- description = lib.mdDoc "Set of dconf profile files, installed at {file}`/etc/dconf/profiles/«name»`.";
- internal = true;
+ databases = lib.mkOption {
+ type = with lib.types; listOf (oneOf [ attrs str path package ]);
+ default = [];
+ description = lib.mdDoc "List of data sources for the profile. An element can be an attrset, or the path of an already compiled database.";
+ };
+ };
+ });
+ description = lib.mdDoc "Attrset of dconf profiles.";
};
- packages = mkOption {
- type = types.listOf types.package;
- default = [];
- description = lib.mdDoc "A list of packages which provide dconf profiles and databases in {file}`/etc/dconf`.";
+ defaultProfile = lib.mkOption {
+ type = with lib.types; nullOr str;
+ default = null;
+ description = lib.mdDoc "The default dconf profile.";
};
};
};
- ###### implementation
-
- config = mkIf (cfg.profiles != {} || cfg.enable) {
- environment.etc.dconf = mkIf (cfg.profiles != {} || cfg.packages != []) {
- source = cfgDir;
- };
+ config = lib.mkIf cfg.enable {
+ environment.etc = lib.attrsets.mapAttrs' (name: value: lib.nameValuePair "dconf/profile/${name}" {
+ text = lib.concatMapStrings (x: "${x}\n") ((lib.optional value.enableUserDb "user-db:user") ++ (map asFileDb value.databases));
+ }) cfg.profiles;
services.dbus.packages = [ pkgs.dconf ];
@@ -59,8 +58,9 @@ in
# For dconf executable
environment.systemPackages = [ pkgs.dconf ];
- # Needed for unwrapped applications
- environment.sessionVariables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.dconf.lib}/lib/gio/modules" ];
+ environment.sessionVariables = {
+ # Needed for unwrapped applications
+ GIO_EXTRA_MODULES = [ "${pkgs.dconf.lib}/lib/gio/modules" ];
+ } // (if cfg.defaultProfile != null then { DCONF_PROFILE = cfg.defaultProfile; } else {});
};
-
}
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 1c3881bef2de2..f6699eb84d819 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -229,39 +229,13 @@ in
systemd.user.services.dbus.wantedBy = [ "default.target" ];
- programs.dconf.profiles.gdm =
- let
- customDconf = pkgs.writeTextFile {
- name = "gdm-dconf";
- destination = "/dconf/gdm-custom";
- text = ''
- ${optionalString (!cfg.gdm.autoSuspend) ''
- [org/gnome/settings-daemon/plugins/power]
- sleep-inactive-ac-type='nothing'
- sleep-inactive-battery-type='nothing'
- sleep-inactive-ac-timeout=0
- sleep-inactive-battery-timeout=0
- ''}
- '';
+ programs.dconf.profiles.gdm.databases = [ "${gdm}/share/gdm/greeter-dconf-defaults" ] ++ lib.lists.optional cfg.gdm.autoSuspend {
+ org.gnome.settings-daemon.plugins.power = {
+ sleep-inactive-ac-type = "nothing";
+ sleep-inactive-battery-type = "nothing";
+ sleep-inactive-ac-timeout = 0;
+ sleep-inactive-battery-timeout = 0;
};
-
- customDconfDb = pkgs.stdenv.mkDerivation {
- name = "gdm-dconf-db";
- buildCommand = ''
- ${pkgs.dconf}/bin/dconf compile $out ${customDconf}/dconf
- '';
- };
- in pkgs.stdenv.mkDerivation {
- name = "dconf-gdm-profile";
- buildCommand = ''
- # Check that the GDM profile starts with what we expect.
- if [ $(head -n 1 ${gdm}/share/dconf/profile/gdm) != "user-db:user" ]; then
- echo "GDM dconf profile changed, please update gdm.nix"
- exit 1
- fi
- # Insert our custom DB behind it.
- sed '2ifile-db:${customDconfDb}' ${gdm}/share/dconf/profile/gdm > $out
- '';
};
# Use AutomaticLogin if delay is zero, because it's immediate.
diff --git a/pkgs/development/libraries/dconf/utils.nix b/pkgs/development/libraries/dconf/utils.nix
new file mode 100644
index 0000000000000..d7c2955a241b2
--- /dev/null
+++ b/pkgs/development/libraries/dconf/utils.nix
@@ -0,0 +1,10 @@
+{ runCommand, dconf }:
+
+{
+ # Builds a dconf database from a keyfile directory
+ mkDconfDb = dir: runCommand "dconf-db" {
+ nativeBuildInputs = [ dconf ];
+ } ''
+ dconf compile $out ${dir}
+ '';
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 05d687b152e39..ba60e14af69a9 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -3703,6 +3703,8 @@ with pkgs;
dconf = callPackage ../development/libraries/dconf { };
+ dconf-utils = callPackage ../development/libraries/dconf/utils.nix { };
+
ddate = callPackage ../tools/misc/ddate { };
ddosify = callPackage ../development/tools/ddosify { };