mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 03:00:06 +02:00
[verified] fix(session): start nested AT-SPI registry
This commit is contained in:
1 parent
1ebf3692fb
commit
25504e0ed4
7 files changed
+1260
-3
No files matched your search
@@ -29,7 +29,7 @@ for var in $(compgen -e); do
|
||||
case $var in
|
||||
LD_LIBRARY_PATH | LD_PRELOAD | STEAM_* | Steam* | SRT_* | PRESSURE_VESSEL_* | MANGOHUD_* | \
|
||||
ENABLE_VK_LAYER_VALVE_steam_overlay_* | STEAMVIDEOTOKEN | QT_IM_MODULE | GTK_IM_MODULE | \
|
||||
XMODIFIERS) unset "$var" ;;
|
||||
XMODIFIERS | AT_SPI_BUS_ADDRESS) unset "$var" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -190,6 +190,21 @@ if [ "$remote" = 1 ]; then
|
||||
"$here/remote-ctl.sh" start
|
||||
fi
|
||||
|
||||
# AT-SPI: start the registry inside Plasma's autostart, after KWin has published the
|
||||
# nested displays. Starting it before startplasma could bind to the host's X display.
|
||||
# This config belongs only to Frametop; the host desktop's autostart is unchanged.
|
||||
autostart=$XDG_CONFIG_HOME/autostart/frametop-atspi.desktop
|
||||
mkdir -p "$(dirname "$autostart")"
|
||||
cat > "$autostart" <<EOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Frametop accessibility
|
||||
Exec="$here/ft-atspi"
|
||||
X-KDE-autostart-phase=2
|
||||
OnlyShowIn=KDE;
|
||||
NoDisplay=true
|
||||
EOF
|
||||
|
||||
# ft-floatd (floating windows) runs inside the Plasma session, on its D-Bus: started from
|
||||
# the session's autostart, which only this desktop reads (XDG_CONFIG_HOME above).
|
||||
autostart=$XDG_CONFIG_HOME/autostart/frametop-floatd.desktop
|
||||
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/python3
|
||||
"""Start AT-SPI on this nested desktop's live bus, after KWin has set its displays."""
|
||||
import ast
|
||||
import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
DBUS = "org.freedesktop.DBus"
|
||||
DBUS_PATH = "/org/freedesktop/DBus"
|
||||
REGISTRY = "org.a11y.atspi.Registry"
|
||||
|
||||
|
||||
def call(address, destination, path, method, *args):
|
||||
return subprocess.run(
|
||||
["gdbus", "call", "--address", address, "--dest", destination,
|
||||
"--object-path", path, "--method", method, "--timeout", "5", *args],
|
||||
check=True, capture_output=True, text=True, timeout=6).stdout.strip()
|
||||
|
||||
|
||||
def stop(child):
|
||||
if child.poll() is None:
|
||||
child.terminate()
|
||||
try:
|
||||
child.wait(timeout=3)
|
||||
except subprocess.TimeoutExpired:
|
||||
child.kill()
|
||||
child.wait()
|
||||
|
||||
|
||||
def run_registry(address, session):
|
||||
# SteamOS's registryd stays alive after a bus disconnect. Keep only our own
|
||||
# child tied to both private buses; no host PID lookup or broad process kill.
|
||||
registry = subprocess.Popen(["/usr/lib/at-spi2-registryd"])
|
||||
try:
|
||||
while registry.poll() is None:
|
||||
try:
|
||||
call(session, DBUS, DBUS_PATH, DBUS + ".GetId")
|
||||
call(address, DBUS, DBUS_PATH, DBUS + ".GetId")
|
||||
except subprocess.SubprocessError:
|
||||
break # Normal session shutdown or loss of its accessibility bus.
|
||||
time.sleep(1)
|
||||
finally:
|
||||
stop(registry)
|
||||
|
||||
|
||||
def start():
|
||||
session = os.environ.get("DBUS_SESSION_BUS_ADDRESS")
|
||||
runtime = os.environ.get("XDG_RUNTIME_DIR", "")
|
||||
if not session or os.path.basename(runtime) != "frametop":
|
||||
return # Do not autolaunch a bus or touch the host desktop.
|
||||
os.environ.pop("AT_SPI_BUS_ADDRESS", None)
|
||||
reply = call(session, "org.a11y.Bus", "/org/a11y/bus", "org.a11y.Bus.GetAddress")
|
||||
address, = ast.literal_eval(reply)
|
||||
if not isinstance(address, str) or not address.startswith("unix:"):
|
||||
raise ValueError("org.a11y.Bus returned no local accessibility bus")
|
||||
if call(address, DBUS, DBUS_PATH, DBUS + ".NameHasOwner", REGISTRY) == "(true,)":
|
||||
return
|
||||
# Activation otherwise inherits the accessibility daemon's old environment (and
|
||||
# DBUS_SESSION_BUS_ADDRESS is the accessibility bus itself). Pin the live bus.
|
||||
env = {key: os.environ.get(key, "") for key in (
|
||||
"DISPLAY", "WAYLAND_DISPLAY", "XAUTHORITY", "XDG_RUNTIME_DIR",
|
||||
"XDG_CONFIG_HOME", "DBUS_SESSION_BUS_ADDRESS")}
|
||||
env["AT_SPI_BUS_ADDRESS"] = address
|
||||
call(address, DBUS, DBUS_PATH, DBUS + ".UpdateActivationEnvironment", repr(env))
|
||||
try:
|
||||
call(address, DBUS, DBUS_PATH, DBUS + ".StartServiceByName", REGISTRY, "0")
|
||||
except subprocess.CalledProcessError:
|
||||
# SteamOS's launcher can select dbus-broker because we are in a user unit,
|
||||
# but the private session bus has no systemd activation manager. Reuse its
|
||||
# bus rather than starting another launcher/bus. Never replace an owner.
|
||||
if call(address, DBUS, DBUS_PATH, DBUS + ".NameHasOwner", REGISTRY) == "(true,)":
|
||||
return
|
||||
os.environ["AT_SPI_BUS_ADDRESS"] = address
|
||||
# registryd itself refuses to queue behind an existing registry, including
|
||||
# races with native activation. The watcher cleans up only our own child.
|
||||
run_registry(address, session)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit(0))
|
||||
try:
|
||||
start()
|
||||
except (OSError, ValueError, SyntaxError, subprocess.SubprocessError) as error:
|
||||
print(f"frametop: accessibility unavailable: {error}", file=sys.stderr)
|
||||
@@ -10,7 +10,7 @@ cg=$(systemctl --user show -p ControlGroup --value "$unit" 2>/dev/null)
|
||||
|
||||
# The desktop's own processes stay in the unit and stop with it: the session, KWin,
|
||||
# Plasma, and the session services it started (portals, input methods, kded, wallet...).
|
||||
own='^(frametop-sessi|dbus-|startplasma|plasma|kwin|Xwayland|ksmserver|krdpserver|Xvnc|xfreerdp|ft-layout|'
|
||||
own='^(frametop-sessi|dbus-|startplasma|plasma|kwin|Xwayland|ksmserver|krdpserver|Xvnc|xfreerdp|ft-layout|ft-atspi|'
|
||||
own+='kded|kactivitymanage|kaccess|kglobalaccel|kscreen|kwalletd|ksecretd|polkit-kde|org_kde_|baloo|'
|
||||
own+='xembedsniproxy|gmenudbusmenu|DiscoverNotifie|kimpanel|ibus|xdg-|at-spi|dconf-service|fusermount|agent)'
|
||||
keep=()
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user