diff --git a/hosts/flubber-machine/default.nix b/hosts/flubber-machine/default.nix index 5fa069a..5756b29 100755 --- a/hosts/flubber-machine/default.nix +++ b/hosts/flubber-machine/default.nix @@ -85,10 +85,13 @@ # monitors, see `modules/desktop/monitors` monitors.enable = true; - monitors.monitors = [ - { name = "DP-2"; scale = 1.0; } - { name = "DP-3"; scale = 2.0; vrr = true; } - { name = "HDMI-A-1"; scale = 1.0; } + monitors.monitors = let + p1080 = { width = 1920; height = 1080; }; + p2160 = { width = 3840; height = 2160; }; + in [ + { name = "HDMI-A-1"; scale = 1.0; resolution = p1080; position = { x = -p1080.width; y = 0; }; } + { name = "DP-2"; scale = 1.0; primary = true; resolution = p1080; position = { x = 0; y = 0; }; } + { name = "DP-3"; scale = 2.0; vrr = true; resolution = p2160; position = { x = p1080.width; y = 0; }; } ]; }; software = { diff --git a/modules/desktop/monitors.nix b/modules/desktop/monitors.nix index 5aea8af..793d865 100644 --- a/modules/desktop/monitors.nix +++ b/modules/desktop/monitors.nix @@ -1,33 +1,64 @@ { lib, config, pkgs, ... }: with lib; +with lib.my; let cfg = config.modules.desktop.monitors; in { options.modules.desktop.monitors = { enable = mkEnableOption "manually configure monitor settings, use if manual configuration is needed"; monitors = mkOption { - type = types.listOf types.attrs; - description = '' - a list of monitor configurations. each entry should be an attribute set with the following keys: - - `name`: The name of the monitor to configure - - `scale`: The scale factor to apply to the monitor - - `vrr`?: Whether or not the display supports variable refresh rate. Defaults to false - note: the first monitor in the list will be considered the "primary" monitor - ''; + type = types.listOf (types.submodule { + options = { + name = mkOption { + type = types.str; + description = "the monitor name to configure. easily fetchable from `niri msg outputs`"; + example = "eDP-1"; + }; + scale = mkOpt (types.nullOr types.float) 1.0; + vrr = mkEnableOption "whether or not to enable VRR (variable refresh rate)"; + primary = mkEnableOption "whether or not the monitor is the primary monitor"; + resolution = mkOpt (types.nullOr (types.submodule { + options = { + width = mkOption { type = types.int; }; + height = mkOption { type = types.int; }; + }; + })) null; + position = mkOpt (types.nullOr (types.submodule { + options = { + x = mkOption { type = types.int; }; + y = mkOption { type = types.int; }; + }; + })) null; + }; + }); example = [ - { name = "eDP-1"; scale = 2.0; } - { name = "HDMI-1"; scale = 1.0; } + { name = "eDP-1"; scale = 2.0; primary = true; } + { name = "HDMI-1"; scale = 1.0; vrr = true; } ]; }; }; config = mkIf cfg.enable { + assertions = [ + { + assertion = builtins.length (builtins.filter (m: m.primary) cfg.monitors) <= 1; + message = "only one monitor should be marked as primary"; + } + ]; + hm.programs.niri.settings.outputs = builtins.listToAttrs (builtins.map (monitor: { name = monitor.name; value = { scale = monitor.scale; - variable-refresh-rate = monitor.vrr or false; + variable-refresh-rate = monitor.vrr; + focus-at-startup = monitor.primary; + position = monitor.position; + } // optionalAttrs (monitor.resolution != null) { + mode = { + width = monitor.resolution.width; + height = monitor.resolution.height; + }; }; }) cfg.monitors); };