Distribution: Linux Mint 22.3 (Zena)
Package version: muffin 6.6.3+zena, cinnamon 6.6.7+zena, X11
Graphics hardware: NVIDIA GeForce RTX 4090 (AD102), proprietary driver
Frequency: Always
Bug description
If a transient window is adopted by the WM before its parent, it never follows that parent to another workspace.
The behaviour is consistent with reload_transient_for() (src/x11/window-props.c) resolving WM_TRANSIENT_FOR only once, via meta_x11_display_lookup_x_window(): when the parent is not managed yet the lookup fails and transient_for becomes NULL, and the early return
if (transient_for == window->xtransient_for)
return;
would prevent any later retry, since the property itself never changes again. meta_window_change_workspace() then walks a transient list that does not contain the child. I have not instrumented muffin to confirm that specific line — the reproducer below establishes the ordering-dependent behaviour, not the exact code path.
The hint stays correct on the client throughout; only the window manager's resolution of it appears to be lost.
Real-world case: the Android emulator's floating control toolbar is a separate top-level window (_NET_WM_WINDOW_TYPE_UTILITY, WM_TRANSIENT_FOR the device window) and is stranded on the old workspace every time.
Steps to reproduce
#!/usr/bin/env python3
# needs python3-xlib
import time
from Xlib import X, Xatom, display
d = display.Display(); s = d.screen(); root = s.root
def win(name, x, w):
o = root.create_window(x, 60, w, 160, 1, s.root_depth, X.InputOutput,
X.CopyFromParent, background_pixel=s.black_pixel)
o.set_wm_name(name); o.set_wm_class("repro", "Repro"); return o
parent, child = win("repro-parent", 60, 260), win("repro-child", 340, 60)
child.set_wm_transient_for(parent)
child.change_property(d.intern_atom("_NET_WM_WINDOW_TYPE"), Xatom.ATOM, 32,
[d.intern_atom("_NET_WM_WINDOW_TYPE_UTILITY")])
child.map(); d.sync(); time.sleep(0.5) # child first -> bug
parent.map(); d.sync() # swap these two lines -> works
print(f"parent 0x{parent.id:08x} child 0x{child.id:08x}", flush=True)
time.sleep(300)
- Run it, note the two window IDs.
wmctrl -i -r <parent> -t 2
- The child stays on the original workspace, while
xprop -id <child> WM_TRANSIENT_FOR still reports the correct parent.
- Swap the two
map() lines so the parent is mapped first — the child now follows correctly.
Deterministic here, 3/3 runs. Mapping both back to back without synchronisation also works; only child-before-parent fails.
Expected behavior
The child follows its parent, as meta_window_change_workspace() intends via meta_window_foreach_transient().
Additional information
Affects any application that maps a utility/tool window before its main window. GNOME Bugzilla 645853 and 692976 described the symptom in 2011/2013 but were mass-closed RESOLVED OBSOLETE in the 2021 GitLab migration without a fix. The same code is present in mutter.
Distribution: Linux Mint 22.3 (Zena)
Package version: muffin 6.6.3+zena, cinnamon 6.6.7+zena, X11
Graphics hardware: NVIDIA GeForce RTX 4090 (AD102), proprietary driver
Frequency: Always
Bug description
If a transient window is adopted by the WM before its parent, it never follows that parent to another workspace.
The behaviour is consistent with
reload_transient_for()(src/x11/window-props.c) resolvingWM_TRANSIENT_FORonly once, viameta_x11_display_lookup_x_window(): when the parent is not managed yet the lookup fails andtransient_forbecomes NULL, and the early returnwould prevent any later retry, since the property itself never changes again.
meta_window_change_workspace()then walks a transient list that does not contain the child. I have not instrumented muffin to confirm that specific line — the reproducer below establishes the ordering-dependent behaviour, not the exact code path.The hint stays correct on the client throughout; only the window manager's resolution of it appears to be lost.
Real-world case: the Android emulator's floating control toolbar is a separate top-level window (
_NET_WM_WINDOW_TYPE_UTILITY,WM_TRANSIENT_FORthe device window) and is stranded on the old workspace every time.Steps to reproduce
wmctrl -i -r <parent> -t 2xprop -id <child> WM_TRANSIENT_FORstill reports the correct parent.map()lines so the parent is mapped first — the child now follows correctly.Deterministic here, 3/3 runs. Mapping both back to back without synchronisation also works; only child-before-parent fails.
Expected behavior
The child follows its parent, as
meta_window_change_workspace()intends viameta_window_foreach_transient().Additional information
Affects any application that maps a utility/tool window before its main window. GNOME Bugzilla 645853 and 692976 described the symptom in 2011/2013 but were mass-closed RESOLVED OBSOLETE in the 2021 GitLab migration without a fix. The same code is present in mutter.