docs: single-instance panels cannot nest; skip panel test when host owns bus

This commit is contained in:
Andrew Hamilton 2026-09-15 23:20:56 +10:00
parent 07ba288b5d
commit 57c5cb7912
3 changed files with 46 additions and 0 deletions

View file

@ -204,6 +204,18 @@ appear:
tabs: the dialogs and auxiliaries feel like part of the one window. `off` keeps
every surface individually reachable, which is kick's original model.
### Panel (`--panel`)
`--panel CMD` launches a wlr-layer-shell panel (e.g. waybar) as an
always-on-top bar that sizes the tabs underneath it. The panel is launched
with a plain exec and shares the login session's D-Bus bus, like every other
compositor's panels. A single-instance panel therefore cannot nest: if the
host session already runs one (e.g. `wf-panel-pi` >= 1.31, which owns
`com.raspberrypi.wfpanelpi`), the nested copy defers to it and exits without
ever mapping, so no bar appears. Use a multi-instance panel, stop the host
copy, or run kick as the session itself (standalone), where no competitor
exists.
## Key bindings
| Key | Action |

13
kick.c
View file

@ -5853,6 +5853,11 @@ static void launch_panel(void) {
if (nullfd > STDERR_FILENO) close(nullfd);
}
}
/* The panel shares the login session's D-Bus bus like every other
compositor's panels do (labwc/sway exec theirs plainly too), so
single-instance panels (wf-panel-pi >= 1.31 owns
com.raspberrypi.wfpanelpi) defer to an already-running host copy
and exit without mapping -- see the --panel README note. */
execlp("/bin/sh", "sh", "-c", server.panel_cmd, NULL);
_exit(127);
}
@ -12370,6 +12375,14 @@ int main(int argc, char *argv[]) {
"panel (e.g. waybar) as an\n"
" always-on-top bar that "
"sizes the tabs underneath it.\n"
" The panel shares the login "
"session's D-Bus bus,\n"
" so a single-instance panel "
"already running on the\n"
" host (e.g. wf-panel-pi) "
"exits without mapping;\n"
" use a multi-instance panel "
"or stop the host copy.\n"
" --focus-priority Favor the active window: "
"it runs at normal\n"
" CPU/IO priority (nice 0, "

View file

@ -1413,6 +1413,24 @@ def _require_host_wayland():
pytest.skip("needs a live host Wayland session (WAYLAND_DISPLAY)")
def _dbus_name_owned(name):
"""True when a session-bus name is already owned (a host singleton runs).
Used to skip tests that nest a single-instance client (wf-panel-pi owns
com.raspberrypi.wfpanelpi): the nested copy would defer to the host's and
exit without mapping. False when there is no session bus to ask."""
try:
out = subprocess.run(
["dbus-send", "--session", "--print-reply", "--dest=org.freedesktop.DBus",
"/org/freedesktop/DBus", "org.freedesktop.DBus.NameHasOwner",
f"string:{name}"],
capture_output=True, text=True, timeout=5,
)
except (OSError, subprocess.SubprocessError):
return False
return out.returncode == 0 and "boolean true" in out.stdout
def _require_xwayland():
"""Skip unless Xwayland and xmessage are available."""
if not HAVE_XWAYLAND:
@ -4979,6 +4997,9 @@ def test_panel_menu_flush_under_bar():
panel = shutil.which("wf-panel-pi")
if not panel:
pytest.skip("wf-panel-pi not installed")
if _dbus_name_owned("com.raspberrypi.wfpanelpi"):
pytest.skip("host already runs wf-panel-pi: the nested single-instance "
"copy would exit without mapping")
with _run_nested(f"{WL} '{RED}'", extra_args=("--panel", panel)) as s:
s.wait_for(r"\[diag\] map app=0", timeout=20.0)