2026-03-28 13:42:35 +00:00
|
|
|
{ config, pkgs, lib, inputs, ... }:
|
2026-01-05 10:26:20 +00:00
|
|
|
|
2025-12-02 21:23:06 +00:00
|
|
|
{
|
2026-04-01 21:14:16 +01:00
|
|
|
config = lib.mkIf (config.networking.hostName == "FredOS-Macbook") {
|
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
|
|
|
tlp
|
|
|
|
|
vesktop
|
|
|
|
|
adwaita-icon-theme
|
|
|
|
|
mission-center
|
|
|
|
|
vlc
|
2026-06-01 15:29:25 +01:00
|
|
|
gnome-text-editor
|
2026-05-18 10:48:22 +01:00
|
|
|
proton-vpn
|
2026-04-01 21:14:16 +01:00
|
|
|
onlyoffice-desktopeditors
|
2026-05-02 00:38:42 -07:00
|
|
|
woeusb
|
2026-05-11 09:30:36 -07:00
|
|
|
vscodium
|
2026-04-01 21:14:16 +01:00
|
|
|
];
|
|
|
|
|
|
2026-06-01 15:29:25 +01:00
|
|
|
programs.geary.enable = true;
|
|
|
|
|
|
2026-05-16 12:42:27 +01:00
|
|
|
nix.settings.max-jobs = 0;
|
|
|
|
|
|
2026-04-01 21:14:16 +01:00
|
|
|
services.tlp.enable = false;
|
|
|
|
|
services.power-profiles-daemon.enable = true;
|
|
|
|
|
|
|
|
|
|
boot.loader.systemd-boot.configurationLimit = 5;
|
|
|
|
|
boot.initrd.systemd.enable = true;
|
2026-05-14 10:44:32 +01:00
|
|
|
|
2026-05-17 12:58:06 +01:00
|
|
|
# Allow video group (fred) to write to /sys/class/backlight and /sys/class/leds
|
|
|
|
|
# (screen brightness and keyboard backlight)
|
|
|
|
|
hardware.acpilight.enable = true;
|
|
|
|
|
|
2026-05-15 12:17:12 +01:00
|
|
|
services.logind.settings.Login = {
|
|
|
|
|
HandleLidSwitch = "suspend";
|
|
|
|
|
HandleLidSwitchExternalPower = "suspend";
|
2026-05-15 12:12:04 +01:00
|
|
|
};
|
|
|
|
|
|
2026-05-19 17:39:38 +01:00
|
|
|
# Disable-while-typing daemon for the bcm5974 touchpad.
|
|
|
|
|
# Hyprland's built-in DWT doesn't work because the keyboard and
|
|
|
|
|
# touchpad share the same USB device, breaking libinput's pairing.
|
|
|
|
|
# A libinput quirk (AttrKeyboardIntegration=internal) was tried but
|
|
|
|
|
# caused libinput to permanently inhibit the touchpad.
|
2026-05-18 17:30:00 +01:00
|
|
|
systemd.services.macbook-dwt = {
|
|
|
|
|
description = "Disable touchpad while typing (bcm5974)";
|
|
|
|
|
after = [ "systemd-udevd.service" ];
|
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
serviceConfig = {
|
|
|
|
|
Type = "simple";
|
|
|
|
|
Restart = "on-failure";
|
|
|
|
|
RestartSec = 3;
|
2026-05-19 17:41:42 +01:00
|
|
|
ExecStopPost = pkgs.writeShellScript "dwt-uninhibit" ''
|
|
|
|
|
for p in /sys/class/input/event*/device/name; do
|
|
|
|
|
if grep -q bcm5974 "$p" 2>/dev/null; then
|
|
|
|
|
echo 0 > "''${p%/name}/inhibited"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
true
|
|
|
|
|
'';
|
2026-05-18 17:30:00 +01:00
|
|
|
ExecStart = "${pkgs.python3.withPackages (p: [])}/bin/python3 ${pkgs.writeText "macbook-dwt.py" ''
|
|
|
|
|
import glob, os, select, struct, time
|
|
|
|
|
|
|
|
|
|
EVENT_SIZE = struct.calcsize("llHHi")
|
|
|
|
|
EV_KEY = 0x01
|
2026-05-19 17:44:35 +01:00
|
|
|
DWT_TIMEOUT = 0.4
|
2026-05-19 17:31:53 +01:00
|
|
|
# Modifier keycodes — don't inhibit touchpad for these
|
|
|
|
|
MODIFIERS = {42, 54, 29, 97, 56, 100, 125, 126} # L/R Shift, Ctrl, Alt, Super
|
2026-05-18 17:30:00 +01:00
|
|
|
|
|
|
|
|
def find_event(name):
|
|
|
|
|
for p in sorted(glob.glob("/sys/class/input/event*/device/name")):
|
|
|
|
|
with open(p) as f:
|
|
|
|
|
if name in f.read():
|
|
|
|
|
return p.split("/")[4]
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
tp = find_event("bcm5974")
|
|
|
|
|
kb = find_event("Apple Internal Keyboard")
|
|
|
|
|
if not tp or not kb:
|
|
|
|
|
raise SystemExit(f"Devices not found: touchpad={tp}, keyboard={kb}")
|
|
|
|
|
|
|
|
|
|
inhibit = f"/sys/class/input/{tp}/device/inhibited"
|
|
|
|
|
active = False
|
|
|
|
|
last_key = 0.0
|
|
|
|
|
|
|
|
|
|
with open(f"/dev/input/{kb}", "rb") as f:
|
|
|
|
|
try:
|
|
|
|
|
while True:
|
|
|
|
|
timeout = max(0, DWT_TIMEOUT - (time.monotonic() - last_key)) if active else None
|
|
|
|
|
r, _, _ = select.select([f], [], [], timeout)
|
|
|
|
|
if r:
|
|
|
|
|
data = os.read(f.fileno(), EVENT_SIZE * 64)
|
|
|
|
|
for off in range(0, len(data) - EVENT_SIZE + 1, EVENT_SIZE):
|
2026-05-19 17:31:53 +01:00
|
|
|
_, _, typ, code, val = struct.unpack("llHHi", data[off:off + EVENT_SIZE])
|
|
|
|
|
if typ == EV_KEY and val and code not in MODIFIERS:
|
2026-05-18 17:30:00 +01:00
|
|
|
last_key = time.monotonic()
|
|
|
|
|
if not active:
|
|
|
|
|
open(inhibit, "w").write("1")
|
|
|
|
|
active = True
|
|
|
|
|
if active and time.monotonic() - last_key >= DWT_TIMEOUT:
|
|
|
|
|
open(inhibit, "w").write("0")
|
|
|
|
|
active = False
|
|
|
|
|
finally:
|
|
|
|
|
open(inhibit, "w").write("0")
|
|
|
|
|
|
|
|
|
|
main()
|
|
|
|
|
''}";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-17 13:47:59 +01:00
|
|
|
home-manager.users.fred = { pkgs, ... }: {
|
2026-05-17 20:38:30 +01:00
|
|
|
wayland.windowManager.hyprland.settings.monitor = [{
|
|
|
|
|
output = "";
|
|
|
|
|
mode = "preferred";
|
|
|
|
|
position = "auto";
|
|
|
|
|
scale = "auto";
|
|
|
|
|
}];
|
2026-05-17 13:18:26 +01:00
|
|
|
|
2026-05-17 13:47:59 +01:00
|
|
|
# wob reads 0-100 integers from a FIFO and shows a progress bar overlay
|
|
|
|
|
systemd.user.services.wob = {
|
|
|
|
|
Unit = {
|
|
|
|
|
Description = "Wayland OSD Bar";
|
|
|
|
|
After = [ "graphical-session.target" ];
|
|
|
|
|
PartOf = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
Service = {
|
|
|
|
|
Type = "simple";
|
|
|
|
|
ExecStart = "${pkgs.writeShellScript "wob-start" ''
|
|
|
|
|
rm -f "%t/wob.fifo"
|
|
|
|
|
mkfifo "%t/wob.fifo"
|
|
|
|
|
tail -f "%t/wob.fifo" | ${pkgs.wob}/bin/wob
|
|
|
|
|
''}";
|
|
|
|
|
ExecStopPost = "${pkgs.coreutils}/bin/rm -f %t/wob.fifo";
|
|
|
|
|
Restart = "on-failure";
|
|
|
|
|
};
|
|
|
|
|
Install.WantedBy = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-18 16:53:12 +01:00
|
|
|
systemd.user.services.ghostty-daemon = {
|
|
|
|
|
Unit = {
|
|
|
|
|
Description = "Ghostty warm instance (no window)";
|
|
|
|
|
After = [ "graphical-session.target" ];
|
|
|
|
|
PartOf = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
Service = {
|
|
|
|
|
Type = "simple";
|
|
|
|
|
ExecStart = "${pkgs.ghostty}/bin/ghostty --initial-window=false";
|
2026-05-18 16:57:05 +01:00
|
|
|
Restart = "always";
|
2026-05-18 16:53:12 +01:00
|
|
|
};
|
|
|
|
|
Install.WantedBy = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.user.services.nemo-warmup = {
|
|
|
|
|
Unit = {
|
|
|
|
|
Description = "Pre-warm Nemo file manager libraries";
|
|
|
|
|
After = [ "graphical-session.target" ];
|
|
|
|
|
PartOf = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
Service = {
|
|
|
|
|
Type = "oneshot";
|
|
|
|
|
ExecStart = "${pkgs.nemo}/bin/nemo --quit";
|
|
|
|
|
};
|
|
|
|
|
Install.WantedBy = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
|
2026-05-17 13:18:26 +01:00
|
|
|
systemd.user.services.kbd-backlight-init = {
|
|
|
|
|
Unit = {
|
|
|
|
|
Description = "Set keyboard backlight to 10% on login";
|
|
|
|
|
After = [ "graphical-session.target" ];
|
|
|
|
|
PartOf = [ "graphical-session.target" ];
|
|
|
|
|
};
|
|
|
|
|
Service = {
|
|
|
|
|
Type = "oneshot";
|
|
|
|
|
ExecStart = "${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight set 10%";
|
|
|
|
|
};
|
|
|
|
|
Install.WantedBy = [ "graphical-session.target" ];
|
|
|
|
|
};
|
2026-05-14 10:44:32 +01:00
|
|
|
};
|
2026-04-01 21:14:16 +01:00
|
|
|
};
|
2025-12-02 21:23:06 +00:00
|
|
|
}
|