useNautilus = false assigns FileChooser to gtk and drops the nautilus D-Bus registration; the GTK3 dialog then follows the same settings.ini as thunar. The deployed niri-portals.conf is gone: /etc/xdg-desktop-portal/ ranks below /etc/xdg/, where programs.niri writes the same file. Its one extra key, Inhibit=none, moves to desktop.nix.
231 lines
11 KiB
Nix
231 lines
11 KiB
Nix
# ABOUTME: Deploys the XDG configs from the moonarch repo and the package set.
|
|
# ABOUTME: Niri, Quickshell, terminal, portals and the packages without a theme.
|
|
|
|
{ pkgs, moonarchSrc, moonarchPkgs, moonarchThemes, ... }:
|
|
|
|
let
|
|
xdg = "${moonarchSrc}/defaults/xdg";
|
|
# waypaper calls `swww`/`swww-daemon`, but the maintained successor ships as
|
|
# `awww`. The symlinks keep the shared config working unchanged.
|
|
swww-compat = pkgs.runCommand "swww-compat" { } ''
|
|
mkdir -p "$out/bin"
|
|
ln -s ${pkgs.awww}/bin/awww "$out/bin/swww"
|
|
ln -s ${pkgs.awww}/bin/awww-daemon "$out/bin/swww-daemon"
|
|
'';
|
|
|
|
wallpaper = "${moonarchSrc}/defaults/backgrounds/wallpaper.jpg";
|
|
|
|
# The FHS path the wallpaper is published under, provided by the tmpfiles
|
|
# link further down. waypaper's config names /usr/share/moonarch/wallpaper.jpg
|
|
# and cannot keep a store path: waypaper reads only the copy in the home
|
|
# directory, which is seeded once and never rewritten, so a store path baked
|
|
# into it survives exactly until the next moonarch bump collects the old
|
|
# source — and then the session comes up black. A path that activation
|
|
# relinks holds across every bump.
|
|
wallpaperPath = "/usr/share/backgrounds/moonarch.jpg";
|
|
|
|
waypaperConfig = pkgs.runCommand "waypaper-config.ini" { } ''
|
|
substitute ${xdg}/waypaper/config.ini "$out" \
|
|
--replace-fail /usr/share/moonarch/wallpaper.jpg ${wallpaperPath}
|
|
'';
|
|
|
|
# niri prefers ~/.config/niri/config.kdl over /etc/niri/config.kdl and does not
|
|
# merge the two, so a home config would otherwise replace the whole deployed
|
|
# one. This seed pulls the system config back in through `include`, which niri
|
|
# 26.04 really does load (verified by pointing an include at a broken file and
|
|
# watching `niri validate` fail on it).
|
|
#
|
|
# It exists for nwg-displays, which writes the output layout to
|
|
# ~/.config/niri/monitor.kdl and adds an include for it here. Without a
|
|
# config.kdl in the home directory nwg-displays refuses to start at all
|
|
# ("Couldn't find niri config directory", exit 0, no window).
|
|
niriUserConfig = pkgs.writeText "niri-config.kdl" ''
|
|
include "/etc/niri/config.kdl"
|
|
'';
|
|
in
|
|
{
|
|
# --- XDG configs -> /etc/xdg/ ---
|
|
#
|
|
# Deployed verbatim from the moonarch repo; defaults/ stays the single
|
|
# source of truth for both distros.
|
|
#
|
|
# defaults/xdg/walker/ is not deployed: the Quickshell launcher covers it.
|
|
environment.etc = {
|
|
# niri reads /etc/niri, not /etc/xdg/niri. Both are provided: the former
|
|
# is what niri actually loads, the latter keeps the layout consistent with
|
|
# moonarch's tree and with any user config that includes it.
|
|
"niri/config.kdl".source = "${xdg}/niri/config.kdl";
|
|
"xdg/niri/config.kdl".source = "${xdg}/niri/config.kdl";
|
|
"xdg/quickshell/moonarch".source = "${xdg}/quickshell/moonarch";
|
|
"xdg/foot/foot.ini".source = "${xdg}/foot/foot.ini";
|
|
# No xdg/pipewire/ entry: PipeWire does not read /etc/xdg, so the file was
|
|
# deployed and inert. It goes through services.pipewire.configPackages
|
|
# in modules/audio.nix instead.
|
|
# Kept for layout parity with moonarch's tree; waypaper itself only reads
|
|
# the copy in the home directory, seeded below.
|
|
"xdg/waypaper/config.ini".source = waypaperConfig;
|
|
|
|
# No stasis entry: /etc/stasis/ is only its fallback for a missing user
|
|
# config, and the seed below means there never is one.
|
|
|
|
# No xdg-desktop-portal entry: moonarch's niri-portals.conf would be
|
|
# deployed to /etc/xdg-desktop-portal/, and portals.conf(5) searches that
|
|
# path — the build-time sysconfdir — only after every directory in
|
|
# $XDG_CONFIG_DIRS. /etc/xdg is one of those, and it is where NixOS writes
|
|
# the same file from xdg.portal.config.niri, which programs.niri defines.
|
|
# The deployed copy would rank below it and decide nothing. What it carries
|
|
# is set under Portals below instead.
|
|
};
|
|
|
|
# --- Compositor ---
|
|
programs.niri.enable = true;
|
|
|
|
# niri searches $XDG_CONFIG_HOME/niri/config.kdl, then /etc/niri/config.kdl —
|
|
# not /etc/xdg. The system path is used directly, so nothing has to be placed
|
|
# in the home directory to bridge there.
|
|
|
|
# config.kdl spawns the polkit agent by its FHS path
|
|
# (/usr/lib/polkit-gnome/...). Provide that path rather than diverging the
|
|
# config, which moonarch owns.
|
|
systemd.tmpfiles.rules = [
|
|
"d /usr/lib 0755 root root -"
|
|
"L+ /usr/lib/polkit-gnome - - - - ${pkgs.polkit_gnome}/libexec"
|
|
# The wallpaper under its FHS name, for the reason given at wallpaperPath.
|
|
# 'L+' replaces the link on every activation, so it always names the
|
|
# current moonarch source and the seeded waypaper config never goes stale.
|
|
"d /usr/share 0755 root root -"
|
|
"d /usr/share/backgrounds 0755 root root -"
|
|
"L+ ${wallpaperPath} - - - - ${wallpaper}"
|
|
];
|
|
|
|
# --- Portals ---
|
|
#
|
|
# The whole assignment lives here, in the one file NixOS writes. programs.niri
|
|
# defines xdg.portal.config.niri with default=gnome;gtk and Access,
|
|
# FileChooser, Notification and Secret — the same four moonarch's
|
|
# niri-portals.conf carries, which is why that file is not deployed; see the
|
|
# note in environment.etc above. Only what moonarch states beyond them is
|
|
# restated below.
|
|
xdg.portal = {
|
|
enable = true;
|
|
extraPortals = with pkgs; [ xdg-desktop-portal-gnome xdg-desktop-portal-gtk ];
|
|
|
|
# Carried over from moonarch's file verbatim, its reasoning included:
|
|
# xdg-desktop-portal-gtk reports the Inhibit interface as success even
|
|
# though nothing implements it under niri, which makes Firefox skip the
|
|
# native Wayland idle-inhibit. With no backend the browser falls back to
|
|
# zwp_idle_inhibit, which niri honors, so windowed video keeps the screen
|
|
# awake. programs.niri leaves this interface unassigned, so stating it here
|
|
# does not collide with the module's definition.
|
|
config.niri."org.freedesktop.impl.portal.Inhibit" = "none";
|
|
};
|
|
|
|
# The file dialog every portal client opens — Firefox's save dialog among
|
|
# them. The option defaults to true, which registers nautilus with D-Bus and
|
|
# leaves org.freedesktop.impl.portal.FileChooser unassigned, so the
|
|
# default=gnome;gtk line hands it to xdg-desktop-portal-gnome and the dialog
|
|
# is nautilus' own: GTK4 and libadwaita, which draw their own style and never
|
|
# read gtk-theme-name out of settings.ini. That is why the dialog came up in
|
|
# Adwaita while thunar, a GTK3 program reading /etc/xdg/gtk-3.0/settings.ini,
|
|
# was themed.
|
|
#
|
|
# Off, the module assigns the interface to gtk and drops the nautilus D-Bus
|
|
# registration; xdg-desktop-portal-gtk then builds the dialog with GTK3 from
|
|
# that same settings.ini. It is set through the option rather than through
|
|
# config.niri above because only the option covers the D-Bus half — and
|
|
# setting the key in both places would collide. Screencasting is unaffected:
|
|
# niri serves org.gnome.Mutter.ScreenCast itself and only the gnome backend
|
|
# calls it, which is why that one stays in extraPortals.
|
|
programs.niri.useNautilus = false;
|
|
environment.systemPackages = with pkgs; [
|
|
# XDG plumbing, before anything that calls into it. xdg-terminal-exec
|
|
# resolves a caller to whichever TerminalEmulator entry the XDG data
|
|
# hierarchy offers — footclient here, which reuses the server niri starts
|
|
# — so nothing downstream has to name an emulator.
|
|
xdg-terminal-exec
|
|
|
|
# Own programs
|
|
moonarchPkgs.moonarch-scripts
|
|
|
|
xwayland-satellite
|
|
|
|
# Bar, notifications, clipboard.
|
|
# Neither waybar nor swaync are installed: the Quickshell bar owns both
|
|
# roles. The "kept as a reserve" notes in moonarch's config date from the
|
|
# migration and do not apply to a fresh setup.
|
|
quickshell
|
|
libnotify
|
|
cliphist
|
|
wl-clipboard
|
|
|
|
# The launcher's start prefix, and why the launcher needs one: Quickshell
|
|
# spawns applications as its own children, and a child inherits its
|
|
# parent's cgroup, so everything started from the launcher lands inside
|
|
# quickshell.service — which systemd kills whole on every restart of the
|
|
# unit (KillMode=control-group is the default). A crash of the bar took the
|
|
# open browser with it, which counted each one as a crash until it stopped
|
|
# restoring the session at all. app2unit wraps systemd-run to put
|
|
# each application in its own transient app-*.scope, the same shape niri
|
|
# gives the windows it spawns itself.
|
|
app2unit
|
|
|
|
# Display and wallpaper
|
|
wlsunset
|
|
brightnessctl
|
|
awww
|
|
swww-compat
|
|
waypaper
|
|
|
|
# Terminal
|
|
foot
|
|
# Media
|
|
vlc
|
|
viewnior
|
|
|
|
# System
|
|
upower
|
|
polkit_gnome
|
|
nwg-displays
|
|
wl-color-picker
|
|
|
|
stasis
|
|
claude-code
|
|
galculator
|
|
];
|
|
|
|
# Polkit agent for privilege prompts inside the session.
|
|
security.polkit.enable = true;
|
|
# The setuid pkexec wrapper is opt-in and off by default. Without it pkexec
|
|
# refuses to run at all, which takes the camera and battery toggles with it —
|
|
# both reach their privileged half through pkexec.
|
|
security.polkit.enablePkexecWrapper = true;
|
|
|
|
# nixpkgs.config.allowUnfree covers the system build only. `nix profile` and
|
|
# friends evaluate a flake purely, so they see neither that setting nor
|
|
# ~/.config/nixpkgs/config.nix, and refuse every unfree package. The hosts
|
|
# already declare unfree as acceptable; this makes the imperative commands
|
|
# agree instead of demanding NIXPKGS_ALLOW_UNFREE=1 in front of each one.
|
|
# Set by PAM at session start, so it takes a re-login, not just a rebuild.
|
|
environment.sessionVariables.NIXPKGS_ALLOW_UNFREE = "1";
|
|
|
|
# Seed configs for programs that read only from the home directory and have
|
|
# no system-wide fallback. 'C' copies once and never overwrites, so user
|
|
# edits survive. This is what moonarch's post-install.sh does imperatively.
|
|
#
|
|
# No Kvantum entry: the theme is a package now, found through XDG_DATA_DIRS.
|
|
# The rule it replaces never worked in a user unit anyway — 'C' recreates the
|
|
# destination with the source's mode, and a store directory is r-xr-xr-x, so
|
|
# copying into it failed silently for anyone but root and left the directory
|
|
# empty (systemd 261, reproduced).
|
|
systemd.user.tmpfiles.rules = [
|
|
"C %h/.config/waypaper/config.ini 0644 - - - ${waypaperConfig}"
|
|
# stasis prefers the user config over /etc and generates its own if none
|
|
# exists, so the moonarch config has to be in place before it starts.
|
|
"C %h/.config/stasis/stasis.rune 0644 - - - ${xdg}/stasis/stasis.rune"
|
|
# No gtklock entry: it reads /etc/xdg, which swaylock could not.
|
|
# nwg-displays needs this file to exist before it will start, and niri would
|
|
# otherwise ignore the monitor.kdl it writes next to it.
|
|
"C %h/.config/niri/config.kdl 0644 - - - ${niriUserConfig}"
|
|
];
|
|
}
|