diff options
| author | Henry J. Webster <hwebs@hwebs.info> | 2026-07-30 19:14:09 -0500 |
|---|---|---|
| committer | Henry J. Webster <hwebs@hwebs.info> | 2026-07-30 19:14:09 -0500 |
| commit | ae5ecbb4199844b2b7883d99cd04ef468a03247d (patch) | |
| tree | c1a87d546917c06a076a860862b91d3ea2bea3e5 | |
| parent | 7498147ab59e26ad7a9d9c6e020ac1400e9b9524 (diff) | |
refactor: shared desktop profile for enzo + kusanagi
profiles/desktop.nix becomes a username-agnostic shared base (niri, dconf, the
dark-theme portal fix, greetd, pipewire base, gpg agent, graphics, Firefox with
blank-home/no-bookmarks prefs, common desktop tools, font base). Both hosts now
import it.
Per-host desktop config splits into machines/<host>/desktop.nix:
- enzo: Adwaita cursor + monospace, HiDPI console font, yambar, hwebs groups.
- kusanagi (new file): GNOME/X11, printing/avahi/udisks2, pro-audio
(rtkit/jack/32-bit), gpg ssh support, richer fonts, Bibata cursor, henz
desktop groups, waybar/nm-applet.
Shared profile is username-agnostic (enzo=hwebs, kusanagi=henz): shared desktop
tools moved to environment.systemPackages, per-user groups stay in machine
files. Firefox now owned by the shared profile, so its redundant enable is
dropped from profiles/apps.nix. Dark theme + Firefox tweaks now apply to both
hosts. Both configurations build.
Assisted-by: Claude:claude-opus-4-8
| -rw-r--r-- | machines/enzo/default.nix | 5 | ||||
| -rw-r--r-- | machines/enzo/desktop.nix | 126 | ||||
| -rw-r--r-- | machines/kusanagi/default.nix | 1 | ||||
| -rw-r--r-- | machines/kusanagi/desktop.nix | 119 | ||||
| -rw-r--r-- | profiles/apps.nix | 2 | ||||
| -rw-r--r-- | profiles/desktop.nix | 201 |
6 files changed, 204 insertions, 250 deletions
diff --git a/machines/enzo/default.nix b/machines/enzo/default.nix index 0e9d6e4..bcb92cb 100644 --- a/machines/enzo/default.nix +++ b/machines/enzo/default.nix @@ -3,8 +3,9 @@ { imports = [ - # enzo's own minimal desktop (not the shared profiles/desktop.nix). Add - # ../../profiles/dev.nix or apps.nix here, or one-off packages below, as needed. + # Shared desktop base + enzo-only extras. Add ../../profiles/dev.nix or + # apps.nix here, or one-off packages below, as needed. + ../../profiles/desktop.nix ./desktop.nix inputs.disko.nixosModules.disko diff --git a/machines/enzo/desktop.nix b/machines/enzo/desktop.nix index d92dda3..8375e13 100644 --- a/machines/enzo/desktop.nix +++ b/machines/enzo/desktop.nix @@ -1,135 +1,31 @@ -# Minimal niri desktop for enzo — deliberately separate from ../../profiles/desktop.nix -# so the laptop can grow on its own terms. Add to it (or switch to the shared -# profile) whenever you want more. +# enzo-only desktop extras. The shared niri/dark/audio/firefox base comes from +# ../../profiles/desktop.nix (imported in ./default.nix); this file holds just +# what's specific to the laptop. { pkgs, ... }: { - # --- Session / login --- - programs.niri.enable = true; - programs.dconf.enable = true; - - # Tell the desktop it's in dark mode. Apps read light/dark from - # xdg-desktop-portal's Settings interface (org.freedesktop.appearance - # color-scheme). This dconf default is the value the portal serves. - programs.dconf.profiles.user.databases = [ - { - settings."org/gnome/desktop/interface".color-scheme = "prefer-dark"; - } - ]; - - # Serve color-scheme from the *gtk* portal backend, not gnome. The niri module - # routes Settings to xdg-desktop-portal-gnome (its default), but that backend - # relies on gnome-settings-daemon — absent under bare niri — so it reports - # "no preference" and web content (LibreWolf's prefers-color-scheme) stays - # light even though GTK chrome follows the dark GTK theme. xdg-desktop-portal- - # gtk reads the dconf color-scheme above directly, so pinning Settings to it - # makes the portal actually report dark and content follows. This key merges - # into the niri module's xdg.portal.config.niri. - xdg.portal = { - extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; - config.niri."org.freedesktop.impl.portal.Settings" = "gtk"; - }; - - services.greetd = { - enable = true; - settings.default_session = { - command = "${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd niri-session"; - user = "greeter"; - }; - }; - # Let tuigreet write its cache (for --remember). - systemd.services.greetd.serviceConfig = { - Type = "idle"; - StandardInput = "tty"; - StandardOutput = "tty"; - StandardError = "journal"; - TTYReset = true; - TTYVHangup = true; - TTYVTDisallocate = true; - }; - - # --- Graphics --- - hardware.graphics.enable = true; - - # --- Audio (playback only; no rtkit/jack — enzo isn't for recording). - # If you ever hear dropouts under load, add: security.rtkit.enable = true; - services.pulseaudio.enable = false; - services.pipewire = { - enable = true; - alsa.enable = true; - pulse.enable = true; - }; - - # --- Fonts (minimal) --- - # TODO move to common - fonts = { - enableDefaultPackages = true; - packages = with pkgs; [ - noto-fonts - nerd-fonts.symbols-only - adwaita-fonts - ]; - fontconfig = { - enable = true; - defaultFonts = { - monospace = [ "Adwaita Mono" ]; - }; - }; - }; + # --- Fonts: enzo's monospace (base font packages come from the shared profile) --- + fonts.fontconfig.defaultFonts.monospace = [ "Adwaita Mono" ]; + # --- Cursor --- environment.sessionVariables = { XCURSOR_THEME = "Adwaita"; XCURSOR_SIZE = "24"; }; - # Cursor theme referenced by XCURSOR_THEME / niri's xcursor-theme. Without this # package the Adwaita cursor files aren't on disk, so named shapes (e.g. the # link "pointer"/hand) fail to load and the cursor never changes on hover. - environment.systemPackages = [ pkgs.adwaita-icon-theme ]; + environment.systemPackages = with pkgs; [ + adwaita-icon-theme + yambar # text status bar + ]; - # --- User: groups + niri essentials --- + # --- User: desktop groups (niri essentials) --- users.users.hwebs.extraGroups = [ "audio" "input" ]; - # Firefox: blank home/new-tab and no bookmarks toolbar, delivered as an - # enterprise policy (no profile to manage). Dark theme is not configured here - # — it comes from the desktop portal (color-scheme dconf + Settings=gtk - # above), which Firefox honors for both chrome and web content. (LibreWolf was - # tried instead but forces content light via its fingerprinting protection - # even with resistFingerprinting off, so plain Firefox is the better fit.) - programs.firefox = { - enable = true; - preferencesStatus = "default"; - preferences = { - # Blank home page + blank new tab - "browser.startup.homepage" = "about:blank"; - "browser.startup.page" = 0; # 0 = blank on startup - "browser.newtabpage.enabled" = false; - # Hide the bookmarks toolbar - "browser.toolbars.bookmarks.visibility" = "never"; - }; - }; - - users.users.hwebs.packages = with pkgs; [ - ghostty # terminal - fuzzel # launcher - swaybg # wallpaper - xwayland-satellite # run X11 apps under niri - mako # notifications - libnotify # notify-send - yambar # text status bar - gnupg # gpg - pinentry-gnome3 # passphrase prompt for the gpg agent - ]; - - # --- GPG --- - # Agent + a GTK pinentry (works under niri). enableSSHSupport is left off so - # gpg-agent doesn't hijack the ssh-agent socket for your existing SSH key; - # turn it on only if you sign in via a GPG auth subkey. - programs.gnupg.agent.enable = true; - # --- Console / greeter font (HiDPI panel) --- # The eDP panel is high-density, so the kernel VT and tuigreet render with a # tiny 8x16 font. A large Terminus bitmap font makes the TTY and the greeter diff --git a/machines/kusanagi/default.nix b/machines/kusanagi/default.nix index 10531c2..c39db8e 100644 --- a/machines/kusanagi/default.nix +++ b/machines/kusanagi/default.nix @@ -6,6 +6,7 @@ { imports = [ ../../profiles/desktop.nix + ./desktop.nix ../../profiles/dev.nix ../../profiles/apps.nix ./hardware-configuration.nix diff --git a/machines/kusanagi/desktop.nix b/machines/kusanagi/desktop.nix new file mode 100644 index 0000000..368022e --- /dev/null +++ b/machines/kusanagi/desktop.nix @@ -0,0 +1,119 @@ +# kusanagi-only desktop extras. The shared niri/dark/audio/firefox base comes +# from ../../profiles/desktop.nix (imported in ./default.nix); this file holds +# the workstation's GNOME session, printing/scanning, pro-audio, richer fonts, +# and cursor theme. (Hardware-specific audio/NAS/server config lives in +# ./default.nix.) +{ pkgs, ... }: + +{ + # --- X11 + GNOME (alongside the niri session) --- + services.xserver.enable = true; + services.xserver.xkb = { + layout = "us"; + variant = ""; + }; + services.displayManager.gdm.enable = false; + services.desktopManager.gnome.enable = true; + + # --- Printing / discovery / disks --- + services.printing = { + enable = true; + drivers = with pkgs; [ gutenprint ]; + }; + + # mDNS: printer discovery, and resolves kusanagi's *.local NAS names. + services.avahi = { + enable = true; + nssmdns4 = true; + openFirewall = true; + }; + + # prevent auto-mounting optical disks + services.udisks2.enable = true; + + # --- Pro audio (extends the shared pipewire base) --- + security.rtkit.enable = true; + services.pipewire = { + alsa.support32Bit = true; + jack.enable = true; + wireplumber.enable = true; + }; + + # --- GPG: forward the ssh-agent socket (workstation signs/auths via GPG) --- + programs.gnupg.agent.enableSSHSupport = true; + + # --- Graphics: 32-bit for Steam/Wine --- + hardware.graphics.enable32Bit = true; + + # --- Fonts: workstation extras + defaults (base packages from shared) --- + fonts = { + packages = with pkgs; [ + noto-fonts-cjk-sans + noto-fonts-cjk-serif + inter + ibm-plex + public-sans + ]; + + fontconfig = { + defaultFonts = { + monospace = [ + "Berkeley Mono" + "Liberation Mono" + "Symbols Nerd Font" + ]; + sansSerif = [ + "Liberation Sans" + "Noto Sans" + ]; + serif = [ "Liberation Serif" ]; + emoji = [ "Nerd Font Symbols Only" ]; + }; + + # Force ui-sans-serif and system-ui to resolve correctly + localConf = '' + <?xml version="1.0"?> + <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> + <fontconfig> + <alias> + <family>system-ui</family> + <prefer> + <family>Liberation Sans</family> + </prefer> + </alias> + <alias> + <family>ui-sans-serif</family> + <prefer> + <family>Liberation Sans</family> + </prefer> + </alias> + </fontconfig> + ''; + }; + + fontDir.enable = true; + }; + + # --- Cursor / renderer --- + environment.sessionVariables = { + GSK_RENDERER = "gl"; + XCURSOR_THEME = "Bibata-Modern-Classic"; + XCURSOR_SIZE = "24"; + HYPRCURSOR_THEME = "Bibata-Modern-Classic"; + HYPRCURSOR_SIZE = "24"; + }; + + # --- User: desktop groups (niri essentials + printing). Hardware groups + # (cdrom/optical/sg/scanner) stay in ./default.nix. --- + users.users.henz.extraGroups = [ + "audio" + "lp" + "input" + ]; + + # --- Desktop tools specific to kusanagi (shared ones come from the profile) --- + environment.systemPackages = with pkgs; [ + waybar + networkmanagerapplet + ]; +} diff --git a/profiles/apps.nix b/profiles/apps.nix index 279ef03..84a23e9 100644 --- a/profiles/apps.nix +++ b/profiles/apps.nix @@ -3,7 +3,7 @@ { programs.steam.enable = true; - programs.firefox.enable = true; + # Firefox (with its prefs) is owned by the shared desktop profile. environment.systemPackages = with pkgs; [ itch diff --git a/profiles/desktop.nix b/profiles/desktop.nix index b56ac68..5a47f96 100644 --- a/profiles/desktop.nix +++ b/profiles/desktop.nix @@ -1,36 +1,48 @@ -# Desktop profile: the GNOME+niri graphical shell, login manager, audio, fonts, -# graphics, printing, a terminal, and the gpg agent. Opt-in per machine. +# Shared desktop base: the niri graphical session, login manager, dark theme, +# audio, graphics, a browser, common desktop tools, and a font base. Imported by +# every graphical machine; per-host extras live in machines/<host>/desktop.nix. +# +# Deliberately username-agnostic (enzo uses hwebs, kusanagi uses henz), so this +# file sets NO users.users.*: shared desktop tools go to environment.systemPackages +# and per-user groups live in the machine files. { pkgs, ... }: { - # Enable the X11 windowing system. - services.xserver.enable = true; - - # Configure keymap in X11 - services.xserver.xkb = { - layout = "us"; - variant = ""; - }; + # --- Session / login --- + programs.niri.enable = true; + programs.dconf.enable = true; - # Enable the GNOME Desktop Environment. - services.displayManager.gdm.enable = false; - services.desktopManager.gnome.enable = true; + # Tell the desktop it's in dark mode. Apps read light/dark from + # xdg-desktop-portal's Settings interface (org.freedesktop.appearance + # color-scheme). This dconf default is the value the portal serves. + programs.dconf.profiles.user.databases = [ + { + settings."org/gnome/desktop/interface".color-scheme = "prefer-dark"; + } + ]; - programs.dconf.enable = true; - programs.niri.enable = true; + # Serve color-scheme from the *gtk* portal backend, not gnome. The niri module + # routes Settings to xdg-desktop-portal-gnome (its default), but that backend + # relies on gnome-settings-daemon — absent under bare niri — so it reports + # "no preference" and web content (Firefox's prefers-color-scheme) stays light + # even though GTK chrome follows the dark GTK theme. xdg-desktop-portal-gtk + # reads the dconf color-scheme above directly, so pinning Settings to it makes + # the portal actually report dark and content follows. This key merges into + # the niri module's xdg.portal.config.niri. + xdg.portal = { + extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + config.niri."org.freedesktop.impl.portal.Settings" = "gtk"; + }; # login screen services.greetd = { enable = true; - settings = { - default_session = { - command = "${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd niri-session"; - user = "greeter"; - }; + settings.default_session = { + command = "${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd niri-session"; + user = "greeter"; }; }; - - # This is required to let tuigreet write to its cache (for --remember) + # Let tuigreet write its cache (for --remember). systemd.services.greetd.serviceConfig = { Type = "idle"; StandardInput = "tty"; @@ -41,131 +53,56 @@ TTYVTDisallocate = true; }; - # prevent auto-mounting optical disks - services.udisks2.enable = true; - - # Enable CUPS to print documents. - services.printing = { - enable = true; - drivers = with pkgs; [ - gutenprint - ]; - }; - - # mDNS: printer discovery, and resolves kusanagi's *.local NAS names. - services.avahi = { - enable = true; - nssmdns4 = true; - openFirewall = true; - }; - + # --- Audio (playback base; kusanagi adds rtkit/jack/32-bit for pro audio) --- services.pulseaudio.enable = false; - security.rtkit.enable = true; services.pipewire = { enable = true; alsa.enable = true; - alsa.support32Bit = true; pulse.enable = true; - jack.enable = true; - wireplumber.enable = true; }; - programs.gnupg.agent = { + # --- Graphics --- + hardware.graphics.enable = true; + + # --- GPG agent (kusanagi adds enableSSHSupport) --- + programs.gnupg.agent.enable = true; + + # --- Firefox: blank home/new-tab and no bookmarks toolbar, as an enterprise + # policy (no profile to manage). Dark theme is not configured here — it comes + # from the portal above, which Firefox honors for both chrome and web content. + programs.firefox = { enable = true; - enableSSHSupport = true; + preferencesStatus = "default"; + preferences = { + "browser.startup.homepage" = "about:blank"; + "browser.startup.page" = 0; # 0 = blank on startup + "browser.newtabpage.enabled" = false; + "browser.toolbars.bookmarks.visibility" = "never"; + }; }; + # --- Common desktop tools (system-wide to stay username-agnostic) --- + environment.systemPackages = with pkgs; [ + ghostty # terminal — required to actually use the GUI + fuzzel # launcher + swaybg # wallpaper + xwayland-satellite # run X11 apps under niri + mako # notifications + libnotify # notify-send + gnupg # gpg + pinentry-gnome3 # passphrase prompt for the gpg agent + ]; + + # --- Fonts (base) --- + # Common packages + fontconfig; each machine sets its own defaultFonts (the + # monospace family differs) and any extra font packages. fonts = { enableDefaultPackages = true; - + fontconfig.enable = true; packages = with pkgs; [ - noto-fonts-cjk-sans - noto-fonts-cjk-serif - inter - nerd-fonts.symbols-only noto-fonts - ibm-plex - public-sans + nerd-fonts.symbols-only adwaita-fonts ]; - - fontconfig = { - enable = true; - - defaultFonts = { - monospace = [ - "Berkeley Mono" - "Liberation Mono" - "Symbols Nerd Font" - ]; - sansSerif = [ - "Liberation Sans" - "Noto Sans" - ]; - serif = [ "Liberation Serif" ]; - emoji = [ "Nerd Font Symbols Only" ]; - }; - - # Force ui-sans-serif and system-ui to resolve correctly - localConf = '' - <?xml version="1.0"?> - <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> - <fontconfig> - <alias> - <family>system-ui</family> - <prefer> - <family>Liberation Sans</family> - </prefer> - </alias> - <alias> - <family>ui-sans-serif</family> - <prefer> - <family>Liberation Sans</family> - </prefer> - </alias> - </fontconfig> - ''; - }; - - fontDir.enable = true; }; - - environment.sessionVariables = { - GSK_RENDERER = "gl"; - XCURSOR_THEME = "Bibata-Modern-Classic"; - XCURSOR_SIZE = "24"; - HYPRCURSOR_THEME = "Bibata-Modern-Classic"; - HYPRCURSOR_SIZE = "24"; - }; - - # Graphics setup - hardware.graphics = { - enable = true; - enable32Bit = true; - }; - - users.users.henz.extraGroups = [ - "audio" - "lp" - "input" - ]; - - environment.systemPackages = with pkgs; [ - # notifications (mako = wayland notification daemon, libnotify = notify-send) - mako - libnotify - ]; - - users.users.henz.packages = with pkgs; [ - ghostty # terminal — required to actually use the GUI - gnupg - pinentry-gnome3 - - # niri support tools - waybar - networkmanagerapplet - xwayland-satellite - fuzzel - swaybg - ]; } |
