MultiMonitorWindowManager
Restarts X11 window management once a session has two displays, where the manager running needs it.
A window manager that reads the monitor set only as it starts tiles a
maximized window across the whole framebuffer rather than the per-display
regions an extended layout defines; restarted, it reads the set the layout
published. None of this applies where the displays are outputs of their
own (has_pluggable_outputs): a second output arriving is a hotplug, which
every manager follows. Which managers need that is measured
(RESTART_TO_READ_MONITORS), not configured, and the one running is
restarted with the command line it was started with plus --replace, so
it keeps the configuration chain its session gave it, less the options
that would run the session's autostart again (restart_command). Both
transports
share this state: once per session, since a second restart would take
window management away from whoever is using it. Wayland sessions manage
their own windows and never restart.
Functions
constructor__init__() -> NoneSource Code
def __init__(self) -> None:
self._done = FalseReturns
Nonefuncensure_for(display_count, is_wayland) -> NoneRestart the running window manager if it is one that needs it and this session has not yet.
The replacement is started detached, so it outlives this process's session.
Source Code
async def ensure_for(self, display_count: int, is_wayland: bool) -> None:
"""Restart the running window manager if it is one that needs it and
this session has not yet.
The replacement is started detached, so it outlives this process's
session.
"""
if is_wayland or self._done or display_count <= 1:
return
self._done = True
if await has_pluggable_outputs():
logger_app_resize.info(
"Multi-monitor setup: the displays are outputs of their own, which "
"every window manager follows live; no restart.")
return
running = await current_wm_name()
needing = next((wm for wm in RESTART_TO_READ_MONITORS
if wm_name_matches(wm, running)), None)
if needing is None:
logger_app_resize.info(
f"Multi-monitor setup: {running or 'no window manager'} keeps its "
"monitor set current; no restart.")
return
replacing = await current_wm_pid()
command = restart_command(wm_command(replacing)) or [needing]
if "--replace" not in command:
command.append("--replace")
logger_app_resize.info(
f"Multi-monitor setup: restarting {needing} to read the monitor set.")
try:
await asyncio.create_subprocess_exec(
*command,
stdout=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.DEVNULL,
start_new_session=True,
)
except Exception as e:
logger_app_resize.error(f"Failed to restart {needing}: {e}")
return
# Before the layout applies: a WM snapshotting the monitor set mid-swap
# re-tiles maximized windows across the whole framebuffer.
if not await wait_for_wm(needing, replacing):
logger_app_resize.warning(
f"{needing} restart not confirmed; applying layout anyway.")paramdisplay_countintparamis_waylandboolReturns
None