From 9c340029e11bce38698bc3f2fc4784de406fb347 Mon Sep 17 00:00:00 2001 From: Jatin K Malik Date: Mon, 3 Aug 2026 16:23:34 -0700 Subject: [PATCH] docs(packaging): prefer Ayatana AppIndicator in Fedora/Arch hints (#638) * docs(packaging): prefer Ayatana AppIndicator in Fedora/Arch hints Follow-up to #621: align docs, AUR depends, package map, dependency check messages, and troubleshooting copy with the Ayatana-first install path so manual installs and AUR users get a working KDE tray icon. Co-authored-by: Jatin K Malik * style(main): black-format Ayatana install hint lines CI black --check failed on the multi-line logger.error calls for the Fedora/Arch package hints. Co-authored-by: Jatin K Malik --------- Co-authored-by: Cursor Agent Co-authored-by: Jatin K Malik --- docs/DISTRO_COMPATIBILITY.md | 6 ++--- docs/INSTALL.md | 8 +++---- packaging/aur/vocalinux/PKGBUILD | 2 +- scripts/check-system-deps.sh | 10 ++++---- scripts/distro-package-map.yaml | 8 ++++--- src/vocalinux/main.py | 15 ++++++------ tests/test_main.py | 34 ++++++++++++++++++++++++---- web/src/app/troubleshooting/page.tsx | 2 +- 8 files changed, 57 insertions(+), 28 deletions(-) diff --git a/docs/DISTRO_COMPATIBILITY.md b/docs/DISTRO_COMPATIBILITY.md index ec5b408..37658e2 100644 --- a/docs/DISTRO_COMPATIBILITY.md +++ b/docs/DISTRO_COMPATIBILITY.md @@ -173,7 +173,7 @@ native dependencies; it does **not** mean beta or unstable packages. If ### Gentoo ```bash -sudo emerge dev-python/pygobject:3 x11-libs/gtk+:3 dev-libs/libappindicator:3 \ +sudo emerge dev-python/pygobject:3 x11-libs/gtk+:3 dev-libs/libayatana-appindicator \ media-libs/portaudio dev-lang/python:3.9 ``` @@ -239,14 +239,14 @@ On Ubuntu 24.04+ or Pop!_OS, install `libgirepository-2.0-dev` if #### Fedora ```bash -sudo dnf install python3-gobject gtk3 gtk3-devel libappindicator-gtk3 \ +sudo dnf install python3-gobject gtk3 gtk3-devel libayatana-appindicator-gtk3 \ gobject-introspection-devel portaudio-devel python3-devel \ python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel ``` #### Arch Linux ```bash -sudo pacman -S python-gobject gtk3 libappindicator gobject-introspection \ +sudo pacman -S python-gobject gtk3 libayatana-appindicator gobject-introspection \ python-cairo portaudio python-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel ``` diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 0038a12..15350f2 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -69,7 +69,7 @@ vocalinux ```bash sudo dnf install -y \ python3-virtualenv python3-devel python3-gobject gtk3 gtk3-devel \ - libappindicator-gtk3 gobject-introspection-devel portaudio-devel \ + libayatana-appindicator-gtk3 gobject-introspection-devel portaudio-devel \ pkg-config xdotool wtype wl-clipboard xclip xsel python3 -m venv ~/.local/share/vocalinux-pypi/venv --system-site-packages @@ -89,7 +89,7 @@ See [AUR.md](AUR.md). Or via PyPI: ```bash sudo pacman -S --needed \ - python python-virtualenv python-gobject gtk3 libappindicator-gtk3 \ + python python-virtualenv python-gobject gtk3 libayatana-appindicator \ gobject-introspection python-cairo portaudio pkg-config xdotool wtype wl-clipboard xclip xsel python -m venv ~/.local/share/vocalinux-pypi/venv --system-site-packages @@ -369,7 +369,7 @@ sudo apt install -y wtype wl-clipboard xclip xsel ```bash sudo dnf install -y \ python3-pip python3-devel python3-virtualenv \ - python3-gobject gtk3 libappindicator-gtk3 \ + python3-gobject gtk3 libayatana-appindicator-gtk3 \ gobject-introspection-devel portaudio-devel \ wget curl unzip xdotool wtype wl-clipboard xclip xsel ``` @@ -378,7 +378,7 @@ sudo dnf install -y \ ```bash sudo pacman -S --noconfirm \ python-pip python-gobject gtk3 \ - libappindicator-gtk3 gobject-introspection \ + libayatana-appindicator gobject-introspection \ python-cairo portaudio python-virtualenv \ wget curl unzip xdotool wtype wl-clipboard xclip xsel ``` diff --git a/packaging/aur/vocalinux/PKGBUILD b/packaging/aur/vocalinux/PKGBUILD index 7c472be..b8e8f0c 100644 --- a/packaging/aur/vocalinux/PKGBUILD +++ b/packaging/aur/vocalinux/PKGBUILD @@ -14,7 +14,7 @@ depends=( 'python>=3.9' 'python-gobject' 'gtk3' - 'libappindicator-gtk3' + 'libayatana-appindicator' 'ibus' 'gobject-introspection' 'python-cairo' diff --git a/scripts/check-system-deps.sh b/scripts/check-system-deps.sh index 82a474e..4acd656 100755 --- a/scripts/check-system-deps.sh +++ b/scripts/check-system-deps.sh @@ -161,10 +161,10 @@ PY echo " sudo apt install -y python3-gi gir1.2-gtk-3.0 gir1.2-gdkpixbuf-2.0 portaudio19-dev python3-dev python3-venv pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "fedora" || "$DETECTED_DISTRO_LIKE" == *"fedora"* || "$DETECTED_DISTRO" == "rhel" || "$DETECTED_DISTRO" == "centos" || "$DETECTED_DISTRO" == "rocky" || "$DETECTED_DISTRO" == "almalinux" ]]; then echo "Fedora/RHEL-based:" - echo " sudo dnf install -y python3-gobject gtk3-devel gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel" + echo " sudo dnf install -y python3-gobject gtk3-devel libayatana-appindicator-gtk3 gobject-introspection-devel portaudio-devel python3-devel python3-virtualenv pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "arch" || "$DETECTED_DISTRO_LIKE" == *"arch"* || "$DETECTED_DISTRO" == "manjaro" || "$DETECTED_DISTRO" == "endeavouros" ]]; then echo "Arch Linux-based:" - echo " sudo pacman -S --needed python-gobject gtk3 gobject-introspection portaudio python pkg-config xdotool wtype wl-clipboard xclip xsel" + echo " sudo pacman -S --needed python-gobject gtk3 libayatana-appindicator gobject-introspection portaudio python pkg-config xdotool wtype wl-clipboard xclip xsel" elif [[ "$DETECTED_DISTRO" == "opensuse" || "$DETECTED_DISTRO_LIKE" == *"suse"* ]]; then echo "openSUSE:" echo " PYVER=\$(python3 -c 'import sys; print(f\"python{sys.version_info.major}{sys.version_info.minor}\")')" @@ -172,7 +172,7 @@ PY echo " If \"\${PYVER}-virtualenv\" is unavailable, try \"\${PYVER}-venv\"." elif [[ "$DETECTED_DISTRO" == "gentoo" ]]; then echo "Gentoo:" - echo " sudo emerge dev-python/pygobject:3 x11-libs/gtk+:3 dev-libs/libappindicator:3 media-libs/portaudio dev-lang/python:3.9 xdotool wtype" + echo " sudo emerge dev-python/pygobject:3 x11-libs/gtk+:3 dev-libs/libayatana-appindicator media-libs/portaudio dev-lang/python:3.9 xdotool wtype" elif [[ "$DETECTED_DISTRO" == "alpine" ]]; then echo "Alpine Linux:" echo " sudo apk add py3-gobject3 py3-pip gtk+3.0 py3-cairo portaudio-dev py3-virtualenv pkgconf xdotool wtype" @@ -194,10 +194,10 @@ PY echo " sudo apt install -y python3-gi gir1.2-gtk-3.0 portaudio19-dev python3-dev pkg-config xdotool wtype wl-clipboard xclip xsel" echo "" echo "Fedora/RHEL-based:" - echo " sudo dnf install -y python3-gobject gtk3-devel portaudio-devel python3-devel pkg-config xdotool wtype wl-clipboard xclip xsel" + echo " sudo dnf install -y python3-gobject gtk3-devel libayatana-appindicator-gtk3 portaudio-devel python3-devel pkg-config xdotool wtype wl-clipboard xclip xsel" echo "" echo "Arch Linux:" - echo " sudo pacman -S python-gobject gtk3 portaudio python pkg-config xdotool wtype wl-clipboard xclip xsel" + echo " sudo pacman -S python-gobject gtk3 libayatana-appindicator portaudio python pkg-config xdotool wtype wl-clipboard xclip xsel" fi echo "" diff --git a/scripts/distro-package-map.yaml b/scripts/distro-package-map.yaml index eec215b..74e67e4 100644 --- a/scripts/distro-package-map.yaml +++ b/scripts/distro-package-map.yaml @@ -22,14 +22,16 @@ system_packages: solus: ["python3-gobject", "gtk3"] # AppIndicator / Ayatana AppIndicator + # Prefer Ayatana: legacy Canonical AppIndicator can load without error but + # fail to register a StatusNotifierItem on modern KDE Plasma. appindicator: ubuntu: ["gir1.2-appindicator3-0.1"] debian_11: ["gir1.2-ayatanaappindicator3-0.1"] debian_12_plus: ["gir1.2-ayatanaappindicator3-0.1"] - fedora: ["libappindicator-gtk3"] - arch: ["libappindicator-gtk3"] + fedora: ["libayatana-appindicator-gtk3"] + arch: ["libayatana-appindicator"] opensuse: ["typelib-1_0-AyatanaAppIndicator3-0_1", "libayatana-appindicator3-1", "typelib-1_0-AppIndicator3-0_1"] - gentoo: ["dev-libs/libappindicator:3"] + gentoo: ["dev-libs/libayatana-appindicator"] alpine: ["libayatana-appindicator"] void: ["libappindicator"] solus: ["libappindicator"] diff --git a/src/vocalinux/main.py b/src/vocalinux/main.py index 4e5a6ff..4087264 100644 --- a/src/vocalinux/main.py +++ b/src/vocalinux/main.py @@ -109,18 +109,19 @@ def check_dependencies(): "GTK3 (install with: sudo apt install python3-gi gir1.2-gtk-3.0)" ) - # Check for AppIndicator3 / Ayatana AppIndicator + # Prefer Ayatana AppIndicator (maintained; registers on KDE Plasma). + # Legacy Canonical AppIndicator3 is only accepted as a fallback. try: import gi - gi.require_version("AppIndicator3", "0.1") - from gi.repository import AppIndicator3 # noqa: F401 + gi.require_version("AyatanaAppIndicator3", "0.1") + from gi.repository import AyatanaAppIndicator3 # noqa: F401 except (ImportError, ValueError): try: import gi - gi.require_version("AyatanaAppIndicator3", "0.1") - from gi.repository import AyatanaAppIndicator3 # noqa: F401 + gi.require_version("AppIndicator3", "0.1") + from gi.repository import AppIndicator3 # noqa: F401 except (ImportError, ValueError): missing_system_deps.append( "AppIndicator3/AyatanaAppIndicator3 - Required for system tray icon" @@ -152,10 +153,10 @@ def check_dependencies(): logger.error(" Then log out and back in. Ubuntu includes this by default.") logger.error("") logger.error(" Fedora:") - logger.error(" sudo dnf install python3-gobject gtk3 libappindicator-gtk3") + logger.error(" sudo dnf install python3-gobject gtk3 libayatana-appindicator-gtk3") logger.error("") logger.error(" Arch Linux:") - logger.error(" sudo pacman -S python-gobject gtk3 libappindicator") + logger.error(" sudo pacman -S python-gobject gtk3 libayatana-appindicator") logger.error("") logger.error(" openSUSE Tumbleweed:") logger.error( diff --git a/tests/test_main.py b/tests/test_main.py index 964e8fb..0721303 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -699,10 +699,9 @@ class TestCheckDependencies(unittest.TestCase): self.assertFalse(result) def test_check_dependencies_missing_appindicator_with_ayatana_fallback(self): - """Test when AppIndicator3 is missing but AyatanaAppIndicator3 is available.""" + """Test when legacy AppIndicator3 is missing but Ayatana is available.""" - # Make gi.require_version raise ValueError for AppIndicator3 only - # AyatanaAppIndicator3 should work as fallback + # Prefer Ayatana; legacy AppIndicator3 is only a fallback. def require_version_side_effect(name, version): if name == "AppIndicator3": raise ValueError("AppIndicator3 not found") @@ -726,7 +725,34 @@ class TestCheckDependencies(unittest.TestCase): ): with patch("vocalinux.main.logger"): result = check_dependencies() - # Should return True because AyatanaAppIndicator3 fallback works + # Should return True because AyatanaAppIndicator3 works + self.assertTrue(result) + + def test_check_dependencies_falls_back_to_legacy_appindicator(self): + """Test when Ayatana is missing but legacy AppIndicator3 is available.""" + + def require_version_side_effect(name, version): + if name == "AyatanaAppIndicator3": + raise ValueError("AyatanaAppIndicator3 not found") + + mock_gi = MagicMock() + mock_gi.require_version = MagicMock(side_effect=require_version_side_effect) + mock_gtk = MagicMock() + mock_appindicator = MagicMock() + mock_pynput = MagicMock() + mock_requests = MagicMock() + + with patch.dict( + "sys.modules", + { + "gi": mock_gi, + "gi.repository": MagicMock(Gtk=mock_gtk, AppIndicator3=mock_appindicator), + "pynput": mock_pynput, + "requests": mock_requests, + }, + ): + with patch("vocalinux.main.logger"): + result = check_dependencies() self.assertTrue(result) def test_check_dependencies_missing_both_appindicators(self): diff --git a/web/src/app/troubleshooting/page.tsx b/web/src/app/troubleshooting/page.tsx index b8ec6c7..27979f1 100644 --- a/web/src/app/troubleshooting/page.tsx +++ b/web/src/app/troubleshooting/page.tsx @@ -153,7 +153,7 @@ const troubleshootingItems = [ "Ensure your desktop environment supports system trays (GNOME requires an AppIndicator extension)", "Install the GNOME AppIndicator extension (pick your distro): Debian/Ubuntu: sudo apt install gnome-shell-extension-appindicator — Fedora: sudo dnf install gnome-shell-extension-appindicator — Arch: sudo pacman -S gnome-shell-extension-appindicator", "Then enable the extension (Extensions app, or: gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com) and log out/in if needed", - "Debian/Ubuntu only — also check ayatana: sudo apt install libayatana-appindicator3-1 (Fedora already pulls libappindicator-gtk3 via the installer)", + "Debian/Ubuntu: sudo apt install libayatana-appindicator3-1 — Fedora: sudo dnf install libayatana-appindicator-gtk3 — Arch: sudo pacman -S libayatana-appindicator (legacy libappindicator-gtk3 can leave the icon missing on KDE)", "Try launching from terminal to see any errors: vocalinux --debug", ], },