# 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//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, ... }: let greeter = pkgs.writeShellScript "tuigreet-fortune" '' exec ${pkgs.tuigreet}/bin/tuigreet \ --time --remember \ --greeting "$(${pkgs.fortune}/bin/fortune)" \ --cmd niri-session ''; in { # --- Session / login --- # NOTE: getting systemd deprecation warning. # See https://github.com/niri-wm/niri/issues/254 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 (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 = "${greeter}"; user = "greeter"; }; }; # Let tuigreet write its cache (for --remember). systemd.services.greetd.serviceConfig = { Type = "idle"; StandardInput = "tty"; StandardOutput = "tty"; StandardError = "journal"; # Better for debugging TTYReset = true; TTYVHangup = true; TTYVTDisallocate = true; }; # --- Audio (playback base; kusanagi adds rtkit/jack/32-bit for pro audio) --- services.pulseaudio.enable = false; services.pipewire = { enable = true; alsa.enable = true; pulse.enable = true; }; # --- 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; 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"; # Silently deny geolocation instead of prompting ("Website would like # your location"). 2 = block, 0 = ask (default), 1 = allow. Per-site # exceptions still override this (padlock icon → Location → Allow). "permissions.default.geo" = 2; # Likewise silently deny "Website would like to send notifications". "permissions.default.desktop-notification" = 2; # Remove the "Profiles" selector button from the toolbar by turning off # the multi-profile feature (Firefox 138+). false = no Profiles button. "browser.profiles.enabled" = false; }; # Note: Firefox View ("View recent browsing across windows and devices") # can't be disabled via pref or policy on modern Firefox — the old # browser.tabs.firefox-view pref was removed in Firefox 123. Remove its # toolbar button manually (right-click the icon → Remove from Toolbar); # the choice persists in the profile. # Restrict the available search engines to exactly these five, in this # order, with DuckDuckGo as default. DuckDuckGo/Google/Wikipedia/eBay are # built-in; only Searx is added. Bing/Amazon/Perplexity (the other # built-ins) are removed. SearchEngines works on regular Firefox as of v139. policies.SearchEngines = { Default = "DuckDuckGo"; Remove = [ "Bing" "Amazon.com" "Perplexity" ]; Add = [ { Name = "Searx"; URLTemplate = "https://searx.be/search?q={searchTerms}"; Method = "GET"; IconURL = "https://searx.be/favicon.ico"; Alias = "searx"; } ]; # NOTE: these are in alphabetical order :( Order = [ "DuckDuckGo" "Searx" "Wikipedia (en)" "eBay" "Google" ]; }; # Auto-installed extensions. normal_installed = installed but the user can # still disable/remove them (force_installed would lock them in). The GUIDs # must match each add-on's internal ID for the policy to take effect. policies.ExtensionSettings = { # uBlock Origin: content/ad blocker. "uBlock0@raymondhill.net" = { install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; installation_mode = "normal_installed"; }; # Proton Pass: password manager + passkeys (replaces KeePassXC). "78272b6fa58f4a1abaac99321d503a20@proton.me" = { install_url = "https://addons.mozilla.org/firefox/downloads/latest/proton-pass/latest.xpi"; installation_mode = "normal_installed"; }; }; policies.PasswordManagerEnabled = false; }; # --- Cursor --- # Both hosts use the Adwaita cursor theme (package below). The theme name must # resolve on the icon path, else clients fall back to a themeless arrow with no # pointer/hand cursor. Matches the shared niri config.kdl cursor block. environment.sessionVariables = { XCURSOR_THEME = "Adwaita"; XCURSOR_SIZE = "24"; }; # --- 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 adwaita-icon-theme # Adwaita cursor + icon theme on the icon path (both # hosts set XCURSOR_THEME=Adwaita; without this the pointer cursor is missing) ]; # --- 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 nerd-fonts.symbols-only adwaita-fonts ]; }; }