feat: per-compositor app config in kick, slim kick-pi

This commit is contained in:
Andrew Hamilton 2026-09-14 07:30:04 +10:00
parent 61f9227683
commit 240c1cea4f
4 changed files with 342 additions and 124 deletions

View file

@ -1300,6 +1300,11 @@ def _spawn_standalone(extra_env, *apps, log=None):
for key in ("XCURSOR_PATH", "XCURSOR_THEME"):
if env.get(key):
cmd.append("%s=%s" % (key, env[key]))
# Opt-outs under test (e.g. KICK_NO_CONFIG_SHADOW) ride the same
# explicit-var discipline as everything else above: env -i wipes the
# dict, so each var the compositor needs must be listed.
if env.get("KICK_NO_CONFIG_SHADOW"):
cmd.append("KICK_NO_CONFIG_SHADOW=" + env["KICK_NO_CONFIG_SHADOW"])
# NOTE: env -i wipes the dict above, so every var the compositor needs
# must be listed explicitly -- a missing KICK_DUMP_DIR silently dumps
# all standalone sessions into shared /tmp/host_N.ppm paths, and
@ -2992,6 +2997,62 @@ def test_background_fullscreen_keeps_normal_layout(tmp_path):
_assert_alive(s, "compositor died")
def test_standalone_shadow_config_scopes_children(tmp_path):
"""Standalone kick builds a shadow config home and scopes children to
it: a tab sees XDG_CONFIG_HOME/DCONF_PROFILE under the shadow, the
shadow gtk settings carry the pinned close-only layout plus the real
theme, and the dconf profile layers the kick-only database first."""
home = tmp_path / "home"
(home / ".config" / "gtk-3.0").mkdir(parents=True)
(home / ".config" / "gtk-3.0" / "settings.ini").write_text(
"[Settings]\ngtk-theme=Adwaita\n")
out = tmp_path / "child-env.out"
with _run_standalone(
{"HOME": str(home)},
"sh -c 'echo XDG_CONFIG_HOME=$XDG_CONFIG_HOME > \"%s\"; "
"echo DCONF_PROFILE=$DCONF_PROFILE >> \"%s\"'" % (out, out),
"%s '#ff0000'" % WL,
wait="any") as s:
assert _wait_out(out, "XDG_CONFIG_HOME=", timeout=15.0)
text = out.read_text()
shadow = os.path.join(str(home), ".cache", "kick", "config")
assert ("XDG_CONFIG_HOME=%s\n" % shadow) in text, \
f"child missed shadow config home: {text!r}"
assert ("DCONF_PROFILE=%s/dconf-profile\n" % shadow) in text, \
f"child missed dconf overlay profile: {text!r}"
pinned = open(os.path.join(shadow, "gtk-3.0",
"settings.ini")).read()
assert "gtk-decoration-layout=:close" in pinned, \
f"layout not pinned: {pinned!r}"
assert "gtk-theme=Adwaita" in pinned, \
f"real theme lost: {pinned!r}"
profile = open(os.path.join(shadow, "dconf-profile")).read()
assert "user-db:kickoverrides" in profile.splitlines(), \
f"overlay db not first: {profile!r}"
_assert_alive(s, "compositor died")
def test_standalone_shadow_config_opt_out(tmp_path):
"""KICK_NO_CONFIG_SHADOW disables the scoped view: children inherit
the plain environment with no XDG_CONFIG_HOME/DCONF_PROFILE override."""
home = tmp_path / "home"
home.mkdir()
out = tmp_path / "child-env.out"
with _run_standalone(
{"HOME": str(home), "KICK_NO_CONFIG_SHADOW": "1"},
"sh -c 'echo XDG_CONFIG_HOME=$XDG_CONFIG_HOME > \"%s\"; "
"echo DCONF_PROFILE=$DCONF_PROFILE >> \"%s\"'" % (out, out),
"%s '#ff0000'" % WL,
wait="any") as s:
assert _wait_out(out, "XDG_CONFIG_HOME=", timeout=15.0)
text = out.read_text()
assert "XDG_CONFIG_HOME=\n" in text, \
f"opt-out leaked a shadow config home: {text!r}"
assert "DCONF_PROFILE=\n" in text, \
f"opt-out leaked a dconf overlay profile: {text!r}"
_assert_alive(s, "compositor died")
def test_alt_f11_toggles_host_fullscreen(tmp_path):
"""prefix+F11 toggles the kick window's fullscreen state in the host;
the resulting configure fullscreens the active tab only (other tabs