From ef0fc9a5c5250c895d61d95b0c5d7a6e16ed9eb3 Mon Sep 17 00:00:00 2001 From: Emma Thorpe Date: Wed, 10 Jun 2026 16:34:06 +0100 Subject: [PATCH] feat(sway): polkit agent, kanshi, night-light, idle-inhibit, lid policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Polkit authentication agent (lxqt-policykit) as a sway-session user service — programs.sway only enables the daemon, so GUI auth dialogs (nemo mount, NM/blueman) previously failed silently. Corrected the header comment that wrongly claimed the agent was handled system-side. - kanshi for output/display management (safe internal-panel default; a documented template for docked/Cinema-Display profiles). - gammastep night-light (manual location; adjust coordinates). - inhibit_idle on fullscreen so video doesn't get blanked/locked. - logind lid policy on the laptops: suspend on battery, lock on AC. Co-Authored-By: Claude Opus 4.8 (1M context) --- lyrathorpe/home/sway.nix | 78 +++++++++++++++++++++++++++++++++++++-- system/modules/laptop.nix | 7 ++++ 2 files changed, 81 insertions(+), 4 deletions(-) diff --git a/lyrathorpe/home/sway.nix b/lyrathorpe/home/sway.nix index b5d2623..f250716 100644 --- a/lyrathorpe/home/sway.nix +++ b/lyrathorpe/home/sway.nix @@ -1,11 +1,13 @@ # Declarative Sway window manager, status bar, lock, idle and notifications. # Imported via ./desktop.nix, so only graphical hosts get it. # -# The compositor binary, PAM and polkit integration come from the system-level +# The compositor binary, PAM and the polkit *daemon* come from the system-level # programs.sway (see ../swaywm.nix); package = null below reuses it instead of -# pulling a second Sway. home-manager owns the user config (~/.config/sway) and -# wires the systemd user session (sway-session.target), which is what lets the -# swayidle/dunst user services start with the desktop. +# pulling a second Sway. The polkit authentication *agent* (the thing that draws +# the GUI auth dialog) is a user service started here. home-manager owns the user +# config (~/.config/sway) and wires the systemd user session (sway-session.target), +# which is what lets the agent/swayidle/dunst/kanshi user services start with the +# desktop. { pkgs, lib, @@ -99,6 +101,16 @@ in criteria.app_id = "launcher"; command = "floating enable, resize set 800 500"; } + # Don't let swayidle blank/lock during fullscreen video. Two rules cover + # native Wayland (app_id) and XWayland (class) clients. + { + criteria.app_id = ".*"; + command = "inhibit_idle fullscreen"; + } + { + criteria.class = ".*"; + command = "inhibit_idle fullscreen"; + } ]; # Binding modes (submenus). Entered from keybindings below; each action @@ -277,6 +289,64 @@ in # an old entry through fuzzel. services.clipman.enable = true; + # Polkit authentication agent. programs.sway (system) enables the polkit + # daemon but no agent, so GUI privilege prompts (nemo mounting a disk, + # NetworkManager/blueman editing a system resource) would otherwise fail + # silently. lxqt-policykit is a small, toolkit-light agent; bind it to the + # Sway session so it starts and stops with the desktop. + systemd.user.services.polkit-lxqt = { + Unit = { + Description = "lxqt-policykit polkit authentication agent"; + PartOf = [ "graphical-session.target" ]; + After = [ "graphical-session.target" ]; + }; + Service = { + ExecStart = "${pkgs.lxqt.lxqt-policykit}/bin/lxqt-policykit-agent"; + Restart = "on-failure"; + }; + Install.WantedBy = [ "sway-session.target" ]; + }; + + # Output/display management. Reacts to hotplug and applies per-display + # mode/scale/position. Profiles are hardware-specific: the safe default below + # just enables the internal laptop panel; add docked/desktop profiles with the + # real identifiers from `swaymsg -t get_outputs` (e.g. the Mac Pro's Apple + # Cinema Display with its scale, or a docked laptop + external monitor). + services.kanshi = { + enable = true; + settings = [ + { + profile.name = "undocked"; + profile.outputs = [ + { + criteria = "eDP-1"; + status = "enable"; + } + ]; + } + # Example to copy per host (fill in real criteria/mode/scale/position): + # { + # profile.name = "desktop"; + # profile.outputs = [ + # { criteria = "Apple Computer Inc Cinema HD ..."; mode = "2560x1600"; scale = 1.0; position = "0,0"; status = "enable"; } + # ]; + # } + ]; + }; + + # Night light. Manual location (no geoclue dependency); adjust the coordinates + # to taste. Warmer at night, neutral by day. + services.gammastep = { + enable = true; + provider = "manual"; + latitude = 51.5; + longitude = -0.13; # London-ish; set to your actual location + temperature = { + day = 6500; + night = 3700; + }; + }; + # fuzzel: the dmenu picker used by clipman, themed Catppuccin Mocha to match # (fuzzel colours are RRGGBBAA -- 8 hex digits). programs.fuzzel = { diff --git a/system/modules/laptop.nix b/system/modules/laptop.nix index 99bb142..127dd95 100644 --- a/system/modules/laptop.nix +++ b/system/modules/laptop.nix @@ -13,6 +13,13 @@ settings.General.EnableNetworkConfiguration = true; }; + # Lid behaviour: suspend on battery, lock on external power (swayidle's + # before-sleep hook locks before the suspend completes either way). + services.logind.settings.Login = { + HandleLidSwitch = "suspend"; + HandleLidSwitchExternalPower = "lock"; + }; + # Bluetooth. The Asahi MBP loads Apple's BT firmware (see its host config) and # the T400 has an optional BT module; enable bluez on both, with blueman as the # GUI/tray manager for the Sway session.