1
0
Fork 0
mirror of https://github.com/nix-community/home-manager.git synced 2025-12-02 15:11:03 +01:00
home-manager/modules/misc/gtk.nix
Austin Horstman d9915499e3 gtk: refactor to support more modular customization
Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
2025-07-11 11:53:47 -05:00

453 lines
13 KiB
Nix

{ config, lib, ... }:
let
inherit (lib)
literalExpression
mkEnableOption
mkIf
mkOption
optional
optionalAttrs
types
;
cfg = config.gtk;
cfg2 = config.gtk.gtk2;
cfg3 = config.gtk.gtk3;
cfg4 = config.gtk.gtk4;
toIni = lib.generators.toINI {
mkKeyValue =
key: value:
let
value' = if lib.isBool value then lib.boolToString value else toString value;
in
"${lib.escape [ "=" ] key}=${value'}";
};
formatGtk2Option =
n: v:
let
v' =
if lib.isBool v then
lib.boolToString v
else if lib.isString v then
''"${v}"''
else
toString v;
in
"${lib.escape [ "=" ] n} = ${v'}";
themeType = types.submodule {
options = {
package = mkOption {
type = types.nullOr types.package;
default = null;
example = literalExpression "pkgs.gnome.gnome-themes-extra";
description = ''
Package providing the theme. This package will be installed
to your profile. If `null` then the theme
is assumed to already be available in your profile.
For the theme to apply to GTK 4, this option is mandatory.
'';
};
name = mkOption {
type = types.str;
example = "Adwaita";
description = "The name of the theme within the package.";
};
};
};
iconThemeType = types.submodule {
options = {
package = mkOption {
type = types.nullOr types.package;
default = null;
example = literalExpression "pkgs.adwaita-icon-theme";
description = ''
Package providing the icon theme. This package will be installed
to your profile. If `null` then the theme
is assumed to already be available in your profile.
'';
};
name = mkOption {
type = types.str;
example = "Adwaita";
description = "The name of the icon theme within the package.";
};
};
};
cursorThemeType = types.submodule {
options = {
package = mkOption {
type = types.nullOr types.package;
default = null;
example = literalExpression "pkgs.vanilla-dmz";
description = ''
Package providing the cursor theme. This package will be installed
to your profile. If `null` then the theme
is assumed to already be available in your profile.
'';
};
name = mkOption {
type = types.str;
example = "Vanilla-DMZ";
description = "The name of the cursor theme within the package.";
};
size = mkOption {
type = types.nullOr types.int;
default = null;
example = 16;
description = ''
The size of the cursor.
'';
};
};
};
# Helper function to generate the settings attribute set for a given version
mkGtkSettings =
{
font,
theme,
iconTheme,
cursorTheme,
}:
optionalAttrs (font != null) {
gtk-font-name =
let
fontSize = if font.size != null then font.size else 11;
in
"${font.name} ${toString fontSize}";
}
// optionalAttrs (theme != null) { "gtk-theme-name" = theme.name; }
// optionalAttrs (iconTheme != null) { "gtk-icon-theme-name" = iconTheme.name; }
// optionalAttrs (cursorTheme != null) { "gtk-cursor-theme-name" = cursorTheme.name; }
// optionalAttrs (cursorTheme != null && cursorTheme.size != null) {
"gtk-cursor-theme-size" = cursorTheme.size;
};
in
{
meta.maintainers = [ lib.maintainers.rycee ];
imports = [
(lib.mkRemovedOptionModule [ "gtk" "gtk3" "waylandSupport" ] ''
This options is not longer needed and can be removed.
'')
];
options.gtk = {
enable = mkEnableOption "GTK theming and configuration";
# Global settings that act as defaults for version-specific settings
font = mkOption {
type = types.nullOr lib.hm.types.fontType;
default = null;
description = "Default font for all GTK versions.";
};
theme = mkOption {
type = types.nullOr themeType;
default = null;
description = "Default theme for all GTK versions.";
};
iconTheme = mkOption {
type = types.nullOr iconThemeType;
default = null;
description = "Default icon theme for all GTK versions.";
};
cursorTheme = mkOption {
type = types.nullOr cursorThemeType;
default = null;
description = "Default cursor theme for all GTK versions.";
};
# GTK2 options
gtk2 = {
enable = mkEnableOption "GTK 2 configuration" // {
default = true;
};
font = mkOption {
type = types.nullOr lib.hm.types.fontType;
default = cfg.font;
defaultText = literalExpression "config.gtk.font";
description = "Font for GTK 2 applications.";
};
theme = mkOption {
type = types.nullOr themeType;
default = cfg.theme;
defaultText = literalExpression "config.gtk.theme";
description = "Theme for GTK 2 applications.";
};
iconTheme = mkOption {
type = types.nullOr iconThemeType;
default = cfg.iconTheme;
defaultText = literalExpression "config.gtk.iconTheme";
description = "Icon theme for GTK 2 applications.";
};
cursorTheme = mkOption {
type = types.nullOr cursorThemeType;
default = cfg.cursorTheme;
defaultText = literalExpression "config.gtk.cursorTheme";
description = "Cursor theme for GTK 2 applications.";
};
extraConfig = mkOption {
type = types.lines;
default = "";
example = "gtk-can-change-accels = 1";
description = "Extra lines to add to {file}`~/.gtkrc-2.0`.";
};
configLocation = mkOption {
type = types.path;
default = "${config.home.homeDirectory}/.gtkrc-2.0";
defaultText = literalExpression ''"''${config.home.homeDirectory}/.gtkrc-2.0"'';
example = literalExpression ''"''${config.xdg.configHome}/gtk-2.0/gtkrc"'';
description = "The location of the GTK 2 configuration file.";
};
};
# GTK3 Options
gtk3 = {
enable = mkEnableOption "GTK 3 configuration" // {
default = true;
};
font = mkOption {
type = types.nullOr lib.hm.types.fontType;
default = cfg.font;
defaultText = literalExpression "config.gtk.font";
description = "Font for GTK 3 applications.";
};
theme = mkOption {
type = types.nullOr themeType;
default = cfg.theme;
defaultText = literalExpression "config.gtk.theme";
description = "Theme for GTK 3 applications.";
};
iconTheme = mkOption {
type = types.nullOr iconThemeType;
default = cfg.iconTheme;
defaultText = literalExpression "config.gtk.iconTheme";
description = "Icon theme for GTK 3 applications.";
};
cursorTheme = mkOption {
type = types.nullOr cursorThemeType;
default = cfg.cursorTheme;
defaultText = literalExpression "config.gtk.cursorTheme";
description = "Cursor theme for GTK 3 applications.";
};
extraConfig = mkOption {
type =
with types;
attrsOf (oneOf [
bool
int
str
]);
default = { };
example = {
gtk-cursor-blink = false;
gtk-recent-files-limit = 20;
};
description = "Extra settings for {file}`$XDG_CONFIG_HOME/gtk-3.0/settings.ini`.";
};
extraCss = mkOption {
type = types.lines;
default = "";
description = "Extra CSS for {file}`$XDG_CONFIG_HOME/gtk-3.0/gtk.css`.";
};
bookmarks = mkOption {
type = types.listOf types.str;
default = [ ];
example = [ "file:///home/jane/Documents" ];
description = "File browser bookmarks.";
};
};
# GTK4 Options
gtk4 = {
enable = mkEnableOption "GTK 4 configuration" // {
default = true;
};
font = mkOption {
type = types.nullOr lib.hm.types.fontType;
default = cfg.font;
defaultText = literalExpression "config.gtk.font";
description = "Font for GTK 4 applications.";
};
theme = mkOption {
type = types.nullOr themeType;
default = cfg.theme;
defaultText = literalExpression "config.gtk.theme";
description = "Theme for GTK 4 applications.";
};
iconTheme = mkOption {
type = types.nullOr iconThemeType;
default = cfg.iconTheme;
defaultText = literalExpression "config.gtk.iconTheme";
description = "Icon theme for GTK 4 applications.";
};
cursorTheme = mkOption {
type = types.nullOr cursorThemeType;
default = cfg.cursorTheme;
defaultText = literalExpression "config.gtk.cursorTheme";
description = "Cursor theme for GTK 4 applications.";
};
extraConfig = mkOption {
type =
with types;
attrsOf (oneOf [
bool
int
str
]);
default = { };
example = {
gtk-cursor-blink = false;
gtk-recent-files-limit = 20;
};
description = "Extra settings for {file}`$XDG_CONFIG_HOME/gtk-4.0/settings.ini`.";
};
extraCss = mkOption {
type = types.lines;
default = "";
description = "Extra CSS for {file}`$XDG_CONFIG_HOME/gtk-4.0/gtk.css`.";
};
};
};
config = mkIf cfg.enable (
lib.mkMerge [
{
home.packages =
let
collectPackages =
cfgVersion:
lib.filter (pkg: pkg != null) (
optional (cfgVersion.enable && cfgVersion.theme != null) cfgVersion.theme.package
++ optional (cfgVersion.enable && cfgVersion.iconTheme != null) cfgVersion.iconTheme.package
++ optional (cfgVersion.enable && cfgVersion.cursorTheme != null) cfgVersion.cursorTheme.package
++ optional (cfgVersion.enable && cfgVersion.font != null) cfgVersion.font.package
);
allPackages = collectPackages cfg2 ++ collectPackages cfg3 ++ collectPackages cfg4;
in
lib.unique allPackages;
# DConf settings are primarily for GNOME/GTK3/4 apps. We'll source them from gtk3 config.
dconf.settings = mkIf cfg3.enable {
"org/gnome/desktop/interface" =
let
settings = mkGtkSettings {
inherit (cfg3)
font
theme
iconTheme
cursorTheme
;
};
in
lib.filterAttrs (_: v: v != null) {
"font-name" = settings."gtk-font-name" or null;
"gtk-theme" = settings."gtk-theme-name" or null;
"icon-theme" = settings."gtk-icon-theme-name" or null;
"cursor-theme" = settings."gtk-cursor-theme-name" or null;
"cursor-size" = settings."gtk-cursor-theme-size" or null;
};
};
}
# GTK2 Configuration
(mkIf cfg2.enable {
home.file.${cfg2.configLocation} = {
text =
let
settings = mkGtkSettings {
inherit (cfg2)
font
theme
iconTheme
cursorTheme
;
};
settingsText = lib.concatMapStrings (n: "${formatGtk2Option n settings.${n}}\n") (
lib.attrNames settings
);
in
''
${settingsText}${cfg2.extraConfig}
'';
};
home.sessionVariables.GTK2_RC_FILES = cfg2.configLocation;
})
# GTK3 Configuration
(mkIf cfg3.enable {
xdg.configFile = {
"gtk-3.0/settings.ini" = {
text = toIni {
Settings =
mkGtkSettings {
inherit (cfg3)
font
theme
iconTheme
cursorTheme
;
}
// cfg3.extraConfig;
};
};
"gtk-3.0/gtk.css" = mkIf (cfg3.extraCss != "") {
text = cfg3.extraCss;
};
"gtk-3.0/bookmarks" = mkIf (cfg3.bookmarks != [ ]) {
text = lib.concatMapStrings (l: l + "\n") cfg3.bookmarks;
};
};
})
# GTK4 Configuration
(mkIf cfg4.enable (
let
gtk4Css =
lib.optionalString (cfg4.theme != null && cfg4.theme.package != null) ''
/**
* GTK 4 reads the theme configured by gtk-theme-name, but ignores it.
* It does however respect user CSS, so import the theme from here.
**/
@import url("file://${cfg4.theme.package}/share/themes/${cfg4.theme.name}/gtk-4.0/gtk.css");
''
+ cfg4.extraCss;
in
{
xdg.configFile."gtk-4.0/settings.ini" = {
text = toIni {
Settings =
mkGtkSettings {
inherit (cfg4)
font
theme
iconTheme
cursorTheme
;
}
// cfg4.extraConfig;
};
};
xdg.configFile."gtk-4.0/gtk.css" = mkIf (gtk4Css != "") {
text = gtk4Css;
};
}
))
]
);
}