Repository navigation
monitors
You can configure each display output individually using the monitor_rule keyword.
Syntax:
monitor_rule=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.
| 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 |
primary |
integer | 0, 1 | Make this monitor the X11 (RandR) primary output for XWayland |
X11 clients — notably fullscreen games that confine or lock the pointer — use the RandR primary output to decide their coordinate origin. The primary output is therefore only ever changed when monitor rules are applied (at startup, on output hotplug, on a config reload), and never as focus or the pointer moves between monitors.
Add primary:1 to the rule of the monitor you want X11 to treat as primary. The rules are matched in order and only the first matching rule applies to a monitor, so put the primary:1 on the rule that actually matches your display. If several rules ask for it, the earliest one wins. Without any primary:1 rule the monitor of the first matching rule is used, and the first connected monitor when no rule matches at all.
# Play on the second display: make it the X11 primary output
monitor_rule=name:^DP-2$,width:2560,height:1440,refresh:144,x:1920,y:0,primary:1| 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.
# Laptop display: 1080p, 60Hz, positioned at origin
monitor_rule=name:^eDP-1$,width:1920,height:1080,refresh:60,x:0,y:10
# Match by make and model instead of name
monitor_rule=make:Chimei Innolux Corporation,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0
# Virtual monitor with pattern matching
monitor_rule=name:HEADLESS-.*,width:1920,height:1080,refresh:60,x:1926,y:0,scale:1,rr:0,vrr:0Several 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 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 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 monitor_rule first, refer to Monitors — Monitor Rules
- you must set
env=WLR_RENDERER,vulkanbefore mango starts.
env=WLR_RENDERER,vulkan
monitor_rule=name:eDP-1,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0,scale:1,vrr:0,rr:0:hdr:1monitor_rule 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
monitor_rule 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.
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:
monitor_rule=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.
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:
monitor_rule=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.
Enable Globally:
allow_tearing=1Enable per Window:
Use a window rule to force tearing for specific games.
window_rule=force_tearing:1,title:vkcube
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 |
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,1
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 sync_obj_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.
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-randr# don't scale xwayland in global to avoid blurry
xwayland_ignore_scale=1
# scale:1.5 to scale native wayland app
monitor_rule=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 -mergeElectron-based applications (VSCodium, Spotify, Discord, ...) and Chromium
browsers can look blurry when the monitor uses a fractional scale (for
example scale:1.25). This is a compatibility issue with fractional scaling,
and such a window becomes sharp again once it is maximized or fullscreened.
Add a window rule to open the affected applications maximized, which fixes the blur:
# VSCodium
window_rule=force_fake_maximize:1,app_id:codiumYou 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.