2023-07-08 18:54:38 +00:00
|
|
|
{ pkgs, config, lib, ... }:
|
|
|
|
|
|
|
|
with config.stylix.fonts;
|
|
|
|
with config.lib.stylix.colors;
|
|
|
|
|
|
|
|
let
|
2023-12-25 03:11:11 +00:00
|
|
|
formatValue = value:
|
|
|
|
if builtins.isBool value
|
|
|
|
then if value then "true" else "false"
|
|
|
|
else builtins.toString value;
|
|
|
|
|
|
|
|
formatSection = path: data:
|
|
|
|
let
|
|
|
|
header = lib.concatStrings (map (p: "[${p}]") path);
|
|
|
|
formatChild = name: formatLines (path ++ [ name ]);
|
|
|
|
children = lib.mapAttrsToList formatChild data;
|
|
|
|
partitioned = lib.partition builtins.isString children;
|
|
|
|
directChildren = partitioned.right;
|
|
|
|
indirectChildren = partitioned.wrong;
|
|
|
|
in
|
|
|
|
lib.optional (directChildren != []) header ++
|
|
|
|
directChildren ++
|
|
|
|
lib.flatten indirectChildren;
|
|
|
|
|
|
|
|
formatLines = path: data:
|
|
|
|
if builtins.isAttrs data
|
|
|
|
then
|
|
|
|
if data?_immutable
|
|
|
|
then
|
|
|
|
if builtins.isAttrs data.value
|
|
|
|
then formatSection (path ++ [ "$i" ]) data.value
|
|
|
|
else "${lib.last path}[$i]=${formatValue data.value}"
|
|
|
|
else formatSection path data
|
|
|
|
else "${lib.last path}=${formatValue data}";
|
|
|
|
|
|
|
|
formatConfig = data:
|
|
|
|
lib.concatStringsSep "\n" (formatLines [] data);
|
|
|
|
|
|
|
|
# Marking a setting as immutable should prevent it being overwritten
|
|
|
|
# through the system settings menu.
|
|
|
|
makeImmutable = value: {
|
|
|
|
_immutable = true;
|
|
|
|
inherit value;
|
|
|
|
};
|
|
|
|
|
|
|
|
# PascalCase is the standard naming for color scheme files. Schemes named
|
|
|
|
# in kebab-case will load when selected manually, but don't work with a
|
|
|
|
# look and feel package.
|
|
|
|
colorschemeSlug = lib.concatStrings
|
|
|
|
(builtins.filter builtins.isString
|
|
|
|
(builtins.split "[^a-zA-Z]" scheme));
|
|
|
|
|
|
|
|
colorEffect = {
|
|
|
|
ColorEffect = 0;
|
|
|
|
ColorAmount = 0;
|
|
|
|
ContrastEffect = 1;
|
|
|
|
ContrastAmount = 0.5;
|
|
|
|
IntensityEffect = 0;
|
|
|
|
IntensityAmount = 0;
|
|
|
|
};
|
|
|
|
|
2023-07-08 18:54:38 +00:00
|
|
|
colors = {
|
|
|
|
BackgroundNormal = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
BackgroundAlternate = "${base01-rgb-r},${base01-rgb-g},${base01-rgb-b}";
|
2023-12-22 20:24:40 +00:00
|
|
|
DecorationFocus = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
|
|
|
|
DecorationHover = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
|
2023-07-08 18:54:38 +00:00
|
|
|
ForegroundNormal = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
|
|
|
ForegroundActive = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
2023-07-09 17:52:46 +00:00
|
|
|
ForegroundInactive = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
2023-07-08 18:54:38 +00:00
|
|
|
ForegroundLink = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
2023-12-25 03:11:11 +00:00
|
|
|
ForegroundVisited = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
2023-07-08 18:54:38 +00:00
|
|
|
ForegroundNegative = "${base08-rgb-r},${base08-rgb-g},${base08-rgb-b}";
|
|
|
|
ForegroundNeutral = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
|
|
|
|
ForegroundPositive = "${base0B-rgb-r},${base0B-rgb-g},${base0B-rgb-b}";
|
2023-07-09 17:52:46 +00:00
|
|
|
};
|
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
colorscheme = {
|
2023-07-08 18:54:38 +00:00
|
|
|
General = {
|
2023-12-25 03:11:11 +00:00
|
|
|
ColorScheme = colorschemeSlug;
|
|
|
|
Name = scheme;
|
2023-07-08 18:54:38 +00:00
|
|
|
};
|
|
|
|
|
2023-07-09 17:52:46 +00:00
|
|
|
"ColorEffects:Disabled" = colorEffect;
|
|
|
|
"ColorEffects:Inactive" = colorEffect;
|
2023-07-08 18:54:38 +00:00
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
"Colors:Window" = colors;
|
|
|
|
"Colors:View" = colors;
|
2023-07-08 18:54:38 +00:00
|
|
|
"Colors:Button" = colors;
|
2023-12-25 03:11:11 +00:00
|
|
|
"Colors:Tooltip" = colors;
|
2023-07-08 18:54:38 +00:00
|
|
|
"Colors:Complementary" = colors;
|
2023-07-09 17:54:42 +00:00
|
|
|
"Colors:Selection" = colors // {
|
2023-12-22 20:24:40 +00:00
|
|
|
BackgroundNormal = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
|
|
|
|
BackgroundAlternate = "${base0D-rgb-r},${base0D-rgb-g},${base0D-rgb-b}";
|
2023-12-25 03:11:11 +00:00
|
|
|
ForegroundNormal = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
ForegroundActive = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
ForegroundInactive = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
ForegroundLink = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
ForegroundVisited = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
2023-07-09 17:54:42 +00:00
|
|
|
};
|
2023-07-08 18:54:38 +00:00
|
|
|
|
|
|
|
WM = {
|
|
|
|
activeBlend = "${base0A-rgb-r},${base0A-rgb-g},${base0A-rgb-b}";
|
|
|
|
activeBackground = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
activeForeground = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
|
|
|
inactiveBlend = "${base03-rgb-r},${base03-rgb-g},${base03-rgb-b}";
|
|
|
|
inactiveBackground = "${base00-rgb-r},${base00-rgb-g},${base00-rgb-b}";
|
|
|
|
inactiveForeground = "${base05-rgb-r},${base05-rgb-g},${base05-rgb-b}";
|
2023-12-25 03:11:11 +00:00
|
|
|
};
|
|
|
|
};
|
2023-07-09 15:39:13 +00:00
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
wallpaperMetadata = {
|
|
|
|
KPlugin = {
|
|
|
|
Id = "stylix";
|
|
|
|
Name = "Stylix";
|
2023-07-08 18:54:38 +00:00
|
|
|
};
|
2023-12-25 03:11:11 +00:00
|
|
|
};
|
2023-07-08 18:54:38 +00:00
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
lookAndFeelMetadata = {
|
|
|
|
KPlugin = {
|
|
|
|
Id = "stylix";
|
|
|
|
Name = "Stylix";
|
|
|
|
Description = "Generated from your Home Manager configuration";
|
|
|
|
ServiceTypes = [ "Plasma/LookAndFeel" ];
|
|
|
|
Website = "https://github.com/danth/stylix";
|
|
|
|
};
|
2023-07-08 18:54:38 +00:00
|
|
|
};
|
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
lookAndFeelDefaults = {
|
|
|
|
kwinrc."org.kde.kdecoration2".library = "org.kde.breeze";
|
|
|
|
plasmarc.Theme.name = "default";
|
2023-12-23 12:34:41 +00:00
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
kdeglobals = {
|
|
|
|
KDE.widgetStyle = "Breeze";
|
|
|
|
General.ColorScheme = colorschemeSlug;
|
|
|
|
};
|
2023-07-13 00:14:22 +00:00
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
# This only takes effect on the first login.
|
|
|
|
Wallpaper.Image = "stylix";
|
|
|
|
};
|
2023-07-13 00:14:22 +00:00
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
# Contains a wallpaper package, a colorscheme file, and a look and feel
|
|
|
|
# package which depends on both.
|
|
|
|
themePackage = pkgs.runCommandLocal "stylix-kde-theme" {
|
|
|
|
colorscheme = formatConfig colorscheme;
|
|
|
|
wallpaperMetadata = builtins.toJSON wallpaperMetadata;
|
|
|
|
wallpaperImage = config.stylix.image;
|
|
|
|
lookAndFeelMetadata = builtins.toJSON lookAndFeelMetadata;
|
|
|
|
lookAndFeelDefaults = formatConfig lookAndFeelDefaults;
|
|
|
|
} ''
|
|
|
|
PATH="${pkgs.imagemagick}/bin:$PATH"
|
|
|
|
|
|
|
|
wallpaper="$out/share/wallpapers/stylix"
|
|
|
|
lookandfeel="$out/share/plasma/look-and-feel/stylix"
|
|
|
|
|
|
|
|
writeText () {
|
|
|
|
mkdir -p "$(dirname "$2")"
|
|
|
|
echo "$1" >"$2"
|
2023-07-13 00:14:22 +00:00
|
|
|
}
|
2023-12-25 03:11:11 +00:00
|
|
|
|
|
|
|
mkdir -p "$wallpaper/contents/images"
|
|
|
|
magick "$wallpaperImage" -thumbnail 400x250 "$wallpaper/contents/screenshot.png"
|
|
|
|
dimensions="$(identify -ping -format '%wx%h' "$wallpaperImage")"
|
|
|
|
magick "$wallpaperImage" "$wallpaper/contents/images/$dimensions.png"
|
|
|
|
|
|
|
|
writeText "$colorscheme" "$out/share/color-schemes/${colorschemeSlug}.colors"
|
|
|
|
writeText "$wallpaperMetadata" "$wallpaper/metadata.json"
|
|
|
|
writeText "$lookAndFeelMetadata" "$lookandfeel/metadata.json"
|
|
|
|
writeText "$lookAndFeelDefaults" "$lookandfeel/contents/defaults"
|
|
|
|
'';
|
|
|
|
|
2023-12-25 18:17:41 +00:00
|
|
|
# The cursor theme can be configured through a look and feel package,
|
|
|
|
# however its size cannot.
|
|
|
|
kcminputrc = {
|
|
|
|
Mouse = {
|
|
|
|
cursorSize = makeImmutable (toString config.stylix.cursor.size);
|
|
|
|
cursorTheme = makeImmutable config.stylix.cursor.name;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
kded5rc = {
|
|
|
|
# The gtkconfig module copies settings from KDE to the GTK configuration.
|
|
|
|
# This blocks Home Manager activation because the same files are already
|
|
|
|
# managed by Stylix.
|
|
|
|
Module-gtkconfig = makeImmutable {
|
|
|
|
autoload = false;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2023-12-25 03:11:11 +00:00
|
|
|
kdeglobals = {
|
|
|
|
KDE.LookAndFeelPackage = makeImmutable "stylix";
|
|
|
|
|
|
|
|
General = rec {
|
|
|
|
font = makeImmutable "${sansSerif.name},${toString sizes.applications},-1,5,50,0,0,0,0,0";
|
|
|
|
fixed = makeImmutable "${monospace.name},${toString sizes.terminal},-1,5,50,0,0,0,0,0";
|
|
|
|
desktopFont = makeImmutable "${sansSerif.name},${toString sizes.desktop},-1,5,50,0,0,0,0,0";
|
|
|
|
menuFont = desktopFont;
|
|
|
|
taskbarFont = desktopFont;
|
|
|
|
toolBarFont = desktopFont;
|
|
|
|
smallestReadableFont = desktopFont;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
configPackage = pkgs.runCommandLocal "stylix-kde-config" {
|
|
|
|
kcminputrc = formatConfig kcminputrc;
|
2023-12-25 18:17:41 +00:00
|
|
|
kded5rc = formatConfig kded5rc;
|
|
|
|
kdeglobals = formatConfig kdeglobals;
|
2023-12-25 03:11:11 +00:00
|
|
|
} ''
|
|
|
|
mkdir "$out"
|
|
|
|
echo "$kcminputrc" >"$out/kcminputrc"
|
2023-12-25 18:17:41 +00:00
|
|
|
echo "$kded5rc" >"$out/kded5rc"
|
|
|
|
echo "$kdeglobals" >"$out/kdeglobals"
|
2023-07-13 00:14:22 +00:00
|
|
|
'';
|
|
|
|
|
2023-07-08 18:54:38 +00:00
|
|
|
in {
|
|
|
|
options.stylix.targets.kde.enable =
|
2023-07-22 12:29:12 +00:00
|
|
|
config.lib.stylix.mkEnableTarget "KDE" pkgs.stdenv.hostPlatform.isLinux;
|
2023-07-08 18:54:38 +00:00
|
|
|
|
|
|
|
config = lib.mkIf config.stylix.targets.kde.enable {
|
2023-12-25 03:11:11 +00:00
|
|
|
home.packages = [ themePackage ];
|
|
|
|
xdg.systemDirs.config = [ "${configPackage}" ];
|
|
|
|
|
|
|
|
# plasma-apply-wallpaperimage is necessary to change the wallpaper
|
|
|
|
# after the first login.
|
|
|
|
#
|
|
|
|
# plasma-apply-lookandfeel is only here to trigger a hot reload, the theme
|
|
|
|
# would still be applied without it if you logged out and back in.
|
|
|
|
#
|
|
|
|
# Home Manager clears $PATH before running the activation script, but we
|
|
|
|
# want to avoid installing these tools explicitly because that would pull
|
|
|
|
# in large dependencies for people who aren't actually using KDE.
|
|
|
|
# The workaround used is to assume a list of common paths where the tools
|
|
|
|
# might be installed, and look there. The ideal solution would require
|
|
|
|
# changes to KDE to make it possible to update the wallpaper through
|
|
|
|
# config files alone.
|
|
|
|
home.activation.stylixLookAndFeel = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
|
|
|
globalPath () {
|
2023-12-28 14:26:15 +00:00
|
|
|
for dir in /run/current-system/sw/bin /usr/bin /bin; do
|
|
|
|
if [ -f "$dir/$1" ]; then
|
|
|
|
echo "$dir/$1"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
2023-12-25 03:11:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wallpaperImage="$(globalPath plasma-apply-wallpaperimage)"
|
|
|
|
if [ -n "$wallpaperImage" ]; then
|
|
|
|
"$wallpaperImage" ${themePackage}/share/wallpapers/stylix
|
2023-12-28 14:26:15 +00:00
|
|
|
else
|
|
|
|
echo "Skipping plasma-apply-wallpaperimage because it's not installed"
|
2023-12-25 03:11:11 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
lookAndFeel="$(globalPath plasma-apply-lookandfeel)"
|
|
|
|
if [ -n "$lookAndFeel" ]; then
|
|
|
|
"$lookAndFeel" --apply stylix
|
2023-12-28 14:26:15 +00:00
|
|
|
else
|
|
|
|
echo "Skipping plasma-apply-lookandfeel because it's not installed"
|
2023-12-25 03:11:11 +00:00
|
|
|
fi
|
|
|
|
'';
|
2023-07-08 18:54:38 +00:00
|
|
|
};
|
|
|
|
}
|