Dotfiles_ArchAP/portal/README.md

19 KiB
Raw Blame History

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.