feat(displays): declarative nomarchy.monitors + nwg-displays arranger
Add a per-output monitor schema (name / resolution / position / scale / transform / mirror / bitdepth / vrr / disable) that generates Hyprland `monitor` rules, keeping the ,preferred,auto,1 wildcard as the fallback. Hyprland applies the rules on hotplug, so a declared external/dock output arranges itself on connect (no kanshi -- it fights Hyprland's own output management). Default [] -> wildcard only, so no change for existing setups; set wayland.windowManager.hyprland.settings.monitor directly to override. nwg-displays ships behind nomarchy.displays.enable (default true) as an interactive arranger -- a helper to discover values; the declarative config stays the source of truth (its output file isn't sourced). Remaining (roadmap): docked/undocked profile switching, workspace-to-monitor binding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,19 @@ let
|
||||
# (rofi.nix renders the same list). Edit them in ./keybinds.nix.
|
||||
keybinds = import ./keybinds.nix;
|
||||
mkBind = b: "${b.mods}, ${b.key}, ${b.action}";
|
||||
|
||||
# A nomarchy.monitors entry -> a Hyprland `monitor` rule. Unset optional
|
||||
# fields are omitted; `resolution = "disable"` collapses to the short form.
|
||||
monitorRule = m:
|
||||
if m.resolution == "disable" then "${m.name}, disable"
|
||||
else lib.concatStringsSep ", " (
|
||||
[ m.name m.resolution (toString m.position) (toString m.scale) ]
|
||||
++ lib.optionals (m.transform != null) [ "transform" (toString m.transform) ]
|
||||
++ lib.optionals (m.mirror != null) [ "mirror" m.mirror ]
|
||||
++ lib.optionals (m.bitdepth != null) [ "bitdepth" (toString m.bitdepth) ]
|
||||
++ lib.optionals (m.vrr != null) [ "vrr" (toString m.vrr) ]
|
||||
++ lib.optional (m.extra != "") m.extra
|
||||
);
|
||||
in
|
||||
{
|
||||
wayland.windowManager.hyprland = lib.mkIf config.nomarchy.hyprland.enable {
|
||||
@@ -59,9 +72,12 @@ in
|
||||
"$mod" = "SUPER";
|
||||
"$terminal" = config.nomarchy.terminal;
|
||||
|
||||
# mkDefault so a downstream `monitor = [...]` replaces it with a
|
||||
# plain assignment (the live ISO uses mkForce for the same reason).
|
||||
monitor = lib.mkDefault [ ",preferred,auto,1" ];
|
||||
# `,preferred,auto,1` is the wildcard fallback for any output not in
|
||||
# nomarchy.monitors; the generated rules are appended and win by name,
|
||||
# and Hyprland applies them on hotplug. mkDefault so a downstream
|
||||
# `monitor = [...]` replaces the lot (the live ISO uses mkForce too).
|
||||
monitor = lib.mkDefault
|
||||
([ ",preferred,auto,1" ] ++ map monitorRule config.nomarchy.monitors);
|
||||
|
||||
# exec-once is a list at normal priority, so downstream additions
|
||||
# CONCATENATE (your autostart runs alongside ours) rather than
|
||||
@@ -183,4 +199,12 @@ in
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# nwg-displays: interactive monitor arranger (applies live via hyprctl and
|
||||
# writes a config file). A helper to find values for nomarchy.monitors —
|
||||
# the declarative config stays the source of truth (we don't source its
|
||||
# output). Gated on its toggle; pointless without the Hyprland session.
|
||||
home.packages = lib.optionals
|
||||
(config.nomarchy.hyprland.enable && config.nomarchy.displays.enable)
|
||||
[ pkgs.nwg-displays ];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user