diff --git a/docs/quickshell-dock-tela-polish-v2.md b/docs/quickshell-dock-tela-polish-v2.md new file mode 100644 index 000000000..1c15ebba4 --- /dev/null +++ b/docs/quickshell-dock-tela-polish-v2.md @@ -0,0 +1,137 @@ +# QuickShell Dock Tela — Polish V2 + +Livraison isolée du 22 octobre 2026, base `d4e2a001`, branche +`quickshell-dock-tela-polish-v2`, worktree +`/home/fy59/.dotfiles-worktrees/quickshell-dock-tela-polish-v2`. +La configuration du bureau actif n’a pas été modifiée ou rechargée. + +## Cause et correction du hover + +La V1 animait la largeur de chaque case de la `Row` et celle de chaque +`ApplicationIcon`. Chaque déplacement du pointeur modifiait donc les positions +suivantes, la largeur de la rangée et potentiellement celle de la surface. +De plus, `ApplicationIcon` calcule le `sourceSize` de son image depuis sa largeur : +la variation de taille demandait de nouvelles résolutions de rasterisation pour +les SVG Tela asynchrones. Ces deux chemins constituent les causes structurelles +identifiées des saccades et du risque de clignotement. Aucun profilage GPU du +bureau physique n’est revendiqué. + +Les cases gardent désormais une largeur de 54 px (plus le séparateur éventuel), +un pas de 57 px et des cibles souris fixes. Les images restent à 46 × 46 px, +avec une résolution demandée fixe de 92 × 92 px. Seul leur `scale` varie de +1 à 1,39, ancré en bas, avec une interpolation OutCubic de 80 ms. La taille +visuelle maximale est ainsi d’environ 64 px. Les deux marges de 12 px à +l’intérieur du viewport protègent aussi les icônes agrandies aux extrémités, +y compris après défilement sur un petit écran. + +L’influence du pointeur est une courbe smoothstep, symétrique, de rayon 76 px. +Ce rayon est inférieur à un pas et demi : seules la case la plus proche et ses +voisines immédiates peuvent recevoir une cible de grossissement non nulle. +Les positions de référence restent indépendantes de la transformation. +Les transitions peuvent brièvement finir leur interpolation après la sortie +du rayon. Aucun IPC, blur, chargement d’image ni relayout n’est déclenché par +l’animation elle-même. Les petits calculs d’influence restent liés au pointeur ; +aucun timer de polling ou délai de regroupement supplémentaire n’est nécessaire. + +## Fond flottant + +Le voile principal passe de 89 % à **16 % d’opacité**, sa hauteur de 70 à 58 px, +avec une bordure de 1 px à 9 % d’opacité. Une `RectangularShadow` QtQuick.Effects, +de géométrie fixe, produit l’ombre diffuse (blur 24, spread 2, noir à 32 %). +Elle ne capture ni les icônes ni le bureau. Le mode de contraste élevé conserve +un fond plus soutenu à 94 % et une bordure à 50 % pour la lisibilité. + +La règle SwayFX du seul namespace `labfy-sway-dock` désactive le flou du fond. +Le compromis retenu est un verre teinté très transparent, sans réfraction ni +flou des fenêtres derrière. Le rendu ne dépend donc plus d’un flou compositeur +recalculé pendant le hover. Les effets de la barre restent inchangés. +`RectangularShadow` nécessite Qt ≥ 6.9 ; l’hôte testé utilise Qt 6.12.0, +QuickShell 0.3.2 et SwayFX 0.6 (Sway 1.12.0). + +## Contrats préservés + +La machine auto-hide conserve sa bande de 4 px, son armement de 180 ms, +sa grâce de sortie de 450 ms et son animation verticale de 210 ms. +`WlrKeyboardFocus.None`, couche Top, `exclusiveZone: 0` et le masque d’entrée +restent en place. Aucune place permanente n’est réservée à l’écran. +Le menu, `FavoritesService`, la résolution Tela et le format des favoris +partagés sont inchangés. Aucun fichier Session V2, Keyring, PAM, greetd ou +logique de session n’a été modifié. + +## Validation + +Les tests s’exécutent dans un Sway privé headless, avec HOME, XDG, +sockets Wayland/Sway et profil Firefox privés, sans bus de session hérité. Les enfants sont arrêtés par +le laboratoire. Les journaux et résultats sont conservés dans +[validation/quickshell-dock-tela-polish-v2](validation/quickshell-dock-tela-polish-v2/). + +Commandes reproductibles depuis le worktree : + +```sh +python -m unittest discover -s tests/applications -v +node tests/applications/test_model.js +python -m unittest discover -s tests/dock -v +node tests/dock/test_models.js +python -m unittest discover -s tests/session_v2 -v +python tests/dock/headless.py +python tests/dock/shell_load.py +python tests/dock/session_compat.py +python tests/session_v2/validate_keyring.py --sway /usr/bin/sway +git diff --check +``` + +Résultats : 7 tests applications, 6 tests dock, 93 tests Session V2 backend, +les deux suites JavaScript, le chargement du shell complet, le scénario dock +et les scénarios Session V2/Keyring avec dock passent. Le validateur Keyring +complet termine avec ses onze contrôles à zéro (succès). + +Le test dock vérifie notamment : + +- 73 positions latérales sans changement de géométrie, sans changement d’état + des images et avec au plus trois influences non nulles ; +- 4,5 secondes de balayage continu, un mouvement souris par frame Qt, + sans changement de géométrie ni d’état de chargement des images ; +- extrémités non rognées après défilement sur une sortie de 400 px ; +- auto-hide, maintien pendant le menu contextuel, drag réel et redémarrage vide ; +- synchronisation menu/dock/client externe et réordonnancement durable ; +- absence de vol de focus vers le dock, fenêtres Kitty/Firefox privées, + reconnexion IPC et changements de résolution ; +- navigation clavier du menu et présence de la règle SwayFX sans blur du dock. + +Le dernier passage mesure 281 intervalles : moyenne 16.00 ms, +95e percentile 16.46 ms, maximum 16.62 ms. +Les intervalles d’animation sont conservés dans `result.json` ; ce sont des +mesures de cadence Qt avec rendu logiciel, pas des timestamps de présentation +matérielle. Ils établissent la stabilité du laboratoire privé. La perception +sur le GPU, le fond d’écran et les sorties physiques de la session active reste +à confirmer après intégration, sans prétendre l’avoir observée ici. + +Captures issues de `grim`, sans retouche : + +- [Dock fermé](validation/quickshell-dock-tela-polish-v2/closed.png). +- [Dock ouvert](validation/quickshell-dock-tela-polish-v2/open.png). +- [Dock survolé](validation/quickshell-dock-tela-polish-v2/zoom.png). +- [Survol sur fond clair : ombre et transparence](validation/quickshell-dock-tela-polish-v2/zoom-light.png). + +## Intégration + +Le patch complet, fichiers nouveaux et PNG compris, se trouve à côté du worktree : +`/home/fy59/.dotfiles-worktrees/quickshell-dock-tela-polish-v2.patch`. +Les changements restent non commités et aucun fichier de favoris n’est livré. + +Après revue, depuis le dépôt principal à la base compatible : + +```sh +cd /home/fy59/.dotfiles +git apply --check /home/fy59/.dotfiles-worktrees/quickshell-dock-tela-polish-v2.patch +git apply /home/fy59/.dotfiles-worktrees/quickshell-dock-tela-polish-v2.patch +swaymsg reload +systemctl --user restart quickshell-labfy-sway.service +``` + +La vérification `git apply --check` est effectuée à la livraison. Les trois +commandes d’application/rechargement restent à exécuter lors de l’intégration. +Le redémarrage QuickShell recharge aussi les autres composants du shell. +Après intégration, vérifier visuellement un balayage latéral, l’auto-hide et +le menu sur les sorties physiques. Il n’est pas nécessaire de réécrire les +favoris ou de redémarrer la session utilisateur. diff --git a/docs/validation/quickshell-dock-tela-polish-v2/applications.log b/docs/validation/quickshell-dock-tela-polish-v2/applications.log new file mode 100644 index 000000000..da2433f55 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/applications.log @@ -0,0 +1,12 @@ +test_bad_state_does_not_get_overwritten (test_backend.FavoritesTests.test_bad_state_does_not_get_overwritten) ... ok +test_seed_order_atomic_update_and_missing_entry (test_backend.FavoritesTests.test_seed_order_atomic_update_and_missing_entry) ... ok +test_graphical_uses_desktop_id_and_uwsm_service (test_backend.LaunchTests.test_graphical_uses_desktop_id_and_uwsm_service) ... ok +test_invalid_id_and_missing_entry (test_backend.LaunchTests.test_invalid_id_and_missing_entry) ... ok +test_nodisplay_entry_is_refused_before_launch (test_backend.LaunchTests.test_nodisplay_entry_is_refused_before_launch) ... ok +test_terminal_entry_already_running_kitty_is_not_wrapped_twice (test_backend.LaunchTests.test_terminal_entry_already_running_kitty_is_not_wrapped_twice) ... ok +test_terminal_preserves_desktop_exec_fields_and_kitty (test_backend.LaunchTests.test_terminal_preserves_desktop_exec_fields_and_kitty) ... ok + +---------------------------------------------------------------------- +Ran 7 tests in 0.004s + +OK diff --git a/docs/validation/quickshell-dock-tela-polish-v2/closed.png b/docs/validation/quickshell-dock-tela-polish-v2/closed.png new file mode 100644 index 000000000..0d5c96b47 Binary files /dev/null and b/docs/validation/quickshell-dock-tela-polish-v2/closed.png differ diff --git a/docs/validation/quickshell-dock-tela-polish-v2/compat.log b/docs/validation/quickshell-dock-tela-polish-v2/compat.log new file mode 100644 index 000000000..feee4bbbe --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/compat.log @@ -0,0 +1,18 @@ +/tmp/labfy-session-v2-TEST_ONLY-s23v41ci +ready PASS +accept PASS +cancel PASS +timeout PASS +absent PASS +still-locked PASS +different PASS +quickshell-restart-during-unlock PASS +keyring_ui WITH_DOCK PASS +success PASS +failure PASS +invalid PASS +new PASS +claimed PASS +real PASS +deferred-real PASS +phase3b_ui WITH_DOCK PASS diff --git a/docs/validation/quickshell-dock-tela-polish-v2/headless.log b/docs/validation/quickshell-dock-tela-polish-v2/headless.log new file mode 100644 index 000000000..f9d4e28be --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/headless.log @@ -0,0 +1 @@ +Dock headless: PASS /tmp/labfy-session-v2-TEST_ONLY-dlggtemr diff --git a/docs/validation/quickshell-dock-tela-polish-v2/javascript.log b/docs/validation/quickshell-dock-tela-polish-v2/javascript.log new file mode 100644 index 000000000..9e80b1e99 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/javascript.log @@ -0,0 +1,2 @@ +Dock state and window models: PASS +ApplicationsModel: PASS diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-backend.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-backend.log new file mode 100644 index 000000000..9755ec110 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-backend.log @@ -0,0 +1,59 @@ +............................/usr/lib/python3.14/site-packages/gi/events.py:803: DeprecationWarning: 'asyncio.AbstractEventLoopPolicy' is deprecated and slated for removal in Python 3.16 + AbstractEventLoopPolicy = getattr(asyncio, "AbstractEventLoopPolicy", object) +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +../usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +./usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +../usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +../usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +.......................................................... +---------------------------------------------------------------------- +Ran 93 tests in 8.443s + +OK diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-focus.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-focus.log new file mode 100644 index 000000000..d52c179d5 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-focus.log @@ -0,0 +1,5 @@ +............................. +---------------------------------------------------------------------- +Ran 29 tests in 0.129s + +OK diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-keyring-runtime.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-keyring-runtime.log new file mode 100644 index 000000000..dc5357997 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-keyring-runtime.log @@ -0,0 +1,4 @@ +/tmp/labfy-session-v2-TEST_ONLY-0p63m0if +stable-final-focus PASS +/tmp/labfy-session-v2-TEST_ONLY-vn3vcup_ +late-refused PASS diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-keyring-ui.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-keyring-ui.log new file mode 100644 index 000000000..7a130bce1 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-keyring-ui.log @@ -0,0 +1,9 @@ +/tmp/labfy-session-v2-TEST_ONLY-p4jqsmpt +ready PASS +accept PASS +cancel PASS +timeout PASS +absent PASS +still-locked PASS +different PASS +quickshell-restart-during-unlock PASS diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-p0-runtime.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-p0-runtime.log new file mode 100644 index 000000000..b7b3e4ebe --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-p0-runtime.log @@ -0,0 +1,5 @@ +guard-replacement PASS APPLICATION_MEMBERSHIP_CHANGED +guard-extra PASS APPLICATION_MEMBERSHIP_CHANGED +last-capture-layout PASS FINAL_TREE_MISMATCH +last-capture-swap PASS RECOVERY_ORDER_CHANGED +guard-finish-layout PASS FINAL_TREE_MISMATCH diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-path-runtime.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-path-runtime.log new file mode 100644 index 000000000..97b5bd712 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-path-runtime.log @@ -0,0 +1,5 @@ +pendant-guard SUCCÈS : quatre swaps, quatre slots, arbre exact, focus vérifié +apres-phase0 SUCCÈS : quatre swaps, quatre slots, arbre exact, focus vérifié +deux-frontieres SUCCÈS : quatre swaps, quatre slots, arbre exact, focus vérifié +autotiling-guard SUCCÈS : quatre swaps, quatre slots, arbre exact, focus vérifié +provider-unaire SUCCÈS : changement externe refusé avant IPC suivant diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-phase3b-ui.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-phase3b-ui.log new file mode 100644 index 000000000..a87285cee --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-phase3b-ui.log @@ -0,0 +1,7 @@ +success PASS +failure PASS +invalid PASS +new PASS +claimed PASS +real PASS +deferred-real PASS diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-qml-qt.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-qml-qt.log new file mode 100644 index 000000000..d9926e9bb --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-qml-qt.log @@ -0,0 +1,10 @@ +********* Start testing of qmltestrunner ********* +Config: Using QtTest library 6.12.0, Qt 6.12.0 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 16.2.1 20260810), arch unknown +PASS : qmltestrunner::SessionExitGateV2::initTestCase() +PASS : qmltestrunner::SessionExitGateV2::test_backend_reason_is_visible_and_logout_stays_gated() +PASS : qmltestrunner::SessionExitGateV2::test_error_or_legacy_success_never_exits() +PASS : qmltestrunner::SessionExitGateV2::test_quit_without_saving_requires_explicit_call() +PASS : qmltestrunner::SessionExitGateV2::test_saved_releases_only_confirmed_action() +PASS : qmltestrunner::SessionExitGateV2::cleanupTestCase() +Totals: 6 passed, 0 failed, 0 skipped, 0 blacklisted, 5ms +********* Finished testing of qmltestrunner ********* diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-qml-unit.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-qml-unit.log new file mode 100644 index 000000000..59acbb363 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-qml-unit.log @@ -0,0 +1,5 @@ +............... +---------------------------------------------------------------------- +Ran 15 tests in 20.330s + +OK diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-results.json b/docs/validation/quickshell-dock-tela-polish-v2/keyring-results.json new file mode 100644 index 000000000..316f4fc7b --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-results.json @@ -0,0 +1,13 @@ +{ + "backend": 0, + "focus": 0, + "qml-unit": 0, + "qml-qt": 0, + "keyring-ui": 0, + "keyring-runtime": 0, + "scratchpad-runtime": 0, + "phase3b-ui": 0, + "p0-runtime": 0, + "path-runtime": 0, + "diff-check": 0 +} diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring-scratchpad-runtime.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring-scratchpad-runtime.log new file mode 100644 index 000000000..ee49c089b --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring-scratchpad-runtime.log @@ -0,0 +1,2 @@ +/tmp/labfy-session-v2-TEST_ONLY-1lfda8ji +PASS save/store/restore/show/hide/new-membership/all-hidden/cold-kitty/no-duplicate diff --git a/docs/validation/quickshell-dock-tela-polish-v2/keyring.log b/docs/validation/quickshell-dock-tela-polish-v2/keyring.log new file mode 100644 index 000000000..65a9f8759 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/keyring.log @@ -0,0 +1,12 @@ +/tmp/labfy-keyring-validation-ibq2bukh +backend 0 +focus 0 +qml-unit 0 +qml-qt 0 +keyring-ui 0 +keyring-runtime 0 +scratchpad-runtime 0 +phase3b-ui 0 +p0-runtime 0 +path-runtime 0 +diff-check 0 diff --git a/docs/validation/quickshell-dock-tela-polish-v2/open.png b/docs/validation/quickshell-dock-tela-polish-v2/open.png new file mode 100644 index 000000000..49ff0ae8a Binary files /dev/null and b/docs/validation/quickshell-dock-tela-polish-v2/open.png differ diff --git a/docs/validation/quickshell-dock-tela-polish-v2/result.json b/docs/validation/quickshell-dock-tela-polish-v2/result.json new file mode 100644 index 000000000..52c73c6e0 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/result.json @@ -0,0 +1,1637 @@ +{ + "status": "PASS", + "initial": { + "ready": true, + "ids": [ + "firefox.desktop", + "kitty.desktop", + "yazi.desktop", + "nvim.desktop", + "org.darktable.darktable.desktop", + "orca-slicer.desktop", + "org.freecad.FreeCAD.desktop", + "org.kde.digikam.desktop", + "AppFlowy.desktop" + ], + "error": "", + "phase": "hidden", + "revealed": false, + "entries": [ + { + "id": "firefox.desktop", + "name": "Mozilla Firefox", + "genericName": "Web Browser", + "keywords": [ + "Internet", + "WWW", + "Browser", + "Web", + "Explorer" + ], + "icon": "firefox", + "iconSource": "file:///usr/share/icons/Tela-circle-purple-dark/scalable/apps/firefox.svg", + "aliases": [ + "firefox" + ], + "newInstance": false, + "category": "Internet", + "pinned": true, + "windows": [] + }, + { + "id": "kitty.desktop", + "name": "kitty", + "genericName": "Terminal emulator", + "keywords": [], + "icon": "kitty", + "iconSource": "file:///usr/share/icons/Tela-circle-purple-dark/scalable/apps/kitty.svg", + "aliases": [ + "kitty" + ], + "newInstance": true, + "category": "Syst\u00e8me", + "pinned": true, + "windows": [] + }, + { + "id": "yazi.desktop", + "name": "Yazi File Manager", + "genericName": "", + "keywords": [ + "File", + "Manager", + "Explorer", + "Browser", + "Launcher" + ], + "icon": "yazi", + "iconSource": "file:///usr/share/icons/hicolor/48x48/apps/yazi.png", + "aliases": [ + "yazi" + ], + "newInstance": false, + "category": "Syst\u00e8me", + "pinned": true, + "windows": [] + }, + { + "id": "nvim.desktop", + "name": "Neovim", + "genericName": "Text Editor", + "keywords": [ + "Text", + "editor" + ], + "icon": "nvim", + "iconSource": "file:///usr/share/icons/Tela-circle-purple-dark/scalable/apps/nvim.svg", + "aliases": [ + "nvim" + ], + "newInstance": false, + "category": "D\u00e9veloppement", + "pinned": true, + "windows": [] + }, + { + "id": "org.darktable.darktable.desktop", + "name": "Darktable Photo Workflow Software", + "genericName": "Virtual Lighttable and Darkroom", + "keywords": [ + "graphics", + "photography", + "raw" + ], + "icon": "darktable", + "iconSource": "file:///usr/share/icons/Tela-circle-purple-dark/scalable/apps/darktable.svg", + "aliases": [ + "darktable", + "org.darktable.darktable" + ], + "newInstance": false, + "category": "Graphisme", + "pinned": true, + "windows": [] + }, + { + "id": "orca-slicer.desktop", + "name": "OrcaSlicer", + "genericName": "", + "keywords": [], + "icon": "OrcaSlicer", + "iconSource": "file:///usr/share/icons/hicolor/192x192/apps/OrcaSlicer.png", + "aliases": [ + "apprun", + "orca-slicer" + ], + "newInstance": false, + "category": "Utilitaires", + "pinned": true, + "windows": [] + }, + { + "id": "org.freecad.FreeCAD.desktop", + "name": "FreeCAD", + "genericName": "CAD Application", + "keywords": [], + "icon": "org.freecad.FreeCAD", + "iconSource": "file:///usr/share/icons/Tela-circle-purple-dark/scalable/apps/org.freecad.FreeCAD.svg", + "aliases": [ + "freecad", + "org.freecad.freecad" + ], + "newInstance": false, + "category": "Graphisme", + "pinned": true, + "windows": [] + }, + { + "id": "org.kde.digikam.desktop", + "name": "digiKam", + "genericName": "Photo Management Program", + "keywords": [], + "icon": "digikam", + "iconSource": "file:///usr/share/icons/Tela-circle-purple-dark/scalable/apps/digikam.svg", + "aliases": [ + "digikam", + "org.kde.digikam" + ], + "newInstance": false, + "category": "Graphisme", + "pinned": true, + "windows": [] + }, + { + "id": "AppFlowy.desktop", + "name": "AppFlowy", + "genericName": "", + "keywords": [ + "Notes" + ], + "icon": "appflowy", + "iconSource": "file:///usr/share/icons/hicolor/scalable/apps/appflowy.svg", + "aliases": [ + "appflowy" + ], + "newInstance": false, + "category": "Internet", + "pinned": true, + "windows": [] + } + ], + "theme": "Tela-circle-purple-dark", + "menu": null, + "searchFocused": false, + "navFocused": false, + "gridFocused": false, + "screenWidth": 1280, + "bodyY": 364, + "width": 562, + "pointerX": -1000, + "tileWidth": 54, + "tiles": [ + { + "x": 0, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 16, + "visualRight": 62, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 57, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 73, + "visualRight": 119, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 114, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 130, + "visualRight": 176, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 171, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 187, + "visualRight": 233, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 228, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 244, + "visualRight": 290, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 285, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 301, + "visualRight": 347, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 342, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 358, + "visualRight": 404, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 399, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 415, + "visualRight": 461, + "iconWidth": 46, + "imageStatus": 1 + }, + { + "x": 456, + "width": 54, + "growth": 0, + "scale": 1, + "visualLeft": 472, + "visualRight": 518, + "iconWidth": 46, + "imageStatus": 1 + } + ], + "context": false + }, + "hoverSamples": [ + { + "pointerX": 45, + "scales": [ + 1.363804782038198, + 1.0157095258055109, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 51, + "scales": [ + 1.3882699550557924, + 1.0548027323828943, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 57, + "scales": [ + 1.3843136851862765, + 1.091309228253847, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 63, + "scales": [ + 1.373286850141958, + 1.1206986191125898, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 69, + "scales": [ + 1.3408528358586607, + 1.1776019752381606, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 75, + "scales": [ + 1.305681608388378, + 1.2234332799799008, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 81, + "scales": [ + 1.2580024360560373, + 1.2748487289194408, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 87, + "scales": [ + 1.2196026259959813, + 1.3090104233033235, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 93, + "scales": [ + 1.1741498267604817, + 1.3432409357273196, + 1.0024931307890408, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 99, + "scales": [ + 1.1416728912650975, + 1.3628458983572371, + 1.0109736368982896, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 105, + "scales": [ + 1.0873033026767522, + 1.3854422056168032, + 1.0394622691784017, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 111, + "scales": [ + 1.0615376146658617, + 1.3882249143461145, + 1.0621942601060335, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 117, + "scales": [ + 1.0241429672683096, + 1.3775922781514893, + 1.1111828894698241, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 123, + "scales": [ + 1.0065390307321243, + 1.3555244887699822, + 1.1548417092675867, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 129, + "scales": [ + 1.0016381307786313, + 1.334227800805353, + 1.186696970448121, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 135, + "scales": [ + 1, + 1.2857378080404833, + 1.245990942981073, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 141, + "scales": [ + 1, + 1.2426400446073833, + 1.2888160829061537, + 1, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 147, + "scales": [ + 1, + 1.2098712046539537, + 1.316621264396069, + 1.0001027272553589, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 153, + "scales": [ + 1, + 1.1651762764597622, + 1.348701019112463, + 1.0048592500011324, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 159, + "scales": [ + 1, + 1.1210207885160686, + 1.3729180386449071, + 1.0198319687657567, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 165, + "scales": [ + 1, + 1.0685981037928376, + 1.3884777989704347, + 1.0549030997871813, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 171, + "scales": [ + 1, + 1.036552155625594, + 1.3843246457052127, + 1.0913145210661823, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 177, + "scales": [ + 1, + 1.0196469552617207, + 1.3732869709621067, + 1.1206986774563943, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 183, + "scales": [ + 1, + 1.0022753856578528, + 1.3408528385041445, + 1.1776019765156591, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 189, + "scales": [ + 1, + 1.0001252792877882, + 1.3168184087535504, + 1.2096279270453352, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 195, + "scales": [ + 1, + 1, + 1.2646255664435333, + 1.2678817124001625, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 201, + "scales": [ + 1, + 1, + 1.2200364356853728, + 1.308553983154517, + 1, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 207, + "scales": [ + 1, + 1, + 1.1731284917173772, + 1.3440476564587591, + 1.002532753157348, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 213, + "scales": [ + 1, + 1, + 1.1287313369884162, + 1.3699002407890941, + 1.015529441631054, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 219, + "scales": [ + 1, + 1, + 1.0874106773358652, + 1.3854975925447648, + 1.039272178046402, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 225, + "scales": [ + 1, + 1, + 1.062353360346548, + 1.3882249143461145, + 1.0613770391697144, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 231, + "scales": [ + 1, + 1, + 1.0241428681567737, + 1.3775922781514893, + 1.111182923603433, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 237, + "scales": [ + 1, + 1, + 1.0065390255055393, + 1.3555244887699822, + 1.1548417110676013, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 243, + "scales": [ + 1, + 1, + 1.001571315438749, + 1.3334517260736825, + 1.1877654820586214, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 249, + "scales": [ + 1, + 1, + 1, + 1.2852112500207933, + 1.2465951521847594, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 255, + "scales": [ + 1, + 1, + 1, + 1.2422315830896524, + 1.2892849275943337, + 1, + 1, + 1, + 1 + ] + }, + { + "pointerX": 261, + "scales": [ + 1, + 1, + 1, + 1.197097072168452, + 1.3268074123175235, + 1.000160070329069, + 1, + 1, + 1 + ] + }, + { + "pointerX": 267, + "scales": [ + 1, + 1, + 1, + 1.1510118807674257, + 1.3579525725649766, + 1.007467520384492, + 1, + 1, + 1 + ] + }, + { + "pointerX": 273, + "scales": [ + 1, + 1, + 1, + 1.108024748464491, + 1.3788864904903757, + 1.0259707460414806, + 1, + 1, + 1 + ] + }, + { + "pointerX": 279, + "scales": [ + 1, + 1, + 1, + 1.079565649932684, + 1.3865718264665194, + 1.0459330060333922, + 1, + 1, + 1 + ] + }, + { + "pointerX": 285, + "scales": [ + 1, + 1, + 1, + 1.0462598464917812, + 1.3862846725543692, + 1.0795371532009201, + 1, + 1, + 1 + ] + }, + { + "pointerX": 291, + "scales": [ + 1, + 1, + 1, + 1.0136379141577305, + 1.3676152122568639, + 1.13317790498388, + 1, + 1, + 1 + ] + }, + { + "pointerX": 297, + "scales": [ + 1, + 1, + 1, + 1.002068961498849, + 1.340664330436317, + 1.178023299851276, + 1, + 1, + 1 + ] + }, + { + "pointerX": 303, + "scales": [ + 1, + 1, + 1, + 1.0001392322308533, + 1.3056716676727467, + 1.2234554982700454, + 1, + 1, + 1 + ] + }, + { + "pointerX": 309, + "scales": [ + 1, + 1, + 1, + 1, + 1.2646406775018222, + 1.2678580979378713, + 1, + 1, + 1 + ] + }, + { + "pointerX": 315, + "scales": [ + 1, + 1, + 1, + 1, + 1.233665522909586, + 1.2966355960016418, + 1, + 1, + 1 + ] + }, + { + "pointerX": 321, + "scales": [ + 1, + 1, + 1, + 1, + 1.1741498266418597, + 1.3432409359924493, + 1.0024931307890408, + 1, + 1 + ] + }, + { + "pointerX": 327, + "scales": [ + 1, + 1, + 1, + 1, + 1.129349274890679, + 1.3695476988829187, + 1.0153328423621721, + 1, + 1 + ] + }, + { + "pointerX": 333, + "scales": [ + 1, + 1, + 1, + 1, + 1.0991118526368178, + 1.381642492341664, + 1.0317914813699147, + 1, + 1 + ] + }, + { + "pointerX": 339, + "scales": [ + 1, + 1, + 1, + 1, + 1.0515551133187797, + 1.3882249143461145, + 1.072290857131641, + 1, + 1 + ] + }, + { + "pointerX": 345, + "scales": [ + 1, + 1, + 1, + 1, + 1.031302112818197, + 1.3814012791361672, + 1.0998593954820672, + 1, + 1 + ] + }, + { + "pointerX": 351, + "scales": [ + 1, + 1, + 1, + 1, + 1.0113010253633286, + 1.362713089675657, + 1.141529633350545, + 1, + 1 + ] + }, + { + "pointerX": 357, + "scales": [ + 1, + 1, + 1, + 1, + 1.0008131200005774, + 1.324146205446569, + 1.2005421506786613, + 1, + 1 + ] + }, + { + "pointerX": 363, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.2857508471322725, + 1.245966768372768, + 1, + 1 + ] + }, + { + "pointerX": 369, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.2559053818860124, + 1.2761665810744798, + 1, + 1 + ] + }, + { + "pointerX": 375, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.1970970750539196, + 1.3268074069680855, + 1.000160070329069, + 1 + ] + }, + { + "pointerX": 381, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.151486270447754, + 1.3575686559483435, + 1.0074655480065615, + 1 + ] + }, + { + "pointerX": 387, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.1070407821140205, + 1.3794115185542348, + 1.0263251664385529, + 1 + ] + }, + { + "pointerX": 393, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.0685753058608392, + 1.3884925759026732, + 1.0549074341167726, + 1 + ] + }, + { + "pointerX": 399, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.0453616958182157, + 1.3864488384842315, + 1.08026193510416, + 1 + ] + }, + { + "pointerX": 405, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.0139062780445325, + 1.3678663125832273, + 1.1326239577178407, + 1 + ] + }, + { + "pointerX": 411, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.0022912412325862, + 1.3408564174454372, + 1.1775823431330856, + 1 + ] + }, + { + "pointerX": 417, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1.0000496853136491, + 1.3053851325913794, + 1.2239032141967106, + 1 + ] + }, + { + "pointerX": 423, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.2646255672533906, + 1.2678817079574416, + 1 + ] + }, + { + "pointerX": 429, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.22003643572808, + 1.3085539829202328, + 1 + ] + }, + { + "pointerX": 435, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.1869415232944303, + 1.3340494428249292, + 1.001599999729484 + ] + }, + { + "pointerX": 441, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.1287313369884275, + 1.3699002407890322, + 1.015529441631054 + ] + }, + { + "pointerX": 447, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.0990870533766723, + 1.3816564407471799, + 1.0317995774913613 + ] + }, + { + "pointerX": 453, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.0625003528527146, + 1.3881672014501516, + 1.061576792831316 + ] + }, + { + "pointerX": 459, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.0321703297321074, + 1.3814012791361672, + 1.0990095389269032 + ] + }, + { + "pointerX": 465, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.0065401423812486, + 1.3555244887699822, + 1.1548409962939408 + ] + }, + { + "pointerX": 471, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1.0008141225084088, + 1.324146205446569, + 1.200541169371066 + ] + }, + { + "pointerX": 477, + "scales": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1.2854107423974463, + 1.246443367916735 + ] + } + ], + "animationTiming": { + "frames": 281, + "meanMs": 15.999635021352313, + "p95Ms": 16.464266000000002, + "maxMs": 16.616559 + }, + "frameSweep": { + "running": false, + "intervals": [ + 15.897642999999999, + 16.411628, + 16.057852, + 16.185438, + 15.240653, + 16.151425, + 16.27814, + 16.183565, + 15.298279999999998, + 16.457805, + 16.308977, + 15.391464000000001, + 16.426786, + 15.367889, + 16.315631, + 16.361515, + 15.333606, + 16.300752000000003, + 16.370462, + 15.413794999999999, + 16.340566000000003, + 16.353811, + 15.348243, + 16.350755000000003, + 16.310109999999998, + 15.317406, + 16.381382, + 16.275386, + 15.363381, + 16.245078, + 16.21301, + 16.376303, + 15.33599, + 16.382474000000002, + 15.361187, + 16.378216000000002, + 16.373799, + 15.369182, + 16.375811, + 16.439491, + 15.462925, + 16.377736, + 15.325671000000002, + 16.593166, + 15.361547, + 16.325098, + 16.464266000000002, + 15.399378, + 16.403033, + 15.398947, + 16.50952, + 15.384971, + 16.463074000000002, + 16.454839, + 15.414386, + 16.544324999999997, + 15.378048, + 16.373507, + 15.35751, + 16.352349, + 16.390179, + 15.376846, + 16.375832, + 16.358379, + 15.344857, + 16.325899, + 16.362486999999998, + 15.53487, + 16.32085, + 15.301837, + 16.316482, + 16.378566, + 15.360706, + 16.352108, + 16.276989, + 15.323697000000001, + 16.406329, + 16.424963, + 15.476421, + 16.545237, + 15.317005, + 16.370290999999998, + 16.374099, + 15.381103999999999, + 16.368118000000003, + 15.362149, + 16.353711, + 16.363297999999997, + 15.339215999999999, + 16.358921, + 16.367907000000002, + 15.337994, + 16.297967, + 16.340567, + 15.320390999999999, + 16.424693, + 16.316330999999998, + 15.326884000000002, + 16.335707000000003, + 16.349794, + 15.417752, + 16.381693, + 15.296035, + 16.303969000000002, + 16.230742, + 16.205566, + 15.333245, + 16.322263, + 16.32127, + 15.321914000000001, + 16.223279, + 16.281457, + 15.560717, + 16.367206, + 16.327382, + 15.224113, + 16.173396, + 16.210784999999998, + 16.371474, + 15.296096, + 16.363379000000002, + 16.338152, + 15.404727, + 16.384068000000003, + 16.332181000000002, + 15.525362, + 16.392622999999997, + 15.364123000000001, + 16.470388, + 15.423582999999999, + 16.379929, + 16.353651, + 15.420055999999999, + 16.414144, + 15.430926, + 16.423711, + 16.406439, + 15.579593, + 16.391892000000002, + 15.372037, + 16.317694, + 16.411829, + 15.379441, + 16.437907000000003, + 15.416981, + 16.408763, + 15.4758, + 16.450751, + 16.421446999999997, + 15.550208, + 16.353571000000002, + 15.526164, + 16.386360999999997, + 15.339256, + 16.323385, + 16.335176, + 15.458298000000001, + 16.429130999999998, + 15.353423, + 16.436715, + 16.437176, + 15.586034, + 16.399176, + 15.451715, + 15.851508, + 16.432367, + 15.388147, + 16.431536, + 16.415997, + 15.342602000000001, + 16.373848, + 16.453447, + 15.460361, + 16.537803, + 15.47078, + 16.388455999999998, + 15.449351, + 16.368969, + 15.398525999999999, + 16.386663, + 16.45047, + 15.407713999999999, + 16.413171000000002, + 15.424294, + 16.441765, + 15.602365, + 16.418250999999998, + 15.399467999999999, + 16.274634, + 16.318436, + 16.242975, + 15.305053000000001, + 16.406459, + 15.460402, + 16.39663, + 16.448447, + 15.436517, + 16.564523, + 15.348944, + 16.332081, + 16.352228, + 15.268595, + 16.348251, + 16.349393, + 15.272803, + 16.418201, + 16.383176, + 15.370424, + 16.369390000000003, + 15.439743, + 16.395849000000002, + 16.376714, + 15.374161, + 16.370853, + 15.39483, + 16.505743, + 16.340697000000002, + 15.306916000000001, + 16.356947, + 16.364030000000003, + 15.383779, + 16.566246, + 15.363391, + 16.385831, + 15.375684, + 16.500604, + 16.399145, + 15.332324, + 16.330778000000002, + 16.309108, + 15.334909000000001, + 16.36962, + 16.005775, + 16.057651, + 16.134884, + 16.153147999999998, + 15.149434, + 16.356547, + 16.436064000000002, + 15.247686, + 16.340595999999998, + 16.368918999999998, + 15.350518000000001, + 16.370222000000002, + 16.342209, + 15.365936, + 16.533545, + 15.351359, + 16.367627, + 16.366515000000003, + 15.372027, + 16.405117, + 15.358281999999999, + 16.303327, + 16.344063, + 15.430556, + 16.406169000000002, + 16.403072, + 15.543726000000001, + 16.337401, + 15.328857, + 16.407861999999998, + 16.391361, + 15.333165, + 16.274773999999997, + 16.333574, + 15.275027, + 16.422698999999998, + 16.33167, + 15.35709, + 16.414784, + 15.407844, + 16.415516, + 16.323034, + 15.38384, + 16.539375, + 15.468908, + 16.501946, + 15.531704, + 16.616559, + 15.40557 + ], + "geometryChanged": false, + "imageChanged": false + }, + "reordered": [ + "kitty.desktop", + "firefox.desktop", + "yazi.desktop", + "nvim.desktop", + "org.darktable.darktable.desktop", + "orca-slicer.desktop", + "org.freecad.FreeCAD.desktop", + "org.kde.digikam.desktop", + "AppFlowy.desktop" + ], + "checks": [ + "shared favorites", + "menu and dock mutations", + "durable reorder", + "empty restart", + "autohide", + "context hold", + "kitty multi-window", + "floating scratchpad explicit focus", + "window close", + "no hover focus", + "real pointer drag", + "fixed layout transform hover", + "stable SVG readiness", + "lateral sweep 73 samples", + "IPC reconnect", + "Firefox private profile", + "desktop install/remove monitoring", + "external writer", + "keyboard menu navigation", + "resolution change", + "SwayFX dock blur disabled" + ] +} diff --git a/docs/validation/quickshell-dock-tela-polish-v2/session.log b/docs/validation/quickshell-dock-tela-polish-v2/session.log new file mode 100644 index 000000000..8c95e3b20 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/session.log @@ -0,0 +1,152 @@ +test_absent_last_existing_directory (test_bootstrap.BootstrapTests.test_absent_last_existing_directory) ... ok +test_absent_no_creation (test_bootstrap.BootstrapTests.test_absent_no_creation) ... ok +test_allowlist_denied (test_bootstrap.BootstrapTests.test_allowlist_denied) ... ok +test_checkpoint_created_between_observations (test_bootstrap.BootstrapTests.test_checkpoint_created_between_observations) ... ok +test_empty_sessions_with_or_without_automatic_allows_without_creation (test_bootstrap.BootstrapTests.test_empty_sessions_with_or_without_automatic_allows_without_creation) ... ok +test_envelope_and_framing_rejected (test_bootstrap.BootstrapTests.test_envelope_and_framing_rejected) ... ok +test_home_fallback_matches_canonical_location (test_bootstrap.BootstrapTests.test_home_fallback_matches_canonical_location) ... ok +test_interleaved_operations_map_unchanged (test_bootstrap.BootstrapTests.test_interleaved_operations_map_unchanged) ... ok +test_last_with_sessions_absent_refuses (test_bootstrap.BootstrapTests.test_last_with_sessions_absent_refuses) ... ok +test_named_only_without_automatic_refuses (test_bootstrap.BootstrapTests.test_named_only_without_automatic_refuses) ... ok +test_os_error_is_not_absence (test_bootstrap.BootstrapTests.test_os_error_is_not_absence) ... ok +test_present_and_corrupt_always_refuse (test_bootstrap.BootstrapTests.test_present_and_corrupt_always_refuse) ... ok +test_sessions_any_entry_refuses_without_content_read (test_bootstrap.BootstrapTests.test_sessions_any_entry_refuses_without_content_read) ... ok +test_sessions_list_error_refuses (test_bootstrap.BootstrapTests.test_sessions_list_error_refuses) ... ok +test_sessions_unsafe_directory_refuses (test_bootstrap.BootstrapTests.test_sessions_unsafe_directory_refuses) ... ok +test_socket_authority_failure_refuses_absence (test_bootstrap.BootstrapTests.test_socket_authority_failure_refuses_absence) ... ok +test_state_symlink_and_relative_state_refuse (test_bootstrap.BootstrapTests.test_state_symlink_and_relative_state_refuse) ... ok +test_symlinks_and_special_last_refuse_without_open (test_bootstrap.BootstrapTests.test_symlinks_and_special_last_refuse_without_open) ... ok +test_unreadable_and_nonprivate_directory_refuse (test_bootstrap.BootstrapTests.test_unreadable_and_nonprivate_directory_refuse) ... ok +test_valid_store_checkpoint_and_unreadable_file_refuse (test_bootstrap.BootstrapTests.test_valid_store_checkpoint_and_unreadable_file_refuse) ... ok +test_equivalent_unary_paths_are_not_identity_changes (test_focus_recovery.FocusRecoveryTests.test_equivalent_unary_paths_are_not_identity_changes) ... ok +test_firefox_command_proven_then_kitty_late_conflict_is_preserved (test_focus_recovery.FocusRecoveryTests.test_firefox_command_proven_then_kitty_late_conflict_is_preserved) ... ok +test_interrupted_intention_preserves_all_evidence (test_focus_recovery.FocusRecoveryTests.test_interrupted_intention_preserves_all_evidence) ... ok +test_layout_change_with_identical_raw_paths_still_refuses (test_focus_recovery.FocusRecoveryTests.test_layout_change_with_identical_raw_paths_still_refuses) ... ok +test_path_evidence_limit_refuses_without_overwriting_history (test_focus_recovery.FocusRecoveryTests.test_path_evidence_limit_refuses_without_overwriting_history) ... ok +test_real_identity_order_workspace_and_branch_changes_still_refuse (test_focus_recovery.FocusRecoveryTests.test_real_identity_order_workspace_and_branch_changes_still_refuse) ... ok +test_prepare_quits_before_resume_and_finish_has_no_delayed_exit (test_guard_protocol.GuardProtocolTests.test_prepare_quits_before_resume_and_finish_has_no_delayed_exit) ... ok +test_resume_without_prepare_refuses_and_still_cleans_owned_helper (test_guard_protocol.GuardProtocolTests.test_resume_without_prepare_refuses_and_still_cleans_owned_helper) ... ok +test_actual_dbus_states (test_keyring.KeyringTests.test_actual_dbus_states) ... /usr/lib/python3.14/site-packages/gi/events.py:803: DeprecationWarning: 'asyncio.AbstractEventLoopPolicy' is deprecated and slated for removal in Python 3.16 + AbstractEventLoopPolicy = getattr(asyncio, "AbstractEventLoopPolicy", object) +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +ok +test_apply_is_excluded_during_unlock (test_keyring.KeyringTests.test_apply_is_excluded_during_unlock) ... ok +test_apply_last_cannot_bypass_gate (test_keyring.KeyringTests.test_apply_last_cannot_bypass_gate) ... /usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +ok +test_ready_preserves_executor_result_and_recovery_required (test_keyring.KeyringTests.test_ready_preserves_executor_result_and_recovery_required) ... /usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +ok +test_remote_error_text_is_never_logged_or_persisted (test_keyring.KeyringTests.test_remote_error_text_is_never_logged_or_persisted) ... ok +test_transaction_prevents_prompt (test_keyring.KeyringTests.test_transaction_prevents_prompt) ... /usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +ok +test_two_processes_and_restart (test_keyring.KeyringTests.test_two_processes_and_restart) ... ok +test_unlock_never_restores (test_keyring.KeyringTests.test_unlock_never_restores) ... /usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +/usr/lib/python3.14/site-packages/gi/events.py:890: DeprecationWarning: 'asyncio.get_event_loop_policy' is deprecated and slated for removal in Python 3.16 + if not isinstance(_get_event_loop_policy(), GLibEventLoopPolicy): +ok +test_complete_refuses_full_identity_placement_and_pending (test_p0_boundaries.BoundaryTests.test_complete_refuses_full_identity_placement_and_pending) ... ok +test_extra_after_first_move_refuses_before_second_staging (test_p0_boundaries.BoundaryTests.test_extra_after_first_move_refuses_before_second_staging) ... ok +test_guard_replacement_and_extra_refuse_before_any_mutation (test_p0_boundaries.BoundaryTests.test_guard_replacement_and_extra_refuse_before_any_mutation) ... ok +test_last_provider_capture_cannot_hide_structure_or_identity_change (test_p0_boundaries.BoundaryTests.test_last_provider_capture_cannot_hide_structure_or_identity_change) ... ok +test_layout_change_in_second_split_focus_observation_refuses (test_p0_boundaries.BoundaryTests.test_layout_change_in_second_split_focus_observation_refuses) ... ok +test_unary_parent_normalization_preserves_canonical_layout (test_p0_boundaries.BoundaryTests.test_unary_parent_normalization_preserves_canonical_layout) ... ok +test_unchanged_final_observation_completes (test_p0_boundaries.BoundaryTests.test_unchanged_final_observation_completes) ... ok +test_changement_apres_capture_canonique_refuse_avant_deplacement (test_path_stability.PathTests.test_changement_apres_capture_canonique_refuse_avant_deplacement) ... ok +test_guard_refuse_les_divergences_avant_tout_ipc (test_path_stability.PathTests.test_guard_refuse_les_divergences_avant_tout_ipc) ... ok +test_ack_requires_verified_current_transaction (test_phase3b.DeploymentTests.test_ack_requires_verified_current_transaction) ... ok +test_limusic_never_launched (test_phase3b.DeploymentTests.test_limusic_never_launched) ... ok +test_async_mapping_completes_before_apply_and_focus_proof (test_prewarm.PrewarmTests.test_async_mapping_completes_before_apply_and_focus_proof) ... ok +test_deferred_marker_and_cli_preserve_cause_for_explicit_retry (test_prewarm.PrewarmTests.test_deferred_marker_and_cli_preserve_cause_for_explicit_retry) ... ok +test_existing_required_journal_refuses_before_launch (test_prewarm.PrewarmTests.test_existing_required_journal_refuses_before_launch) ... ok +test_focus_change_after_proof_refuses_without_publication (test_prewarm.PrewarmTests.test_focus_change_after_proof_refuses_without_publication) ... ok +test_intruder_extra_identity_session_and_owner_refuse_without_publication (test_prewarm.PrewarmTests.test_intruder_extra_identity_session_and_owner_refuse_without_publication) ... ok +test_launch_failure_preserves_clients_and_retry_does_not_duplicate (test_prewarm.PrewarmTests.test_launch_failure_preserves_clients_and_retry_does_not_duplicate) ... ok +test_missing_managed_autostart_refuses_before_launch (test_prewarm.PrewarmTests.test_missing_managed_autostart_refuses_before_launch) ... ok +test_missing_collision_and_live_publisher (test_provider.ProviderTests.test_missing_collision_and_live_publisher) ... ok +test_capture_is_deterministic_for_a_stable_tree (test_scratchpad.ScratchpadTests.test_capture_is_deterministic_for_a_stable_tree) ... ok +test_capture_store_reload_and_no_internal_workspace (test_scratchpad.ScratchpadTests.test_capture_store_reload_and_no_internal_workspace) ... ok +test_change_between_reads_and_ambiguous_focus_refuse (test_scratchpad.ScratchpadTests.test_change_between_reads_and_ambiguous_focus_refuse) ... ok +test_empty_focus_workspace_is_persisted (test_scratchpad.ScratchpadTests.test_empty_focus_workspace_is_persisted) ... ok +test_group_ancestor_is_not_admitted_by_leaf_identity (test_scratchpad.ScratchpadTests.test_group_ancestor_is_not_admitted_by_leaf_identity) ... ok +test_hidden_focus_is_rejected_before_command (test_scratchpad.ScratchpadTests.test_hidden_focus_is_rejected_before_command) ... ok +test_initial_scratchpad_add_predicts_source_workspace_focus (test_scratchpad.ScratchpadTests.test_initial_scratchpad_add_predicts_source_workspace_focus) ... ok +test_journal_detects_identity_output_scratchpad_and_interruption (test_scratchpad.ScratchpadTests.test_journal_detects_identity_output_scratchpad_and_interruption) ... ok +test_layer_shell_can_leave_no_sway_focus (test_scratchpad.ScratchpadTests.test_layer_shell_can_leave_no_sway_focus) ... ok +test_legacy_journal_not_reinterpreted (test_scratchpad.ScratchpadTests.test_legacy_journal_not_reinterpreted) ... ok +test_multiple_focused_nodes_are_still_refused (test_scratchpad.ScratchpadTests.test_multiple_focused_nodes_are_still_refused) ... ok +test_runtime_visibility_assignment_never_exposes_hidden_peer (test_scratchpad.ScratchpadTests.test_runtime_visibility_assignment_never_exposes_hidden_peer) ... ok +test_shown_and_multiple_hidden (test_scratchpad.ScratchpadTests.test_shown_and_multiple_hidden) ... ok +test_strict_versions_and_scratchpad_references (test_scratchpad.ScratchpadTests.test_strict_versions_and_scratchpad_references) ... ok +test_checkpoint_failed_validation_preserves_old (test_unit.BackendTests.test_checkpoint_failed_validation_preserves_old) ... ok +test_checkpoint_permissions (test_unit.BackendTests.test_checkpoint_permissions) ... ok +test_cli_execute_required (test_unit.BackendTests.test_cli_execute_required) ... ok +test_cli_storage_checkpoint_and_startup_mock (test_unit.BackendTests.test_cli_storage_checkpoint_and_startup_mock) ... ok +test_coexistence_and_migration (test_unit.BackendTests.test_coexistence_and_migration) ... ok +test_command_injection (test_unit.BackendTests.test_command_injection) ... ok +test_counts (test_unit.BackendTests.test_counts) ... ok +test_exact_inverted (test_unit.BackendTests.test_exact_inverted) ... ok +test_interchangeable_best_effort (test_unit.BackendTests.test_interchangeable_best_effort) ... ok +test_intermediate_directory_permissions (test_unit.BackendTests.test_intermediate_directory_permissions) ... ok +test_json_schema_matches_fixture (test_unit.BackendTests.test_json_schema_matches_fixture) ... ok +test_json_strict (test_unit.BackendTests.test_json_strict) ... ok +test_launch_policy (test_unit.BackendTests.test_launch_policy) ... ok +test_lock (test_unit.BackendTests.test_lock) ... ok +test_multi_output_preflight_synthetic (test_unit.BackendTests.test_multi_output_preflight_synthetic) ... ok +test_native_strict (test_unit.BackendTests.test_native_strict) ... ok +test_paths_links (test_unit.BackendTests.test_paths_links) ... ok +test_plan_pure (test_unit.BackendTests.test_plan_pure) ... ok +test_references (test_unit.BackendTests.test_references) ... ok +test_report_rejects_private_fields_and_bool_version (test_unit.BackendTests.test_report_rejects_private_fields_and_bool_version) ... ok +test_resume_attempts_all_owned_helpers (test_unit.BackendTests.test_resume_attempts_all_owned_helpers) ... ok +test_schema_exact (test_unit.BackendTests.test_schema_exact) ... ok +test_types_version_and_identity (test_unit.BackendTests.test_types_version_and_identity) ... ok +test_unsupported_states (test_unit.BackendTests.test_unsupported_states) ... ok + +---------------------------------------------------------------------- +Ran 93 tests in 8.405s + +OK diff --git a/docs/validation/quickshell-dock-tela-polish-v2/shell.log b/docs/validation/quickshell-dock-tela-polish-v2/shell.log new file mode 100644 index 000000000..bd1ea7002 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/shell.log @@ -0,0 +1 @@ +Full shell private-compositor load: PASS /tmp/labfy-session-v2-TEST_ONLY-vx5tlv5i diff --git a/docs/validation/quickshell-dock-tela-polish-v2/unit.log b/docs/validation/quickshell-dock-tela-polish-v2/unit.log new file mode 100644 index 000000000..d935bbb78 --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/unit.log @@ -0,0 +1,11 @@ +test_inheritance_from_a_private_test_theme (test_shared.Icons.test_inheritance_from_a_private_test_theme) ... ok +test_tela_desktop_icon_and_absolute (test_shared.Icons.test_tela_desktop_icon_and_absolute) ... ok +test_nine_move_missing_anchor_and_empty (test_shared.Persistence.test_nine_move_missing_anchor_and_empty) ... ok +test_real_concurrent_processes_keep_all_additions_during_moves (test_shared.Persistence.test_real_concurrent_processes_keep_all_additions_during_moves) ... ok +test_toggle_is_atomic_and_does_not_depend_on_a_stale_ui_list (test_shared.Persistence.test_toggle_is_atomic_and_does_not_depend_on_a_stale_ui_list) ... ok +test_wayland_xwayland_scratchpad_and_explicit_focus (test_shared.Sway.test_wayland_xwayland_scratchpad_and_explicit_focus) ... ok + +---------------------------------------------------------------------- +Ran 6 tests in 0.735s + +OK diff --git a/docs/validation/quickshell-dock-tela-polish-v2/validation.json b/docs/validation/quickshell-dock-tela-polish-v2/validation.json new file mode 100644 index 000000000..7085b4b2c --- /dev/null +++ b/docs/validation/quickshell-dock-tela-polish-v2/validation.json @@ -0,0 +1,39 @@ +{ + "status": "PASS", + "base": "d4e2a0013e7a9452add80dddc110e036ebe4ee96", + "backendTests": { + "applications": 7, + "dock": 6, + "sessionV2": 93 + }, + "javascript": [ + "ApplicationsModel: PASS", + "Dock state and window models: PASS" + ], + "graphical": [ + "private Sway dock scenario", + "complete shell load", + "Session V2 and Keyring with dock" + ], + "keyring": { + "backend": 0, + "focus": 0, + "qml-unit": 0, + "qml-qt": 0, + "keyring-ui": 0, + "keyring-runtime": 0, + "scratchpad-runtime": 0, + "phase3b-ui": 0, + "p0-runtime": 0, + "path-runtime": 0, + "diff-check": 0 + }, + "finalChecks": [ + "git diff --check: PASS", + "git apply --check against unchanged main checkout: PASS", + "no Binding loop, assignment, ReferenceError or TypeError in final dock lab logs", + "main checkout git status --short: empty" + ], + "finalShellLab": "/tmp/labfy-session-v2-TEST_ONLY-ywdppzn5", + "activeSessionModified": false +} diff --git a/docs/validation/quickshell-dock-tela-polish-v2/zoom-light.png b/docs/validation/quickshell-dock-tela-polish-v2/zoom-light.png new file mode 100644 index 000000000..2d4fafb98 Binary files /dev/null and b/docs/validation/quickshell-dock-tela-polish-v2/zoom-light.png differ diff --git a/docs/validation/quickshell-dock-tela-polish-v2/zoom.png b/docs/validation/quickshell-dock-tela-polish-v2/zoom.png new file mode 100644 index 000000000..15e17fb52 Binary files /dev/null and b/docs/validation/quickshell-dock-tela-polish-v2/zoom.png differ diff --git a/quickshell/.config/quickshell/labfy-sway/dock/AutoHide.js b/quickshell/.config/quickshell/labfy-sway/dock/AutoHide.js index 8bd958885..7ba70c51d 100644 --- a/quickshell/.config/quickshell/labfy-sway/dock/AutoHide.js +++ b/quickshell/.config/quickshell/labfy-sway/dock/AutoHide.js @@ -17,5 +17,9 @@ function next(state, event, input) { } function influence(distance) { - return Math.max(0, 1 - Math.abs(distance) / 115); + // CONTRACT: 57 px resting pitch; a radius below 1.5 pitches affects + // at most the nearest slot and its immediate neighbours. Smoothstep has + // zero slope at both ends, avoiding a kink as an icon enters the halo. + const t = Math.max(0, 1 - Math.abs(distance) / 76); + return t * t * (3 - 2 * t); } diff --git a/quickshell/.config/quickshell/labfy-sway/dock/Dock.qml b/quickshell/.config/quickshell/labfy-sway/dock/Dock.qml index d25fd821d..45c7359e3 100644 --- a/quickshell/.config/quickshell/labfy-sway/dock/Dock.qml +++ b/quickshell/.config/quickshell/labfy-sway/dock/Dock.qml @@ -1,5 +1,6 @@ import QtQuick import QtQuick.Controls +import QtQuick.Effects import Quickshell import Quickshell.Wayland import "../applications" @@ -21,7 +22,7 @@ PanelWindow { WlrLayershell.keyboardFocus: WlrKeyboardFocus.None WlrLayershell.namespace: "labfy-sway-dock" color: "transparent" - implicitWidth: Math.max(96, Math.min(screen.width - 24, items.width + 28)) + implicitWidth: Math.max(96, Math.min(screen.width - 24, items.width + 52)) implicitHeight: 360 property string phase: "hidden" readonly property bool revealed: phase === "shown" || phase === "waiting" || phase === "held" @@ -96,27 +97,33 @@ PanelWindow { onHoveredChanged: { dock.reconcile(); if (!hovered) dock.pointerX = -1000; } onPointChanged: dock.pointerX = point.position.x } - Rectangle { - // Discreet local shadow, no screen capture or blur sampling. - x: 2; y: 34; width: parent.width - 4; height: 70 - radius: 26; color: Theme.shadow + // WHY: an analytic shadow needs neither a captured backdrop nor a + // moving blur source. Its geometry stays fixed throughout hover. + RectangularShadow { + x: 16; y: 43; width: parent.width - 32; height: 48 + radius: 20; blur: 24; spread: 2 + color: Qt.rgba(0, 0, 0, 0.32) } Rectangle { - x: 0; y: 29; width: parent.width; height: 70 - radius: 25 - color: Qt.rgba(Theme.base.r, Theme.base.g, Theme.base.b, Theme.highContrast ? 1 : 0.89) - border.color: Theme.strongBorder; border.width: 1 + x: 14; y: 36; width: parent.width - 28; height: 58 + radius: 20 + color: Qt.rgba(Theme.base.r, Theme.base.g, Theme.base.b, Theme.highContrast ? 0.94 : 0.16) + border.color: Qt.rgba(Theme.text.r, Theme.text.g, Theme.text.b, Theme.highContrast ? 0.5 : 0.09) + border.width: 1 } Flickable { id: viewport x: 12; y: 0; width: parent.width - 24; height: 105 - contentWidth: items.width; contentHeight: height + // CONTRACT: reserve visual overflow inside the clipped viewport, + // including at both scroll limits, for the 1.39x end icons. + contentWidth: items.width + 24; contentHeight: height clip: true interactive: dock.draggingId === "" boundsBehavior: Flickable.StopAtBounds ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AsNeeded } Row { id: items + x: 12 height: viewport.height spacing: 3 move: Transition { NumberAnimation { properties: "x"; duration: 110; easing.type: Easing.OutCubic } } @@ -128,29 +135,32 @@ PanelWindow { required property var modelData required property int index readonly property bool separator: index === dock.pinnedCount && dock.pinnedCount > 0 - readonly property real center: viewport.x + x + width / 2 - viewport.contentX - // WHY: measuring against the animated x/width feeds - // scale back into its own binding. Stable resting slots - // keep magnification deterministic and free of loops. - readonly property real baseCenter: viewport.x + index * 57 + 27 + readonly property real center: viewport.x + items.x + x + width / 2 - viewport.contentX + // INVARIANT: pointer influence uses fixed layout slots. + // Only the visual transform changes: Row, hit targets, + // window width and SVG raster size never follow hover. + readonly property real baseCenter: viewport.x + items.x + index * 57 + 27 + (index >= dock.pinnedCount && dock.pinnedCount > 0 ? 13 : 0) - viewport.contentX readonly property real growth: dock.revealed && bodyHover.hovered ? AutoHide.influence(baseCenter - dock.pointerX) : 0 - width: 54 + growth * 19 + (separator ? 13 : 0) + width: 54 + (separator ? 13 : 0) height: 105 - Behavior on width { NumberAnimation { duration: 95; easing.type: Easing.OutCubic } } Rectangle { visible: tile.separator x: 2; y: 45; width: 1; height: 32; color: Theme.strongBorder } ApplicationIcon { id: icon - width: 46 + tile.growth * 21; height: width + // WHY: ApplicationIcon derives sourceSize from width. + // Fixed dimensions avoid async SVG reload/fallback flashes. + width: 46; height: 46 x: (parent.width - width + (tile.separator ? 12 : 0)) / 2 - y: 83 - height + y: 37 + transformOrigin: Item.Bottom + scale: 1 + tile.growth * 0.39 + Behavior on scale { NumberAnimation { duration: 80; easing.type: Easing.OutCubic } } iconSource: tile.modelData.iconSource || "" opacity: dock.draggingId === tile.modelData.id ? 0.5 : 1 - Behavior on width { NumberAnimation { duration: 95; easing.type: Easing.OutCubic } } } Rectangle { anchors.horizontalCenter: icon.horizontalCenter diff --git a/sway/.config/sway/swayfx b/sway/.config/sway/swayfx index 033e54f25..99504c2f1 100644 --- a/sway/.config/sway/swayfx +++ b/sway/.config/sway/swayfx @@ -27,10 +27,11 @@ layer_effects "labfy-sway-bar" { corner_radius 4 } -# CONTRACT: only the dock's layer surface receives blur; no window rule or -# focus/restore policy is changed. Its transparent input strip stays clear. +# CONTRACT: dock glass uses a light tint and analytic QML shadow. Disabling +# backdrop blur avoids compositor blur work on every magnification frame. +# No window rule or focus/restore policy is changed. layer_effects "labfy-sway-dock" { - blur $bar_blur + blur disable blur_xray disable blur_ignore_transparent enable shadows disable diff --git a/tests/dock/headless.py b/tests/dock/headless.py index fb4833580..1414de75f 100644 --- a/tests/dock/headless.py +++ b/tests/dock/headless.py @@ -13,7 +13,7 @@ from headless import Lab from ipc_proxy import IpcProxy SOURCE = REPO / 'quickshell/.config/quickshell/labfy-sway' -ARTIFACTS = REPO / 'docs/validation/quickshell-dock-tela' +ARTIFACTS = REPO / 'docs/validation/quickshell-dock-tela-polish-v2' NINE = ['firefox.desktop', 'kitty.desktop', 'yazi.desktop', 'nvim.desktop', 'org.darktable.darktable.desktop', 'orca-slicer.desktop', 'org.freecad.FreeCAD.desktop', 'org.kde.digikam.desktop', 'AppFlowy.desktop'] @@ -23,8 +23,8 @@ class DockLab(Lab): super().__init__() self.config=self.directory/'dock-sway.conf' base=(REPO/'tests/session_v2/fixtures/headless.conf').read_text() - effects=(REPO/'sway/.config/sway/swayfx').read_text().split('# CONTRACT: only the dock')[1] - effects=effects[effects.index('layer_effects'):] + effects=(REPO/'sway/.config/sway/swayfx').read_text().split('layer_effects "labfy-sway-dock"')[1] + effects='layer_effects "labfy-sway-dock"'+effects self.config.write_text(base+'\noutput HEADLESS-1 bg #11111b solid_color\nset $bar_blur enable\n'+effects) def start(self, argv): if argv[0]==os.environ.get('LABFY_TEST_SWAY','sway'): @@ -49,6 +49,31 @@ ShellRoot { D.Dock { id: dock; modelData: Quickshell.screens[0] } PanelWindow { id: bar; implicitWidth: 100; implicitHeight: 30; anchors.top: true; color: "transparent" } LazyLoader { id: menu; active: false; A.ApplicationsMenu { barWindow: bar } } + // TEST_ONLY: one pointer move per animation frame avoids measuring IPC + // process startup instead of continuous production hover. These are Qt + // animation intervals, not hardware presentation timestamps. + FrameAnimation { + id: sweepFrames + property var intervals: [] + property real origin: 0 + property bool geometryChanged: false + property bool imageChanged: false + property var baseline: [] + running: false + onTriggered: { + if (currentFrame > 1) intervals.push(frameTime * 1000); + const cycle = (elapsedTime * 0.7) % 2; + input.mouseMove(dock.surfaceBody, 51 + 420 * (cycle <= 1 ? cycle : 2 - cycle), 70); + const tiles=Array.from(dock.contentItemRow.children).filter(t => t.modelData); + for (let i=0; i= 4.5) running=false; + } + } TestCase { id: input; name: "DockInput"; when: false } IpcHandler { target: "dockTest" @@ -64,10 +89,30 @@ ShellRoot { bodyY:dock.surfaceBody.y, width:dock.width, pointerX:dock.pointerX, tileWidth:dock.contentItemRow.children[0] ? dock.contentItemRow.children[0].width : 0, + tiles:Array.from(dock.contentItemRow.children).filter(t => t.modelData).map(t => ({ + x:t.x, width:t.width, growth:t.growth, scale:t.children[1].scale, + visualLeft:t.children[1].mapToItem(dock.contentItemRow.parent.parent,0,0).x, + visualRight:t.children[1].mapToItem(dock.contentItemRow.parent.parent,46,0).x, + iconWidth:t.children[1].width, imageStatus:t.children[1].children[0].status})), context:!!dock.contextEntry}); } + function startFrames(): void { + sweepFrames.intervals=[]; sweepFrames.origin=dock.width; + sweepFrames.baseline=Array.from(dock.contentItemRow.children).filter(t => t.modelData) + .map(t => ({x:t.x,width:t.width,status:t.children[1].children[0].status})); + sweepFrames.start(); + } + function frames(): string { + return JSON.stringify({running:sweepFrames.running, intervals:sweepFrames.intervals, + geometryChanged:sweepFrames.geometryChanged,imageChanged:sweepFrames.imageChanged}); + } function edge(): void { input.mouseMove(dock.edgeArea, dock.edgeArea.width/2, 2); } function body(): void { input.mouseMove(dock.surfaceBody, 35, 70); } + function sweep(x:real): void { input.mouseMove(dock.surfaceBody, x, 70); } + function scrollEnd(): void { + const v=dock.contentItemRow.parent.parent; v.contentX=Math.max(0,v.contentWidth-v.width); + } + function scrollStart(): void { dock.contentItemRow.parent.parent.contentX=0; } function leave(): void { input.mouseMove(dock.contentItem, 1, 1); } function menuToggle(id:string): void { if (!menu.active) menu.active=true; menu.item.toggleFavorite(id); } function dockToggle(id:string): void { A.FavoritesService.toggle(id); } @@ -120,8 +165,33 @@ ShellRoot { capture('closed') call('edge'); wait(lambda s:s['revealed']); time.sleep(.35) capture('open') + resting=call('state') call('body'); time.sleep(.3); zoom=call('state'); capture('zoom') - assert zoom['tileWidth']>54, zoom + lab.command('output HEADLESS-1 bg #aab4c8 solid_color') + time.sleep(.2); capture('zoom-light') + lab.command('output HEADLESS-1 bg #11111b solid_color') + assert zoom['tileWidth']==54 and zoom['tiles'][0]['scale']>1, zoom + assert zoom['tiles'][0]['visualLeft']>=0,zoom + # Exercise production hover across slot boundaries. Layout and image + # readiness must remain stable while visual transforms change. + samples=[] + for x in range(45, 480, 6): + call('sweep',x) + state=call('state') + assert state['phase']=='shown',state + assert state['width']==resting['width'],state + assert [(t['x'],t['width'],t['iconWidth']) for t in state['tiles']]==[(t['x'],t['width'],t['iconWidth']) for t in resting['tiles']],state + assert sum(t['growth']>0 for t in state['tiles'])<=3,state + assert [t['imageStatus'] for t in state['tiles']]==[t['imageStatus'] for t in resting['tiles']],state + samples.append({'pointerX':state['pointerX'],'scales':[t['scale'] for t in state['tiles']]}) + call('startFrames') + time.sleep(4.8) + frames=call('frames') + assert not frames['running'] and len(frames['intervals'])>30,frames + assert not frames['geometryChanged'] and not frames['imageChanged'],frames + intervals=sorted(frames['intervals']) + timing={'frames':len(intervals),'meanMs':sum(intervals)/len(intervals), + 'p95Ms':intervals[int((len(intervals)-1)*.95)],'maxMs':max(intervals)} call('leave'); wait(lambda s:s['phase']=='hidden') call('edge'); wait(lambda s:s['revealed']); time.sleep(.3) call('rightClick'); wait(lambda s:s['phase']=='held'); time.sleep(.7) @@ -199,6 +269,16 @@ ShellRoot { lab.command('output HEADLESS-1 mode 800x600') resized=wait(lambda s:s['screenWidth']==800) assert resized['width']<=776,resized + # Magnified end icons keep their visual margin at both scroll limits. + lab.command('output HEADLESS-1 mode 400x600') + wait(lambda s:s['screenWidth']==400) + call('edge'); wait(lambda s:s['revealed']); time.sleep(.3) + call('scrollEnd'); call('sweep',325); time.sleep(.15) + end=call('state') + assert end['tiles'][-1]['scale']>1 and end['tiles'][-1]['visualRight']<=end['width']-24,end + call('scrollStart'); call('sweep',51); time.sleep(.15) + start=call('state') + assert start['tiles'][0]['scale']>1 and start['tiles'][0]['visualLeft']>=0,start lab.command('output HEADLESS-1 mode 1280x720') wait(lambda s:s['screenWidth']==1280) # Existing empty state must stay empty, including a bridge restart. @@ -208,9 +288,9 @@ ShellRoot { process=lab.start(['quickshell','-p',str(qml)]) time.sleep(1) assert wait(lambda s:s['ready'])['ids']==[] - (ARTIFACTS/'result.json').write_text(json.dumps(dict(status='PASS',initial=initial, + (ARTIFACTS/'result.json').write_text(json.dumps(dict(status='PASS',initial=initial,hoverSamples=samples,animationTiming=timing,frameSweep=frames, reordered=reordered['ids'],checks=['shared favorites','menu and dock mutations','durable reorder', 'empty restart','autohide','context hold','kitty multi-window','floating scratchpad explicit focus', - 'window close','no hover focus','real pointer drag','zoom growth','IPC reconnect','Firefox private profile','desktop install/remove monitoring','external writer','keyboard menu navigation','resolution change','SwayFX dock blur rule']),indent=2)+'\n') + 'window close','no hover focus','real pointer drag','fixed layout transform hover', 'stable SVG readiness', 'lateral sweep 73 samples','IPC reconnect','Firefox private profile','desktop install/remove monitoring','external writer','keyboard menu navigation','resolution change','SwayFX dock blur disabled']),indent=2)+'\n') proxy.close() print('Dock headless: PASS',lab.directory) diff --git a/tests/dock/test_models.js b/tests/dock/test_models.js index 903ed765f..19f36fbe1 100644 --- a/tests/dock/test_models.js +++ b/tests/dock/test_models.js @@ -24,8 +24,15 @@ input.held=false; assert.equal(event(),'waiting'); assert.equal(event('deadline'),'hidden'); input.held=true; event(); input.suppressed=true; assert.equal(event(),'hidden'); assert.equal(hide.influence(0),1); -assert.ok(hide.influence(55)>hide.influence(100)); -assert.equal(hide.influence(115),0); +assert.ok(hide.influence(25)>hide.influence(55)); +assert.equal(hide.influence(76),0); +assert.equal(hide.influence(-76),0); +assert.equal(hide.influence(-35),hide.influence(35)); +for (let cursor=0; cursor<570; ++cursor) { + const affected=Array.from({length:10},(_,i)=>i).filter(i=>hide.influence(i*57-cursor)>0); + assert.ok(affected.length<=3); + assert.ok(affected.length===0 || affected.at(-1)-affected[0]<=2); +} const model=load('applications/WindowModel.js'); const apps=[{id:'kitty.desktop',aliases:['kitty'],iconSource:'file:///tela/kitty.svg'}, {id:'org.app.desktop',aliases:['startup-class','executable']},