MultiMonitorWindowManager
Hands X11 window management to Openbox once a session has two displays.
XFCE and Plasma tile a maximized window across the whole framebuffer rather than against the per-display regions an extended layout defines, so a session running one of them swaps to Openbox the first time it extends. Both transports share this state: the swap is attempted once per session either way, since a second one would restart window management under whoever is using it. Wayland sessions manage their own windows and never swap.
Functions
func__init__(self) -> NoneSource Code
def __init__(self) -> None:
self._swapped = False
self._supported: Optional[bool] = NoneparamselfReturns
Nonefuncensure_for(self, display_count, is_wayland) -> NoneSwap if this session needs it and has not already been swapped.
Openbox is started detached, so the window manager outlives this
process's session, and on its stock config chain (user/system rc.xml):
a hand-written minimal config would strip the stock \<mouse>
bindings (titlebar double-click maximize, middle-click, menus) that the
compiled-in defaults do not cover, leaving presses on decorations dead.
Source Code
async def ensure_for(self, display_count: int, is_wayland: bool) -> None:
"""Swap if this session needs it and has not already been swapped.
Openbox is started detached, so the window manager outlives this
process's session, and on its stock config chain (user/system rc.xml):
a hand-written minimal config would strip the stock ``<mouse>``
bindings (titlebar double-click maximize, middle-click, menus) that the
compiled-in defaults do not cover, leaving presses on decorations dead.
"""
if is_wayland or self._swapped or display_count <= 1:
return
if self._supported is None:
self._supported = bool(
shutil.which("xfce4-session") or shutil.which("startplasma-x11"))
if not self._supported:
return
self._swapped = True
if "openbox" in (await current_wm_name()).lower():
logger_app_resize.info(
"Multi-monitor setup: Openbox already manages the session; no WM swap.")
return
logger_app_resize.info("Multi-monitor setup: switching to Openbox.")
try:
await asyncio.create_subprocess_exec(
"openbox", "--replace",
stdout=asyncio.subprocess.DEVNULL,
stderr=asyncio.subprocess.DEVNULL,
start_new_session=True,
)
except Exception as e:
logger_app_resize.error(f"Failed to switch to Openbox: {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("openbox"):
logger_app_resize.warning(
"Openbox takeover not confirmed; applying layout anyway.")paramselfparamdisplay_countintparamis_waylandboolReturns
None