| .. | ||
| .config | ||
| README.md | ||
Yazi comme FileChooser du portail
Package GNU Stow : stow -d ~/.dotfiles -t ~ portal. Les fichiers actifs dans
~/.config/xdg-desktop-portal/ et
~/.config/xdg-desktop-portal-termfilechooser/ sont des liens Stow. La règle
SwayFX est dans le package sway.
Dépendances
Arch Linux : xdg-desktop-portal, xdg-desktop-portal-gtk,
xdg-desktop-portal-wlr, kitty, yazi, jq, swayfx, libinih,
libsystemd, meson, ninja et scdoc pour une compilation complète. Le
backend retenu est
hunkyburrito/xdg-desktop-portal-termfilechooser,
version 1.4.3, commit bcb2387949e4eb38a35390ebf1693f92869e619d dans
l'installation testée. Le paquet AUR
xdg-desktop-portal-termfilechooser-hunkyburrito-git existe aussi.
Cette machine utilise une installation Meson utilisateur sous ~/.local, sans
changer les backends système. Les fichiers nécessaires sont
~/.local/libexec/xdg-desktop-portal-termfilechooser,
~/.local/share/dbus-1/services/org.freedesktop.impl.portal.desktop.termfilechooser.service
et ~/.local/share/xdg-desktop-portal/portals/termfilechooser.portal.
La procédure de reproduction, conservée dans ce dépôt indépendamment du cache
de construction, est la suivante (sans l'exécuter pendant une simple publication) :
git clone https://github.com/hunkyburrito/xdg-desktop-portal-termfilechooser.git
cd xdg-desktop-portal-termfilechooser
git checkout --detach bcb2387949e4eb38a35390ebf1693f92869e619d
meson setup build --prefix="$HOME/.local"
meson compile -C build
meson install -C build
Contrôler ensuite les trois chemins ci-dessus et la configuration Stow de ce
dossier. Le dépôt source et le répertoire build sont temporaires et ne font
pas partie des dotfiles. Cette procédure installe uniquement dans le préfixe
utilisateur ; elle ne remplace aucun paquet système.
Après installation ou mise à jour du backend, recharger seulement
xdg-desktop-portal.service après avoir vérifié qu'aucune session de partage
d'écran ou requête portal n'est en cours.
Routage et fenêtre
FileChooser utilise termfilechooser, ScreenCast et Screenshot utilisent
wlr, Secret utilise gnome-keyring, et les autres interfaces disponibles
gardent gtk. XDG_CURRENT_DESKTOP=sway:wlroots:swayfx sélectionne la
configuration utilisateur portals.conf avant les fichiers système propres à
Sway. Le wrapper lance Kitty avec --class labfy-yazi-filechooser ; SwayFX
flotte et centre uniquement cet app_id. Kitty calcule au lancement une taille
de 1000 × 650, bornée à la sortie SwayFX active avec une marge de 40 pixels.
La fenêtre reste redimensionnable et sur le workspace courant. Le thème Kitty
et le thème Yazi Catppuccin Mocha sont ceux de la configuration habituelle.
Firefox 157 utilise le portail FileChooser en mode automatique quand il est
disponible. Aucun GTK_USE_PORTAL global ni préférence de profil n'est
nécessaire dans cette installation. Pour diagnostiquer un profil différent,
vérifier widget.use-xdg-desktop-portal.file-picker dans about:config : 1
force le portail, 0 le désactive, 2 suit le mode automatique.
Utilisation
Dans le sélecteur, o ou Entrée valide le ou les fichiers survolés ou
sélectionnés. Espace sélectionne chaque fichier en mode multiple. q annule
un choix de fichier ; Q annule aussi et ne transmet pas le dossier courant.
Pour un dossier, entrer dedans puis appuyer sur q ; Q annule. M ouvre le
menu des supports, g puis Espace permet de saisir un chemin. Ouvrir un
fichier via Yazi sans mode chooser n'est pas la même opération : ici, le
wrapper utilise --chooser-file pour remettre les chemins à l'application.
Pour « Enregistrer sous », le backend crée un fichier provisoire annoté. Le
déplacer avec x, naviguer vers la destination, le déposer avec p, puis le
renommer avec r si nécessaire. Valider le fichier avec o ou Entrée, puis
répondre o au prompt de confirmation du wrapper. Le prompt avertit que
l'application peut écraser une destination existante ; répondre autrement
annule. Q dans Yazi annule également et le backend supprime le provisoire
resté à son emplacement d'origine. Si le provisoire a été déplacé avant une
annulation, supprimer manuellement ce fichier déplacé. Les essais doivent
utiliser un dossier temporaire et éviter tout écrasement de données réelles.
Les applications GTK/Qt qui utilisent leurs dialogues natifs plutôt que le portail conservent leur comportement. Ce réglage ne change aucune association MIME et ne remplace pas les portails d'autres interfaces.
Vidéo Firefox et inhibition de l'inactivité (diagnostic du 9 octobre 2026)
Lors de ce diagnostic, swayidle.service lançait swaylock après 300 s,
éteint les sorties après 360 s et met les lecteurs en pause après 420 s. Le
verrouillage manuel et la protection before-sleep sont indépendants. Le
symptôme historique n'a pas été observé à l'instant exact du verrouillage ;
la configuration et les mesures courtes ci-dessous identifient la chaîne
d'inactivité en cause, sans attribuer rétroactivement chaque verrouillage à
swayidle.
La tasse « Maintenir éveillé » de QuickShell est une demande manuelle distincte.
Elle utilise un IdleInhibitor sur la barre persistante, qui survit à la
fermeture du Control Center. Dans le test, l'observateur swayidle à 6 s ne
s'est pas déclenché pendant que l'utilisateur confirmait la tasse activée ;
après sa désactivation, il s'est déclenché à 6 s sans vidéo. Lors d'une seconde
activation, le marqueur est resté absent avec le Control Center fermé, puis
avec une fenêtre Firefox de test sans vidéo en plein écran. Ce résultat
confirme l'effet de l'inhibition manuelle en fenêtre normale et en plein écran.
Après la seconde désactivation, l'observateur a de nouveau déclenché à 6 s.
L'expiration des durées n'a pas été mesurée ici. La tasse ne doit pas servir de
substitut à la demande propre à Firefox.
Avec Firefox 157.0.1 natif Wayland, une vidéo locale avec image et son produit
une demande video-playing vers org.freedesktop.portal.Inhibit. Le portail
actif sélectionne GTK par default=gtk, lequel reçoit la demande via
org.freedesktop.impl.portal.Inhibit. GTK répond à Firefox avec un chemin de
requête, mais son relais vers org.freedesktop.ScreenSaver échoue : le journal
du backend indique explicitement l'absence de propriétaire de ce nom D-Bus.
Le code GTK 1.15.3 répond avant de connaître le résultat de ce relais. Une
réponse D-Bus réussie de Firefox ne prouve donc pas que swayidle est inhibé.
Avec la tasse désactivée, l'observateur à 6 s s'est déclenché pendant cette
lecture par le portail, comme sans lecture. Les demandes de Firefox sont
libérées à la pause et à la fermeture du média ; l'audio peut conserver son
inhibition environ 10 s après la pause.
Le protocole Wayland natif existe dans SwayFX. Un Firefox de test lancé avec
MOZ_WAKE_LOCK_TYPE=WaylandIdleInhibit l'a acquis en lecture avec Firefox
focalisé, en fenêtre normale, en plein écran et après passage du focus au
terminal. Dans ces mesures courtes, l'observateur à 6 s n'a pas déclenché. Ce
mécanisme ne couvre toutefois pas la reprise après pause avec le terminal
focalisé : Firefox 157 tente une nouvelle acquisition, mais ne rapporte pas de
réussite.
Dans l'essai à pause longue, l'observateur a déclenché environ 17 s après la
pause (délai audio puis délai de 6 s), et est resté en état d'inactivité après
la reprise.
Une entrée org.freedesktop.impl.portal.Inhibit=none supprimerait le relais
GTK défaillant, sans créer d'inhibition. Elle n'est pas installée tant que
ce cas sans focus échoue ; aucun portail n'a été redémarré et les routes
FileChooser=termfilechooser, ScreenCast=wlr, Screenshot=wlr, Secret et
les autres interfaces GTK sont conservées.
Le pont utilisateur décrit ci-dessous fournit désormais le destinataire
org.freedesktop.ScreenSaver manquant. La règle Inhibit=none n'est pas
installée et aucun portail ni swayidle n'a été redémarré.
Pont ScreenSaver vers QuickShell (9 octobre 2026)
Firefox demande org.freedesktop.portal.Inhibit, le backend GTK relaie vers
org.freedesktop.ScreenSaver.Inhibit, puis
labfy-idle-bridge.service transmet le nombre de demandes valides à
QuickShell. L'IdleInhibitor de la barre persistante est actif si le maintien
manuel ou au moins une demande applicative est actif. La tasse reste
visible sans fond dans la barre : elle est rouge dès qu'une de ces sources est
active, et neutre sinon. Son infobulle distingue les sources et la durée
manuelle restante lorsqu'elle existe. Les deux sources
restent indépendantes : désactiver ou laisser expirer la tasse ne libère pas
une vidéo encore demandée ; une pause vidéo ne change ni la durée ni le
minuteur manuels. La petite indication dans la sous-page Maintenir éveillé
signale une demande applicative sans lui attribuer une identité non vérifiée.
Le helper Python 3 utilise PyGObject/Gio déjà installé, exclusivement sur le
bus de session. Il expose seulement Inhibit(ss) -> u et UnInhibit(u) sur
/org/freedesktop/ScreenSaver, avec introspection. Chaque appel reçoit un
cookie non nul propre à la connexion D-Bus appelante. La libération vérifie
ce propriétaire ; sa disparition libère toutes ses demandes. En pratique,
GTK est ce propriétaire direct : la fermeture du navigateur d'origine dépend
de la fermeture des requêtes portal par GTK. Les tests réels ont observé
UnInhibit après pause, fermeture du média et arrêt du navigateur de test.
Le pont ne déduit aucune vidéo d'un titre, d'un flux audio ou de MPRIS.
Mesure avec Firefox de test Wayland, profil et vidéo locale isolés, tasse
désactivée : l'observateur swayidle configuré avec un fichier vide et un
marqueur à 6 s déclenche sans lecture. En lecture, il ne déclenche ni en
fenêtre normale avec le terminal focalisé, ni en plein écran. Après deux
pauses longues, il déclenche quand les demandes vidéo et audio sont libérées ;
la reprise sans redonner le focus à Firefox le désactive à nouveau. À la
fermeture du média ou du navigateur de test, il déclenche à nouveau après la
libération des demandes. La demande audio est restée environ 10 s après la
pause dans ces essais, avant le délai de 6 s de l'observateur. Une tasse
manuelle active a maintenu la protection pendant une pause ; sa désactivation
pendant la lecture reprise n'a pas supprimé la protection applicative.
L'expiration réelle d'une durée manuelle et Netflix au délai habituel de 300 s
restent à vérifier séparément. Les demandes applicatives peuvent provenir
d'autres usages que d'une vidéo visible : le pont suit le portail, il ne
classe pas le contenu de la fenêtre.
Contrôle ciblé du 9 octobre 2026 : une activation manuelle de 30 minutes,
Control Center fermé, a conservé la tasse et la surface de barre pendant
130 secondes. Un observateur swayidle temporaire avec configuration vide,
seul un marqueur privé à 8 s et aucune action de verrouillage ou d'extinction,
ne s'est pas déclenché. Le même contrôle de 130 secondes en mode « Jusqu'à
désactivation », avec un nouveau marqueur, a donné le même résultat. Les
relevés à 0, 30, 55, 65, 90 et 130 secondes ont conservé le PID QuickShell
2349 et un seul chargement de configuration. La sous-page confirmait le mode
illimité après la seconde mesure. Ces contrôles établissent le fonctionnement
au-delà d'une minute dans la session stable ; ils ne mesurent ni l'expiration
complète à 30 minutes ni une demande applicative concurrente durant ces deux
phases. Après désactivation manuelle, un contrôle négatif neuf à 6 s a fini
par déclencher son marqueur ; les marqueurs des phases actives n'étaient donc
pas simplement inopérants.
Le journal utilisateur de la session précédente montre des rechargements
QuickShell à 08:01:31 et 08:02:15 sous le même PID 14333. Les fichiers
WorkspaceOverview.qml et Bar.qml portent des modifications à ces secondes.
À cette date, un rechargement reconstruisait ShellRoot avec le maintien
manuel initialisé à false ; il pouvait donc retirer la protection même si
le PID ne changeait pas. Faute d'horodatage du constat initial, ce lien restait
une explication plausible, sans attribution prouvée. La correction V5
ci-dessous conserve désormais ce choix lors des rechargements QML ; un arrêt
complet du processus reste distinct et libère l'inhibition.
Un rechargement ultérieur, pendant la mise à jour de la tasse, a révélé un
second défaut distinct : le nouveau SocketServer ouvrait le chemin fixe
avant la destruction de l'ancien. L'ancien retirait ensuite ce chemin ; le
helper ne pouvait plus se reconnecter et répondait bridge unavailable or full aux nouvelles demandes. IdleBridgeReceiver.qml diffère maintenant
l'ouverture de la socket de 250 ms après le chargement QML. Une demande
applicative temporaire a été acquise puis libérée avec succès ; la tasse est
devenue rouge pendant la demande, et un observateur neuf à 6 s n'a déclenché
qu'après sa libération. Le même résultat a été vérifié avec un rechargement
pendant que la demande restait active : chemin de socket présent, demande
retransmise, tasse rouge et inhibition effective. Ce défaut concernait la
reconnexion automatique, pas l'échéance du minuteur manuel.
Après ces changements QML, deux nouveaux contrôles réels de 130 secondes ont été effectués, l'un à 30 minutes et l'autre en mode illimité. À chacun des relevés 0, 30, 55, 65, 90 et 130 s, la tasse est restée rouge, la surface de barre était présente, le PID 2349 et le nombre de chargements étaient stables, et un observateur à 8 s avec marqueur neuf n'avait pas déclenché. Enfin, une demande D-Bus temporaire acquise puis libérée pendant le mode manuel illimité n'a ni masqué la tasse ni libéré l'inhibition manuelle. Après désactivation du mode illimité de test, la tasse est redevenue neutre et un dernier observateur à 6 s a déclenché son marqueur privé. L'état manuel a ainsi été ramené à sa valeur initiale.
Maintien manuel après rechargement QML (contrôle V5, 9 octobre 2026)
Le signalement situait un nouveau verrouillage vers 13:36–13:40, sans heure
exacte. Le processus QuickShell 2349, lancé à 09:23:01, avait rechargé sa
configuration pour la dernière fois à 13:24:37 avant ce signalement.
swayidle.service utilisait toujours 300 s pour swaylock, 360 s pour
l'extinction, 420 s pour la pause média et before-sleep pour le verrouillage
avant suspension. Aucun fichier de configuration implicite de swayidle
n'était présent. Le journal contient deux succès swaymsg sous l'identifiant
swayidle à 13:36:40 et 13:38:41, compatibles avec l'extinction et la reprise
de sortie. Il ne consignait ni la sélection manuelle, ni l'état de
l'inhibiteur au moment du verrouillage : la chaîne précise de cet incident
reste donc non prouvée. L'état observé après déverrouillage n'a pas été traité
comme une mesure rétroactive.
Le code actif avant V5 plaçait le booléen manuel dans ShellRoot avec la
valeur initiale false. V5 utilise PersistentProperties avec une identité
stable pour conserver seulement l'activation, la durée choisie et l'échéance
absolue. Une expiration pendant un rechargement est effacée au chargement.
Les demandes applicatives restent resynchronisées depuis le pont, sans
partager le stockage manuel. Les deux rechargements réels à 14:00:34 et
14:01:09 ont restauré le mode illimité sous le même PID. Lors du second,
le nouvel hôte de l'inhibiteur était mappé et enabled=true avant la
destruction journalisée de l'ancien hôte, environ 24 ms après. Il n'existe
pas d'accusé d'inhibition du compositeur ; ces transitions décrivent le
cycle QML, et l'observation swayidle ci-dessous teste son effet réel.
Le mode illimité a été activé depuis le bouton à 13:47:51, panneau fermé.
Un observateur swayidle sur wayland-1 et seat0, avec fichier de
configuration vide, respect normal des inhibiteurs et seule action de
création d'un marqueur privé à 8 s, n'a pas déclenché entre 13:48:55 et
13:59:17, soit 10 min 22 s sans rechargement. Un nouvel observateur de même
type n'a pas déclenché entre 13:59:34 et 14:11:28 ; son dernier rechargement
réel était à 14:01:09, soit 10 min 19 s avant la fin de la mesure. Aucun
swaylock n'était présent lors des relevés. Ces mesures dépassent 300 et
360 s dans la session réelle ; elles ne transforment pas l'icône seule en
preuve de protection. L'observateur ne sait pas mesurer les entrées humaines :
la confirmation de leur absence pendant ces fenêtres reste à obtenir.
Le contrôle de libération volontaire du mode manuel reste à terminer. À
14:19:36, le diagnostic indiquait encore manual: true et zéro demande
applicative ; aucun marqueur négatif n'avait donc pu être obtenu. Les deux
observateurs temporaires ont été arrêtés sans modifier swayidle.service.
Le mécanisme PersistentProperties ne sauvegarde rien après l'arrêt ou le
crash du processus QuickShell ; une nouvelle session repart désactivée. Une
échéance limitée est exprimée en temps civil, afin de survivre au
rechargement : un changement manuel de l'horloge système peut donc modifier
la durée effective. Le premier chargement de V5 depuis l'ancien code ne
pouvait pas récupérer le booléen non conservé ; le mode a été réactivé
volontairement pour les mesures ci-dessus. Le verrouillage manuel et celui
avant suspension restent indépendants.
Le helper envoie un état complet puis des mises à jour ordonnées sur la socket
privée du répertoire XDG_RUNTIME_DIR. QuickShell confirme la prise en compte
de chaque état ; cette confirmation n'est pas un accusé du compositeur. Une
déconnexion efface immédiatement la contribution applicative dans QuickShell.
À la reconnexion, le helper renvoie seulement ses demandes encore valides.
Un redémarrage du helper perd ses demandes en mémoire : les applications
doivent renouveler leur requête ; il peut y avoir une interruption temporaire
de protection. Le compteur de cookies seul est conservé dans le répertoire
runtime de la session afin qu'un ancien cookie ne désactive pas une nouvelle
demande après ce redémarrage. Aucun nom d'application, motif ou état de
demande n'est stocké sur disque ni journalisé. Le pont limite les demandes à
256 et les libellés reçus à 512 octets chacun.
Le service utilisateur est voulu par wayland-session@sway.desktop.target,
après le service QuickShell. Il acquiert le nom D-Bus sans remplacer un autre
propriétaire et échoue proprement en cas de conflit. GTK utilise
DO_NOT_AUTO_START pour ce destinataire : un fichier d'activation D-Bus seul
ne suffirait pas. Le processus reste événementiel, avec une limite mémoire
systemd de 96 Mio. Pour diagnostiquer :
systemctl --user status labfy-idle-bridge.service
busctl --user introspect org.freedesktop.ScreenSaver /org/freedesktop/ScreenSaver
python ~/.dotfiles/tests/test_idle_bridge.py
Pour désactiver le pont, arrêter et désactiver uniquement
labfy-idle-bridge.service, puis retirer son lien Stow de
wayland-session@sway.desktop.target.wants lors du retour arrière. Le mode
manuel QuickShell reste disponible. Aucun changement de portals.conf, de
backend, de swayidle, du verrouillage manuel ou de la protection avant
suspension n'est nécessaire. Sans ce pont, le défaut du relais GTK décrit
ci-dessus réapparaît tant qu'aucun autre service ScreenSaver fonctionnel ne
prend le relais.