fix: icône barre de menu sur Tahoe — stub libpython + abandon de rumps
Sur macOS Tahoe (26.5), le NSStatusItem n'est jamais placé (fenêtre h=0) si : 1. l'exécutable du processus n'appartient pas au bundle lancé (le python framework se ré-exécute → identité dépareillée) → stub C qui dlopen libpython et exécute app.py DANS le processus du bundle ; 2. l'item est créé par rumps (cause interne non isolée, l'API native fonctionne) → app.py réécrit en pyobjc pur (NSStatusItem + NSMenu). Le stub transmet argv à python quand il y en a (workers multiprocessing de MLX) — sinon bombe à fork (9 instances observées). PYTHONUNBUFFERED pour que les print atteignent ~/Library/Logs/Zonza.log. Auto-diagnostic du placement de l'icône au démarrage. rumps retiré des dépendances. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+34
-23
@@ -1,17 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Construit Zonza.app — un LANCEUR léger (pas un bundle autonome).
|
||||
# Construit Zonza.app — un stub compilé qui embarque libpython dans le processus.
|
||||
#
|
||||
# Pourquoi un lanceur plutôt que PyInstaller/py2app : empaqueter MLX + multiprocessing +
|
||||
# hotkey globale sans compte développeur Apple se bat en permanence contre macOS (bombe à
|
||||
# fork, permissions TCC réinitialisées à chaque rebuild, shaders Metal non bundlés). Le
|
||||
# lanceur exécute le code via le venv du dépôt, où TOUT fonctionne de façon stable.
|
||||
# Pourquoi un stub C (et pas un script bash qui exec python) : sur macOS Tahoe (26),
|
||||
# le gestionnaire de barre de menu refuse de placer le NSStatusItem d'un processus
|
||||
# dont l'exécutable principal n'appartient pas au bundle lancé (le python framework
|
||||
# se ré-exécute → identité dépareillée → icône invisible, fenêtre de hauteur 0).
|
||||
# Le stub dlopen libpython et exécute app.py DANS le processus du bundle : l'identité
|
||||
# est cohérente et l'icône s'affiche. (Validé par tests le 2026-06-13.)
|
||||
#
|
||||
# Pourquoi pas PyInstaller/py2app : empaqueter MLX (shaders Metal) échoue ; le code
|
||||
# tourne donc depuis le dépôt + son venv (ne pas les supprimer).
|
||||
#
|
||||
# RÈGLE DE PROPRETÉ : ce script est l'UNIQUE chemin de build. Il construit DIRECTEMENT
|
||||
# dans /Applications — jamais dans /tmp ni dans le dépôt. C'est ce qui garantit qu'une
|
||||
# seule entrée existe dans LaunchServices (l'historique de builds éparpillés est ce qui
|
||||
# avait créé des icônes en double avec l'ancienne app Dictée).
|
||||
#
|
||||
# Limite : non distribuable seul (l'utilisateur doit cloner le dépôt + créer le venv).
|
||||
# dans /Applications — jamais dans /tmp ni dans le dépôt (l'historique de builds
|
||||
# éparpillés est ce qui avait créé des icônes en double avec l'ancienne app Dictée).
|
||||
#
|
||||
# Usage : ./build_app.sh → installe directement /Applications/Zonza.app
|
||||
set -euo pipefail
|
||||
@@ -22,20 +24,25 @@ PYBIN="$HERE/.venv/bin/python3"
|
||||
|
||||
[ -x "$PYBIN" ] || { echo "Erreur : venv introuvable ($PYBIN). Lance : python3 -m venv .venv && .venv/bin/pip install -r requirements.txt"; exit 1; }
|
||||
|
||||
# chemins python injectés dans le stub
|
||||
PYDYLIB="$("$PYBIN" -c "import sys; print(sys.base_prefix)")/../../Python"
|
||||
PYDYLIB="$(cd "$(dirname "$PYDYLIB")" && pwd)/Python"
|
||||
SITE="$("$PYBIN" -c "import sysconfig; print(sysconfig.get_paths()['purelib'])")"
|
||||
[ -f "$PYDYLIB" ] || { echo "Erreur : dylib python introuvable ($PYDYLIB)"; exit 1; }
|
||||
|
||||
# icône (générée si absente)
|
||||
[ -f "$HERE/assets/icon.icns" ] || { "$PYBIN" "$HERE/assets/make_icon.py" && "$HERE/assets/make_icns.sh"; }
|
||||
|
||||
echo "→ construction du lanceur $APP …"
|
||||
echo "→ construction de $APP …"
|
||||
rm -rf "$APP"
|
||||
mkdir -p "$CONTENTS/MacOS" "$CONTENTS/Resources"
|
||||
|
||||
# exécutable : un script qui lance l'app via le python du venv (PWD = dépôt)
|
||||
cat > "$CONTENTS/MacOS/zonza" <<LAUNCHER
|
||||
#!/bin/bash
|
||||
cd "$HERE"
|
||||
exec "$PYBIN" "$HERE/app.py" >> "\$HOME/Library/Logs/Zonza.log" 2>&1
|
||||
LAUNCHER
|
||||
chmod +x "$CONTENTS/MacOS/zonza"
|
||||
# stub compilé : libpython embarqué, exécutable = celui du bundle
|
||||
clang -O2 \
|
||||
-DPYTHON_DYLIB="\"$PYDYLIB\"" \
|
||||
-DAPP_PY="\"$HERE/app.py\"" \
|
||||
-DVENV_SITE="\"$SITE\"" \
|
||||
"$HERE/launcher/stub.c" -o "$CONTENTS/MacOS/zonza"
|
||||
|
||||
# icône
|
||||
cp "$HERE/assets/icon.icns" "$CONTENTS/Resources/icon.icns"
|
||||
@@ -49,8 +56,8 @@ cat > "$CONTENTS/Info.plist" <<'PLIST'
|
||||
<key>CFBundleName</key><string>Zonza</string>
|
||||
<key>CFBundleDisplayName</key><string>Zonza</string>
|
||||
<key>CFBundleIdentifier</key><string>cloud.mrtechlab.zonza</string>
|
||||
<key>CFBundleVersion</key><string>1.0</string>
|
||||
<key>CFBundleShortVersionString</key><string>1.0</string>
|
||||
<key>CFBundleVersion</key><string>1.1</string>
|
||||
<key>CFBundleShortVersionString</key><string>1.1</string>
|
||||
<key>CFBundlePackageType</key><string>APPL</string>
|
||||
<key>CFBundleExecutable</key><string>zonza</string>
|
||||
<key>CFBundleIconFile</key><string>icon</string>
|
||||
@@ -61,11 +68,15 @@ cat > "$CONTENTS/Info.plist" <<'PLIST'
|
||||
</plist>
|
||||
PLIST
|
||||
|
||||
# enregistrement propre dans LaunchServices (remplace toute entrée précédente du même chemin)
|
||||
# signature ad-hoc avec identifiant stable : les permissions TCC (Accessibilité,
|
||||
# Surveillance de l'entrée, Micro) restent acquises d'un rebuild à l'autre.
|
||||
codesign --force --sign - --identifier "cloud.mrtechlab.zonza" "$APP"
|
||||
|
||||
# enregistrement propre dans LaunchServices
|
||||
LSREGISTER=/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
|
||||
"$LSREGISTER" -f "$APP" 2>/dev/null || true
|
||||
touch "$APP"
|
||||
|
||||
echo "✓ $APP installé."
|
||||
echo " Lance Zonza depuis Spotlight, accorde Surveillance de l'entrée + Accessibilité une"
|
||||
echo " fois (à 'python3' ou 'Zonza' selon ce que macOS propose), c'est définitif."
|
||||
echo " Au premier lancement, accorde à « Zonza » : Accessibilité + Surveillance de"
|
||||
echo " l'entrée (Réglages > Confidentialité). Logs : ~/Library/Logs/Zonza.log"
|
||||
|
||||
Reference in New Issue
Block a user