Skip to content

Multi Monitor

NullString1 edited this page Jan 13, 2026 · 1 revision

Multi-Monitor Setup

Configuring multiple displays in NullOS with Hyprland.

Overview

Hyprland supports multi-monitor setups with per-monitor configuration for:

  • Resolution and refresh rate
  • Position and rotation
  • Scale and transform
  • Wallpapers
  • Workspaces

Quick Start

Automatic Configuration

Hyprland auto-detects monitors:

# List connected monitors
hyprctl monitors

# Sample output:
# Monitor eDP-1 (ID 0):
#   1920x1080@60Hz at 0x0
#   scale: 1.00
#   ...

Basic Configuration

In home/hyprland/settings.nix:

monitor = [
  "eDP-1,1920x1080@60,0x0,1"
  "HDMI-A-1,1920x1080@60,1920x0,1"
];

Format: name,resolution@rate,position,scale


Monitor Naming

Find Monitor Names

# While displays are connected
hyprctl monitors

# Shows:
# Monitor HDMI-A-1 (ID 1):
#   ...

Common Names

Laptops:

  • eDP-1 - Internal laptop display
  • eDP-2 - Less common second internal display

External:

  • HDMI-A-1, HDMI-A-2 - HDMI ports
  • DP-1, DP-2, DP-3 - DisplayPort
  • DVI-D-1 - DVI port
  • VGA-1 - VGA port (rare)

NVIDIA: When using NVIDIA, names may include HDMI-1-0 format.


Resolution & Refresh Rate

Standard Resolution

monitor = [
  "HDMI-A-1,1920x1080@60,auto,1"
];

High Refresh Rate

monitor = [
  "DP-1,2560x1440@144,auto,1"
];

4K Display

monitor = [
  "HDMI-A-1,3840x2160@60,auto,1.5"  # With scaling
];

List Available Modes

# Get supported resolutions/rates
hyprctl monitors | grep -A 20 "Monitor HDMI-A-1"

Or use GUI tool:

nwg-displays

Positioning

Automatic Positioning

monitor = [
  "eDP-1,1920x1080@60,auto,1"
  "HDMI-A-1,1920x1080@60,auto,1"
];

Hyprland arranges monitors automatically.

Manual Positioning

monitor = [
  # Laptop screen at 0,0
  "eDP-1,1920x1080@60,0x0,1"
  
  # External monitor to the right
  "HDMI-A-1,1920x1080@60,1920x0,1"
];

Coordinates:

  • 0x0 - Top-left corner
  • 1920x0 - 1920 pixels to the right
  • 0x1080 - 1080 pixels down

Vertical Stacking

monitor = [
  # Top monitor
  "HDMI-A-1,1920x1080@60,0x0,1"
  
  # Bottom monitor
  "HDMI-A-2,1920x1080@60,0x1080,1"
];

Complex Layout

monitor = [
  # Center main display
  "DP-1,2560x1440@144,0x0,1"
  
  # Left vertical display
  "HDMI-A-1,1920x1080@60,-1080x0,1,transform,1"
  
  # Right display
  "HDMI-A-2,1920x1080@60,2560x0,1"
];

Scaling

Fractional Scaling

monitor = [
  # 1.5x scaling for 4K
  "HDMI-A-1,3840x2160@60,auto,1.5"
  
  # 2x scaling for very high DPI
  "eDP-1,2880x1800@60,auto,2"
];

Common scales:

  • 1 - No scaling (1080p, 1440p)
  • 1.25 - Small increase (2K on 24")
  • 1.5 - Recommended for 4K 27"
  • 2 - Apple Retina style (4K 24")

Per-Monitor DPI

Different monitors can have different scales:

monitor = [
  "eDP-1,1920x1080@60,0x0,1"      # Laptop: no scaling
  "HDMI-A-1,3840x2160@60,1920x0,1.5"  # 4K: scaled
];

Rotation & Transform

Rotate Display

monitor = [
  "HDMI-A-1,1920x1080@60,auto,1,transform,1"
];

Transform values:

  • 0 - Normal
  • 1 - 90° clockwise
  • 2 - 180°
  • 3 - 270° clockwise
  • 4 - Flipped
  • 5 - Flipped + 90°
  • 6 - Flipped + 180°
  • 7 - Flipped + 270°

Vertical Monitor

monitor = [
  # Main horizontal
  "DP-1,2560x1440@144,0x0,1"
  
  # Side vertical
  "HDMI-A-1,1920x1080@60,2560x0,1,transform,1"
];

Note: Position uses rotated dimensions.


Mirroring

Mirror Displays

monitor = [
  "eDP-1,1920x1080@60,0x0,1"
  "HDMI-A-1,1920x1080@60,0x0,1,mirror,eDP-1"
];

Clone with Different Scaling

monitor = [
  "eDP-1,1920x1080@60,0x0,1"
  "HDMI-A-1,3840x2160@60,0x0,2,mirror,eDP-1"
];

Disabling Monitors

Disable Specific Monitor

monitor = [
  "eDP-1,disable"  # Turn off laptop screen
  "HDMI-A-1,1920x1080@60,0x0,1"
];

Conditional Disable

# When lid closed, disable laptop screen
bindl = [
  ",switch:on:Lid Switch,exec,hyprctl keyword monitor eDP-1,disable"
  ",switch:off:Lid Switch,exec,hyprctl keyword monitor eDP-1,1920x1080@60,0x0,1"
];

Per-Monitor Configuration

Wallpapers

With hyprpaper:

# hyprpaper.conf
preload = ~/wallpapers/wall1.png
preload = ~/wallpapers/wall2.png

wallpaper = eDP-1,~/wallpapers/wall1.png
wallpaper = HDMI-A-1,~/wallpapers/wall2.png

Workspaces

Bind workspaces to specific monitors:

workspace = [
  "1, monitor:eDP-1"
  "2, monitor:eDP-1"
  "3, monitor:HDMI-A-1"
  "4, monitor:HDMI-A-1"
];

Or default monitor per workspace:

workspace = [
  "1, monitor:eDP-1, default:true"
  "3, monitor:HDMI-A-1, default:true"
];

Dynamic Configuration

Runtime Changes

# Change resolution
hyprctl keyword monitor HDMI-A-1,1920x1080@60,auto,1

# Disable monitor
hyprctl keyword monitor eDP-1,disable

# Enable monitor
hyprctl keyword monitor eDP-1,preferred,auto,1

Monitor Hotplug

Hyprland automatically handles monitor connection/disconnection.

Auto-enable:

monitor = [
  ",preferred,auto,1"  # Catch-all for unknown monitors
];

Laptop Configurations

Docked Mode

monitor = [
  # Disable laptop screen when docked
  "eDP-1,disable"
  
  # Use external monitors
  "HDMI-A-1,2560x1440@144,0x0,1"
  "HDMI-A-2,1920x1080@60,2560x0,1"
];

Portable Mode

monitor = [
  # Only laptop screen
  "eDP-1,1920x1080@60,0x0,1"
];

Presentation Mode

monitor = [
  # Mirror to projector
  "eDP-1,1920x1080@60,0x0,1"
  "HDMI-A-1,1920x1080@60,0x0,1,mirror,eDP-1"
];

Gaming Monitor

Optimized for Gaming

monitor = [
  "DP-1,2560x1440@165,0x0,1"
];

# In Hyprland config
misc {
  vrr = 1  # Variable refresh rate (G-Sync/FreeSync)
}

env = [
  "WLR_DRM_NO_ATOMIC,1"  # If screen tearing
];

GUI Configuration Tools

nwg-displays

Install via home/nwg-displays.nix:

nwg-displays

Features:

  • Visual monitor positioning
  • Resolution/refresh rate selection
  • Generates Hyprland config
  • Test before applying

wdisplays

Alternative tool:

nix-shell -p wdisplays --run wdisplays

Configuration Examples

Dual Monitor Setup

monitor = [
  # Left monitor (vertical)
  "DP-1,1920x1080@60,0x180,1,transform,3"
  
  # Center main monitor
  "HDMI-A-1,2560x1440@144,1080x0,1"
  
  # Right monitor
  "DP-2,1920x1080@60,3640x180,1"
];

workspace = [
  "1, monitor:HDMI-A-1, default:true"  # Main on center
  "2, monitor:HDMI-A-1"
  "3, monitor:DP-1"     # Code on left
  "4, monitor:DP-2"     # Chat on right
];

Triple Monitor Gaming

monitor = [
  # Left
  "HDMI-A-1,1920x1080@60,0x0,1"
  
  # Center (main gaming)
  "DP-1,2560x1440@165,1920x0,1"
  
  # Right
  "HDMI-A-2,1920x1080@60,4480x0,1"
];

workspace = [
  "1, monitor:DP-1, default:true"     # Game
  "2, monitor:HDMI-A-1, default:true" # Discord
  "3, monitor:HDMI-A-2, default:true" # Music/Browser
];

Ultrawide + Laptop

monitor = [
  # Ultrawide main
  "DP-1,3440x1440@144,0x0,1"
  
  # Laptop below
  "eDP-1,1920x1080@60,760x1440,1"
];

workspace = [
  "1, monitor:DP-1"
  "2, monitor:DP-1"
  "3, monitor:DP-1"
  "9, monitor:eDP-1"  # Monitoring workspace
  "10, monitor:eDP-1" # Music
];

Waybar Integration

Per-Monitor Waybar

# In waybar config
{
  "output": "HDMI-A-1",
  "layer": "top",
  ...
}

Multiple configs:

# waybar-main.json for DP-1
# waybar-secondary.json for HDMI-A-1

# Launch both
exec-once = [
  "waybar -c ~/.config/waybar/main.json"
  "waybar -c ~/.config/waybar/secondary.json"
];

Environment Variables

Monitor-Specific

env = [
  # Force monitor for specific apps
  "WLR_DRM_DEVICES,/dev/dri/card1:/dev/dri/card0"
];

NVIDIA Multi-Monitor

env = [
  "WLR_DRM_NO_ATOMIC,1"
  "LIBVA_DRIVER_NAME,nvidia"
  "GBM_BACKEND,nvidia-drm"
  "__GLX_VENDOR_LIBRARY_NAME,nvidia"
];

See NVIDIA for complete NVIDIA setup.


Troubleshooting

Monitor Not Detected

# Check available outputs
hyprctl monitors all

# Force detect
hyprctl reload

# Check kernel detection
ls /sys/class/drm/

Wrong Resolution

# List supported modes
hyprctl monitors | grep "available modes" -A 20

# Try preferred mode
monitor = HDMI-A-1,preferred,auto,1

# Force specific mode
monitor = HDMI-A-1,1920x1080@60,auto,1

Screen Tearing

# Enable VRR
misc {
  vrr = 1
}

# Or disable atomic (NVIDIA)
env = WLR_DRM_NO_ATOMIC,1

Positioning Issues

# Use GUI to visualize
nwg-displays

# Check current positions
hyprctl monitors | grep -E "(Monitor|at)"

Scaling Problems

# Try integer scaling first
monitor = HDMI-A-1,3840x2160@60,auto,2

# If blurry, disable fractional
render {
  explicit_sync = 1
}

Black Screen

# Boot to terminal (Ctrl+Alt+F2)
# Check monitors
DISPLAY=:0 hyprctl monitors

# Try safe mode
monitor = ,preferred,auto,1

Advanced Configuration

Per-Monitor Input

# Different mouse sensitivity per monitor
input {
  # Not directly supported, but workaround:
}

# Use scripts to change on workspace focus
workspace = [
  "1, monitor:eDP-1, on-created-empty:set-high-sens"
  "3, monitor:HDMI-A-1, on-created-empty:set-low-sens"
];

Monitor Profiles

Create scripts for different setups:

# ~/.config/hypr/scripts/monitor-laptop.sh
hyprctl keyword monitor eDP-1,1920x1080@60,0x0,1
hyprctl keyword monitor HDMI-A-1,disable

# ~/.config/hypr/scripts/monitor-desk.sh
hyprctl keyword monitor eDP-1,disable
hyprctl keyword monitor HDMI-A-1,2560x1440@144,0x0,1
hyprctl keyword monitor HDMI-A-2,1920x1080@60,2560x0,1

Bind to keys:

bind = [
  "$mod SHIFT, F7, exec, ~/.config/hypr/scripts/monitor-laptop.sh"
  "$mod SHIFT, F8, exec, ~/.config/hypr/scripts/monitor-desk.sh"
];

Best Practices

  1. Use Preferred Mode - Let Hyprland auto-detect when possible
  2. Integer Scaling - Avoid fractional scaling if possible for clarity
  3. Consistent Refresh Rates - Mixing can cause issues
  4. Test Before Committing - Use hyprctl runtime commands first
  5. Document Layout - Comment your monitor positions

Complete Example

# home/hyprland/monitors.nix
{ config, pkgs, vars, ... }:

{
  wayland.windowManager.hyprland.settings = {
    monitor = [
      # Primary 1440p gaming monitor
      "DP-1,2560x1440@165,1080x0,1"
      
      # Left vertical coding monitor
      "HDMI-A-1,1920x1080@60,0x180,1,transform,3"
      
      # Right communication monitor
      "HDMI-A-2,1920x1080@60,3640x180,1"
      
      # Laptop screen (disabled when docked)
      "eDP-1,disable"
      
      # Catch-all for unknown monitors
      ",preferred,auto,1"
    ];
    
    workspace = [
      # Main monitor - gaming/primary work
      "1, monitor:DP-1, default:true"
      "2, monitor:DP-1"
      
      # Left monitor - code/terminals
      "3, monitor:HDMI-A-1, default:true"
      "4, monitor:HDMI-A-1"
      
      # Right monitor - communication
      "5, monitor:HDMI-A-2, default:true"
      "6, monitor:HDMI-A-2"
    ];
    
    # Enable VRR for gaming
    misc = {
      vrr = 1;
    };
  };
}

Next Steps

Clone this wiki locally