wlpdisplays
A Python utility that prints connected Wayland monitor information as structured JSON by parsing wayland-info output.
AI was used during development, with parts of human code, human review and testing of all code.
This is a personal tool I wanted and I'm sharing it in case it's useful to others.
Features
- Merges
wl_outputandxdg_output_v1data fromwayland-info - Per-monitor details: name, description, physical size, resolution, refresh rate, logical position/size, scale factors
- Future-proof: unknown key-value fields are auto-captured with type coercion (
"true"→true,"42"→42) - JSON output for easy consumption in scripts and status bars
- Sort monitors top-left to bottom-right
- Compact one-line output
--stdinmode for debugging with pre-recordedwayland-infooutput- Auto-pulls a precompiled
wayland-infofrom the Debian repos when none is installed, with three pull modes (see below)
Example Output
[
{
"name": "HDMI-A-1",
"description": "Samsung Electric Company U28E590",
"x": 0,
"y": 0,
"scale": 1.5,
"physical_width_mm": 608,
"physical_height_mm": 345,
"make": "Samsung Electric Company",
"model": "U28E590",
"subpixel_orientation": "unknown",
"output_transform": "normal",
"width_px": 3840,
"height_px": 2160,
"refresh_hz": 60.0,
"flags": "current",
"output": 66,
"logical_x": 0,
"logical_y": 0,
"logical_width": 2560,
"logical_height": 1440,
"scale_x": 1.5,
"scale_y": 1.5,
"int_scale": 2
}
]
Usage
wlpdisplays [options]
Options
| Flag | Description |
|---|---|
-h, --help |
Show help and exit |
-c, --compact |
Print JSON on one line (no indentation) |
-s, --sort |
Sort monitors top-left to bottom-right |
-v, --version |
Show version and exit |
-i, --stdin |
Read raw wayland-info data from stdin instead of running wayland-info |
-w, --wayland-info-path PATH |
Path to the wayland-info binary (default: wayland-info). Explicit paths are used as-is and not downloaded unless enabled |
-o, --pull-once |
If wayland-info is missing from PATH, download it once into the cache; never check for or apply updates |
-n, --never-pull |
Never download wayland-info; only use a system-installed or already-cached copy |
-p, --pull |
Explicitly enable auto-update pulling (default behavior); mainly overrides the no-download default of -w |
Pull modes
If wayland-info is not installed on the system, wlpdisplays can fetch a
precompiled binary straight from the official Debian pool (wayland-utils
package, .deb) and cache it in ~/.cache/wlpdisplays/bin/. Extraction is
pure Python, no dpkg/ar needed. The flags select one of three modes:
| Flag / default | Behavior |
|---|---|
(default) / -p, --pull |
Use/download the cached copy; check Debian for newer versions at most once per day and re-download if a newer release exists. |
-o, --pull-once |
Download only if the download target has no copy yet; never updates afterwards. |
-n, --never-pull |
Never touch the network; only use a system-installed or already-cached binary. |
When -w, --wayland-info-path PATH is given, that path is used as-is —
no downloading by default. Combine it with -o for a one-time pull or with
-p to restore the full auto-update behavior.
Pull state (last pull time as unix timestamp, last version pulled, source URL)
is stored in ~/.cache/wlpdisplays/wayland-info.json. Set
WLPDISPLAYS_CACHE_DIR to relocate that directory.
# Default: auto-pull + daily update checks
wlpdisplays
# Pull once, then never go online again
wlpdisplays --pull-once
# Fully offline: fail instead of downloading
wlpdisplays --never-pull
# Sorted, compact output
wlpdisplays --sort --compact
# Debug with pre-recorded output from another machine
wlpdisplays --stdin < waylandinfo-streaming-raw-out.log
Note: downloaded binaries come from Debian's package repository over HTTPS but are not signature-verified locally. If that matters for your threat model, install
wayland-utilsthrough your distro's package manager instead (it takes precedence over any cached copy).
Requirements
- Python 3.9+
wayland-info(fromwayland-utils) — optional: if missing, it is auto-pulled from the Debian repos unless--never-pullis set; also not needed when using--stdin
If your distro ships it, installing via the package manager is preferred:
sudo pacman -S wayland-utils
Installation
As a dependency (PyPI)
pipx install wlpdisplays
or with uv:
uv tool install wlpdisplays
On many distributions a plain pip install wlpdisplays is refused due to PEP 668
("externally managed environment"). Install it in a virtual environment instead,
e.g. pipx, uv tool install, or your project's venv:
python3 -m venv .venv && source .venv/bin/activate && pip install wlpdisplays
Once installed, the wlpdisplays command is available on your PATH,
and the module can be imported in your own code.
As a single file
The entire tool lives in one self-contained file, wlpdisplays.py.
Grab it from the repo and run it directly, no install needed:
git clone https://codeberg.org/marvin1099/wlpdisplays.git
cd wlpdisplays
chmod +x wlpdisplays.py
./wlpdisplays.py
A wlpdisplays symlink to the .py file is included, so ./wlpdisplays works too.
Or download just the file:
curl -O https://codeberg.org/marvin1099/wlpdisplays/raw/branch/main/wlpdisplays.py
./wlpdisplays.py
Optionally install it into your PATH without the .py extension, user-wide (~/.local/bin) needs no sudo:
install -Dm755 wlpdisplays.py ~/.local/bin/wlpdisplays
...or system-wide:
sudo install -Dm755 wlpdisplays.py /usr/local/bin/wlpdisplays
After that, wlpdisplays is a plain command: wlpdisplays --sort --compact.
Library Usage
wlpdisplays.py is also a normal Python module, so you can use it as a library:
import wlpdisplays as wlp
# Query the running Wayland session directly
monitors = wlp.get_outputs()
# ...or push in raw wayland-info text (e.g. from a file or another machine)
with open("waylandinfo.log") as f:
raw = f.read()
monitors = wlp.get_outputs(raw=raw)
# Sort top-left to bottom-right
monitors = wlp.get_outputs(raw=raw, sort=True)
# Control how a missing wayland-info is obtained:
# omitted: "update" for the default name, offline-safe for
# explicit binary= paths (like the CLI's -w)
# None / "update": force auto-update pulling (also for explicit paths)
# True / "once": first-time pull only, never updates
# False / "never": no network at all
monitors = wlp.get_outputs(pull=False)
# Compact, single-line JSON — the library equivalent of the -c flag
print(wlp.to_json(monitors, compact=True))
# Just resolve a runnable wayland-info path (system PATH -> cache -> download)
path = wlp.ensure_wayland_info(pull="update")
# Explicit paths are used as-is and NOT downloaded by default;
# pass pull=None to still enable the cache/download chain:
path = wlp.ensure_wayland_info("/opt/bin/wayland-info", pull=None)
The data and formatting steps are separate, so you can grab monitor dicts,
work with them, and only serialize when needed.
The lower-level building blocks are still exposed:
wl_outputs, xdg_outputs = wlp.parse_wayland_info(raw)
monitors = wlp.merge_outputs(wl_outputs, xdg_outputs)
Public API:
| Function | Description |
|---|---|
get_outputs(raw=None, *, sort=False, binary="wayland-info", pull=...) |
Get monitor dicts; pass raw to skip running wayland-info; omitted pull = auto for the default name, offline-safe for explicit paths; also accepts None/"update", True/"once", False/"never" |
to_json(outputs, *, compact=False) |
Serialize monitor dicts to JSON (one line when compact) |
run_wayland_info(binary="wayland-info", *, pull=...) |
Run wayland-info (or binary) and return its raw output |
ensure_wayland_info(binary="wayland-info", *, pull=...) |
Resolve a runnable binary path, pulling from Debian if needed |
parse_wayland_info(raw) |
Parse raw wayland-info text into (wl_outputs, xdg_outputs) |
merge_outputs(...) |
Merge parsed wl_output + xdg_output_v1 data into one list |
WaylandInfoError |
Raised when wayland-info cannot be run or pulled |
Note: when used as a library, failures raise
WaylandInfoErrorinstead of exiting the process. ThewlpdisplaysCLI still exits with an error message.
Development
Run the test suite (stdlib only, no dependencies):
python3 -m unittest discover
Notes
This tool is designed for Wayland environments.
If run under X11 or headless setups, it will issue a warning and attempt to continue gracefully.
Unknown fields in wayland-info output are captured automatically via a key-value fallback parser
with type coercion, no code changes needed if the protocol adds new properties.
Metadata
Release files for wlpdisplays 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wlpdisplays-0.3.0.tar.gz | 30.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wlpdisplays-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.6 kB
Release files / wlpdisplays-0.3.0.tar.gz
| Download URL | wlpdisplays-0.3.0.tar.gz |
|---|---|
| Size | 30.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7b76026a4af52d24f4326cd85bc65ae3bd236abddd000f72079b8c14c2219094
|
|
BLAKE2b-256 checksum How to use checksums |
97d1db0e61804f5fdc330bbb6a62114f6957e86c1a7ee4e7ea1e7dc2872f5886
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / wlpdisplays-0.3.0-py3-none-any.whl
| Download URL | wlpdisplays-0.3.0-py3-none-any.whl |
|---|---|
| Size | 23.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fc75827d7f893e3705ff8644e8a9b826cffb26f0bf916f9cc3ec0cdfec8543fe
|
|
BLAKE2b-256 checksum How to use checksums |
d13413a72a4339abd26f2f6ae08ad6e19b7aa6455b28831b1e3c6600df0aa2ff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|