Monitors
Manage display outputs, resolution, scaling, and tearing.
Monitor Rules
You can configure each display output individually using the monitorrule keyword.
Syntax:
monitorrule=name:Values,Parameter:Values,Parameter:ValuesInfo: If any of the matching fields (
name,make,model,serial) are set, all of the set ones must match to be considered a match. Usewlr-randrto get your monitor's name, make, model, and serial.
Parameters
| Parameter | Type | Values | Description |
|---|---|---|---|
name | string | Any | Match by monitor name (supports regex) |
make | string | Any | Match by monitor manufacturer |
model | string | Any | Match by monitor model |
serial | string | Any | Match by monitor serial number |
width | integer | 0-9999 | Monitor width |
height | integer | 0-9999 | Monitor height |
refresh | float | 0.001-9999.0 | Monitor refresh rate |
x | integer | 0-99999 | X position |
y | integer | 0-99999 | Y position |
scale | float | 0.01-100.0 | Monitor scale |
vrr | integer | 0, 1 | Enable variable refresh rate |
hdr | integer | 0, 1 | Enable hdr support |
hdr_min_lum | float | 0.0-10000.0 | Mastering display minimum luminance, cd/m² (0 = unset) |
hdr_max_lum | float | 0.0-10000.0 | Mastering display peak luminance, also sent as max_cll, cd/m² (0 = unset) |
hdr_max_avg_lum | float | 0.0-10000.0 | Max frame-average light level (max_fall), cd/m² (0 = unset) |
hdr_force | integer | 0, 1 | Enable HDR even when the EDID does not advertise BT.2020/PQ |
icc | string | - | Path to an ICC profile applied as the output color transform (e.g. /usr/share/color/icc/MyDisplay.icc). Mutually exclusive with hdr: when both are set, HDR takes precedence and the ICC profile is ignored. Set hdr:0 to use the ICC profile |
rr | integer | 0-7 | Monitor transform |
custom | integer | 0, 1 | Enable custom mode (not supported on all displays — may cause black screen) |
disable | integer | 0, 1 | Disable the monitor |
Transform Values
| Value | Rotation |
|---|---|
0 | No transform |
1 | 90° counter-clockwise |
2 | 180° counter-clockwise |
3 | 270° counter-clockwise |
4 | 180° vertical flip |
5 | Flip + 90° counter-clockwise |
6 | Flip + 180° counter-clockwise |
7 | Flip + 270° counter-clockwise |
Critical: If you use XWayland applications, never use negative coordinates for your monitor positions. This is a known XWayland bug that causes click events to malfunction. Always arrange your monitors starting from
0,0and extend into positive coordinates.
Note: that "name" is a regular expression. If you want an exact match, you need to add
^and$to the beginning and end of the expression, for example,^eDP-1$matches exactly the stringeDP-1.
Examples
# Laptop display: 1080p, 60Hz, positioned at origin
monitorrule=name:^eDP-1$,width:1920,height:1080,refresh:60,x:0,y:10
# Match by make and model instead of name
monitorrule=make:Chimei Innolux Corporation,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0
# Virtual monitor with pattern matching
monitorrule=name:HEADLESS-.*,width:1920,height:1080,refresh:60,x:1926,y:0,scale:1,rr:0,vrr:0Monitor Spec Format
Several commands (focusmon, tagmon, disable_monitor, enable_monitor, toggle_monitor, viewcrossmon, tagcrossmon) accept a monitor_spec string to identify a monitor.
Format:
name:xxx&&make:xxx&&model:xxx&&serial:xxx- Any field can be omitted and there is no order requirement.
- If all fields are omitted, the string is treated as the monitor name directly (e.g.,
eDP-1). - Use
wlr-randrto find your monitor's name, make, model, and serial.
Examples:
# By name (shorthand)
mmsg dispatch toggle_monitor,eDP-1
# By make and model
mmsg dispatch toggle_monitor,make:Chimei Innolux Corporation&&model:0x15F5
# By serial
mmsg dispatch toggle_monitor,serial:12345678Tearing (Game Mode)
Tearing allows games to bypass the compositor's VSync for lower latency.
| Setting | Default | Description |
|---|---|---|
allow_tearing | 0 | Global tearing control: 0 (Disable), 1 (Enable), 2 (Fullscreen only). |
HDR
HDR is only supported in wl-only branch, since it requires the
vulkanrenderer but scenefx is not supported yet.
| Setting | Default | Description |
|---|---|---|
hdr_depth | 2 | Set the hdr depth for the current display. 0 is Default, 1 is HDR8, 2 is HDR10. |
- you should enable HDR in monitorrule first, refer to Monitors — Monitor Rules
- you must set
env=WLR_RENDERER,vulkanbefore mango starts.
for example(must relogin once after setting):
env=WLR_RENDERER,vulkan
monitorrule=name:eDP-1,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0,scale:1,vrr:0,rr:0:hdr:1Toggling HDR at runtime
monitorrule sets the state at startup; togglehdr changes it without a config
reload, the way sway's output <name> hdr on|off|toggle does.
mmsg dispatch togglehdr # toggle the focused monitor
mmsg dispatch togglehdr,on # force on
mmsg dispatch togglehdr,off,eDP-1 # a named output
mmsg dispatch togglehdr,toggle,all # every output at onceWith no argument it toggles the focused monitor. Reloading the config re-applies
monitorrule and overrides whatever togglehdr last set.
all applies to every enabled output. In toggle mode it makes one decision for
all of them — if anything is on, everything goes off — rather than flipping each
output against its own state. Outputs that cannot do HDR are skipped without
their state being touched.
Mastering display metadata
hdr:1 alone declares BT.2020 primaries and the PQ transfer function, but leaves
the mastering display fields at zero, so the panel has nothing to tone-map
against. Set them to your panel's values:
monitorrule=name:eDP-1,...,hdr:1,hdr_max_lum:616,hdr_max_avg_lum:400di-edid-decode prints them under HDR Static Metadata Data Block. hdr_max_lum
is sent both as the mastering peak and as max_cll. Leaving any of the three at 0
leaves that field unset, which is the previous behaviour.
hdr_min_lumhas no effect on wlroots 0.20.x: the minimum was scaled the wrong way inbackend/drm/atomic.cand every value underflowed to 0. Fixed upstream by wlroots commitf6a01b40, not backported to the 0.20 branch.
Panels whose EDID hides the HDR block
Some panels declare HDR only inside a DisplayID 2.0 extension, with the
CTA-861 blocks nested in a container (tag 0x81). This is legal EDID 1.4, but
wlroots reads HDR capability through libdisplay-info's CTA path and comes back
empty, so hdr:1 is silently ignored on a panel that handles PQ.
hdr_force:1 skips the two EDID-derived checks:
monitorrule=name:eDP-1,...,hdr:1,hdr_force:1,hdr_max_lum:616,hdr_max_avg_lum:400It does not skip the renderer check: output colour transforms only exist in the
Vulkan renderer, so WLR_RENDERER=vulkan is still required.
Configuration
Enable Globally:
allow_tearing=1Enable per Window:
Use a window rule to force tearing for specific games.
windowrule=force_tearing:1,title:vkcubeTearing Behavior Matrix
force_tearing \ allow_tearing | DISABLED (0) | ENABLED (1) | FULLSCREEN_ONLY (2) |
|---|---|---|---|
| UNSPECIFIED (0) | Not Allowed | Follows tearing_hint | Only fullscreen follows tearing_hint |
| ENABLED (1) | Not Allowed | Allowed | Only fullscreen allowed |
| DISABLED (2) | Not Allowed | Not Allowed | Not Allowed |
Graphics Card Compatibility
Warning: Some graphics cards require setting the
WLR_DRM_NO_ATOMICenvironment variable before mango starts to successfully enable tearing.
Add this to config and relogin mango:
env=WLR_DRM_NO_ATOMIC,1GPU Compatibility
If mango cannot display correctly or shows a black screen, try selecting a specific GPU:
# Use a single GPU
WLR_DRM_DEVICES=/dev/dri/card1 mango
# Use multiple GPUs
WLR_DRM_DEVICES=/dev/dri/card0:/dev/dri/card1 mangoSome GPUs have compatibility issues with syncobj_enable=1 — it may crash apps like kitty that use syncobj. Set env=WLR_DRM_NO_ATOMIC,1 in config.conf and relogin to resolve this.
Power Management
You can control monitor power using the mmsg IPC tool.
Notice: This sleep command does not remove the monitor, it only turns the power off.
# Turn power off
mmsg dispatch sleep_monitor,eDP-1
# Turn power on
mmsg dispatch wakeup_monitor,eDP-1
# Toggle power
mmsg dispatch sleep_toggle_monitor,eDP-1You can also use wlr-randr for monitor management:
# remove a monitor
mmsg dispatch disable_monitor,eDP-1
# add a monitor
mmsg dispatch enable_monitor,eDP-1
# Show all monitors spec
wlr-randrScreen Scale(1.5 scale example)
# don't scale xwayland in global to avoid blurry
xwayland_ignore_scale=1
# scale:1.5 to scale native wayland app
monitorrule=name:eDP-1,width:1920,height:1080,refresh:60,x:0,y:0,scale:1.5
# use dpi to scale xwayland(1.5 * 96 = 144)
exec-once=echo "Xft.dpi: 144" | xrdb -mergeVirtual Monitors
You can create and manage virtual displays through IPC commands:
# Create virtual output
mmsg dispatch create_virtual_output
# Destroy all virtual outputs
mmsg dispatch destroy_all_virtual_outputYou can configure virtual monitors using wlr-randr:
# Show all monitors
wlr-randr
# Configure virtual monitor
wlr-randr --output HEADLESS-1 --pos 1921,0 --scale 1 --custom-mode 1920x1080@60HzVirtual monitors can be used for screen sharing with tools like Sunshine and Moonlight, allowing other devices to act as extended monitors.